やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

SQLite3ドットコマンド(.databases)

 接続中のDBを一覧する。

成果物

.help

.databases               List names and files of attached databases

.databases

インメモリ

sqlite3 :memory: ".databases"
main: 

ファイル

sqlite3 A.db ".databases"
main: /tmp/work/A.db

attach

sqlite3 :memory: \
"attach database 'A.db' as 'A';" \
".databases"
main: 
A: /tmp/work/Sqlite3.DotCommand.clone.20190819072205/A.db
DB保存パス DB名
:memory: main
A.db A

特殊なDB名

 以下のDB名は予約されているためattachas句で使えない。

DB名 概要
main sqlite3の第一引数で開いたDBの名前
temp 一時テーブルや一時データオブジェクトを保持するDBの名前

 使うとエラーが出る。

sqlite3 :memory: \
"attach database 'A.db' as 'temp';" \
".databases"
Error: database temp is already in use
sqlite3 :memory: \
"attach database 'A.db' as 'main';" \
".databases"
Error: database main is already in use

mainの名前を変更したい

 その方法は見つけられなかった。代案としてインメモリをmainとしてattachする方法を提案する。

 期待値は以下。

保存パス DB名
A.db A
B.db B

 テスト用DBファイル作成。

sqlite3 A.db ".exit"
sqlite3 B.db ".exit"

 attachして名前を付ける。

sqlite3 :memory: \
"attach database 'A.db' as 'A';" \
"attach database 'B.db' as 'B';" \
".databases"
main: 
A: /tmp/work/A.db
B: /tmp/work/B.db

名前付きインメモリ

 以下の2パターンのみ可能。

  • 同一インメモリDBとして共有する(テーブル結合可)
  • 異なるインメモリDBとしてテーブル結合できず

 以下はできない。

  • 異なるインメモリDBとしてattachする

 インメモリDBは通常、1プロセス内に1つだけ作成できる。また、シェルでsqlite3 :memory:コマンドを実行する際も1プロセス内になる。よってインメモリDBを同一プロセス内に2つ以上作ることはできないため、区別する必要もない。区別のために名付ける必要もない。

 ただし、Tclなどプログラムのコード内では、1つのプロセス内で複数のDBコネクションを持つことができる。このとき、インメモリDBを複数開くと、別々の無名インメモリDBとなる。これらはATTACH不可。

 もし異なるインメモリDBを作り、それらのテーブルを使いたいなら、URIパラメータfile:$db_name?mode=memory&cache=sharedを使えば可能。ただしインメモリDBは一つだけでありattach文のようにDB名を付与することは不可。同一DB内にあるものとして操作する。

名前付きインメモリの共有

 名前付きインメモリを共有するなら成功した。

named_memory_shared.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であるかのように区別することができない。

名前付きインメモリのattachは不可?

 ファイルが作成されてしまった。

package require sqlite3

#proc openInMem { db db_name } { sqlite3 $db file:$db_name?mode=memory&cache=shared -uri true }
proc openInMem { db db_name } { sqlite3 $db file:$db_name?mode=memory -uri true }
openInMem Main "Main"
openInMem Users "Users"
openInMem Items "Items"
Users eval { create table users(id integer primary key, name text, has text); }
Users eval { insert into users(name,has) values('Yamada','[1,2]'); }
Users eval { insert into users(name,has) values('Suzuki','[1]'); }
Users eval { insert into users(name,has) values('Tanaka','[]'); }
Items eval { create table items(id integer primary key, name text); }
Items eval { insert into items(name) values('おにぎり'); }
Items eval { insert into items(name) values('日の丸弁当'); }
Items eval { insert into items(name) values('たくあん'); }

set res [Users eval { select * from users; }]
puts $res
set res [Items eval { select * from items; }]
puts $res

Main eval { attach database Users as U; }
Main eval { attach database Items as I; }
set res [Main eval { pragma database_list; }]
puts $res

#Main eval { select * from U.users; }
#Main eval { select * from Users.users; }
#Main eval { select * from 2.users; }
#Main eval { select * from users; }
#Main eval { select json_each((select has from U.users where U.users.name='Yamada')); }

Items close
Users close
Main close
1 Yamada {[1,2]} 2 Suzuki {[1]} 3 Tanaka {[]}
1 おにぎり 2 日の丸弁当 3 たくあん
0 main {} 2 U /tmp/work/Users 3 I /tmp/work/Items

 attachできているように見える。だが、コメントアウトした以下のコードを実行すると「テーブルがない」エラーになる。

#Main eval { select * from U.users; }
no such table: U.users
    while executing
"Main eval { select * from U.users; }"
    (file "0.tcl" line 27)

 以下も同様。

Main eval { select * from Users.users; }
Main eval { select * from users; }

 以下に至っては解析不能.databasesの結果にidらしき数値が見えたので念のため試した。

Main eval { select * from 2.users; }
unrecognized token: "2.users"

 しかも実行するとUsers,Itemsファイルが作成されていた。もはやインメモリですらない。その原因はattach。これを実行したときにファイルが作成されるようだ。

  • インメモリDBを複数作ったら別々のDBになってしまう
    • cache=sharedすると統合される
      • 別名のDBとして扱うことはできない(select DbName.TableName.ColumnName;のようなDbName付与不可)
    • attachするとファイル化されてしまう

DB共有

named_memory_shared_2.tcl

package require sqlite3

proc openInMem { db db_name } { sqlite3 $db file:$db_name?mode=memory&cache=shared -uri true }
#proc openInMem { db db_name } { sqlite3 $db file:$db_name?mode=memory -uri true }
openInMem Main "Users"
openInMem Main "Items"

Main eval { create table users(id integer primary key, name text, has text); }
Main eval { insert into users(name,has) values('Yamada','[1,2]'); }
Main eval { insert into users(name,has) values('Suzuki','[1]'); }
Main eval { insert into users(name,has) values('Tanaka','[]'); }
Main eval { create table items(id integer primary key, name text); }
Main eval { insert into items(name) values('おにぎり'); }
Main eval { insert into items(name) values('日の丸弁当'); }
Main eval { insert into items(name) values('たくあん'); }

set res [Main eval { pragma database_list; }]
puts $res

set res [Main eval { select * from users; }]
puts $res
set res [Main eval { select * from items; }]
puts $res

set res [Main eval { select json_each.value from users u, json_each(u.has); }]
puts $res
set res [Main eval { select json_each.value from users u, json_each(u.has) where json_valid(u.has) and u.name='Yamada'; }]
puts $res
set res [Main eval { select name from items, (select json_each.value from users u, json_each(u.has) where json_valid(u.has) and u.name='Yamada') as has where has.value=items.id; }]
puts $res

Main close

 出力結果。

0 main {}
1 Yamada {[1,2]} 2 Suzuki {[1]} 3 Tanaka {[]}
1 おにぎり 2 日の丸弁当 3 たくあん
1 2 1
1 2
おにぎり 日の丸弁当

 最後の行に「おにぎり」「日の丸弁当」がある。これはYamadahasしていたitemsである。テーブルは共有された。

 念の為、DBファイルが出力されていないことを確認。

ls -1 | grep -e 'Main' -e 'Users' -e 'Items'



同一テーブル名ならどうなる?

同一変数名

named_memory_shared_3.tcl

package require sqlite3

proc openInMem { db db_name } { sqlite3 $db file:$db_name?mode=memory&cache=shared -uri true }
openInMem Main "Users"
openInMem Main "Items"

Main eval { create table users(id integer primary key, name text, has text); }
Main eval { create table users(id integer primary key, name text, has text); }
Main close
table users already exists
    while executing
"Main eval { create table users(id integer primary key, name text, has text); }"
    (file "named_memory_shared_4.tcl" line 9)

異なる変数名

named_memory_shared_4.tcl

package require sqlite3

proc openInMem { db db_name } { sqlite3 $db file:$db_name?mode=memory&cache=shared -uri true }
#proc openInMem { db db_name } { sqlite3 $db file:$db_name?mode=memory -uri true }
openInMem Users "Users"
openInMem Items "Items"

Users eval { create table users(id integer primary key, name text, has text); }
Items eval { create table users(id integer primary key, name text, has text); }
Users close
Items close



 エラーなし。あれ?

named_memory_shared_4_1.tcl

package require sqlite3

proc openInMem { db db_name } { sqlite3 $db file:$db_name?mode=memory&cache=shared -uri true }
#proc openInMem { db db_name } { sqlite3 $db file:$db_name?mode=memory -uri true }
openInMem Users "Users"
openInMem Items "Items"

Users eval { create table users(id integer primary key, name text, has text); }
Users eval { insert into users(name, has) values('A', '[1]'); }
Items eval { create table users(id integer primary key, name text, has text); }
Items eval { insert into users(name, has) values('B', '[2]'); }

set res [Users eval { select * from users; }]
puts $res
set res [Items eval { select * from users; }]
puts $res

Users close
Items close
tclsh named_memory_shared_4.tcl
1 A {[1]}
1 B {[2]}

 それぞれ別のDBとなり共有されず。

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux

前回まで