HTML5.JP

Ads

WHATWG - HTML5 Working Draft 日本語訳

4.11 クライアント側のデータベースストレージ

一部、直訳ではなく意訳した部分がございます。原文と表現が異なることがございますので、ご了承ください。この日本語訳は、私が理解を深めるために、自分なりに日本語化したものです。本日本語訳には、翻訳上の誤りがある可能性があります。したがって、内容について一切保証をするものではありません。正確さを求める場合には、必ず原文を参照してください。当方は、この文書によって利用者が被るいかなる損害の責任を負いません。もし誤りなどを見つけたら、当サイトのお問い合わせより連絡いただければ幸いです。

概要

HTML 5 で規定しているクライアントサイド・ストレージに関する仕様です。ブラウザー側に、SQL を使ってデータを蓄積したり検索することができるようになります。

日本語訳

HTML 5

Working Draft — 3 November 2007

4.11. クライアント側のデータベースストレージ

4.11.1. はじめに

...

4.11.2. データベース

origin はそれぞれに関連付けられたデータベースを持ちます。各データベースは、名前と現バージョンを持ちます。この API からドメイン用に利用可能なデータベースを列挙したり削除する方法は一切用意されていません。

各データベースは同時には一つのバージョンとなり、個々のデータベースが同時に別々のバージョンで存在することはありえません。バージョンは、製作者が追加的に、そして、非破壊的に、さらに、想定外にデータベースへ書き込みを行おうとするリスクのある古いコード(例えば、別のブラウザーウィンドウで)を実行することなしに、スキーマの変更ができるよう考えられています。

openDatabase() メソッドは Database オブジェクトを返します。このメソッドは4つの引数をとります。:データベース名、データベースバージョン、表示名、見積サイズです。見積サイズは、単位はバイトとなり、データベースに蓄積する予定のデータのサイズを表します。

もし指定されたデータベースのバージョンが空文字列ではなく、かつ、データベースがすでに存在しているもののバージョンが違っていた場合、このメソッドは INVALID_STATE_ERR 例外を発出しなければいけません。

そうでなければ、もし指定されたデータベースが空文字だったり、データベースがまだ存在していなかったり、データベースが存在しているものの openDatabase() メソッドに指定されたバージョンがデータベースと関連付けられている現バージョンと同じなら、このメソッドは Database オブジェクトを返さなければいけません。このオブジェクトは、メソッドが呼び出された Window オブジェクトの ブラウジングコンテキストアクティブドキュメントorigin と関連付けられたもので、指定された名前を持ったデータベースを表します。該当のデータベースが存在しない場合、このオブジェクトは最初に生成されなければいけません。

空文字列を含むすべての文字列は、有効なデータベース名です。データベース名は、大文字・小文字を区別します。

実装は、サポートする名前のセットにデータベース名をマッピングして(例えば、ハッシュアルゴリズムを使って)、すべての文字列のサブセットをデータベース名として対応しさえすれば、これをサポートすることができます。

ユーザーエージェントは、ユーザーエクスペリエンスを最適化するため、表示名と見積データベースサイズを使うことが求められます。例えば、ユーザーエージェントは、ユーザーに初期割り当てサイズを提示するため、見積サイズを使うことができます。こうすることで、それが何百メガバイトを使うと分かっているサイトに、これは先行投資であると宣言させることができるようになります。ユーザーエージェントは、割り当てサイズを増やすのに5メガバイトごとに許可を求めてユーザーにプロンプトを出さなくても良くなります。

interface Database {
  void transaction(in SQLTransactionCallback callback);
  void transaction(in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback);
  void transaction(in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback);

  readonly attribute DOMString version;
  void changeVersion(in DOMString oldVersion, in DOMString newVersion, in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback);
};

interface SQLTransactionCallback {
  void handleEvent(in SQLTransaction transaction);
};

interface SQLTransactionErrorCallback {
  boolean handleEvent(in SQLError error);
};

transaction() メソッドは、一つまたは二つの引数をとります。このメソッドは、呼び出されたら、すぐに返し、第一引数の transaction callback 、第二引数があれば error callback 、第三引数があれば success callback を使って、そして、preflight operationpostflight operation なしに、非同期に transaction steps を実行しなければいけません。

データベースが開かれたときのバージョンは、この Database オブジェクトの expected version です。expected version がない場合は、それは空文字列となります。 — どんなバージョンでも問題ありません。

version 属性は、取得時においては、データベースの現バージョンを返さなければいけません(Database オブジェクトの expected version とは対照的に)。

changeVersion() メソッドを使うことで、スクリプトから、自動的にバージョン番号を確かめたり、スキーマのアップデートと同時にバージョン番号を変更することができます。このメソッドは、呼び出されたら、すぐに返し、第三引数の transaction callback 、第四引数の error callback 、第五引数の success callback 、そして次に示す preflight operation を使って、transaction steps を実行しなければいけません。

  1. changeVersion() メソッドに指定された第一引数の値が、データベースの実際のバージョンと正確に一致しているかをチェックします。もし不一致なら、preflight operation は失敗となります。

... そして postflight operation は次の通りです。

  1. データベースの実際のバージョンを、changeVersion() メソッドに指定された第二引数の値に変更します。
  2. Database オブジェクトの expected version を、changeVersion() メソッドに指定された第二引数の値に変更します。

4.11.3. SQLステートメントを実行する

transaction() and changeVersion() メソッドは、SQLTransaction オブジェクトとともにコールバックを呼び出します。

typedef sequence<Object> ObjectArray;

interface SQLTransaction {
  void executeSql(in DOMString sqlStatement);
  void executeSql(in DOMString sqlStatement, in ObjectArray arguments);
  void executeSql(in DOMString sqlStatement, in ObjectArray arguments, in SQLStatementCallback callback);
  void executeSql(in DOMString sqlStatement, in ObjectArray arguments, in SQLStatementCallback callback, in SQLStatementErrorCallback errorCallback);
};

interface SQLStatementCallback {
  void handleEvent(in SQLTransaction transaction, in SQLResultSet resultSet);
};

interface SQLStatementErrorCallback {
  boolean handleEvent(in SQLTransaction transaction, in SQLError error);それとも、これらの引数はひっくり返しにすべきか? どちらにせよ、我々は何かとつじつまが合っていない。我々は何とつじつまを合わせるべきなのか?
};

executeSql(sqlStatement, arguments, callback, errorCallback) メソッドが呼び出されたら、ユーザーエージェントは次に挙げるアルゴリズムを実行しなければいけません。(このアルゴリズムは比較的に簡単ですが、実際に SQL を発行するわけではありません。— この処理の大半は実際には transaction steps の一環として処理されます。)

  1. QLTransactionCallback, SQLStatementCallback, or SQLStatementErrorCallback の実行中にこのメソッドが呼び出されなかったら、INVALID_STATE_ERR 例外を発出します。(SQLTransactionErrorCallback の中から呼び出し、それゆえに例外を発出します。SQLTransactionErrorCallback ハンドラーは、処理が失敗した時にだけ呼び出されます。そして、SQL ステートメントは失敗した処理に追加されることはありません。)
  2. このメソッドの第一引数 (sqlStatement) を、? 文字がステートメント内のリテラルの場所で使うことができるという点が例外的ですが、SQL ステートメントとして解析します。[SQL]

  3. arguments 配列内の同じ位置の引数の値で ? プレースホルダーを置き換えます。(最初の ? プレースホルダーは arguments 配列内の最初の値で置き換えられます。一般的に、n番目の ? プレースホルダーは arguments 配列内のn番目の値で置き換えられます。)

    第二引数が省略されたり null だった場合は、arguments 配列を空として扱います。

    その結果は、ステートメントと同じものになります。

  4. sqlStatement の構文が正しくない場合(リテラル部分での ? プレースホルダーの利用は除く)や、サポートされていない機能がステートメントで使われている場合(例えばセキュリティーの理由で)や、arguments 配列の要素数がステートメント内の ? プレースホルダーの数と一致しない場合や、それ以外の理由でステートメントが解析できない場合は、そのステートメントを bogus (偽物)として印付けします。
  5. SQLTransaction オブジェクトの生成元の Database オブジェクトが、空文字列でもデータベースの実際のバージョンでもない expected version を持っているなら、そのステートメントを bogus (偽物)として印付けします。 (Error code 2.)

  6. トランザクション内でそのステートメントをキューに溜めます。(もしあれば)第三引数をそのステートメントの結果セットコールバックとし、(もしあれば)第四引数をエラーコールバックとします。

ユーザーエージェントは、全くリソースのない完全に空の環境にデータベースがホスティングされていたかのように振舞わなければいけません。例えば、ファイルシステムから読み出しや書き込みを行おうとすると失敗します。

ユーザーエージェントは、各 origin 用に許可された領域の総量を制限すべきです。しかし、データベースが容量制限に達したら、ユーザーにプロンプトを表示し、上限を拡張しても構いません。ユーザーエージェントは、各データベースがどれくらいの容量を使っているのか、ユーザーが分かるようにすべきです。

通常は、origin ごとに5メガバイトの任意制限が推奨されます。実装に関するフィードバックは歓迎です。将来的にはフィードバックを参考にして、この提案が更新されるでしょう。

SQL は、本質的には、多重並列接続をサポートします。製作者は、複数のスクリプトが同時に同じデータベースに作用する場合(同じページが2つの異なる ブラウジングコンテキスト で開かれたときに起る可能性があります。)を取り扱うために、トランザクション機能を適切に利用すべきです。

ユーザーエージェントは、BEGIN, COMMIT, ROLLBACK SQL 機能を使うステートメントを、サポートされていないものとみなさなければいけません(それゆえに、それらを bogus として印付けします)。これらのステートメントが、データベース API 自身によって管理されている明示的なトランザクションを妨げないようにします。

本仕様の将来版で、より詳細に正確な SQL サブセットの要件を定義するでしょう。

4.11.4. データベース問い合わせ結果

executeSql() メソッドは、引数として SQLResultSet オブジェクトを使ってコールバックを呼び出します。

interface SQLResultSet {
  readonly attribute int insertId;
  readonly attribute int rowsAffected;
  readonly attribute SQLResultSetRowList rows;
};

insertId 属性は、ステートメントが行を挿入したなら、SQLResultSet オブジェクトの SQL ステートメントがデータベースに挿入された行の行 ID を返さなければいけません。もしステートメントが複数の行を挿入したなら、最後の行の ID が一つだけ返されなければいけません。もしステートメントが1行も挿入しなかったら、この属性は INVALID_ACCESS_ERR 例外を発出しなければいけません。

rowsAffected 属性は、SQL ステートメントによって影響を受けた行の数を返さなければいけません。もしステートメントが1行も影響を与えなかったなら、この属性はゼロを返さなければいけません。"SELECT" ステートメントでは、この属性はゼロを返します(データベースの問い合わせが行に影響を与えることはないため)。

rows 属性は、返された行を表す SQLResultSetRowList を返さなければいけません。これは、データベースによって返された順番となります。1行も返らなかった場合は、このオブジェクトは空になります。

interface SQLResultSetRowList {
  readonly attribute unsigned long length;
  DOMObject item(in unsigned long index);
};

SQLResultSetRowList オブジェクトは、それが表わす行の数(データベースによって返された行の数)を返さなければいけない length 属性を持ちます。

item(index) 属性は、指定されたインデックス index を使って行を返さなければいけません。該当する行がなければ、このメソッドは INDEX_SIZE_ERR 例外を発出しなければいけません。

各行は、native ordered dictionary データタイプによって表されなければいけません。ECMAScriptバインディングにおいては、これは Object でなければいけません。各行のオブジェクトは、カラムごとに一つのプロパティ(または辞書エントリ)を持たなければいけません。これらプロパティは、これらのカラムがデータベースによって返された順番で列挙されます。各プロパティは、データベースによって返されたとおりに、カラムの名前とセルの値を持たなければけません。

4.11.5. エラー

データベース API におけるエラーは、引数の一つに SQLError オブジェクトを持つコールバックを使って報告されます。

interface SQLError {
  readonly attribute unsigned int code;
  readonly attribute DOMString message;
};

code DOM 属性は、下表から最も適切なコードを返さなければいけません。

Code 状態
0 データベースには関係がない理由で処理が失敗しました。該当するエラーコードは他にはありません。
1 他のエラーコードに該当しないデータベース上の理由のため、ステートメントが失敗しました。
2 データベースの expected version が実際のデータベースバージョンと一致しないため、ステートメントが失敗しました。
3 データベースから返されたデータが大きすぎるため、ステートメントが失敗しました。SQL の "LIMIT" 修飾子が結果セットのサイズを低減するのに役に立つかもしれません。
4 ストレージ領域の残容量が足りないか、もしくは、ストレージ容量制限に達したが、ユーザーがデータベース領域の拡張を拒否したため、ステートメントが失敗しました。
5 トランザクションの最初のステートメントが読み取り専用のステートメントでしたが、同じトランザクションの後続のステートメントがデータベースを変更しようとしました。しかし、そのトランザクションは、もう一つのトランザクションが書き込みロックを取得する前に、書き込みロックの取得に失敗しました。そして、前者のトランザクションが依存していたデータベースの一部を変更しました。そのため、ステートメントが失敗しました。
6 制約違反により、INSERT, UPDATE, REPLACE ステートメントが失敗しました。例えば、行が挿入されようとしたけれども、主キーカラムに指定された値が現存の行の値と重複したことが原因です。

我々は、さらに完全なコードリストを定義すべきです。どのコードが必要とされるのかを決定するためにも、実装に関するフィードバックが求められます。

message DOM 属性は、直面したエラーを説明するエラーメッセージを返さなければいけません。このメッセージは、ユーザーの言語にローカライズされるべきです。

4.11.6. 処理モデル

transaction steps は次の通りです。これらのステップは非同期に実行されなければいけません。これらのステップは、transaction callback, error callback(オプション), success callback(オプション), preflight operation(オプション), postflight operation(オプション)で呼び出されます。

  1. データベースへ新規の SQL トランザクションを開始し、そのトランザクションを表す SQLTransaction オブジェクトを生成します。

  2. トランザクションの開始でエラーが発生したら、最後のステップへジャンプします。

  3. preflight operation が transaction steps のこのインスタンス用に定義されたら、それを実行します。失敗したら、最後のステップへジャンプします。(これは基本的には changeVersion() メソッド用のフックです。)

  4. 前述の SQLTransaction オブジェクトを唯一の引数として transaction callback を呼び出します。

  5. コールバックが呼び出せなかったら(例えば、それが null だった場合)、もしくは、コールバックが呼び出され例外を発出されたら、最後のステップへジャンプします。

  6. トランザクションのキューにステートメントが溜まっている間、トランザクションに溜まっている各ステートメントに対して、古いものから順に次のステップを実行します。各ステートメントは、一つのステートメント、一つの result set callback、一つの error callback(オプション)を持ちます。

    1. ステートメントが bogus として印付けされているなら、下記の "エラーの場合" へジャンプします。

    2. トランザクションのコンテキストでステートメントを実行します。 [SQL]

    3. ステートメントが失敗したら、下記の "エラーの場合" へジャンプします。

    4. ステートメントの結果を表す SQLResultSet オブジェクトを生成します。
    5. SQLTransaction オブジェクトを第一引数として、新規の SQLResultSet を第二引数として、ステートメントの result set callback を呼び出します。そして、
    6. コールバックが呼び出され、例外が発出されたら、全体ステップの最後のステップへジャンプします。

    7. もし次のステートメントがあれば次のステートメントに、または次のステートメントがなければ次の全体ステップへ移動します。

    エラーの場合(さらに厳密には、もし上記のサブステップが "エラーの場合" へジャンプする指示をしたなら)、次のサブステップを実行します。

    1. ステートメントが関連付けられた error callback を持つなら、SQLTransaction オブジェクトと、これらサブステップの実行を引き起こしたエラーを表す新規に構成された SQLError オブジェクトを2つの引数として、その error callback をそれぞれ呼び出します。
    2. error callback が false を返した場合、もし次のステートメントがあれば次のステートメントに、もし次のステートメントがなければ次の全体ステップに移動します。

    3. そうでなければ、error callback は false を返さなかったか、error callback が存在しなかったということになります。全体ステップの最後のステップへジャンプします。

  7. postflight operation がトランザクションステップのインスタンス用に定義されていたなら、それを実行します。失敗したら、最後のステップへジャンプします。(これは基本的には changeVersion() メソッド用のフックです。)

  8. トランザクションをコミットします。

  9. トランザクションのコミットでエラーが発生したら、最後のステップへジャンプします。

  10. success callback を呼び出します。

  11. これらのステップを終了します。次のステップは何か問題がある場合にだけ使います。

  12. このトランザクションで発生した最後のエラーを表す新規に構成された SQLError オブジェクトを使って、error callback を呼び出します。error callback が false を返し、最後のエラーがトランザクションコミット時の自身の失敗でないなら、 トランザクションコミットを試みます。もしそれに失敗したら、もしくは、コールバックを呼び出せなかったら(例えば、そのメソッドが一つだけの引数で呼び出された)、もしくは、それが false を返したら、トランザクションをロールバックします。トランザクションの未発行のステートメントは破棄されます。

4.11.7. プライバシー

globalStorage の機能とは対照的ですが、(管理された方法ではあるが)意図的に複数のドメイン、プロトコル、ポートからデータにアクセス可能としているこのデータベース機能は、データベースと同じ origin で実行するスクリプトに限定されます。 Thus, it is expected that the privacy implications be equivalent to those already present in allowing scripts to communicate with their originating host.

ユーザーエージェントは、クッキーの復活でこの機能を使うことのリスクを低減するためにも、ユーザーインタフェース上ではクッキーと同じ方法でデータベースに蓄積されたデータを取り扱うことが推奨されます。。

4.11.8. セキュリティー

4.11.8.1. ユーザーエージェント

ユーザーエージェントの実装は、セキュリティーの意味で、サポートするすべての SQL ステートメントを検査することが強く推奨されます。例えば、LOAD DATA INFILE はセキュリティーリスクをもたらしそうです。それをサポートする理由はほとんどありません。

一般的に、ユーザーエージェントは、データベースがディスク上にどうやって蓄積されるのかを制御する機能をサポートしないことが推奨されます。例えば、データのディスク表現に使われる文字エンコーディングをウェブ制作者がコントロールできるようにする理由はほとんどありません。ECMAScript のすべてのデータは暗黙的に UTF-16 なのですから。

4.11.8.2. SQL インジェクション

製作者は、executeSql() メソッドの ? プレースホルダー機能の利用が強く推奨されます。そして、決してオンザフライで SQL ステートメントを構成しないよう強く推奨されます。

サイト運営者情報 | プライバシーポリシー | 当サイトのご利用条件 | お問い合わせ | サイトマップ
Copyright © 2007-2011 Futomi Hatano (@futomi) All Rights Reserved.