From 39162b2030fb0a35a6bb28dc636b5a71b8df8d1c Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Thu, 19 Jan 2017 12:30:27 -0500 Subject: [PATCH] Fix failure to enforce partitioning contraint for internal partitions. When a tuple is inherited into a partitioning root, no partition constraints need to be enforced; when it is inserted into a leaf, the parent's partitioning quals needed to be enforced. The previous coding got both of those cases right. When a tuple is inserted into an intermediate level of the partitioning hierarchy (i.e. a table which is both a partition itself and in turn partitioned), it must enforce the partitioning qual inherited from its parent. That case got overlooked; repair. Amit Langote --- src/backend/commands/copy.c | 1 - src/backend/commands/tablecmds.c | 1 - src/backend/executor/execMain.c | 42 ++++++++++++++++++++++------ src/include/executor/executor.h | 1 - src/test/regress/expected/insert.out | 6 ++++ src/test/regress/sql/insert.sql | 5 ++++ 6 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 1fd2162794..75386212e0 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2432,7 +2432,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 e633a50dd2..06e43cbb3a 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1324,7 +1324,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 ff277d300a..5457f8fbde 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,13 +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; } @@ -1327,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 = @@ -3132,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 d424031676..eb180fdb63 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 0382560d39..729d9ebbbc 100644 --- a/src/test/regress/expected/insert.out +++ b/src/test/regress/expected/insert.out @@ -358,5 +358,11 @@ 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, p1, p11; diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql index a6eab8f365..5509555fc5 100644 --- a/src/test/regress/sql/insert.sql +++ b/src/test/regress/sql/insert.sql @@ -221,5 +221,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, p1, p11;