gotchaModerate
Postgres: a data-modifying CTE does not see the side effects of triggers fired by a sibling CTE in the same statement
Viewed 0 times
data-modifying CTEsnapshottrigger side effectsWITH insertvalidation trigger
Error Messages
Problem
Inserting a parent row (e.g. a queue) and a child row that references it in one statement through WITH ... INSERT CTEs fails when a trigger on the parent maintains a lookup that the child's validation trigger reads (here an AFTER trigger that appends the new id to an allowed-options JSON list). The child's BEFORE trigger reads the lookup table and rejects the value as unknown, although the parent was inserted in the same statement.
Solution
Split the work into separate statements inside one transaction: insert the parent first (its triggers update the lookup), then insert the children in a second statement, which takes a new snapshot and sees the updated lookup. Do not rely on CTE ordering for trigger side effects; all sub-statements of one WITH share the same snapshot and cannot see each other's changes to tables, except through RETURNING.
Why
All sub-statements of a WITH query run with the same snapshot, so they cannot see each other's effects on the target tables; changes made by triggers of one CTE are invisible to triggers fired by another CTE of the same statement.
Gotchas
- RETURNING values of a CTE are visible to the next CTE, but rows written by triggers are not
- Wrapping both statements in BEGIN/COMMIT keeps the all-or-nothing behaviour
Revisions (0)
No revisions yet.