* we don't need to if there's no BR trigger defined on the
* partition.
*/
- if (resultRelInfo->ri_PartitionCheck &&
+ if (resultRelInfo->ri_RelationDesc->rd_rel->relispartition &&
(proute == NULL || has_before_insert_row_trig))
ExecPartitionCheck(resultRelInfo, myslot, estate, true);
Relation partition_root,
int instrument_options)
{
- List *partition_check = NIL;
-
MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
resultRelInfo->type = T_ResultRelInfo;
resultRelInfo->ri_RangeTableIndex = resultRelationIndex;
resultRelInfo->ri_ReturningSlot = NULL;
resultRelInfo->ri_TrigOldSlot = NULL;
resultRelInfo->ri_TrigNewSlot = NULL;
-
- /*
- * Partition constraint, which also includes the partition constraint of
- * all the ancestors that are partitions. Note that it will be checked
- * even in the case of tuple-routing where this table is the target leaf
- * partition, if there any BR triggers defined on the table. Although
- * tuple-routing implicitly preserves the partition constraint of the
- * target partition for a given row, the BR triggers may change the row
- * such that the constraint is no longer satisfied, which we must fail for
- * by checking it explicitly.
- *
- * If this is a partitioned table, the partition constraint (if any) of a
- * given row will be checked just before performing tuple-routing.
- */
- partition_check = RelationGetPartitionQual(resultRelationDesc);
-
- resultRelInfo->ri_PartitionCheck = partition_check;
resultRelInfo->ri_PartitionRoot = partition_root;
resultRelInfo->ri_PartitionInfo = NULL; /* may be set later */
resultRelInfo->ri_CopyMultiInsertBuffer = NULL;
* ExecPartitionCheck --- check that tuple meets the partition constraint.
*
* Returns true if it meets the partition constraint. If the constraint
- * fails and we're asked to emit to error, do so and don't return; otherwise
+ * fails and we're asked to emit an error, do so and don't return; otherwise
* return false.
*/
bool
/*
* If first time through, build expression state tree for the partition
- * check expression. Keep it in the per-query memory context so they'll
- * survive throughout the query.
+ * check expression. (In the corner case where the partition check
+ * expression is empty, ie there's a default partition and nothing else,
+ * we'll be fooled into executing this code each time through. But it's
+ * pretty darn cheap in that case, so we don't worry about it.)
*/
if (resultRelInfo->ri_PartitionCheckExpr == NULL)
{
- List *qual = resultRelInfo->ri_PartitionCheck;
+ /*
+ * Ensure that the qual tree and prepared expression are in the
+ * query-lifespan context.
+ */
+ MemoryContext oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
+ List *qual = RelationGetPartitionQual(resultRelInfo->ri_RelationDesc);
resultRelInfo->ri_PartitionCheckExpr = ExecPrepareCheck(qual, estate);
+ MemoryContextSwitchTo(oldcxt);
}
/*
Bitmapset *insertedCols;
Bitmapset *updatedCols;
- Assert(constr || resultRelInfo->ri_PartitionCheck);
+ Assert(constr); /* we should not be called otherwise */
- if (constr && constr->has_not_null)
+ if (constr->has_not_null)
{
int natts = tupdesc->natts;
int attrChk;
}
}
- if (constr && constr->num_check > 0)
+ if (constr->num_check > 0)
{
const char *failed;
* 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 (rootResultRelInfo->ri_PartitionCheck)
+ if (rootResultRelInfo->ri_RelationDesc->rd_rel->relispartition)
ExecPartitionCheck(rootResultRelInfo, slot, estate, true);
/* start with the root partitioned table */
/* Check the constraints of the tuple */
if (rel->rd_att->constr)
ExecConstraints(resultRelInfo, slot, estate);
- if (resultRelInfo->ri_PartitionCheck)
+ if (rel->rd_rel->relispartition)
ExecPartitionCheck(resultRelInfo, slot, estate, true);
/* OK, store the tuple and create index entries for it */
/* Check the constraints of the tuple */
if (rel->rd_att->constr)
ExecConstraints(resultRelInfo, slot, estate);
- if (resultRelInfo->ri_PartitionCheck)
+ if (rel->rd_rel->relispartition)
ExecPartitionCheck(resultRelInfo, slot, estate, true);
simple_table_tuple_update(rel, tid, slot, estate->es_snapshot,
* one; except that if we got here via tuple-routing, we don't need to
* if there's no BR trigger defined on the partition.
*/
- if (resultRelInfo->ri_PartitionCheck &&
+ if (resultRelationDesc->rd_rel->relispartition &&
(resultRelInfo->ri_PartitionRoot == NULL ||
(resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_insert_before_row)))
* row. So skip the WCO checks if the partition constraint fails.
*/
partition_constraint_failed =
- resultRelInfo->ri_PartitionCheck &&
+ resultRelationDesc->rd_rel->relispartition &&
!ExecPartitionCheck(resultRelInfo, slot, estate, false);
if (!partition_constraint_failed &&
* Does the updated tuple still satisfy the current
* partition's constraint?
*/
- if (partrelinfo->ri_PartitionCheck == NULL ||
+ if (!partrel->rd_rel->relispartition ||
ExecPartitionCheck(partrelinfo, remoteslot_part, estate,
false))
{
/* ON CONFLICT evaluation state */
OnConflictSetState *ri_onConflict;
- /* partition check expression */
- List *ri_PartitionCheck;
-
- /* partition check expression state */
+ /* partition check expression state (NULL if not set up yet) */
ExprState *ri_PartitionCheckExpr;
- /* relation descriptor for root partitioned table */
+ /* relation descriptor for partitioned table's root, if any */
Relation ri_PartitionRoot;
- /* Additional information specific to partition tuple routing */
+ /* info for partition tuple routing (NULL if not set up yet) */
struct PartitionRoutingInfo *ri_PartitionInfo;
- /* For use by copy.c when performing multi-inserts */
+ /* for use by copy.c when performing multi-inserts */
struct CopyMultiInsertBuffer *ri_CopyMultiInsertBuffer;
} ResultRelInfo;