なかなか面白そうな機能だったので、ちょっと試してみました。情報源は、WebKitの開発ブログ「WebKit Dose HTML5 Client-side Database Storage」とサンプル「Notes Demo」です。
■データベースは「なに」を使っている?
「SQLite」です。
■データベースは「どうやって」確認する?
今、Safariが管理しているデータベースに関しては、メニューバー「Safari」→「環境設定」→「セキュリティ」→「データベースの表示」から確認する事が出来ます。また、ここからデータベースの削除を行う事もできます。
↑「データベースの表示」をクリックすると、データベースの一覧が表示される。「取り除く」を実行するとデータベースファイルが削除されます。(物理的に消えます)
■データベースは「いつ」作成されるのか?
これは、javascriptで「openDatabase()」が実行された時です。(これはSQLiteっぽいですね!)
■データベースは「どこ」にあるのか?
「~/Library/Safari/Databases」以下です。もう少し詳しく紹介すると、管理用のデータベース「~/Library/Safari/Databases/Databases.db」とドメイン毎に実データを格納するデータベースが存在します。例えば「Notes Demo」にアクセスしていた場合、「~/Library/Safari/Databases/http_webkit.org_0/0000000000000001.db」がデータベースの実体になります。(ファイル名は異なるかもしれません。)
という訳で、クライアント側のデータベースをクロスドメイン対応する事は、出来ない or 何らかのテクニックが必要になると思われます。
※このディレクトリ、ファイルはSafariが自動的に管理(作成、削除)されるので、利用するだけなら意識する必要ありません。一応、念のため。
■「Databases.db」ってどんなデータベース?
クライアント側のデータベースを管理するためのデータベースです。Safariで操作した時やjavascriptの「openDatabase()」を実行した時に更新されているようです。また、このデータベースには、テーブル「Databases」と「Origins」が含まれています。「Notes Demo」にアクセス済みの状態で、「.schema 〜」と「select * from 〜」を実行した結果をまとめてみました。
- 「Databases」のスキーマ
CREATE TABLE Databases(
guid INTEGER PRIMARY KEY AUTOINCREMENT,
origin TEXT,
name TEXT,
displayName TEXT,
estimatedSize INTEGER,
path TEXT
); - 「Databases」のデータ
1
http_webkit.org_0
NoteTest
HTML5 Database API example
200000
0000000000000001.db - メモ
- 「guid」は、オートインクリメントされる数値で、データベースのファイル名と関連しているようです。
- 「origin」は「(プロトコル)_(ドメイン名)_(ポート)」の書式です。また、ポートの指定が無い時は「0」となります。(80番の時に「0」になるのかも...)
- 「name」はデータベースの名前で、大文字、小文字は区別されます。
- 「displayName」はSafariの「データベースの表示」の「名前」として表示されます。
- 「estimatedSize」はまだよく分かっていません...。
- 「path」はデータベースのファイル名です。00...が付いて16桁になりますが、「guid」と同じ値です。
- 「Origins」のスキーマ
CREATE TABLE Origins (
origin TEXT UNIQUE ON CONFLICT REPLACE,
quota INTEGER NOT NULL ON CONFLICT FAIL
); - 「Origins」のデータ
http_webkit.org_0
10485760 - メモ
- 「origin」は「Databases」表の「origin」と同じデータ。ただし、制約が付けられているところをみると、コチラがマスターデータと思われます。
- 「quota」はSafariの「データベースを表示」→「最大サイズ」で設定した値が入る。データベースの容量制限に用いられる思われます。
■「0000000000000001.db」ってどんなデータベース?
クライアント側のデータベースです。ここに実データが格納されます。また、データを格納するテーブルとは別に「__WebKitDatabaseInfoTable__」が作成されます。これも管理用テーブルのようです。
- 「__WebKitDatabaseInfoTable__」のスキーマ
CREATE TABLE __WebKitDatabaseInfoTable__ (
key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,
value TEXT NOT NULL ON CONFLICT FAIL
); - 「__WebKitDatabaseInfoTable__」のデータ
WebKitDatabaseVersionKey
1.0
■JavaScriptからデータベースにアクセスする方法は?
「Notes Demo」のソースコードが参考になると思います。データベースの初期化処理、CRUD全てを網羅していて、サンプルとして非常によく出来ていると思いました。ポイントとなりそうな箇所をピックアップしてみました。
- データベースを開く処理(57行目〜64行目)
try {
if (window.openDatabase) {
db = openDatabase("NoteTest", "1.0", "HTML5 Database API example", 200000);
if (!db)
alert("Failed to open the database on disk. This is probably because the version was bad or there is not enough space left in this domain's quota");
} else
alert("Couldn't open the database. Please try with a WebKit nightly with this feature enabled");
} catch(err) { }
window.openDatabaseでクライアント側のデータベースを利用できるか判定しています。
openDatabae()の引数は左から、「データベース名」、「バージョン」、「ディスプレイ名」、「サイズ」です。データベースを開くには、「データベース名」だけでもOKです。その場合、ディスプレイ名などは「undefined」や「0」などが設定されます。(openDatabase()される時に管理情報が更新されています)例えば、Safariから管理する時にデータベースの名前が「undefined」と表示されてしまうので、実際には設定した方が良さそうです。 - データベースの初期化処理(287行目〜298行目)
function loaded()
{
db.transaction(function(tx) {
tx.executeSql("SELECT COUNT(*) FROM WebkitStickyNotes", [], function(result) {
loadNotes();
}, function(tx, error) {
tx.executeSql("CREATE TABLE WebKitStickyNotes (id REAL UNIQUE, note TEXT, timestamp REAL, left TEXT, top TEXT, zindex REAL)", [], function(result) {
loadNotes();
});
});
});
}
executeSql()の引数は、左から「SQL文」、「バインド変数の配列」、「コールバック関数」、「エラー発生時のコールバック関数」です。
初回アクセス時、SQL文「SELECT COUNT(*) ...」を実行しても、まだテーブルも作られていない状態なのでエラーが発生します。その場合、エラー発生時のコールバック関数が実行され、「CREATE TABLE ...」でテーブルが作成されるようになっています。 - データベースのCRUD
- C(INSERT文):230〜233行目db.transaction(function(tx) {
tx.executeSql("SELECT id, note, timestamp, left, top, zindex FROM WebKitStickyNotes", [], function(tx, result) {
for (var i = 0; i < result.rows.length; ++i) {
var row = result.rows.item(i);
var note = new Note();
note.id = row['id'];
note.text = row['note'];
note.timestamp = row['timestamp'];
note.left = row['left'];
note.top = row['top'];
note.zIndex = row['zindex'];
if (row['id'] > highestId)
highestId = row['id'];
if (row['zindex'] > highestZ)
highestZ = row['zindex'];
}
if (!result.rows.length)
newNote();
}, function(tx, error) {
alert('Failed to retrieve notes from database - ' + error.message);
return;
});
});
- U(UPDATE文):219〜222行目db.transaction(function (tx)
{
tx.executeSql("UPDATE WebKitStickyNotes SET note = ?, timestamp = ?, left = ?, top = ?, zindex = ? WHERE id = ?", [note.text, note.timestamp, note.left, note.top, note.zIndex, note.id]);
});
- D(DELETE文):178〜181行目
いずれも、executeSql()で実行されます。SQL文の「?」はバインド変数を意味します。また、「?」の出現位置と2番目の引数で渡される配列の位置がマッピングされます。db.transaction(function(tx)
{
tx.executeSql("DELETE FROM WebKitStickyNotes WHERE id = ?", [note.id]);
});
以上、Safari3.1の「Client-side Database Storage」に関して、調べた事をまとめてみました。まだ手探りな状態なので、推測ベースの情報が多く含まれています。その点はご了承下さい。
0 件のコメント:
コメントを投稿