PostgreSQLのユーザー定義型

2010.05.11 Author: Sinn

PostgreSQLのユーザー定義型を利用して、
内部で暗号化されたカラムを作成したので、その過程でハマったことを
覚書も兼ねて投稿しておきます。

1. 可変長データのサイズ設定

可変長データは、内部的に

/************************/
typedef struct
{
int4 sz; // 構造体の総サイズ
char val[1]; // データ格納位置(ダミー)
} EncryptedText
/************************/

のように表現されているのですが、

/************************/
EncryptedText a;
a.sz = 100;
/************************/

のように書くとNG。
この場合、専用のマクロを使って

/************************/
SET_VARSIZE(a, 100);
/************************/

としなければいけません。
また、ここで設定した値を取り出す場合も

/************************/
VARSIZE(a);
/************************/

とする必要があり、実際のデータ(val部分)にアクセスする場合も

/************************/
VARDATA(a);
/************************/

とします。全てマクロ経由でアクセスしないとダメということです。

2. 他で定義されている関数の呼び出し

今回は暗号化するということで、pg_cryptoモジュールで定義されている pgp_sym_encrypt/decryptを使用しましたが、これらのプロトタイプ宣言は

/************************/
Datum pgp_sym_encrypt(PG_FUNCTION_ARGS)
/************************/

となっています。pgp_sym_encryptの内部では

/************************/
bytea* pgp_sym_encrypt(const char *str, const char *pass, const char *cipher_algo);
/************************/

と同等なのですが、この形式で呼び出すことはできません。
なんとかして暗号化対象文字列をPG_FUNCTION_ARGS形式に変換する必要があるのですが、、
仕方なく、PostgreSQLのソースコードに潜ると・・・
こんなものがありました。

/************************/
Datum DirectFunctionCall3(関数ポインタ, Datum, Datum, Datum);
/************************/

Call3の部分は、渡す引数の数に応じて1~5まであります。
これを使えば、引数がPG_FUNCTION_ARGSで定義されている関数を呼び出すことができます。

3.メモリリーク対策

PostgreSQLのメモリ確保は、pallocを使用します。 これを使うと、1回のクエリ(トランザクション)終了時に使用していたメモリを解放してくれるので 基本的にメモリリークはありません。 ただし、戻り値以外の変数領域確保にpallocを使った場合は、ちゃんとpfreeで解放する必要があり ます。


次回は、作成したC言語関数を登録する際にハマったことを書く予定です。