読者です 読者をやめる 読者になる 読者になる

Foreign Key制約とcascade

OSS/Linux

PostgreSQLにはForeign Keyの機能が実装されている。

これは実際には行トリガとして実装されており、テーブルのINSERT/UPDATE/DELETEが発生した際に、それらの操作で対象となったタプルが制約条件を満たすかどうかをチェックするため、個々のタプルに対して呼び出される。

これらの操作を実装するトリガ関数は内部的にSQL文を生成し、再帰的に問い合わせを実行する。実装を見てみると、驚いたことにSQL文の文字列を動的に生成して字句解析から順に実行している。

で、SE-PostgreSQLの場合これでは問題が発生する場合がある。
外部キー制約の CASCADE ルールを用いた場合、これは被参照側(主キー)が更新を行った場合に、参照側(外部キー)も同じ値に更新される。
この時、トリガ関数は UPDATE 文を生成して参照側のテーブルのうち対象のタプルを全て更新しようとするが、SE-PostgreSQLは入力されたクエリに強制的に検索条件(sepgsql_tuple_perm()関数)を追加して権限のないタプルを結果セットからフィルタリングする。
そのため、参照側テーブルの中にupdate権限のないタプルがあった場合には、参照側テーブルの一部だけCASCADEルールによって更新され、その他のタプルは更新不整合が発生してしまう。

このため、トリガの延長で実行される場合には、sepgsql_tuple_perm()関数ではなく、sepgsql_tuple_perm_abort()関数を強制的に付与するように変更した。
sepgsql_tuple_perm()関数は権限のないタプルに対して false を返し、これがwhere句の中に出現することで結果セットから権限のないタプルを排除するが、sepgsql_tuple_perm_abort()の場合は、権限のないタプルを見つけるとトランザクションをアボートする。

つまり、外部キーを利用する場合には、被参照側テーブルに対する権限も持っていなければならない。多少強めの規制かもしれないが、抜け穴があるよりはよっぽど良いだろう。

既にこの辺の細かな事まで考慮に入っているということで判るように、『未踏』の枠組みでのSE-PostgreSQLの開発は、順調に進行中。目指せ『スーパークリエーター』認定!