かきすて

正しいかどうかよくわからない知識をよくわからないままとりあえず公開してみようというコンセプトで運営しています。

PL/pgSQLでパーティショニングしたテーブルにINSERTしたときROW_COUNTがとれない

PL/pgSQLでは

GET DIAGNOSTICS count = ROW_COUNT;

という感じの記述をすると、直前のクエリで影響を受けた行数をとることができる。
が、パーティショニングしてるテーブルにINSERTした場合、必ず0が入ってしまう。PostgreSQL9.1.12で確認。
親テーブルでなく、継承した子テーブルに直接INSERTすると、ちゃんととれる。

なぜとれないのか

たぶん、BEFORE INSERTのトリガでNULLを返してるから。

PostgreSQLでパーティショニングを実現するとき、親テーブルにBEFORE INSERTトリガを張って、適切な子テーブルに振り分け、親テーブルにデータが入ってしまわないようにNULLを返すようにすると良いよと、公式のドキュメントに書いてある。ので、今回この現象を確認したテーブルも、そういう実装にしていた。
https://www.postgresql.jp/document/9.3/html/ddl-partitioning.html

で、BEFORE INSERTでNULLを返したときの挙動はこんな感じらしい。

BEFOREとして発行された行レベルトリガがNULLを返す場合には、トリガマネージャに実際の行への操作を取りやめるように通知します(つまり、その後にトリガが発行されず、そのINSERT/UPDATE/DELETEはその行に対して実行されません)。

https://www.postgresql.jp/document/9.2/html/plpgsql-trigger.html

「行への操作を取りやめ」てるので、INSERTした行数が0ってことになるのだと思う。