HOOKを試してみた
本業が一段落ついたので、以前から気になっていたHOOKの組み込みをやってみた。
HOOKの調査
HOOKってPostgreSQL文書にもきちんと書いていないような気がするんだけど、幸いcontribでHOOKを使った実装例
- contrib/auth_delay
- contrib/auto_explain
- contrib/pg_stat_statements
- contrib/passwordcheck
がいくつもあるので、それを元にちょっと勉強がてら試してみよう。
今回はとっつきやすそうなExecutorの開始(ExecutorStart_hook)と終了(ExecutorFinish_hook)にHOOKをかけて、elog()でメッセージを出すだけのものを作ってみる。
このHOOKなるものがどうやって呼ばれているのかも気になったので、PostgreSQLのソースを探してみたけど、どうやら src/backend/executor/execMain.c の中でHOOKの呼び出しをやっているっぽい(Finishもほぼ同じ)。
void ExecutorStart(QueryDesc *queryDesc, int eflags) { if (ExecutorStart_hook) (*ExecutorStart_hook) (queryDesc, eflags); else standard_ExecutorStart(queryDesc, eflags); }
ExecutorStart_hook がNULLならstandard_ExecutorStart()を呼び出して、NULLじゃない(関数ポインタが設定されている?)なら、ExecutorStart_hookに設定した関数を呼び出すようだ。
なので、自作HOOK関数内で、自作コードを実行した後に、standard_ExecutorStart()を呼ばないと切ないこと(PostgreSQLのExectorが動かない)になるんだな。
実装
ということで、こんな感じで実装してみた。
/*------------------------------------------------------------------------- * exec.c *------------------------------------------------------------------------- */ #include "postgres.h" #include "executor/executor.h" PG_MODULE_MAGIC; extern void _PG_init(void); extern ExecutorStart_hook_type ExecutorStart_hook ; extern ExecutorFinish_hook_type ExecutorFinish_hook; /* * myExecutorStart_hook */ static void myExecutorStart_hook(QueryDesc *queryDesc, int eflags) { elog(NOTICE, "エグゼQ太 ハジマタ\(^o^)/"); standard_ExecutorStart(queryDesc, eflags); // 本来のExecutorのエントリ } /* * myExecutorFinish_hook */ static void myExecutorFinish_hook(QueryDesc *queryDesc) { elog(NOTICE, "エグゼQ太 オワタ\(^o^)/"); standard_ExecutorFinish(queryDesc); // 本来のExecutorのエントリ } /* * Module initialization function */ void _PG_init(void) { /* activate hook module is loaded */ ExecutorStart_hook = myExecutorStart_hook; ExecutorFinish_hook = myExecutorFinish_hook; }
これを make; make install して myexechook.so という共有ライブラリを作成して
実行
このHOOKをPostgreSQLに組み込むために、 postgresql.conf に以下のエントリを追加する。
shared_preload_libraries = 'myexechook'
これで、PostgreSQLを起動。
すると起動メッセージに共有ライブラリの組み込みのメッセージが出力される。組み込み完了!
$ pg_ctl start -D ~/pgdata/ server starting LOG: loaded library "myexechook" LOG: database system was shut down at 2012-10-30 17:11:10 JST LOG: autovacuum launcher started LOG: database system is ready to accept connections
PostgreSQLが起動したので、psqlからテキトーにSQLを実行してみる。
$ psql postgres psql (9.2.1) Type "help" for help. postgres=# SELECT 1; NOTICE: エグゼQ太 ハジマタ\(^o^)/ NOTICE: エグゼQ太 オワタ\(^o^)/ ?column? ---------- 1 (1 row)
elog()が出力されたので、HOOK関数経由でExecutorが呼ばれたことが確認できた。
今後は、各HOOK関数の引数の中を吟味して、どういうイケてるHOOKが出来そうか考えないとなあ・・・。