From cd3d63ee5fb33fea1c269efa3db1c6b401c38db1 Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Mon, 9 Nov 2026 17:42:38 -0500 Subject: [PATCH 1/3] Fix stored generated columns in transition tables of partitioned tables The transition table got the root tuple before stored generated columns were computed. Skip this shortcut for such partitions. Backpatch-through: 14 --- src/backend/commands/copyfrom.c | 9 ++++++--- src/backend/executor/nodeModifyTable.c | 13 +++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c index 89f48c8951b..28d8f06340d 100644 --- a/src/backend/commands/copyfrom.c +++ b/src/backend/commands/copyfrom.c @@ -1269,10 +1269,13 @@ CopyFrom(CopyFromState cstate) * If we're capturing transition tuples, we might need to convert * from the partition rowtype to root rowtype. But if there are no * BEFORE triggers on the partition that could change the tuple, - * we can just remember the original unconverted tuple to avoid a - * needless round trip conversion. + * and no stored generated columns that are computed later on the + * converted tuple, we can just remember the original unconverted + * tuple to avoid a needless round trip conversion. */ - if (!has_before_insert_row_trig) + if (!has_before_insert_row_trig && + !(resultRelInfo->ri_RelationDesc->rd_att->constr && + resultRelInfo->ri_RelationDesc->rd_att->constr->has_generated_stored)) original_insert_tuple = myslot; /* diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index cb73cc61821..445aef47ca2 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -4378,19 +4378,24 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate, /* * If we're capturing transition tuples, we might need to convert from the * partition rowtype to root partitioned table's rowtype. But if there - * are no BEFORE triggers on the partition that could change the tuple, we - * can just remember the original unconverted tuple to avoid a needless - * round trip conversion. + * are no BEFORE triggers on the partition that could change the tuple, + * and no stored generated columns that are computed later on the + * converted tuple, we can just remember the original unconverted tuple to + * avoid a needless round trip conversion. */ if (mtstate->mt_transition_capture != NULL) { + TupleDesc partdesc = RelationGetDescr(partrel->ri_RelationDesc); bool has_before_insert_row_trig; + bool has_generated_stored; has_before_insert_row_trig = (partrel->ri_TrigDesc && partrel->ri_TrigDesc->trig_insert_before_row); + has_generated_stored = (partdesc->constr && + partdesc->constr->has_generated_stored); *tcs_original_insert_tuple = - !has_before_insert_row_trig ? slot : NULL; + (!has_before_insert_row_trig && !has_generated_stored) ? slot : NULL; } /* -- 2.37.1 (Apple Git-137.1)