Sqlite入門

SQLite入門してみた。

気になった関数メモ

気になった主要な関数を羅列する。

sqlite3_exec()

DBとSQL文を受け取って実行する。shell_execも同様にDBに対してSQLを実行する。 ただしcallbackが異なるとコメントに書かれていた。

shell_callback()

シェルに向けて表示している。p->modeで表示モードを切り分けている。 だいぶいろいろなモード(Line, Explain, Column, Semi, List, Html, Tcl, Csv, Insert, Ascii)が存在する。

sqlite3Prepare()

UTF-8で書かれたSQL文を実行ハンドラにコンパイルしている。

process_input()

コマンド群の入力を受け付けている。特にone_input_line()が1行文のコマンド入力を受け取っている。 そのためprocess_input()ではINTERACTIVEモードでプロンプトを出し分けたり エラーハンドリングを特別扱いするための処理を行ったりしていた。

do_meta_command()

.loadなど.で始まるコマンドの実行を担っている。

sqlite3RegisterGlobalFunctions()

SQLで使われる関数を登録する。 関数には色々(function, function2, vfunction, dfunction, aggregate, ..)な種類が色々ある。 sqlite3.c:11947 から各種定義と説明を読める。

したこと

動きの確認

configure && makeをするとカレント以下にsqlite3が作られた。 実行バイナリ本体は.libs以下にある。

1
$ gdb .libs/lt-sqlite3

よくわからないのでとりあえず、main()関数, read,writeシステムコールの3つにブレイクポイントを設定する。

123
b main
catch syscall read
catch syscall write

あとは動かす。

123
r ./test.data 'CREATE TABLE test (id int, text string, author string);'
// なんか止まったらスタックトレースを確認
bt

関数の引数でも最適化で消えてたりするみたい。読み書きが行われるタイミングで

1234567
#0  0x00007ffff7ba1690 in sqlite3VdbeList (p=<optimized out>) at sqlite3.c:68078
#1  sqlite3Step (p=<optimized out>) at sqlite3.c:5998
#2  sqlite3_step (pStmt=<optimized out>) at sqlite3.c:6064
#3  0x000000000040791a in shell_exec (db=0x613080,
.....
#4  0x00000000004030a8 in main (argc=<optimized out>, argv=<optimized out>)
    at /home/vagrant/src/bld/../SQLite-bda77dda/src/shell.c:4798

関数の呼び出し関係を俯瞰する

下を行って呼び出し関係を終えるようにするとだいぶ楽になる。ただしgraphvizが必要となる。 Doxygenの設定ファイルで生成する項目をちゃんと決めないと欲しい情報が出てくれない。

123456789
doxygen -g
vim Doxygen # 下に守勢する
EXTRACT_STATIC = YES
HAVE_DOT       = YES
CALL_GRAPH     = YES
CALLER_GRAPH   = YES

doxygen Doxygen
python -m SimpleHTTPServer

だいたいしたみたいが画像が全ての関数について手に入れられるしブラウザ上で探索できるので便利。

process\_input sqlite3Prepare

コードを読む

shell_exec()などが文字列としてSQL文を受け取っているのでどこかでパースやコンパイルしているはずと当たりをつけて中を追う。 またchar配列のSQL文が格納されたzSqlを引数に取るはずと想像して読むとsqlite3Prepareがみつかる。 コメントにはコンパイルすると書かれている。

この関数の中でsqlite3RunParser()が呼ばれており実際にコードを読むとパースしている。

sqlite3RunParser()./src/parse.cに書かれていて同ディレクトリにparse.y が存在するからコードジェネレートされていると予想した。

yaccを疑ったけれど動かない。lemonっぽい。 試してみたら動いたので当たりの気配がした。調べたら正しかった。 LALR(1)に対応したパーサージェネレータらしい。 lex + yaccよりオススメしている人もいるので調べてみても良さそう。

12
$ gcc -g -o lemon ./tool/lemon.c
$ ./lemon ../SQLite-a721fc0d/src/parse.y

拡張を使ってみる(fts5)

SQLite は拡張モジュールが使える仕組みになっている。 v3.9.0ではjson1,fts5 などの拡張が追加されている。

Compiling A Loadable Extensionを参考にビルド・ロードして使って見る。

12345678
gcc -g -lm -fPIC -shared fts4.c -o fts5.so
./sqlite3
>> .load fts5
>> CREATE VIRTUAL TABLE email USING fts5(sender, title, body);
>> INSERT INTO email ('masu_mi', 'test', 'test body');
>> INSERT INTO email ('masumi', 'test', 'find my iphone');
>> INSERT INTO email ('masumi', 'hoge', 'kick us');
>> SELECT * FROM email WHERE email MATCH 'kick';
comments powered by Disqus