cstate->rel,
1, /* dummy rangetable index */
true, /* do load partition check expression */
+ NULL,
0);
ExecOpenIndices(resultRelInfo, false);
for (;;)
{
TupleTableSlot *slot,
- *oldslot = NULL;
+ *oldslot;
bool skip_tuple;
Oid loaded_oid = InvalidOid;
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
/* Determine the partition to heap_insert the tuple into */
+ oldslot = slot;
if (cstate->partition_dispatch_info)
{
int leaf_part_index;
* point on. Use a dedicated slot from this point on until
* we're finished dealing with the partition.
*/
- oldslot = slot;
slot = cstate->partition_tuple_slot;
Assert(slot != NULL);
ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
/* Check the constraints of the tuple */
if (cstate->rel->rd_att->constr ||
resultRelInfo->ri_PartitionCheck)
- ExecConstraints(resultRelInfo, slot, estate);
+ ExecConstraints(resultRelInfo, slot, oldslot, estate);
if (useHeapMultiInsert)
{
{
resultRelInfo = saved_resultRelInfo;
estate->es_result_relation_info = resultRelInfo;
-
- /* Switch back to the slot corresponding to the root table */
- Assert(oldslot != NULL);
- slot = oldslot;
}
}
}
resultRelation,
resultRelationIndex,
true,
+ NULL,
estate->es_instrument);
resultRelInfo++;
}
Relation resultRelationDesc,
Index resultRelationIndex,
bool load_partition_check,
+ Relation partition_root,
int instrument_options)
{
MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
resultRelInfo->ri_PartitionCheck =
RelationGetPartitionQual(resultRelationDesc,
true);
+ /*
+ * The following gets set to NULL unless we are initializing leaf
+ * partitions for tuple-routing.
+ */
+ resultRelInfo->ri_PartitionRoot = partition_root;
}
/*
rel,
0, /* dummy rangetable index */
true,
+ NULL,
estate->es_instrument);
estate->es_trig_target_relations =
lappend(estate->es_trig_target_relations, rInfo);
return ExecQual(resultRelInfo->ri_PartitionCheckExpr, econtext, true);
}
+/*
+ * 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.
+ *
+ * Note: 'slot' contains the tuple to check the constraints of, which may
+ * have been converted from the original input tuple after tuple routing,
+ * while 'orig_slot' contains the original tuple to be shown in the message,
+ * if an error occurs.
+ */
void
ExecConstraints(ResultRelInfo *resultRelInfo,
- TupleTableSlot *slot, EState *estate)
+ TupleTableSlot *slot, TupleTableSlot *orig_slot,
+ EState *estate)
{
Relation rel = resultRelInfo->ri_RelationDesc;
TupleDesc tupdesc = RelationGetDescr(rel);
slot_attisnull(slot, attrChk))
{
char *val_desc;
+ Relation orig_rel = rel;
+ TupleDesc orig_tupdesc = tupdesc;
+
+ /*
+ * choose the correct relation to build val_desc from the
+ * tuple contained in orig_slot
+ */
+ if (resultRelInfo->ri_PartitionRoot)
+ {
+ rel = resultRelInfo->ri_PartitionRoot;
+ tupdesc = RelationGetDescr(rel);
+ }
insertedCols = GetInsertedColumns(resultRelInfo, estate);
updatedCols = GetUpdatedColumns(resultRelInfo, estate);
modifiedCols = bms_union(insertedCols, updatedCols);
val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
- slot,
+ orig_slot,
tupdesc,
modifiedCols,
64);
ereport(ERROR,
(errcode(ERRCODE_NOT_NULL_VIOLATION),
errmsg("null value in column \"%s\" violates not-null constraint",
- NameStr(tupdesc->attrs[attrChk - 1]->attname)),
+ NameStr(orig_tupdesc->attrs[attrChk - 1]->attname)),
val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
- errtablecol(rel, attrChk)));
+ errtablecol(orig_rel, attrChk)));
}
}
}
if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)
{
char *val_desc;
+ Relation orig_rel = rel;
+
+ /* See the comment above. */
+ if (resultRelInfo->ri_PartitionRoot)
+ {
+ rel = resultRelInfo->ri_PartitionRoot;
+ tupdesc = RelationGetDescr(rel);
+ }
insertedCols = GetInsertedColumns(resultRelInfo, estate);
updatedCols = GetUpdatedColumns(resultRelInfo, estate);
modifiedCols = bms_union(insertedCols, updatedCols);
val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
- slot,
+ orig_slot,
tupdesc,
modifiedCols,
64);
ereport(ERROR,
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
- RelationGetRelationName(rel), failed),
+ RelationGetRelationName(orig_rel), failed),
val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
- errtableconstraint(rel, failed)));
+ errtableconstraint(orig_rel, failed)));
}
}
!ExecPartitionCheck(resultRelInfo, slot, estate))
{
char *val_desc;
+ Relation orig_rel = rel;
+
+ /* See the comment above. */
+ if (resultRelInfo->ri_PartitionRoot)
+ {
+ rel = resultRelInfo->ri_PartitionRoot;
+ tupdesc = RelationGetDescr(rel);
+ }
insertedCols = GetInsertedColumns(resultRelInfo, estate);
updatedCols = GetUpdatedColumns(resultRelInfo, estate);
modifiedCols = bms_union(insertedCols, updatedCols);
val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
- slot,
+ orig_slot,
tupdesc,
modifiedCols,
64);
ereport(ERROR,
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("new row for relation \"%s\" violates partition constraint",
- RelationGetRelationName(rel)),
+ RelationGetRelationName(orig_rel)),
val_desc ? errdetail("Failing row contains %s.", val_desc) : 0));
}
}
partrel,
1, /* dummy */
false,
+ rel,
0);
/*
Relation resultRelationDesc;
Oid newId;
List *recheckIndexes = NIL;
- TupleTableSlot *oldslot = NULL;
+ TupleTableSlot *oldslot = slot;
/*
* get the heap tuple out of the tuple table slot, making sure we have a
* point on, until we're finished dealing with the partition.
* Use the dedicated slot for that.
*/
- oldslot = slot;
slot = mtstate->mt_partition_tuple_slot;
Assert(slot != NULL);
ExecSetSlotDescriptor(slot, RelationGetDescr(partrel));
* Check the constraints of the tuple
*/
if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck)
- ExecConstraints(resultRelInfo, slot, estate);
+ ExecConstraints(resultRelInfo, slot, oldslot, estate);
if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
{
{
resultRelInfo = saved_resultRelInfo;
estate->es_result_relation_info = resultRelInfo;
-
- /* Switch back to the slot corresponding to the root table */
- Assert(oldslot != NULL);
- slot = oldslot;
}
/*
resultRelInfo, slot, estate);
/*
- * Check the constraints of the tuple
+ * Check the constraints of the tuple. Note that we pass the same
+ * slot for the orig_slot argument, because unlike ExecInsert(), no
+ * 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, slot, estate);
/*
* replace the heap tuple