From 8d3a6e9474c9209ad8985998080f3d9ce3bd50b7 Mon Sep 17 00:00:00 2001 From: amit Date: Tue, 13 Dec 2016 15:07:41 +0900 Subject: [PATCH 4/7] Fix a bug of insertion into an internal partition. Since implicit partition constraints are not inherited, an internal partition's constraint was not being enforced when targeted directly. So, include such constraint when setting up leaf partition result relations for tuple-routing. Reported by: n/a Patch by: Amit Langote Reports: n/a --- src/backend/commands/copy.c | 1 - src/backend/commands/tablecmds.c | 1 - src/backend/executor/execMain.c | 41 ++++++++++++++++++++++++++++-------- src/include/executor/executor.h | 1 - src/test/regress/expected/insert.out | 6 ++++++ src/test/regress/sql/insert.sql | 5 +++++ 6 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index afbfb9f6e8..5aa4449e3e 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2429,7 +2429,6 @@ CopyFrom(CopyState cstate) InitResultRelInfo(resultRelInfo, cstate->rel, 1, /* dummy rangetable index */ - true, /* do load partition check expression */ NULL, 0); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3c08551d38..2e51124eb3 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1323,7 +1323,6 @@ ExecuteTruncate(TruncateStmt *stmt) InitResultRelInfo(resultRelInfo, rel, 0, /* dummy rangetable index */ - false, NULL, 0); resultRelInfo++; diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 6a82c18571..c991a18ce8 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -824,10 +824,10 @@ InitPlan(QueryDesc *queryDesc, int eflags) resultRelationOid = getrelid(resultRelationIndex, rangeTable); resultRelation = heap_open(resultRelationOid, RowExclusiveLock); + InitResultRelInfo(resultRelInfo, resultRelation, resultRelationIndex, - true, NULL, estate->es_instrument); resultRelInfo++; @@ -1218,10 +1218,11 @@ void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, - bool load_partition_check, Relation partition_root, int instrument_options) { + List *partition_check = NIL; + MemSet(resultRelInfo, 0, sizeof(ResultRelInfo)); resultRelInfo->type = T_ResultRelInfo; resultRelInfo->ri_RangeTableIndex = resultRelationIndex; @@ -1257,14 +1258,38 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo, resultRelInfo->ri_ConstraintExprs = NULL; resultRelInfo->ri_junkFilter = NULL; resultRelInfo->ri_projectReturning = NULL; - if (load_partition_check) - resultRelInfo->ri_PartitionCheck = - RelationGetPartitionQual(resultRelationDesc); /* - * The following gets set to NULL unless we are initializing leaf - * partitions for tuple-routing. + * If partition_root has been specified, that means we are builiding the + * ResultRelationInfo for one of its leaf partitions. In that case, we + * need *not* initialize the leaf partition's constraint, but rather the + * the partition_root's (if any). We must do that explicitly like this, + * because implicit partition constraints are not inherited like user- + * defined constraints and would fail to be enforced by ExecConstraints() + * after a tuple is routed to a leaf partition. */ + if (partition_root) + { + /* + * Root table itself may or may not be a partition; partition_check + * would be NIL in the latter case. + */ + partition_check = RelationGetPartitionQual(partition_root); + + /* + * This is not our own partition constraint, but rather an ancestor's. + * So any Vars in it bear the ancestor's attribute numbers. We must + * switch them to our own. + */ + if (partition_check != NIL) + partition_check = map_partition_varattnos(partition_check, + resultRelationDesc, + partition_root); + } + else + partition_check = RelationGetPartitionQual(resultRelationDesc); + + resultRelInfo->ri_PartitionCheck = partition_check; resultRelInfo->ri_PartitionRoot = partition_root; } @@ -1328,7 +1353,6 @@ ExecGetTriggerResultRel(EState *estate, Oid relid) InitResultRelInfo(rInfo, rel, 0, /* dummy rangetable index */ - true, NULL, estate->es_instrument); estate->es_trig_target_relations = @@ -3133,7 +3157,6 @@ ExecSetupPartitionTupleRouting(Relation rel, InitResultRelInfo(leaf_part_rri, partrel, 1, /* dummy */ - false, rel, 0); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 70ecf108a3..4fed4e101f 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -189,7 +189,6 @@ extern void CheckValidResultRel(Relation resultRel, CmdType operation); extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, - bool load_partition_check, Relation partition_root, int instrument_options); extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid); diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out index b120954997..6a6aac5a88 100644 --- a/src/test/regress/expected/insert.out +++ b/src/test/regress/expected/insert.out @@ -339,6 +339,12 @@ alter table p add constraint check_b check (b = 3); insert into p values (1, 2); ERROR: new row for relation "p11" violates check constraint "check_b" DETAIL: Failing row contains (1, 2). +-- check that inserting into an internal partition successfully results in +-- checking its partition constraint before inserting into the leaf partition +-- selected by tuple-routing +insert into p1 (a, b) values (2, 3); +ERROR: new row for relation "p11" violates partition constraint +DETAIL: Failing row contains (3, 2). -- cleanup drop table p cascade; NOTICE: drop cascades to 2 other objects diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql index 3d2fdb92c5..171196df6d 100644 --- a/src/test/regress/sql/insert.sql +++ b/src/test/regress/sql/insert.sql @@ -200,5 +200,10 @@ alter table p add constraint check_b check (b = 3); -- after "(1, 2)" is routed to it insert into p values (1, 2); +-- check that inserting into an internal partition successfully results in +-- checking its partition constraint before inserting into the leaf partition +-- selected by tuple-routing +insert into p1 (a, b) values (2, 3); + -- cleanup drop table p cascade; -- 2.11.0