Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit70ef509

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

File tree

6 files changed

+221
-166
lines changed

6 files changed

+221
-166
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 wecan reach here before initializing the info */
1336+
/*Compute the info if wedidn'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: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,9 @@ ExecCheckTIDVisible(EState *estate,
358358
*
359359
* This fills the resultRelInfo's ri_GeneratedExprs field and makes an
360360
* associated ResultRelInfoExtra struct to hold ri_extraUpdatedCols.
361-
* (Currently, ri_extraUpdatedCols is consulted only in UPDATE, but we might
362-
* as well fill it for INSERT too.)
361+
* (Currently, ri_extraUpdatedCols is consulted only in UPDATE, but we
362+
* must fill it in other cases too, since for example cmdtype might be
363+
* MERGE yet an UPDATE might happen later.)
363364
*/
364365
void
365366
ExecInitStoredGenerated(ResultRelInfo*resultRelInfo,
@@ -1918,9 +1919,10 @@ ExecUpdatePrologue(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
19181919
}
19191920

19201921
/*
1921-
* ExecUpdatePrepareSlot -- subroutine forExecUpdate
1922+
* ExecUpdatePrepareSlot -- subroutine forExecUpdateAct
19221923
*
19231924
* Apply the final modifications to the tuple slot before the update.
1925+
* (This is split out because we also need it in the foreign-table code path.)
19241926
*/
19251927
staticvoid
19261928
ExecUpdatePrepareSlot(ResultRelInfo*resultRelInfo,
@@ -1973,13 +1975,14 @@ ExecUpdateAct(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
19731975
updateCxt->crossPartUpdate= false;
19741976

19751977
/*
1976-
* If we generate a new candidate tuple after EvalPlanQual testing, we
1977-
* must loop back here and recheck any RLS policies and constraints. (We
1978-
* don't need to redo triggers, however. If there are any BEFORE triggers
1979-
* then trigger.c will have done table_tuple_lock to lock the correct
1980-
* tuple, so there's no need to do them again.)
1978+
* If we move the tuple to a new partition, we loop back here to recompute
1979+
* GENERATED values (which are allowed to be different across partitions)
1980+
* and recheck any RLS policies and constraints. We do not fire any
1981+
* BEFORE triggers of the new partition, however.
19811982
*/
1982-
lreplace:;
1983+
lreplace:
1984+
/* Fill in GENERATEd columns */
1985+
ExecUpdatePrepareSlot(resultRelInfo,slot,estate);
19831986

19841987
/* ensure slot is independent, consider e.g. EPQ */
19851988
ExecMaterializeSlot(slot);
@@ -2279,6 +2282,7 @@ ExecUpdate(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
22792282
}
22802283
elseif (resultRelInfo->ri_FdwRoutine)
22812284
{
2285+
/* Fill in GENERATEd columns */
22822286
ExecUpdatePrepareSlot(resultRelInfo,slot,estate);
22832287

22842288
/*
@@ -2301,9 +2305,13 @@ ExecUpdate(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
23012305
}
23022306
else
23032307
{
2304-
/* Fill in the slot appropriately */
2305-
ExecUpdatePrepareSlot(resultRelInfo,slot,estate);
2306-
2308+
/*
2309+
* If we generate a new candidate tuple after EvalPlanQual testing, we
2310+
* must loop back here to try again. (We don't need to redo triggers,
2311+
* however. If there are any BEFORE triggers then trigger.c will have
2312+
* done table_tuple_lock to lock the correct tuple, so there's no need
2313+
* to do them again.)
2314+
*/
23072315
redo_act:
23082316
result=ExecUpdateAct(context,resultRelInfo,tupleid,oldtuple,slot,
23092317
canSetTag,&updateCxt);
@@ -2887,7 +2895,6 @@ lmerge_matched:;
28872895
result=TM_Ok;
28882896
break;
28892897
}
2890-
ExecUpdatePrepareSlot(resultRelInfo,newslot,context->estate);
28912898
result=ExecUpdateAct(context,resultRelInfo,tupleid,NULL,
28922899
newslot, false,&updateCxt);
28932900
if (result==TM_Ok&&updateCxt.updated)
@@ -4149,9 +4156,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
41494156

41504157
/*
41514158
* For INSERT/UPDATE/MERGE, prepare to evaluate any generated columns.
4152-
* We must do this now, even if we never insert or update any rows,
4153-
* because we have to fill resultRelInfo->ri_extraUpdatedCols for
4154-
* possible use by the trigger machinery.
4159+
* We must do this now, even if we never insert or update any rows, to
4160+
* cover the case where a MERGE does some UPDATE operations and later
4161+
* some INSERTs. We'll need ri_GeneratedExprs to cover all generated
4162+
* columns, so we force it now. (It might be sufficient to do this
4163+
* only for operation == CMD_MERGE, but we'll avoid changing the data
4164+
* structure definition in back branches.)
41554165
*/
41564166
if (operation==CMD_INSERT||operation==CMD_UPDATE||operation==CMD_MERGE)
41574167
ExecInitStoredGenerated(resultRelInfo,estate,operation);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp