]> granicus.if.org Git - postgresql/commitdiff
Fix failure to enforce partitioning contraint for internal partitions.
authorRobert Haas <rhaas@postgresql.org>
Thu, 19 Jan 2017 17:30:27 +0000 (12:30 -0500)
committerRobert Haas <rhaas@postgresql.org>
Thu, 19 Jan 2017 17:30:27 +0000 (12:30 -0500)
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
src/backend/commands/tablecmds.c
src/backend/executor/execMain.c
src/include/executor/executor.h
src/test/regress/expected/insert.out
src/test/regress/sql/insert.sql

index 1fd2162794832c76d8c2f0e275724d0cd7cf4b07..75386212e0696fc6bb9596e5265c595fc1c64332 100644 (file)
@@ -2432,7 +2432,6 @@ CopyFrom(CopyState cstate)
        InitResultRelInfo(resultRelInfo,
                                          cstate->rel,
                                          1,            /* dummy rangetable index */
-                                         true,         /* do load partition check expression */
                                          NULL,
                                          0);
 
index e633a50dd2db4f08f3edb7b05273bd9648e4992b..06e43cbb3a273efb9127d65d253adedd91dee59d 100644 (file)
@@ -1324,7 +1324,6 @@ ExecuteTruncate(TruncateStmt *stmt)
                InitResultRelInfo(resultRelInfo,
                                                  rel,
                                                  0,    /* dummy rangetable index */
-                                                 false,
                                                  NULL,
                                                  0);
                resultRelInfo++;
index ff277d300a8d553fe6c8cc3aad047bb6988a8cb2..5457f8fbde5d9455514cf7d117737edb516b4790 100644 (file)
@@ -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);
 
index d424031676f966f7f056c1d328abe78f63663d16..eb180fdb631bb72ebf064e88358b3575dd0a6917 100644 (file)
@@ -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);
index 0382560d3950a2dbe1719d2e13bf75bf66a1db6a..729d9ebbbc6286e3687c0899cc41cdaf43e956b6 100644 (file)
@@ -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;
index a6eab8f36566d0d536cc8238c55f3d4c2c3f8767..5509555fc578b4f49592d428153c66fd562dff72 100644 (file)
@@ -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;