v52-0001-refactor-MergePartitionsMoveRows.no-cfbot
application/octet-stream
Filename: v52-0001-refactor-MergePartitionsMoveRows.no-cfbot
Type: application/octet-stream
Part: 0
From a89bce4f39c16dc9e3ad247401b238554e520b87 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Thu, 21 Aug 2025 10:49:50 +0800
Subject: [PATCH v52 1/1] refactor MergePartitionsMoveRows
mainly make MergePartitionsMoveRows more aligned with ATRewriteTable.
based on v52-0001-Implement-ALTER-TABLE-.-MERGE-PARTITIONS-.-comma.patch
also convert one ereport(ERROR...) to elog(ERROR ...)
within createTableConstraints.
---
src/backend/commands/tablecmds.c | 105 ++++++++++++++-----------------
1 file changed, 48 insertions(+), 57 deletions(-)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index cc24a92c504..9ecd1838077 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -22133,52 +22133,6 @@ buildExpressionExecutionStates(AlteredTableInfo *tab, Relation newPartRel, EStat
}
}
-/*
- * evaluateGeneratedExpressionsAndCheckConstraints: evaluate any generated
- * expressions for "tab" (AlteredTableInfo structure) whose inputs come from
- * the new tuple (insertslot) of new partition (newPartRel).
- */
-static void
-evaluateGeneratedExpressionsAndCheckConstraints(AlteredTableInfo *tab,
- Relation newPartRel,
- TupleTableSlot *insertslot,
- ExprContext *econtext)
-{
- econtext->ecxt_scantuple = insertslot;
-
- foreach_ptr(NewColumnValue, ex, tab->newvals)
- {
- if (!ex->is_generated)
- continue;
-
- insertslot->tts_values[ex->attnum - 1]
- = ExecEvalExpr(ex->exprstate,
- econtext,
- &insertslot->tts_isnull[ex->attnum - 1]);
- }
-
- foreach_ptr(NewConstraint, con, tab->constraints)
- {
- switch (con->contype)
- {
- case CONSTR_CHECK:
- if (!ExecCheck(con->qualstate, econtext))
- ereport(ERROR,
- errcode(ERRCODE_CHECK_VIOLATION),
- errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
- con->name, RelationGetRelationName(newPartRel)),
- errtableconstraint(newPartRel, con->name));
- break;
- case CONSTR_NOTNULL:
- case CONSTR_FOREIGN:
- /* Nothing to do here */
- break;
- default:
- elog(ERROR, "unrecognized constraint type: %d",
- (int) con->contype);
- }
- }
-}
/*
* getAttributesList: build a list of columns (ColumnDef) based on parent_rel
@@ -22363,12 +22317,9 @@ createTableConstraints(List **wqueue, AlteredTableInfo *tab,
* possible to guarantee it would work in future.
*/
if (found_whole_row)
- ereport(ERROR,
- errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot convert whole-row table reference"),
- errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
- ccname,
- RelationGetRelationName(parent_rel)));
+ elog(ERROR, "Constraint \"%s\" contains a whole-row reference to table \"%s\".",
+ ccname,
+ RelationGetRelationName(parent_rel));
constr = makeNode(Constraint);
constr->contype = CONSTR_CHECK;
@@ -22580,7 +22531,6 @@ MergePartitionsMoveRows(List **wqueue, List *mergingPartitions, Relation newPart
{
CommandId mycid;
EState *estate;
- ExprContext *econtext;
AlteredTableInfo *tab;
ListCell *ltab;
@@ -22597,8 +22547,6 @@ MergePartitionsMoveRows(List **wqueue, List *mergingPartitions, Relation newPart
buildExpressionExecutionStates(tab, newPartRel, estate);
- econtext = GetPerTupleExprContext(estate);
-
mycid = GetCurrentCommandId(true);
/* Prepare a BulkInsertState for table_tuple_insert. */
@@ -22609,12 +22557,16 @@ MergePartitionsMoveRows(List **wqueue, List *mergingPartitions, Relation newPart
foreach_oid(merging_oid, mergingPartitions)
{
+ ExprContext *econtext;
TupleTableSlot *srcslot;
TupleConversionMap *tuple_map;
TableScanDesc scan;
+ MemoryContext oldCxt;
Snapshot snapshot;
Relation mergingPartition;
+ econtext = GetPerTupleExprContext(estate);
+
/*
* Partition is already locked in the transformPartitionCmdForMerge
* function.
@@ -22635,6 +22587,12 @@ MergePartitionsMoveRows(List **wqueue, List *mergingPartitions, Relation newPart
snapshot = RegisterSnapshot(GetLatestSnapshot());
scan = table_beginscan(mergingPartition, snapshot, 0, NULL);
+ /*
+ * Switch to per-tuple memory context and reset it for each tuple
+ * produced, so we don't leak memory.
+ */
+ oldCxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
+
while (table_scan_getnextslot(scan, ForwardScanDirection, srcslot))
{
TupleTableSlot *insertslot;
@@ -22676,9 +22634,41 @@ MergePartitionsMoveRows(List **wqueue, List *mergingPartitions, Relation newPart
* the new tuple. We assume these columns won't reference each
* other, so that there's no ordering dependency.
*/
- evaluateGeneratedExpressionsAndCheckConstraints(tab, newPartRel,
- insertslot, econtext);
+ econtext->ecxt_scantuple = insertslot;
+ foreach_ptr(NewColumnValue, ex, tab->newvals)
+ {
+ if (!ex->is_generated)
+ continue;
+
+ insertslot->tts_values[ex->attnum - 1]
+ = ExecEvalExpr(ex->exprstate,
+ econtext,
+ &insertslot->tts_isnull[ex->attnum - 1]);
+ }
+
+ /* Now check any constraints */
+ foreach_ptr(NewConstraint, con, tab->constraints)
+ {
+ switch (con->contype)
+ {
+ case CONSTR_CHECK:
+ if (!ExecCheck(con->qualstate, econtext))
+ ereport(ERROR,
+ errcode(ERRCODE_CHECK_VIOLATION),
+ errmsg("check constraint \"%s\" of relation \"%s\" is violated by some row",
+ con->name, RelationGetRelationName(newPartRel)),
+ errtableconstraint(newPartRel, con->name));
+ break;
+ case CONSTR_NOTNULL:
+ case CONSTR_FOREIGN:
+ /* Nothing to do here */
+ break;
+ default:
+ elog(ERROR, "unrecognized constraint type: %d",
+ (int) con->contype);
+ }
+ }
/* Write the tuple out to the new relation. */
table_tuple_insert(newPartRel, insertslot, mycid,
ti_options, bistate);
@@ -22686,6 +22676,7 @@ MergePartitionsMoveRows(List **wqueue, List *mergingPartitions, Relation newPart
ResetExprContext(econtext);
}
+ MemoryContextSwitchTo(oldCxt);
table_endscan(scan);
UnregisterSnapshot(snapshot);
--
2.34.1