SQLite3学習 ビルドオプション動作確認(SQLITE_ALLOW_URI_AUTHORITY)
URIが使えた。インメモリと同一プロセス内における共有もできた。
成果物
情報源
DB接続文字列
種類 | ファイル | メモリ | 共有メモリ |
---|---|---|---|
Path | /tmp/a.db | :memory: | 不可 |
URI | file:///tmp/a.db | file::memory: | file::memory:?cache=shared |
インタフェースごとの接続
接続 | CLI | Tcl |
---|---|---|
ファイル(path) | sqlite3 /tmp/a.db |
sqlite3 db /tmp/a.db |
ファイル(URI) | sqlite3 file:///tmp/a.db |
sqlite3 db file:///tmp/a.db -uri true |
メモリ | sqlite3 |
sqlite3 db :memory: |
共有メモリ(URI) | 不可 | sqlite3 db file::memory:?cache=shared -uri true |
共有メモリ(path) | 不可 | 不可sqlite3 db file::memory:?cache=shared -uri true |
SQLITE_ALLOW_URI_AUTHORITY
ファイルパスでなくURIでも参照できることを確認した。
$ sqlite3 file:///tmp/work/a.db ... sqlite> .tables sqlite> .exit $ ls a.db
インメモリ
インメモリにも使える。
CLI
$ sqlite3 file::memory: SQLite version 3.29.0 2019-07-10 17:32:03 Enter ".help" for usage hints. sqlite> create table AAA(id primary key, name text); sqlite> insert into AAA values(1, 'A'); sqlite> select * from AAA; 1|A sqlite> .exit $ ls (file::memory:という名のファイルが作成されていないことを確認)
Tcl
sqlite3 db_name file::memory: -uri true
shared
同一プロセス内なら共有できる。共有しないと接続するたびに別のDBとして扱われる。
rc = sqlite3_open("file::memory:?cache=shared", &db);
ATTACH DATABASE 'file::memory:?cache=shared' AS aux1;
上記のような記法となる。確かめてみる。
CLI(不可)
インメモリでAAA
テーブルを作成する。そしてテーブル名一覧を出力する。
$ sqlite3 file::memory:?cache=shared "create table AAA(id primary key, name text);" ".tables"; AAA
テーブル作成と一覧を別の接続に分けて、共有できるか確認してみる。
$ { sqlite3 file::memory:?cache=shared "create table AAA(id primary key, name text);"; sqlite3 file::memory:?cache=shared ".tables"; } (何も出力されず)
共有されていない。原因はおそらくsqlite3
コマンドを実行するとそれぞれ別プロセスになってしまうから。cache=shared
で共有できるのは同一プロセス内のみ。
Tcl(非共有)
SQLite3 Tclインターフェース
tclでSQLite3のDBファイルを作成・読込するにはsqlite3
コマンドを使う。
sqlite3 変数名 パス オプション
たとえば変数名とパスを指定するとそのDBファイルを開ける。なければ新規生成。
sqlite3 db_name /tmp/a.db
たとえばパスにURI機能を使って以下のように指定すると共有インメモリを使える。
sqlite3 db_name file::memory:?cache=shared -uri true
以下は共有しないとエラーになる。
- 接続1で
create table
する - 接続2で1のテーブルに対して
insert
するつもり - 2でテーブルが存在せずエラーとなる(接続ごとに別DBとして扱われるため)
in_memory.tcl
package require sqlite3 # db1とdb2は接続を共有していない! sqlite3 db1 file::memory: -uri true db1 eval { CREATE TABLE users (id INT,name TEXT) } sqlite3 db2 file::memory: -uri true # 共有してないのでusersテーブルが作成されておらずエラーになる! db2 eval { INSERT INTO users VALUES (1,'yamada') }
実行するとエラー。users
テーブルが存在しないのにinsert
しようとしたから。db1
とdb2
は別のDBとして扱われる。
$ tclsh in_memory.tcl
no such table: users while executing "db2 eval { INSERT INTO users VALUES (1,'yamada') }" (file "/tmp/work/Sqlite3.BuildOptions.SQLITE_ALLOW_URI_AUTHORITY.20190805092444/src/in_memory.tcl" line 7)
まあ、この場合は同じ接続を使えばいいだけなんだけど。
DBを共有するクエリが?cache=shared
。ためしてみる。
Tcl(共有)
tclでSQLite3のDBファイルを作成・読込するにはsqlite3
コマンドを使う。
sqlite3 変数名 パス オプション
パスにURI機能を使って以下のように指定すると共有インメモリを使える。
sqlite3 db_name file::memory:?cache=shared -uri true
試してみる。
$ vim sqlite.tcl
sqlite.tcl
package require sqlite3 sqlite3 db1 file::memory:?cache=shared -uri true db1 eval { CREATE TABLE users (id INT,name TEXT) } sqlite3 db2 file::memory:?cache=shared -uri true db2 eval { INSERT INTO users VALUES (1,'yamada') } set resultset [db1 eval { SELECT * FROM users }] foreach row $resultset { puts $row } set resultset [db2 eval { SELECT * FROM users }] foreach row $resultset { puts $row } db1 close db2 close
実行。
$ tclsh sqlite.tcl 1 yamada 1 yamada
異なるDB接続db1
,db2
間で共有できていることがわかった。
shared
(名前付き)
以下のような記法になる。
rc = sqlite3_open("file:memdb1?mode=memory&cache=shared", &db);
ATTACH DATABASE 'file:memdb1?mode=memory&cache=shared' AS aux1;
確かめてみる。
Tcl
共有できた
$ vim sqlite_shared_name_1.tcl
sqlite_shared_name_1.tcl
package require sqlite3 sqlite3 db1 file:memdb1?mode=memory&cache=shared -uri true db1 eval { CREATE TABLE users (id INT,name TEXT) } sqlite3 db2 file:memdb1?mode=memory&cache=shared -uri true db2 eval { INSERT INTO users VALUES (1,'yamada') } set resultset [db1 eval { SELECT * FROM users }] foreach row $resultset { puts $row } set resultset [db2 eval { SELECT * FROM users }] foreach row $resultset { puts $row } db1 close db2 close
実行。できた。
$ tclsh sqlite_shared_name_1.tcl 1 yamada 1 yamada
だが、これだと名前無しのときと変わらない。名前付きは他のDBと区別できる点が優れている。そこを確認したい。
つまり、同一プロセス内にて2つ以上のDBを作り、各DBに対して2つ以上の接続をもたせ、共有できているかを確認する。そして各DBは区別されていることも確認する。
$ vim sqlite_shared_name_2.tcl
sqlite_shared_name_2.tcl
package require sqlite3 proc openInMem { db db_name } { sqlite3 $db file:$db_name?mode=memory&cache=shared -uri true } proc create { db tbl_name } { $db eval "CREATE TABLE $tbl_name (id INT,name TEXT);" } proc insert { db tbl_name } { $db eval "INSERT INTO $tbl_name VALUES (1,'yamada');" } proc show { db tbl_name } { set result [$db eval "SELECT * FROM $tbl_name;"] foreach row $result { puts $row } } openInMem dbA1 "memdbA" create dbA1 "AAA" openInMem dbA2 "memdbA" insert dbA2 "AAA" show dbA1 "AAA" show dbA2 "AAA" openInMem dbB1 "memdbB" create dbB1 "BBB" openInMem dbB2 "memdbB" insert dbB2 "BBB" show dbB1 "BBB" show dbB2 "BBB" # no such table #dbA1 eval { select * from BBB } #dbA2 eval { select * from BBB } #dbB1 eval { select * from AAA } #dbB2 eval { select * from AAA } dbA1 close dbA2 close dbB1 close dbB2 close
実行。できた。
$ tclsh sqlite_shared_name_2.tcl 1 yamada 1 yamada 1 yamada 1 yamada
上記では以下のことが確認できた。
- 同一プロセス内で接続を共有できた
- 名前が同じDBなら異なる接続であっても共有できる
- 名前が異なるDBとは区別される
- 名前を指定すれば任意のメモリDBへ接続できる
table | DB | 接続 |
---|---|---|
AAA |
memdbA |
dbA1 |
AAA |
memdbA |
dbA2 |
BBB |
memdbB |
dbB1 |
BBB |
memdbB |
dbB2 |
memdbA
, memdbB
という2種類のDBに、テーブルAAA
, BBB
を作った。各DBには一方の名前のテーブルしか存在しない。もしmemdbA
でBBB
テーブルを探したら存在せずno such table
エラーになる。上記コードのコメントアウトを解除して実行すると以下のようになる。
$ tclsh sqlite_shared_name_2.tcl
no such table: AAA
no such table: BBB
これで名前付きだとDBを区別することがわかった。
単に:memory:
だけでは「任意のメモリDB」へはアクセスできない。単一のメモリDBのみである。名前付きにすることで、別個のメモリDBを作ることができる。まあ、そんな用途がどれくらいあるかは知らないが。
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13
- bash 4.4.12(1)-release
- SQLite 3.29.0
$ uname -a Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux