mirror of
https://github.com/postgres/postgres.git
synced 2025-06-27 23:21:58 +03:00
Prevent BEFORE triggers from violating partitioning constraints.
Since tuple-routing implicitly checks the partitioning constraints
at least for the levels of the partitioning hierarchy it traverses,
there's normally no need to revalidate the partitioning constraint
after performing tuple routing. However, if there's a BEFORE trigger
on the target partition, it could modify the tuple, causing the
partitioning constraint to be violated. Catch that case.
Also, instead of checking the root table's partition constraint after
tuple-routing, check it beforehand. Otherwise, the rules for when
the partitioning constraint gets checked get too complicated, because
you sometimes have to check part of the constraint but not all of it.
This effectively reverts commit 39162b2030
in favor of a different approach altogether.
Report by me. Initial debugging by Jeevan Ladhe. Patch by Amit
Langote, reviewed by me.
Discussion: http://postgr.es/m/CA+Tgmoa9DTgeVOqopieV8d1QRpddmP65aCdxyjdYDoEO5pS5KA@mail.gmail.com
This commit is contained in:
@ -414,6 +414,16 @@ ExecInsert(ModifyTableState *mtstate,
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* We always check the partition constraint, including when the tuple
|
||||
* got here via tuple-routing. However we don't need to in the latter
|
||||
* case if no BR trigger is defined on the partition. Note that a BR
|
||||
* trigger might modify the tuple such that the partition constraint
|
||||
* is no longer satisfied, so we need to check in that case.
|
||||
*/
|
||||
bool check_partition_constr =
|
||||
(resultRelInfo->ri_PartitionCheck != NIL);
|
||||
|
||||
/*
|
||||
* Constraints might reference the tableoid column, so initialize
|
||||
* t_tableOid before evaluating them.
|
||||
@ -431,9 +441,16 @@ ExecInsert(ModifyTableState *mtstate,
|
||||
resultRelInfo, slot, estate);
|
||||
|
||||
/*
|
||||
* Check the constraints of the tuple
|
||||
* No need though if the tuple has been routed, and a BR trigger
|
||||
* doesn't exist.
|
||||
*/
|
||||
if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck)
|
||||
if (saved_resultRelInfo != NULL &&
|
||||
!(resultRelInfo->ri_TrigDesc &&
|
||||
resultRelInfo->ri_TrigDesc->trig_insert_before_row))
|
||||
check_partition_constr = false;
|
||||
|
||||
/* Check the constraints of the tuple */
|
||||
if (resultRelationDesc->rd_att->constr || check_partition_constr)
|
||||
ExecConstraints(resultRelInfo, slot, estate);
|
||||
|
||||
if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
|
||||
|
Reference in New Issue
Block a user