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

Commitd4fa18a

Browse files
committed
Avoid testing tuple visibility without buffer lock in RI_FKey_check().
Despite the argumentation I wrote in commit7a2fe85, it's unsafe to dothis, because in corner cases it's possible for HeapTupleSatisfiesSelfto try to set hint bits on the target tuple; and at least since 8.2 wehave required the buffer content lock to be held while setting hint bits.The added regression test exercises one such corner case. Unpatched, itcauses an assertion failure in assert-enabled builds, or otherwise wouldcause a hint bit change in a buffer we don't hold lock on, which giventhe right race condition could result in checksum failures or other dataconsistency problems. The odds of a problem in the field are probablypretty small, but nonetheless back-patch to all supported branches.Report: <19391.1477244876@sss.pgh.pa.us>
1 parent24542e2 commitd4fa18a

File tree

3 files changed

+54
-11
lines changed

3 files changed

+54
-11
lines changed

‎src/backend/utils/adt/ri_triggers.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include"parser/parse_coerce.h"
4343
#include"parser/parse_relation.h"
4444
#include"miscadmin.h"
45+
#include"storage/bufmgr.h"
4546
#include"utils/acl.h"
4647
#include"utils/builtins.h"
4748
#include"utils/fmgroids.h"
@@ -289,20 +290,17 @@ RI_FKey_check(PG_FUNCTION_ARGS)
289290
* We should not even consider checking the row if it is no longer valid,
290291
* since it was either deleted (so the deferred check should be skipped)
291292
* or updated (in which case only the latest version of the row should be
292-
* checked). Test its liveness according to SnapshotSelf.
293-
*
294-
* NOTE: The normal coding rule is that one must acquire the buffer
295-
* content lock to call HeapTupleSatisfiesVisibility. We can skip that
296-
* here because we know that AfterTriggerExecute just fetched the tuple
297-
* successfully, so there cannot be a VACUUM compaction in progress on the
298-
* page (either heap_fetch would have waited for the VACUUM, or the
299-
* VACUUM's LockBufferForCleanup would be waiting for us to drop pin). And
300-
* since this is a row inserted by our open transaction, no one else can
301-
* be entitled to change its xmin/xmax.
293+
* checked). Test its liveness according to SnapshotSelf. We need pin
294+
* and lock on the buffer to call HeapTupleSatisfiesVisibility. Caller
295+
* should be holding pin, but not lock.
302296
*/
303-
Assert(new_row_buf!=InvalidBuffer);
297+
LockBuffer(new_row_buf,BUFFER_LOCK_SHARE);
304298
if (!HeapTupleSatisfiesVisibility(new_row,SnapshotSelf,new_row_buf))
299+
{
300+
LockBuffer(new_row_buf,BUFFER_LOCK_UNLOCK);
305301
returnPointerGetDatum(NULL);
302+
}
303+
LockBuffer(new_row_buf,BUFFER_LOCK_UNLOCK);
306304

307305
/*
308306
* Get the relation descriptors of the FK and PK tables.

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,3 +1319,25 @@ begin;
13191319
(2 rows)
13201320

13211321
commit;
1322+
--
1323+
-- Test deferred FK check on a tuple deleted by a rolled-back subtransaction
1324+
--
1325+
create table pktable2(f1 int primary key);
1326+
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "pktable2_pkey" for table "pktable2"
1327+
create table fktable2(f1 int references pktable2 deferrable initially deferred);
1328+
insert into pktable2 values(1);
1329+
begin;
1330+
insert into fktable2 values(1);
1331+
savepoint x;
1332+
delete from fktable2;
1333+
rollback to x;
1334+
commit;
1335+
begin;
1336+
insert into fktable2 values(2);
1337+
savepoint x;
1338+
delete from fktable2;
1339+
rollback to x;
1340+
commit; -- fail
1341+
ERROR: insert or update on table "fktable2" violates foreign key constraint "fktable2_f1_fkey"
1342+
DETAIL: Key (f1)=(2) is not present in table "pktable2".
1343+
drop table pktable2, fktable2;

‎src/test/regress/sql/foreign_key.sql

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,3 +943,26 @@ begin;
943943
update selfrefset a=456where a=123;
944944
select a, bfrom selfref;
945945
commit;
946+
947+
--
948+
-- Test deferred FK check on a tuple deleted by a rolled-back subtransaction
949+
--
950+
createtablepktable2(f1intprimary key);
951+
createtablefktable2(f1intreferences pktable2 deferrable initially deferred);
952+
insert into pktable2values(1);
953+
954+
begin;
955+
insert into fktable2values(1);
956+
savepoint x;
957+
deletefrom fktable2;
958+
rollback to x;
959+
commit;
960+
961+
begin;
962+
insert into fktable2values(2);
963+
savepoint x;
964+
deletefrom fktable2;
965+
rollback to x;
966+
commit;-- fail
967+
968+
droptable pktable2, fktable2;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp