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

Commitd986d4e

Browse files
committed
Fix crash caused by EPQ happening with a before update trigger present.
When ExecBRUpdateTriggers()'s GetTupleForTrigger() follows an EPQchain the former needs to run the result tuple through the junkfilteragain, and update the slot containing the new version of the tuple tocontain that new version. The input tuple may already be in thejunkfilter's output slot, which used to be OK - we don't need theprevious version anymore. Unfortunatelyff11e7f started to useExecCopySlot() to update newslot, and ExecCopySlot() doesn't supportcopying a slot into itself, leading to a slot in a corruptstate, which then can cause crashes or other symptoms.Fix this by skipping the ExecCopySlot() when copying into itself.While we could have easily made ExecCopySlot() handle that case, itseems better to add an assert forbidding doing so instead. As the goalof copying might be to make the contents of one slot independent fromanother, it seems failure prone to handle doing so silently.A follow-up commit will add tests for the obviously under-coveredcombination of EPQ and triggers. Done as a separate commit as it mightmake sense to backpatch them further than this bug.Also remove confusion with confusing variable names for slots inExecBRDeleteTriggers() and ExecBRUpdateTriggers().Bug: #16036Reported-By: Антон ВласовAuthor: Andres FreundDiscussion:https://postgr.es/m/16036-28184c90d952fb7f@postgresql.orgBackpatch: 12-, whereff11e7f was merged
1 parenta586cc4 commitd986d4e

File tree

2 files changed

+24
-21
lines changed

2 files changed

+24
-21
lines changed

‎src/backend/commands/trigger.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2773,20 +2773,20 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
27732773
Assert(HeapTupleIsValid(fdw_trigtuple) ^ItemPointerIsValid(tupleid));
27742774
if (fdw_trigtuple==NULL)
27752775
{
2776-
TupleTableSlot*newSlot;
2776+
TupleTableSlot*epqslot_candidate=NULL;
27772777

27782778
if (!GetTupleForTrigger(estate,epqstate,relinfo,tupleid,
2779-
LockTupleExclusive,slot,&newSlot))
2779+
LockTupleExclusive,slot,&epqslot_candidate))
27802780
return false;
27812781

27822782
/*
27832783
* If the tuple was concurrently updated and the caller of this
27842784
* function requested for the updated tuple, skip the trigger
27852785
* execution.
27862786
*/
2787-
if (newSlot!=NULL&&epqslot!=NULL)
2787+
if (epqslot_candidate!=NULL&&epqslot!=NULL)
27882788
{
2789-
*epqslot=newSlot;
2789+
*epqslot=epqslot_candidate;
27902790
return false;
27912791
}
27922792

@@ -3026,11 +3026,11 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
30263026
Assert(HeapTupleIsValid(fdw_trigtuple) ^ItemPointerIsValid(tupleid));
30273027
if (fdw_trigtuple==NULL)
30283028
{
3029-
TupleTableSlot*newSlot=NULL;
3029+
TupleTableSlot*epqslot_candidate=NULL;
30303030

30313031
/* get a copy of the on-disk tuple we are planning to update */
30323032
if (!GetTupleForTrigger(estate,epqstate,relinfo,tupleid,
3033-
lockmode,oldslot,&newSlot))
3033+
lockmode,oldslot,&epqslot_candidate))
30343034
return false;/* cancel the update action */
30353035

30363036
/*
@@ -3045,11 +3045,14 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
30453045
* nor our caller have any more interest in the prior contents of that
30463046
* slot.
30473047
*/
3048-
if (newSlot!=NULL)
3048+
if (epqslot_candidate!=NULL)
30493049
{
3050-
TupleTableSlot*slot=ExecFilterJunk(relinfo->ri_junkFilter,newSlot);
3050+
TupleTableSlot*epqslot_clean;
30513051

3052-
ExecCopySlot(newslot,slot);
3052+
epqslot_clean=ExecFilterJunk(relinfo->ri_junkFilter,epqslot_candidate);
3053+
3054+
if (newslot!=epqslot_clean)
3055+
ExecCopySlot(newslot,epqslot_clean);
30533056
}
30543057

30553058
trigtuple=ExecFetchSlotHeapTuple(oldslot, true,&should_free_trig);
@@ -3311,17 +3314,17 @@ GetTupleForTrigger(EState *estate,
33113314
ItemPointertid,
33123315
LockTupleModelockmode,
33133316
TupleTableSlot*oldslot,
3314-
TupleTableSlot**newSlot)
3317+
TupleTableSlot**epqslot)
33153318
{
33163319
Relationrelation=relinfo->ri_RelationDesc;
33173320

3318-
if (newSlot!=NULL)
3321+
if (epqslot!=NULL)
33193322
{
33203323
TM_Resulttest;
33213324
TM_FailureDatatmfd;
33223325
intlockflags=0;
33233326

3324-
*newSlot=NULL;
3327+
*epqslot=NULL;
33253328

33263329
/* caller must pass an epqstate if EvalPlanQual is possible */
33273330
Assert(epqstate!=NULL);
@@ -3361,21 +3364,20 @@ GetTupleForTrigger(EState *estate,
33613364
caseTM_Ok:
33623365
if (tmfd.traversed)
33633366
{
3364-
TupleTableSlot*epqslot;
3365-
3366-
epqslot=EvalPlanQual(epqstate,
3367-
relation,
3368-
relinfo->ri_RangeTableIndex,
3369-
oldslot);
3367+
*epqslot=EvalPlanQual(epqstate,
3368+
relation,
3369+
relinfo->ri_RangeTableIndex,
3370+
oldslot);
33703371

33713372
/*
33723373
* If PlanQual failed for updated tuple - we must not
33733374
* process this tuple!
33743375
*/
3375-
if (TupIsNull(epqslot))
3376+
if (TupIsNull(*epqslot))
3377+
{
3378+
*epqslot=NULL;
33763379
return false;
3377-
3378-
*newSlot=epqslot;
3380+
}
33793381
}
33803382
break;
33813383

‎src/include/executor/tuptable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ static inline TupleTableSlot *
476476
ExecCopySlot(TupleTableSlot*dstslot,TupleTableSlot*srcslot)
477477
{
478478
Assert(!TTS_EMPTY(srcslot));
479+
AssertArg(srcslot!=dstslot);
479480

480481
dstslot->tts_ops->copyslot(dstslot,srcslot);
481482

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp