Factor error generation out of ExecPartitionCheck.
authorRobert Haas <rhaas@postgresql.org>
Fri, 5 Jan 2018 20:18:03 +0000 (15:18 -0500)
committerRobert Haas <rhaas@postgresql.org>
Fri, 5 Jan 2018 20:22:33 +0000 (15:22 -0500)
At present, we always raise an ERROR if the partition constraint
is violated, but a pending patch for UPDATE tuple routing will
consider instead moving the tuple to the correct partition.
Refactor to make that simpler.

Amit Khandekar, reviewed by Amit Langote, David Rowley, and me.

Discussion: http://postgr.es/m/CAJ3gD9cue54GbEzfV-61nyGpijvjZgCcghvLsB0_nL8Nm8HzCA@mail.gmail.com

src/backend/commands/copy.c
src/backend/executor/execMain.c
src/backend/executor/execPartition.c
src/backend/executor/execReplication.c
src/backend/executor/nodeModifyTable.c
src/include/executor/executor.h

index 66cbff7eadc28ccdd4f7da9b7686cc72893190b1..6bfca2a4af25164e09b6fdb8a9d1826d2c1746e5 100644 (file)
@@ -2731,7 +2731,7 @@ CopyFrom(CopyState cstate)
 
                /* Check the constraints of the tuple */
                if (cstate->rel->rd_att->constr || check_partition_constr)
-                   ExecConstraints(resultRelInfo, slot, estate);
+                   ExecConstraints(resultRelInfo, slot, estate, true);
 
                if (useHeapMultiInsert)
                {
index d8bc5028e81b4ac7c1fd000b64ee42a3c73e4d21..16822e962af834dffa24c99606bf071477e2af8f 100644 (file)
@@ -1849,16 +1849,12 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
  * ExecPartitionCheck --- check that tuple meets the partition constraint.
  *
  * Exported in executor.h for outside use.
+ * Returns true if it meets the partition constraint, else returns false.
  */
-void
+bool
 ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
                   EState *estate)
 {
-   Relation    rel = resultRelInfo->ri_RelationDesc;
-   TupleDesc   tupdesc = RelationGetDescr(rel);
-   Bitmapset  *modifiedCols;
-   Bitmapset  *insertedCols;
-   Bitmapset  *updatedCols;
    ExprContext *econtext;
 
    /*
@@ -1886,52 +1882,69 @@ ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
     * As in case of the catalogued constraints, we treat a NULL result as
     * success here, not a failure.
     */
-   if (!ExecCheck(resultRelInfo->ri_PartitionCheckExpr, econtext))
-   {
-       char       *val_desc;
-       Relation    orig_rel = rel;
+   return ExecCheck(resultRelInfo->ri_PartitionCheckExpr, econtext);
+}
+
+/*
+ * ExecPartitionCheckEmitError - Form and emit an error message after a failed
+ * partition constraint check.
+ */
+void
+ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
+                           TupleTableSlot *slot,
+                           EState *estate)
+{
+   Relation    rel = resultRelInfo->ri_RelationDesc;
+   Relation    orig_rel = rel;
+   TupleDesc   tupdesc = RelationGetDescr(rel);
+   char       *val_desc;
+   Bitmapset  *modifiedCols;
+   Bitmapset  *insertedCols;
+   Bitmapset  *updatedCols;
 
-       /* See the comment above. */
-       if (resultRelInfo->ri_PartitionRoot)
+   /*
+    * Need to first convert the tuple to the root partitioned table's row
+    * type. For details, check similar comments in ExecConstraints().
+    */
+   if (resultRelInfo->ri_PartitionRoot)
+   {
+       HeapTuple   tuple = ExecFetchSlotTuple(slot);
+       TupleDesc   old_tupdesc = RelationGetDescr(rel);
+       TupleConversionMap *map;
+
+       rel = resultRelInfo->ri_PartitionRoot;
+       tupdesc = RelationGetDescr(rel);
+       /* a reverse map */
+       map = convert_tuples_by_name(old_tupdesc, tupdesc,
+                                    gettext_noop("could not convert row type"));
+       if (map != NULL)
        {
-           HeapTuple   tuple = ExecFetchSlotTuple(slot);
-           TupleDesc   old_tupdesc = RelationGetDescr(rel);
-           TupleConversionMap *map;
-
-           rel = resultRelInfo->ri_PartitionRoot;
-           tupdesc = RelationGetDescr(rel);
-           /* a reverse map */
-           map = convert_tuples_by_name(old_tupdesc, tupdesc,
-                                        gettext_noop("could not convert row type"));
-           if (map != NULL)
-           {
-               tuple = do_convert_tuple(tuple, map);
-               ExecSetSlotDescriptor(slot, tupdesc);
-               ExecStoreTuple(tuple, slot, InvalidBuffer, false);
-           }
+           tuple = do_convert_tuple(tuple, map);
+           ExecSetSlotDescriptor(slot, tupdesc);
+           ExecStoreTuple(tuple, slot, InvalidBuffer, false);
        }
-
-       insertedCols = GetInsertedColumns(resultRelInfo, estate);
-       updatedCols = GetUpdatedColumns(resultRelInfo, estate);
-       modifiedCols = bms_union(insertedCols, updatedCols);
-       val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
-                                                slot,
-                                                tupdesc,
-                                                modifiedCols,
-                                                64);
-       ereport(ERROR,
-               (errcode(ERRCODE_CHECK_VIOLATION),
-                errmsg("new row for relation \"%s\" violates partition constraint",
-                       RelationGetRelationName(orig_rel)),
-                val_desc ? errdetail("Failing row contains %s.", val_desc) : 0));
    }
+
+   insertedCols = GetInsertedColumns(resultRelInfo, estate);
+   updatedCols = GetUpdatedColumns(resultRelInfo, estate);
+   modifiedCols = bms_union(insertedCols, updatedCols);
+   val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
+                                            slot,
+                                            tupdesc,
+                                            modifiedCols,
+                                            64);
+   ereport(ERROR,
+           (errcode(ERRCODE_CHECK_VIOLATION),
+            errmsg("new row for relation \"%s\" violates partition constraint",
+                   RelationGetRelationName(orig_rel)),
+            val_desc ? errdetail("Failing row contains %s.", val_desc) : 0));
 }
 
 /*
  * ExecConstraints - check constraints of the tuple in 'slot'
  *
- * This checks the traditional NOT NULL and check constraints, as well as
- * the partition constraint, if any.
+ * This checks the traditional NOT NULL and check constraints, and if
+ * requested, checks the partition constraint.
  *
  * Note: 'slot' contains the tuple to check the constraints of, which may
  * have been converted from the original input tuple after tuple routing.
@@ -1939,7 +1952,8 @@ ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
  */
 void
 ExecConstraints(ResultRelInfo *resultRelInfo,
-               TupleTableSlot *slot, EState *estate)
+               TupleTableSlot *slot, EState *estate,
+               bool check_partition_constraint)
 {
    Relation    rel = resultRelInfo->ri_RelationDesc;
    TupleDesc   tupdesc = RelationGetDescr(rel);
@@ -2055,8 +2069,9 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
        }
    }
 
-   if (resultRelInfo->ri_PartitionCheck)
-       ExecPartitionCheck(resultRelInfo, slot, estate);
+   if (check_partition_constraint && resultRelInfo->ri_PartitionCheck &&
+       !ExecPartitionCheck(resultRelInfo, slot, estate))
+       ExecPartitionCheckEmitError(resultRelInfo, slot, estate);
 }
 
 
index 115be026353762baf7d611a8792b2f870b9da37f..8c0d2df63c7a8635bf500de4781e342acfac4020 100644 (file)
@@ -167,8 +167,9 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
     * First check the root table's partition constraint, if any.  No point in
     * routing the tuple if it doesn't belong in the root table itself.
     */
-   if (resultRelInfo->ri_PartitionCheck)
-       ExecPartitionCheck(resultRelInfo, slot, estate);
+   if (resultRelInfo->ri_PartitionCheck &&
+       !ExecPartitionCheck(resultRelInfo, slot, estate))
+       ExecPartitionCheckEmitError(resultRelInfo, slot, estate);
 
    /* start with the root partitioned table */
    parent = pd[0];
index 732ed42fe53abea223d918102355b2fca1e64c62..32891abbdf54e5ed38eace42fe8d488fc0627172 100644 (file)
@@ -401,7 +401,7 @@ ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot)
 
        /* Check the constraints of the tuple */
        if (rel->rd_att->constr)
-           ExecConstraints(resultRelInfo, slot, estate);
+           ExecConstraints(resultRelInfo, slot, estate, true);
 
        /* Store the slot into tuple that we can inspect. */
        tuple = ExecMaterializeSlot(slot);
@@ -466,7 +466,7 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
 
        /* Check the constraints of the tuple */
        if (rel->rd_att->constr)
-           ExecConstraints(resultRelInfo, slot, estate);
+           ExecConstraints(resultRelInfo, slot, estate, true);
 
        /* Store the slot into tuple that we can write. */
        tuple = ExecMaterializeSlot(slot);
index 95e0748d8f40fdf8fc8b8535fbfe870d036c8356..55dff5b21a6eb0ae4a54481829c6f0379f9df23d 100644 (file)
@@ -487,7 +487,7 @@ ExecInsert(ModifyTableState *mtstate,
 
        /* Check the constraints of the tuple */
        if (resultRelationDesc->rd_att->constr || check_partition_constr)
-           ExecConstraints(resultRelInfo, slot, estate);
+           ExecConstraints(resultRelInfo, slot, estate, true);
 
        if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
        {
@@ -1049,7 +1049,7 @@ lreplace:;
         * tuple-routing is performed here, hence the slot remains unchanged.
         */
        if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck)
-           ExecConstraints(resultRelInfo, slot, estate);
+           ExecConstraints(resultRelInfo, slot, estate, true);
 
        /*
         * replace the heap tuple
index e6569e1038b0e79df1349aea0226ccfd748005e5..a782fae0f8342fc0982369d45686ff5adad7c3b1 100644 (file)
@@ -187,9 +187,12 @@ extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
 extern void ExecCleanUpTriggerState(EState *estate);
 extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
 extern void ExecConstraints(ResultRelInfo *resultRelInfo,
-               TupleTableSlot *slot, EState *estate);
-extern void ExecPartitionCheck(ResultRelInfo *resultRelInfo,
+               TupleTableSlot *slot, EState *estate,
+               bool check_partition_constraint);
+extern bool ExecPartitionCheck(ResultRelInfo *resultRelInfo,
                   TupleTableSlot *slot, EState *estate);
+extern void ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
+                                   TupleTableSlot *slot, EState *estate);
 extern void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
                     TupleTableSlot *slot, EState *estate);
 extern LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo);