dbsql

Table of Contents

dependency

ArchLinuxのdb5.3が、何につられて導入されたか? 専用のチェックコマンド が用意されてると思うんだけど、見つけられなかった 。ちょいと消極的かつ強引だけど、いきなりの暴挙に出る。

[sakae@arch ~]$ sudo pacman -R db5.3
checking dependencies...
error: failed to prepare transaction (could not satisfy dependencies)
:: removing db5.3 breaks dependency 'db5.3' required by perl

perlさんが必要としてるから、削除できませんと、拒否された。問題ないもの なら、

[sakae@arch ~]$ sudo pacman -R indent
[sudo] password for sakae:
checking dependencies...

Packages (1) indent-2.2.13-1

Total Removed Size:  0.46 MiB

:: Do you want to remove these packages? [Y/n] y
:: Running pre-transaction hooks...
(1/1) Removing old entries from the info directory file...
:: Processing package changes...
(1/1) removing indent                              [######################] 100%
:: Running post-transaction hooks...
(1/1) Arming ConditionNeedsUpdate...

こんな風に、淡々と処理が進むよ。安心したまえ。

c++ game

ゲームで学ぶ探索アルゴリズム実践入門

WindowsにWSLなウブンツを入れて、サンプルを動かす方針だけど、オイラーは、 OpenBSD上の、c++さ。

vbox$ c++ -O3 -std=c++17 00_MazeState.cpp

こんな風にコンパイルするらしい。コメントがちゃんとUTFになってるのは、 ウブのおかげか。 スタイルがオイラーの趣味ではないけど、ガマン。

盤面の図が多数掲載されているので非常にわかりやすい。タイマーを使って計 算を打ち切りにする方法が解説されててよかった。

Reading symbols from a.out...
(gdb) b randomAction(MazeState const&)
Breakpoint 1 at 0x6966: file 00_MazeState.cpp, line 127.
(gdb) r
Starting program: /tmp/sample_code/03_OnePlayerGame/a.out

Breakpoint 1, randomAction (state=...) at 00_MazeState.cpp:127
127         auto legal_actions = state.legalActions();
(gdb) bt
#0  randomAction (state=...) at 00_MazeState.cpp:127
#1  0x18eb3b06 in playGame (seed=121321) at 00_MazeState.cpp:141
#2  0x18eb3c2a in main () at 00_MazeState.cpp:147

gdbを走らせるのは、オイラーの性だな。

(gdb) set print pretty
(gdb) p state
$1 = (const State &) @0xcf7e9478: {
  static dx = {1, -1, 0, 0},
  static dy = <same as static member of an already seen type>,
  points_ = {{4, 6, 1, 3}, {0, 0, 2, 0}, {7, 5, 6, 6}},
  turn_ = 0,
  character_ = {
    y_ = 1,
    x_ = 1
  },
  game_score_ = 0
}

こういうデータなら、ちゃんと見えるけど、深い所の奴は不快な表示になるん だよなあ。やっぱり普通のC言語がいいな。

ガマンが臨界に逹っしたので整形しとく。リナで実施。

sakae@deb:~/src/gameAIsearch/03_OnePlayerGame$ for f in *.cpp
> do
> indent -kr $f
> done
sakae@deb:~/src/gameAIsearch/03_OnePlayerGame$ wc 00_MazeState.cpp /tmp/00_MazeState.cpp
 130  429 4450 00_MazeState.cpp
 148  440 3874 /tmp/00_MazeState.cpp

無駄なブラケットだけの行が無くなって、コンパクトになった。

The Kernighan & Ritchie style is used throughout their well-known  book
"The  C  Programming  Language".   It is enabled with the ‘-kr’ option.
The Kernighan & Ritchie style corresponds to the following set  of  op‐
tions:

     -nbad -bap -bbo -nbc -br -brs -c33 -cd33 -ncdb -ce -ci4 -cli0
     -cp33 -cs -d0 -di1 -nfc1 -nfca -hnl -i4 -ip0 -l75 -lp -npcs
     -nprs -npsl -saf -sai -saw -nsc -nsob -nss -par

Berkeley indent だと、-orig か。気にいったスタイルが決定したら、 $HOME/.indent.proに指定しとく。こういう論争を嫌って、gofmtとかが用意さ れてるんだな。あれ、gofmtは流用できないのかな? ダメダわさ。ガチガチに チャックしてるよ。まあ、あたりまえ。

それより、深刻な問題が*BSDのindentに内在してる。コメントが文字化けする んだ。下記はサンプルの一部。

[sakae@fb /tmp/sample_code/03_OnePlayerGame]$ cat 00_MazeState.cpp | head -2
// 一人ゲームの例
// 1ターンに上下左右四方向のいずれかに1マスずつ進む。

そして、整形結果もダンプ

[sakae@fb /tmp/sample_code/03_OnePlayerGame]$ hd 00_MazeState.cpp |head -2
00000000  2f 2f 20 e4 b8 80 e4 ba  ba e3 82 b2 e3 83 bc e3  |// .............|
00000010  83 a0 e3 81 ae e4 be 8b  0a 2f 2f 20 31 e3 82 bf  |.........// 1...|
[sakae@fb /tmp/sample_code/03_OnePlayerGame]$ hd aa |head -2
00000000  2f 2f 20 e4 b8 37 e4 ba  ba e3 82 b2 e3 83 bc e3  |// ..7..........|
00000010  83 a0 e3 81 ae e4 be 8b  0a 2f 2f 31 20 e3 20 82  |.........//1 . .|

いずれindentの動作を検証してみよう。それより、参考資料をみる方が、楽し いな。

じじいのプログラミング

chokudaiのブログ

sys/time.h of Linux

上では、リナに負けてしまったので、今度はBSDの優位性を強調してみる。 前回、時間計測で、リナには定義されていないBSDだけのマクロを使ってしまっ た。同等がどの程度実装されてるか確認。

# define TIMEVAL_TO_TIMESPEC(tv, ts) {                                   \
        (ts)->tv_sec = (tv)->tv_sec;                                    \
        (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
}
# define TIMESPEC_TO_TIMEVAL(tv, ts) {                                   \
        (tv)->tv_sec = (ts)->tv_sec;                                    \
        (tv)->tv_usec = (ts)->tv_nsec / 1000;                           \
}

# define timersub(a, b, result)                                               \
  do {                                                                        \
    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                             \
    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                          \
    if ((result)->tv_usec < 0) {                                              \
      --(result)->tv_sec;                                                     \
      (result)->tv_usec += 1000000;                                           \
    }                                                                         \
  } while (0)

timeval,timespecの相互変換が有って、timevalの減算も有るのに、timespec 版の減算が未定義。抜けてるな。

dbsql

try run

今回は、こんなデータを与えてみる。オイラーのパソコン遍歴の一部だ。

create table pc(mypc text, year integer);
insert into pc(mypc,year) values('MZ80K', 1979);
insert into pc(mypc,year) values('FM-11', 1983);
insert into pc(mypc,year) values('Macintosh SE', 1989);

起動する時、rlwrapをかませておくと、ヒストリーが使えて便利。

vbox$ rlwrap dbsql pc.db
dbsql> .headers on
dbsql> select * from pc;
mypc|year
MZ80K|1979
FM-11|1983
dbsql> insert into pc(mypc,year) values('Macintosh SE', 1989);
dbsql> select * from pc where year > 1980;
mypc|year
FM-11|1983
Macintosh SE|1989
dbsql> select * from pc where year < 1980;
mypc|year
MZ80K|1979
vbox$ ls -l pc.db*
-rw-r-----  1 sakae  wheel  32768 Mar 25 15:42 pc.db

pc.db-journal:
total 4516
-rw-r-----  1 sakae  wheel  3211264 Mar 25 15:42 __db.001
-rw-r-----  1 sakae  wheel   163840 Mar 25 15:42 __db.002
-rw-r-----  1 sakae  wheel    90112 Mar 25 15:42 __db.003
-rw-r-----  1 sakae  wheel       25 Mar 25 15:42 __db.register
-rw-r-----  1 sakae  wheel  2097152 Mar 25 15:42 log.0000000001
-rw-r--r--  1 sakae  wheel      117 Mar 25 15:19 sql-errors.txt

なんとオマケっぽい、ジャーナルdirが作成されて、その中に、色々なものが 格納されてる。多分削除しちゃっても動くんではなかろうか? 動いた。

メタコマンド

dbsql> .explain on
dbsql> select * from pc;
mypc  year
----  -------------
MZ80K  1979
FM-11  1983
Macintosh SE  1989

ヘッダー宜しく、列の説明が付いた。

dbsql> .stat :env:
Statistics for environment
Sat Mar 25 15:53:47 2023        Local time
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Default database environment information:
0x120897        Magic number
0       Panic value
5.3.28  Environment version
9       Btree version
9       Hash version
1       Lock version
19      Log version
4       Queue version
2       Sequence version
1       Txn version
:
0x3df06000      DB_ENV
4       ENV handle mutex [0/12 0% !Own]
/tmp/pc.db-journal      Home
DB_CREATE, DB_FORCE, DB_INIT_LOCK, DB_INIT_LOG, DB_INIT_MPOOL, DB_INIT_TXN, DB_R
DONLY, DB_THREAD, DB_TXN_NOSYNC Open flags
0660    Mode
56486   Pid cache
!Set    Lockfhp
!Set    Locker
 Set    Internal recovery table
240     Number of recovery table slots
:
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Primary REGINFO information:
Environment     Region type
1       Region ID
/tmp/pc.db-journal/__db.001     Region name
0x61030000      Region address
:
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Environment file handle information
/tmp/pc.db-journal/__db.register        file-handle.file name
0       file-handle.mutex [!Set]
0       file-handle.reference count
:
/tmp/pc.db-journal/__db.002     file-handle.file name
0       file-handle.mutex [!Set]
0       file-handle.reference count
:
/tmp/pc.db-journal/__db.003     file-handle.file name
0       file-handle.mutex [!Set]
0       file-handle.reference count
:
/tmp/pc.db-journal/../pc.db     file-handle.file name
1095    file-handle.mutex [0/0 0% !Own]
4       file-handle.reference count
:

この他に、.stat pc ってな具合に指定して、テーブルの情報も引きだせる。 意味はよく分からないけど。。

タイマーで実行時間も計測できます。

dbsql> .timer  on
dbsql> select count(*) from bld;
8155
CPU Time: user 0.060090 sys 0.087353
dbsql> select count(*) from bld;
8155
CPU Time: user 0.006173 sys 0.020307
dbsql> select avg(ppm) from bld;
58.1648068669528
CPU Time: user 0.008309 sys 0.023798

.import

.import FILE TABLE     Import data from FILE into TABLE

こんなメタコマンドが用意されてる。ファイルの形式は何の説明もないけど、 多分あれでしょう。そして昔やったsqlite3に習ってみると。

dbsql> .import bld.csv bld
Error: no such table: bld
dbsql> create table bld(ymd text, hi text, low text, ppm text);
dbsql> .import bld.csv bld
Error: bld.csv line 1: expected 4 columns of data but found 1
dbsql> .import bldsp bld
Error: bldsp line 1: expected 4 columns of data but found 1

カンマ区切りだ駄目ならスペース区切り、でも駄目だわさ。後はタブ区切り?

shell.c

1686  if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){
1687    char *zTable = azArg[2];    /* Insert data into this table */
1688    char *zFile = azArg[1];     /* The file from which to extract data */
1689    sqlite3_stmt *pStmt = NULL; /* A statement */

このあたりにBPかなあ、なんて思っていたら、こんな案内を発見。

".separator STRING      Change separator used by output mode and .import\n"

やってみる。

dbsql> .separator ','
dbsql> .import bld.csv bld
dbsql> select * from bld limit 3;
12010104,118,73,57
12010121,109,70,71
12010204,128,82,60

デケタ。

inside dbsql

やっぱりgdbだよな。 初回は、色々やるので大変。

#0  sqlite3VdbeExec (p=0x209cb0e8) at ../lang/sql/generated/sqlite3.c:53487
#1  0x0048e227 in sqlite3Step (p=0x209cb0e8)
    at ../lang/sql/generated/sqlite3.c:51781
#2  0x0048ddfd in sqlite3_step (pStmt=0x209cb0e8)
    at ../lang/sql/generated/sqlite3.c:51846
#3  0x00492dc8 in sqlite3_exec (db=0x20954008,
    zSql=0x20991cc8 "SELECT name, rootpage, sql FROM 'main'.sqlite_master ORDER BY rowid", xCallback=0x4c2ec0 <sqlite3InitCallback>, pArg=0xffbfda20,
    pzErrMsg=0x0) at ../lang/sql/generated/sqlite3.c:77454
:
#18 0x00493d81 in sqlite3_prepare_v2 (db=0x20954008,
    zSql=0x20953100 "select * from pc;", nBytes=-1, ppStmt=0xffbfe09c,
    pzTail=0xffbfe094) at ../lang/sql/generated/sqlite3.c:80916
#19 0x0046e655 in shell_exec (db=0x20954008,
    zSql=0x20953100 "select * from pc;", xCallback=0x46ea20 <shell_callback>,
    pArg=0xffbfe1c8, pzErrMsg=0xffbfe14c)
    at ../lang/sql/sqlite/src/shell.c:1092
#20 0x0046fd86 in process_input (p=0xffbfe1c8, in=0x0)
    at ../lang/sql/sqlite/src/shell.c:2515
#21 0x0046aa8f in main (argc=2, argv=0xffbfeb3c)
    at ../lang/sql/sqlite/src/shell.c:2946

こちらが本筋。

#0  sqlite3VdbeExec (p=0x209cb2a8) at ../lang/sql/generated/sqlite3.c:53487
#1  0x0048e227 in sqlite3Step (p=0x209cb2a8)
    at ../lang/sql/generated/sqlite3.c:51781
#2  0x0048ddfd in sqlite3_step (pStmt=0x209cb2a8)
    at ../lang/sql/generated/sqlite3.c:51846
#3  0x0046e756 in shell_exec (db=0x20954008,
    zSql=0x20953100 "select * from pc;", xCallback=0x46ea20 <shell_callback>,
    pArg=0xffbfe1c8, pzErrMsg=0xffbfe14c)
    at ../lang/sql/sqlite/src/shell.c:1120
#4  0x0046fd86 in process_input (p=0xffbfe1c8, in=0x0)
    at ../lang/sql/sqlite/src/shell.c:2515
#5  0x0046aa8f in main (argc=2, argv=0xffbfeb3c)
    at ../lang/sql/sqlite/src/shell.c:2946

コンパイルのログから、dbsqlqが構築される様子をぬきだした。

ar cr libdb_sql-5.3.a sqlite3.o db185.o mut_tas.o mut_pthread.o  ...
libtool: link: cc -g -o dbsql -pthread shell.o  libdb_sql-5.3.a -ldl -lpthread -pthread

核になるのは、リンクしてる物。何が違うかと調べたら。sqlite3のライブラ リィの有無だけだった。

[sakae@fb /tmp]$ diff DD SS
3c3,4
< libdb-5.3.a
---
> libdb_sql-5.3.a
> sqlite3.o

sqlite3.c/openDatabase()

/*
** Berkley DB customization!
** Register any Berkeley DB specific extension functions.
*/
add_sequence_functions(db);
/* End Berkeley DB customization. */

独自の拡張をやってるんだな。

int add_sequence_functions(sqlite3 *db)
{
        int rc;
        rc = sqlite3CreateFunc(db, "create_sequence", -1, SQLITE_ANY, 0,
            db_seq_create_func, 0, 0, 0);
        rc = sqlite3CreateFunc(db, "drop_sequence", -1, SQLITE_ANY, 0,
            db_seq_drop_func, 0, 0, 0);
        rc = sqlite3CreateFunc(db, "nextval", 1, SQLITE_ANY, 0,
            db_seq_nextval_func, 0, 0, 0);
        rc = sqlite3CreateFunc(db, "currval", 1, SQLITE_ANY, 0,
            db_seq_currval_func, 0, 0, 0);
        return (rc);
}

パーサーまで手を入れているんで、大変な事ですよ。

何で調べたかと言うと、bdbは既に優れたB木のシステムを持っている。ならば、 これを有効利用して、パーサーまでの部分をsqlite3から借用したものと想像 してたからだ。

Architecture of SQLite そう、この図のバックエンド部をバークレーDBが担 当してると思っていたのさ。どうやら違ったわい。なるべくsqliteを活用しま しょって方針なのね。


This year's Index

Home