Skip to content

Commit 1e05ea5

Browse files
committed
Fix some more cases of missed GENERATED-column updates.
If UPDATE is forced to retry after an EvalPlanQual check, it neglected to repeat GENERATED-column computations, even though those might well have changed since we're dealing with a different tuple than before. Fixing this is mostly a matter of looping back a bit further when we retry. In v15 and HEAD that's most easily done by altering the API of ExecUpdateAct so that it includes computing GENERATED expressions. Also, if an UPDATE in a partitioned table turns into a cross-partition INSERT operation, we failed to recompute GENERATED columns. That's a bug since 8bf6ec3 allowed partitions to have different generation expressions; although it seems to have no ill effects before that. Fixing this is messier because we can now have situations where the same query needs both the UPDATE-aligned set of GENERATED columns and the INSERT-aligned set, and it's unclear which set will be generated first (else we could hack things by forcing the INSERT-aligned set to be generated, which is indeed how fe9e658 made it work for MERGE). The best fix seems to be to build and store separate sets of expressions for the INSERT and UPDATE cases. That would create ABI issues in the back branches, but so far it seems we can leave this alone in the back branches. Per bug #17823 from Hisahiro Kauchi. The first part of this affects all branches back to v12 where GENERATED columns were added. Discussion: https://postgr.es/m/17823-b64909cf7d63de84@postgresql.org
1 parent e9051ec commit 1e05ea5

File tree

6 files changed

+207
-164
lines changed

6 files changed

+207
-164
lines changed

src/backend/executor/execUtils.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,7 @@ ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
13331333
{
13341334
ListCell *lc;
13351335

1336-
/* In some code paths we can reach here before initializing the info */
1336+
/* Compute the info if we didn't already */
13371337
if (relinfo->ri_GeneratedExprs == NULL)
13381338
ExecInitStoredGenerated(relinfo, estate, CMD_UPDATE);
13391339
foreach(lc, estate->es_resultrelinfo_extra)

src/backend/executor/nodeModifyTable.c

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,6 +1813,15 @@ ExecUpdate(ModifyTableState *mtstate,
18131813
bool partition_constraint_failed;
18141814
bool update_indexes;
18151815

1816+
/*
1817+
* If we generate a new candidate tuple after EvalPlanQual testing, we
1818+
* must loop back here to try again. (We don't need to redo triggers,
1819+
* however. If there are any BEFORE triggers then trigger.c will have
1820+
* done table_tuple_lock to lock the correct tuple, so there's no need
1821+
* to do them again.)
1822+
*/
1823+
lreplace:
1824+
18161825
/*
18171826
* Constraints and GENERATED expressions might reference the tableoid
18181827
* column, so (re-)initialize tts_tableOid before evaluating them.
@@ -1827,17 +1836,6 @@ ExecUpdate(ModifyTableState *mtstate,
18271836
ExecComputeStoredGenerated(resultRelInfo, estate, slot,
18281837
CMD_UPDATE);
18291838

1830-
/*
1831-
* Check any RLS UPDATE WITH CHECK policies
1832-
*
1833-
* If we generate a new candidate tuple after EvalPlanQual testing, we
1834-
* must loop back here and recheck any RLS policies and constraints.
1835-
* (We don't need to redo triggers, however. If there are any BEFORE
1836-
* triggers then trigger.c will have done table_tuple_lock to lock the
1837-
* correct tuple, so there's no need to do them again.)
1838-
*/
1839-
lreplace:;
1840-
18411839
/* ensure slot is independent, consider e.g. EPQ */
18421840
ExecMaterializeSlot(slot);
18431841

@@ -1852,6 +1850,7 @@ lreplace:;
18521850
resultRelationDesc->rd_rel->relispartition &&
18531851
!ExecPartitionCheck(resultRelInfo, slot, estate, false);
18541852

1853+
/* Check any RLS UPDATE WITH CHECK policies */
18551854
if (!partition_constraint_failed &&
18561855
resultRelInfo->ri_WithCheckOptions != NIL)
18571856
{
@@ -2996,9 +2995,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
29962995

29972996
/*
29982997
* For INSERT and UPDATE, prepare to evaluate any generated columns.
2999-
* We must do this now, even if we never insert or update any rows,
3000-
* because we have to fill resultRelInfo->ri_extraUpdatedCols for
3001-
* possible use by the trigger machinery.
2998+
* (This is probably not necessary any longer, but we'll refrain from
2999+
* changing it in back branches, in case extension code expects it.)
30023000
*/
30033001
if (operation == CMD_INSERT || operation == CMD_UPDATE)
30043002
ExecInitStoredGenerated(resultRelInfo, estate, operation);

0 commit comments

Comments
 (0)