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

Commitf337658

Browse files
committed
Fix locking a tuple updated by an aborted (sub)transaction
When heap_lock_tuple decides to follow the update chain, it tried toalso lock any version of the tuple that was created by an update thatwas subsequently rolled back. This is pointless, since for all intentsand purposes that tuple exists no more; and moreover it causesmisbehavior, as reported independently by Marko Tiikkaja and MartiRaudsepp: some SELECT FOR UPDATE/SHARE queries may fail to returnthe tuples, and assertion-enabled builds crash.Fix by having heap_lock_updated_tuple test the xmin and return successimmediately if the tuple was created by an aborted transaction.The condition where tuples become invisible occurs when an updated tuplechain is followed by heap_lock_updated_tuple, which reports the problemas HeapTupleSelfUpdated to its caller heap_lock_tuple, which in turnpropagates that code outwards possibly leading the calling code(ExecLockRows) to believe that the tuple exists no longer.Backpatch to 9.3. Only on 9.5 and newer this leads to a visiblefailure, because of commit27846f0; before that, heap_lock_tupleskips the whole dance when the tuple is already locked by the sametransaction, because of the ancient HeapTupleSatisfiesUpdate behavior.Still, the buggy condition may also exist in more convoluted scenariosinvolving concurrent transactions, so it seems safer to fix the bug inthe old branches too.Discussion:https://www.postgresql.org/message-id/CABRT9RC81YUf1=jsmWopcKJEro=VoeG2ou6sPwyOUTx_qteRsg@mail.gmail.comhttps://www.postgresql.org/message-id/48d3eade-98d3-8b9a-477e-1a8dc32a724d@joh.to
1 parentf3b3e87 commitf337658

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

‎src/backend/access/heap/heapam.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5403,6 +5403,17 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
54035403
returnHeapTupleMayBeUpdated;
54045404
}
54055405

5406+
/*
5407+
* Also check Xmin: if this tuple was created by an aborted
5408+
* (sub)transaction, then we already locked the last live one in the
5409+
* chain, thus we're done, so return success.
5410+
*/
5411+
if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(mytup.t_data)))
5412+
{
5413+
UnlockReleaseBuffer(buf);
5414+
returnHeapTupleMayBeUpdated;
5415+
}
5416+
54065417
old_infomask=mytup.t_data->t_infomask;
54075418
old_infomask2=mytup.t_data->t_infomask2;
54085419
xmax=HeapTupleHeaderGetRawXmax(mytup.t_data);

‎src/test/regress/expected/combocid.out

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,30 @@ SELECT ctid,cmin,* FROM combocidtest;
140140
(0,6) | 0 | 444
141141
(3 rows)
142142

143+
-- test for bug reported in
144+
-- CABRT9RC81YUf1=jsmWopcKJEro=VoeG2ou6sPwyOUTx_qteRsg@mail.gmail.com
145+
CREATE TABLE IF NOT EXISTS testcase(
146+
id int PRIMARY KEY,
147+
balance numeric
148+
);
149+
INSERT INTO testcase VALUES (1, 0);
150+
BEGIN;
151+
SELECT * FROM testcase WHERE testcase.id = 1 FOR UPDATE;
152+
id | balance
153+
----+---------
154+
1 | 0
155+
(1 row)
156+
157+
UPDATE testcase SET balance = balance + 400 WHERE id=1;
158+
SAVEPOINT subxact;
159+
UPDATE testcase SET balance = balance - 100 WHERE id=1;
160+
ROLLBACK TO SAVEPOINT subxact;
161+
-- should return one tuple
162+
SELECT * FROM testcase WHERE id = 1 FOR UPDATE;
163+
id | balance
164+
----+---------
165+
1 | 400
166+
(1 row)
167+
168+
ROLLBACK;
169+
DROP TABLE testcase;

‎src/test/regress/sql/combocid.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,21 @@ SELECT ctid,cmin,* FROM combocidtest;
9191
COMMIT;
9292

9393
SELECT ctid,cmin,*FROM combocidtest;
94+
95+
-- test for bug reported in
96+
-- CABRT9RC81YUf1=jsmWopcKJEro=VoeG2ou6sPwyOUTx_qteRsg@mail.gmail.com
97+
CREATETABLEIF NOT EXISTS testcase(
98+
idintPRIMARY KEY,
99+
balancenumeric
100+
);
101+
INSERT INTO testcaseVALUES (1,0);
102+
BEGIN;
103+
SELECT*FROM testcaseWHEREtestcase.id=1 FORUPDATE;
104+
UPDATE testcaseSET balance= balance+400WHERE id=1;
105+
SAVEPOINT subxact;
106+
UPDATE testcaseSET balance= balance-100WHERE id=1;
107+
ROLLBACK TO SAVEPOINT subxact;
108+
-- should return one tuple
109+
SELECT*FROM testcaseWHERE id=1 FORUPDATE;
110+
ROLLBACK;
111+
DROPTABLE testcase;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp