diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 770c75fe2c..277e74b173 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2721,30 +2721,35 @@ CopyFrom(CopyState cstate) } else { + bool check_partition_constr; + /* - * 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. + * We must validate the partition constraint when copying + * directly into a partition, or when the tuple has been + * routed here and a BR trigger exists. Such a trigger could + * have changed the tuple so that it violates the partition + * constraint. If no such trigger exists then the correct + * partition has already been selected, so we can skip the + * check. */ - bool check_partition_constr = - (resultRelInfo->ri_PartitionCheck != NIL); - - if (saved_resultRelInfo != NULL && - !(resultRelInfo->ri_TrigDesc && - resultRelInfo->ri_TrigDesc->trig_insert_before_row)) + if (resultRelInfo->ri_PartitionCheck != NIL && + saved_resultRelInfo == NULL) + check_partition_constr = true; + else if (saved_resultRelInfo && resultRelInfo->ri_TrigDesc && + resultRelInfo->ri_TrigDesc->trig_insert_before_row) + check_partition_constr = true; + else check_partition_constr = false; /* - * If the target is a plain table, check the constraints of - * the tuple. + * Check the tuple is valid against all constraints, and the + * partition constraint, if required. */ if (resultRelInfo->ri_FdwRoutine == NULL && (resultRelInfo->ri_RelationDesc->rd_att->constr || check_partition_constr)) - ExecConstraints(resultRelInfo, slot, estate, true); + ExecConstraints(resultRelInfo, slot, estate, + check_partition_constr); if (useHeapMultiInsert) { diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index c4c841cdd7..555116c07f 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -367,15 +367,6 @@ ExecInsert(ModifyTableState *mtstate, WCOKind wco_kind; bool check_partition_constr; - /* - * 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. - */ - check_partition_constr = (resultRelInfo->ri_PartitionCheck != NIL); - /* * Constraints might reference the tableoid column, so initialize * t_tableOid before evaluating them. @@ -402,17 +393,30 @@ ExecInsert(ModifyTableState *mtstate, ExecWithCheckOptions(wco_kind, resultRelInfo, slot, estate); /* - * No need though if the tuple has been routed, and a BR trigger - * doesn't exist. + * We must validate the partition constraint when inserting directly + * into a partition, or when the tuple has been routed here and a BR + * trigger exists. Such a trigger could have changed the tuple so + * that it violates the partition constraint. If no such trigger + * exists then the correct partition has already been selected, so we + * can skip the check. */ - if (resultRelInfo->ri_PartitionRoot != NULL && - !(resultRelInfo->ri_TrigDesc && - resultRelInfo->ri_TrigDesc->trig_insert_before_row)) + if (resultRelInfo->ri_PartitionCheck != NIL && + !resultRelInfo->ri_PartitionRoot) + check_partition_constr = true; + else if (resultRelInfo->ri_PartitionRoot && + resultRelInfo->ri_TrigDesc && + resultRelInfo->ri_TrigDesc->trig_insert_before_row) + check_partition_constr = true; + else check_partition_constr = false; - /* Check the constraints of the tuple */ + /* + * Check the tuple is valid against all constraints, and the partition + * constraint, if required. + */ if (resultRelationDesc->rd_att->constr || check_partition_constr) - ExecConstraints(resultRelInfo, slot, estate, true); + ExecConstraints(resultRelInfo, slot, estate, + check_partition_constr); if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0) {