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

Commitd487afb

Browse files
committed
Fix PlanRowMark/ExecRowMark structures to handle inheritance correctly.
In an inherited UPDATE/DELETE, each target table has its own subplan,because it might have a column set different from other targets. Thismeans that the resjunk columns we add to support EvalPlanQual might beat different physical column numbers in each subplan. The EvalPlanQualrewrite I did for 9.0 failed to account for this, resulting in possiblemisbehavior or even crashes during concurrent updates to the same row,as seen in a recent report from Gordon Shannon. Revise the data structureso that we track resjunk column numbers separately for each subplan.I also chose to move responsibility for identifying the physical columnnumbers back to executor startup, instead of assuming that numbers derivedduring preprocess_targetlist would stay valid throughout subsequentmassaging of the plan. That's a bit slower, so we might want to considerundoing it someday; but it would complicate the patch considerably anddidn't seem justifiable in a bug fix that has to be back-patched to 9.0.
1 parent7a32ff9 commitd487afb

File tree

12 files changed

+192
-122
lines changed

12 files changed

+192
-122
lines changed

‎src/backend/executor/execJunk.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,22 @@ ExecInitJunkFilterConversion(List *targetList,
207207
*/
208208
AttrNumber
209209
ExecFindJunkAttribute(JunkFilter*junkfilter,constchar*attrName)
210+
{
211+
returnExecFindJunkAttributeInTlist(junkfilter->jf_targetList,attrName);
212+
}
213+
214+
/*
215+
* ExecFindJunkAttributeInTlist
216+
*
217+
* Find a junk attribute given a subplan's targetlist (not necessarily
218+
* part of a JunkFilter).
219+
*/
220+
AttrNumber
221+
ExecFindJunkAttributeInTlist(List*targetlist,constchar*attrName)
210222
{
211223
ListCell*t;
212224

213-
foreach(t,junkfilter->jf_targetList)
225+
foreach(t,targetlist)
214226
{
215227
TargetEntry*tle=lfirst(t);
216228

‎src/backend/executor/execMain.c

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -744,9 +744,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
744744
erm->prti=rc->prti;
745745
erm->markType=rc->markType;
746746
erm->noWait=rc->noWait;
747-
erm->ctidAttNo=rc->ctidAttNo;
748-
erm->toidAttNo=rc->toidAttNo;
749-
erm->wholeAttNo=rc->wholeAttNo;
750747
ItemPointerSetInvalid(&(erm->curCtid));
751748
estate->es_rowMarks=lappend(estate->es_rowMarks,erm);
752749
}
@@ -1386,6 +1383,71 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
13861383
}
13871384

13881385

1386+
/*
1387+
* ExecFindRowMark -- find the ExecRowMark struct for given rangetable index
1388+
*/
1389+
ExecRowMark*
1390+
ExecFindRowMark(EState*estate,Indexrti)
1391+
{
1392+
ListCell*lc;
1393+
1394+
foreach(lc,estate->es_rowMarks)
1395+
{
1396+
ExecRowMark*erm= (ExecRowMark*)lfirst(lc);
1397+
1398+
if (erm->rti==rti)
1399+
returnerm;
1400+
}
1401+
elog(ERROR,"failed to find ExecRowMark for rangetable index %u",rti);
1402+
returnNULL;/* keep compiler quiet */
1403+
}
1404+
1405+
/*
1406+
* ExecBuildAuxRowMark -- create an ExecAuxRowMark struct
1407+
*
1408+
* Inputs are the underlying ExecRowMark struct and the targetlist of the
1409+
* input plan node (not planstate node!). We need the latter to find out
1410+
* the column numbers of the resjunk columns.
1411+
*/
1412+
ExecAuxRowMark*
1413+
ExecBuildAuxRowMark(ExecRowMark*erm,List*targetlist)
1414+
{
1415+
ExecAuxRowMark*aerm= (ExecAuxRowMark*)palloc0(sizeof(ExecAuxRowMark));
1416+
charresname[32];
1417+
1418+
aerm->rowmark=erm;
1419+
1420+
/* Look up the resjunk columns associated with this rowmark */
1421+
if (erm->relation)
1422+
{
1423+
Assert(erm->markType!=ROW_MARK_COPY);
1424+
1425+
/* if child rel, need tableoid */
1426+
if (erm->rti!=erm->prti)
1427+
{
1428+
snprintf(resname,sizeof(resname),"tableoid%u",erm->prti);
1429+
aerm->toidAttNo=ExecFindJunkAttributeInTlist(targetlist,
1430+
resname);
1431+
}
1432+
1433+
/* always need ctid for real relations */
1434+
snprintf(resname,sizeof(resname),"ctid%u",erm->prti);
1435+
aerm->ctidAttNo=ExecFindJunkAttributeInTlist(targetlist,
1436+
resname);
1437+
}
1438+
else
1439+
{
1440+
Assert(erm->markType==ROW_MARK_COPY);
1441+
1442+
snprintf(resname,sizeof(resname),"wholerow%u",erm->prti);
1443+
aerm->wholeAttNo=ExecFindJunkAttributeInTlist(targetlist,
1444+
resname);
1445+
}
1446+
1447+
returnaerm;
1448+
}
1449+
1450+
13891451
/*
13901452
* EvalPlanQual logic --- recheck modified tuple(s) to see if we want to
13911453
* process the updated version under READ COMMITTED rules.
@@ -1676,19 +1738,21 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
16761738
/*
16771739
* EvalPlanQualInit -- initialize during creation of a plan state node
16781740
* that might need to invoke EPQ processing.
1679-
* Note: subplan can be NULL if it will be set later with EvalPlanQualSetPlan.
1741+
*
1742+
* Note: subplan/auxrowmarks can be NULL/NIL if they will be set later
1743+
* with EvalPlanQualSetPlan.
16801744
*/
16811745
void
16821746
EvalPlanQualInit(EPQState*epqstate,EState*estate,
1683-
Plan*subplan,intepqParam)
1747+
Plan*subplan,List*auxrowmarks,intepqParam)
16841748
{
16851749
/* Mark the EPQ state inactive */
16861750
epqstate->estate=NULL;
16871751
epqstate->planstate=NULL;
16881752
epqstate->origslot=NULL;
16891753
/* ... and remember data that EvalPlanQualBegin will need */
16901754
epqstate->plan=subplan;
1691-
epqstate->rowMarks=NIL;
1755+
epqstate->arowMarks=auxrowmarks;
16921756
epqstate->epqParam=epqParam;
16931757
}
16941758

@@ -1698,25 +1762,14 @@ EvalPlanQualInit(EPQState *epqstate, EState *estate,
16981762
* We need this so that ModifyTuple can deal with multiple subplans.
16991763
*/
17001764
void
1701-
EvalPlanQualSetPlan(EPQState*epqstate,Plan*subplan)
1765+
EvalPlanQualSetPlan(EPQState*epqstate,Plan*subplan,List*auxrowmarks)
17021766
{
17031767
/* If we have a live EPQ query, shut it down */
17041768
EvalPlanQualEnd(epqstate);
17051769
/* And set/change the plan pointer */
17061770
epqstate->plan=subplan;
1707-
}
1708-
1709-
/*
1710-
* EvalPlanQualAddRowMark -- add an ExecRowMark that EPQ needs to handle.
1711-
*
1712-
* Currently, only non-locking RowMarks are supported.
1713-
*/
1714-
void
1715-
EvalPlanQualAddRowMark(EPQState*epqstate,ExecRowMark*erm)
1716-
{
1717-
if (RowMarkRequiresRowShareLock(erm->markType))
1718-
elog(ERROR,"EvalPlanQual doesn't support locking rowmarks");
1719-
epqstate->rowMarks=lappend(epqstate->rowMarks,erm);
1771+
/* The rowmarks depend on the plan, too */
1772+
epqstate->arowMarks=auxrowmarks;
17201773
}
17211774

17221775
/*
@@ -1766,13 +1819,17 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
17661819

17671820
Assert(epqstate->origslot!=NULL);
17681821

1769-
foreach(l,epqstate->rowMarks)
1822+
foreach(l,epqstate->arowMarks)
17701823
{
1771-
ExecRowMark*erm= (ExecRowMark*)lfirst(l);
1824+
ExecAuxRowMark*aerm= (ExecAuxRowMark*)lfirst(l);
1825+
ExecRowMark*erm=aerm->rowmark;
17721826
Datumdatum;
17731827
boolisNull;
17741828
HeapTupleDatatuple;
17751829

1830+
if (RowMarkRequiresRowShareLock(erm->markType))
1831+
elog(ERROR,"EvalPlanQual doesn't support locking rowmarks");
1832+
17761833
/* clear any leftover test tuple for this rel */
17771834
EvalPlanQualSetTuple(epqstate,erm->rti,NULL);
17781835

@@ -1788,7 +1845,7 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
17881845
Oidtableoid;
17891846

17901847
datum=ExecGetJunkAttribute(epqstate->origslot,
1791-
erm->toidAttNo,
1848+
aerm->toidAttNo,
17921849
&isNull);
17931850
/* non-locked rels could be on the inside of outer joins */
17941851
if (isNull)
@@ -1804,7 +1861,7 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
18041861

18051862
/* fetch the tuple's ctid */
18061863
datum=ExecGetJunkAttribute(epqstate->origslot,
1807-
erm->ctidAttNo,
1864+
aerm->ctidAttNo,
18081865
&isNull);
18091866
/* non-locked rels could be on the inside of outer joins */
18101867
if (isNull)
@@ -1829,7 +1886,7 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
18291886

18301887
/* fetch the whole-row Var for the relation */
18311888
datum=ExecGetJunkAttribute(epqstate->origslot,
1832-
erm->wholeAttNo,
1889+
aerm->wholeAttNo,
18331890
&isNull);
18341891
/* non-locked rels could be on the inside of outer joins */
18351892
if (isNull)

‎src/backend/executor/nodeLockRows.c

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,13 @@ ExecLockRows(LockRowsState *node)
5858

5959
/*
6060
* Attempt to lock the source tuple(s). (Note we only have locking
61-
* rowmarks inlr_rowMarks.)
61+
* rowmarks inlr_arowMarks.)
6262
*/
6363
epq_started= false;
64-
foreach(lc,node->lr_rowMarks)
64+
foreach(lc,node->lr_arowMarks)
6565
{
66-
ExecRowMark*erm= (ExecRowMark*)lfirst(lc);
66+
ExecAuxRowMark*aerm= (ExecAuxRowMark*)lfirst(lc);
67+
ExecRowMark*erm=aerm->rowmark;
6768
Datumdatum;
6869
boolisNull;
6970
HeapTupleDatatuple;
@@ -84,7 +85,7 @@ ExecLockRows(LockRowsState *node)
8485
Oidtableoid;
8586

8687
datum=ExecGetJunkAttribute(slot,
87-
erm->toidAttNo,
88+
aerm->toidAttNo,
8889
&isNull);
8990
/* shouldn't ever get a null result... */
9091
if (isNull)
@@ -101,7 +102,7 @@ ExecLockRows(LockRowsState *node)
101102

102103
/* fetch the tuple's ctid */
103104
datum=ExecGetJunkAttribute(slot,
104-
erm->ctidAttNo,
105+
aerm->ctidAttNo,
105106
&isNull);
106107
/* shouldn't ever get a null result... */
107108
if (isNull)
@@ -189,9 +190,10 @@ ExecLockRows(LockRowsState *node)
189190
* so as to avoid overhead in the common case where there are no
190191
* concurrent updates.)
191192
*/
192-
foreach(lc,node->lr_rowMarks)
193+
foreach(lc,node->lr_arowMarks)
193194
{
194-
ExecRowMark*erm= (ExecRowMark*)lfirst(lc);
195+
ExecAuxRowMark*aerm= (ExecAuxRowMark*)lfirst(lc);
196+
ExecRowMark*erm=aerm->rowmark;
195197
HeapTupleDatatuple;
196198
Bufferbuffer;
197199

@@ -251,6 +253,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
251253
{
252254
LockRowsState*lrstate;
253255
Plan*outerPlan=outerPlan(node);
256+
List*epq_arowmarks;
254257
ListCell*lc;
255258

256259
/* check for unsupported flags */
@@ -262,7 +265,6 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
262265
lrstate=makeNode(LockRowsState);
263266
lrstate->ps.plan= (Plan*)node;
264267
lrstate->ps.state=estate;
265-
EvalPlanQualInit(&lrstate->lr_epqstate,estate,outerPlan,node->epqParam);
266268

267269
/*
268270
* Miscellaneous initialization
@@ -288,32 +290,27 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
288290
lrstate->ps.ps_ProjInfo=NULL;
289291

290292
/*
291-
* Locate the ExecRowMark(s) that this node is responsible for. (InitPlan
292-
* should already have built the global list of ExecRowMarks.)
293+
* Locate the ExecRowMark(s) that this node is responsible for, and
294+
* construct ExecAuxRowMarks for them. (InitPlan should already have
295+
* built the global list of ExecRowMarks.)
293296
*/
294-
lrstate->lr_rowMarks=NIL;
297+
lrstate->lr_arowMarks=NIL;
298+
epq_arowmarks=NIL;
295299
foreach(lc,node->rowMarks)
296300
{
297301
PlanRowMark*rc= (PlanRowMark*)lfirst(lc);
298-
ExecRowMark*erm=NULL;
299-
ListCell*lce;
302+
ExecRowMark*erm;
303+
ExecAuxRowMark*aerm;
300304

301305
Assert(IsA(rc,PlanRowMark));
302306

303307
/* ignore "parent" rowmarks; they are irrelevant at runtime */
304308
if (rc->isParent)
305309
continue;
306310

307-
foreach(lce,estate->es_rowMarks)
308-
{
309-
erm= (ExecRowMark*)lfirst(lce);
310-
if (erm->rti==rc->rti)
311-
break;
312-
erm=NULL;
313-
}
314-
if (erm==NULL)
315-
elog(ERROR,"failed to find ExecRowMark for PlanRowMark %u",
316-
rc->rti);
311+
/* find ExecRowMark and build ExecAuxRowMark */
312+
erm=ExecFindRowMark(estate,rc->rti);
313+
aerm=ExecBuildAuxRowMark(erm,outerPlan->targetlist);
317314

318315
/*
319316
* Only locking rowmarks go into our own list.Non-locking marks are
@@ -322,11 +319,15 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
322319
* do an EPQ recheck.
323320
*/
324321
if (RowMarkRequiresRowShareLock(erm->markType))
325-
lrstate->lr_rowMarks=lappend(lrstate->lr_rowMarks,erm);
322+
lrstate->lr_arowMarks=lappend(lrstate->lr_arowMarks,aerm);
326323
else
327-
EvalPlanQualAddRowMark(&lrstate->lr_epqstate,erm);
324+
epq_arowmarks=lappend(epq_arowmarks,aerm);
328325
}
329326

327+
/* Now we have the info needed to set up EPQ state */
328+
EvalPlanQualInit(&lrstate->lr_epqstate,estate,
329+
outerPlan,epq_arowmarks,node->epqParam);
330+
330331
returnlrstate;
331332
}
332333

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp