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

Commitd8d5a00

Browse files
committed
Fix EvalPlanQual bug when query contains both locked and not-locked rels.
In commitafb9249, we (probably I) made ExecLockRows assignnull test tuples to all relations of the query while setting up to do anEvalPlanQual recheck for a newly-updated locked row. This was sheerestbrain fade: we should only set test tuples for relations that are lockableby the LockRows node, and in particular empty test tuples are only sensiblefor inheritance child relations that weren't the source of the currenttuple from their inheritance tree. Setting a null test tuple for anunrelated table causes it to return NULLs when it should not, as exhibitedin bug #14034 from Bronislav Houdek. To add insult to injury, doing it thewrong way required two loops where one would suffice; so the corrected codeis even a bit shorter and faster.Add a regression test case based on his example, and back-patch to 9.5where the bug was introduced.
1 parent2f38b3e commitd8d5a00

File tree

3 files changed

+60
-22
lines changed

3 files changed

+60
-22
lines changed

‎src/backend/executor/nodeLockRows.c

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -262,29 +262,15 @@ ExecLockRows(LockRowsState *node)
262262
*/
263263
if (epq_needed)
264264
{
265-
inti;
266-
267265
/* Initialize EPQ machinery */
268266
EvalPlanQualBegin(&node->lr_epqstate,estate);
269267

270268
/*
271-
* Transfer already-fetched tuples into the EPQ state, and make sure
272-
* its test tuples for other tables are reset to NULL.
273-
*/
274-
for (i=0;i<node->lr_ntables;i++)
275-
{
276-
EvalPlanQualSetTuple(&node->lr_epqstate,
277-
i+1,
278-
node->lr_curtuples[i]);
279-
/* freeing this tuple is now the responsibility of EPQ */
280-
node->lr_curtuples[i]=NULL;
281-
}
282-
283-
/*
284-
* Next, fetch a copy of any rows that were successfully locked
285-
* without any update having occurred. (We do this in a separate pass
286-
* so as to avoid overhead in the common case where there are no
287-
* concurrent updates.)
269+
* Transfer any already-fetched tuples into the EPQ state, and fetch a
270+
* copy of any rows that were successfully locked without any update
271+
* having occurred. (We do this in a separate pass so as to avoid
272+
* overhead in the common case where there are no concurrent updates.)
273+
* Make sure any inactive child rels have NULL test tuples in EPQ.
288274
*/
289275
foreach(lc,node->lr_arowMarks)
290276
{
@@ -293,15 +279,25 @@ ExecLockRows(LockRowsState *node)
293279
HeapTupleDatatuple;
294280
Bufferbuffer;
295281

296-
/*ignore non-active child tables */
282+
/*skip non-active child tables, but clear their test tuples */
297283
if (!erm->ermActive)
298284
{
299285
Assert(erm->rti!=erm->prti);/* check it's child table */
286+
EvalPlanQualSetTuple(&node->lr_epqstate,erm->rti,NULL);
300287
continue;
301288
}
302289

303-
if (EvalPlanQualGetTuple(&node->lr_epqstate,erm->rti)!=NULL)
304-
continue;/* it was updated and fetched above */
290+
/* was tuple updated and fetched above? */
291+
if (node->lr_curtuples[erm->rti-1]!=NULL)
292+
{
293+
/* yes, so set it as the EPQ test tuple for this rel */
294+
EvalPlanQualSetTuple(&node->lr_epqstate,
295+
erm->rti,
296+
node->lr_curtuples[erm->rti-1]);
297+
/* freeing this tuple is now the responsibility of EPQ */
298+
node->lr_curtuples[erm->rti-1]=NULL;
299+
continue;
300+
}
305301

306302
/* foreign tables should have been fetched above */
307303
Assert(erm->relation->rd_rel->relkind!=RELKIND_FOREIGN_TABLE);

‎src/test/isolation/expected/eval-plan-qual.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,22 @@ accountid balance
144144

145145
checking 1050
146146
savings 600
147+
148+
starting permutation: updateforss readforss c1 c2
149+
step updateforss:
150+
UPDATE table_a SET value = 'newTableAValue' WHERE id = 1;
151+
UPDATE table_b SET value = 'newTableBValue' WHERE id = 1;
152+
153+
step readforss:
154+
SELECT ta.id AS ta_id, ta.value AS ta_value,
155+
(SELECT ROW(tb.id, tb.value)
156+
FROM table_b tb WHERE ta.id = tb.id) AS tb_row
157+
FROM table_a ta
158+
WHERE ta.id = 1 FOR UPDATE OF ta;
159+
<waiting ...>
160+
step c1: COMMIT;
161+
step readforss: <... completed>
162+
ta_id ta_value tb_row
163+
164+
1 newTableAValue (1,tableBValue)
165+
step c2: COMMIT;

‎src/test/isolation/specs/eval-plan-qual.spec

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,18 @@ setup
1616
INSERTINTOc1SELECT0,a/3,a%3FROMgenerate_series(0,9)a;
1717
INSERTINTOc2SELECT1,a/3,a%3FROMgenerate_series(0,9)a;
1818
INSERTINTOc3SELECT2,a/3,a%3FROMgenerate_series(0,9)a;
19+
20+
CREATETABLEtable_a (idinteger,valuetext);
21+
CREATETABLEtable_b (idinteger,valuetext);
22+
INSERTINTOtable_aVALUES (1,'tableAValue');
23+
INSERTINTOtable_bVALUES (1,'tableBValue');
1924
}
2025

2126
teardown
2227
{
2328
DROPTABLEaccounts;
2429
DROPTABLEpCASCADE;
30+
DROPTABLEtable_a,table_b;
2531
}
2632

2733
session"s1"
@@ -64,6 +70,15 @@ step "lockwithvalues"{
6470
FORUPDATEOFa1;
6571
}
6672

73+
# these tests exercise EvalPlanQual with a SubLink sub-select (which should be
74+
# unaffected by any EPQ recheck behavior in the outer query); cf bug #14034
75+
76+
step"updateforss"{
77+
UPDATEtable_aSETvalue='newTableAValue'WHEREid=1;
78+
UPDATEtable_bSETvalue='newTableBValue'WHEREid=1;
79+
}
80+
81+
6782
session"s2"
6883
setup{BEGINISOLATIONLEVELREADCOMMITTED; }
6984
step"wx2"{UPDATEaccountsSETbalance=balance+450WHEREaccountid='checking'; }
@@ -81,6 +96,13 @@ step "returningp1" {
8196
WITHuAS (UPDATEpSETb=bWHEREa>0RETURNING* )
8297
SELECT*FROMu;
8398
}
99+
step"readforss"{
100+
SELECTta.idASta_id,ta.valueASta_value,
101+
(SELECTROW(tb.id,tb.value)
102+
FROMtable_btbWHEREta.id=tb.id)AStb_row
103+
FROMtable_ata
104+
WHEREta.id=1FORUPDATEOFta;
105+
}
84106
step"c2"{COMMIT; }
85107

86108
session"s3"
@@ -95,3 +117,4 @@ permutation "readp1" "writep1" "readp2" "c1" "c2"
95117
permutation"writep2""returningp1""c1""c2"
96118
permutation"wx2""partiallock""c2""c1""read"
97119
permutation"wx2""lockwithvalues""c2""c1""read"
120+
permutation"updateforss""readforss""c1""c2"

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp