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が出来そうか考えないとなあ・・・。