1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-18 04:29:09 +03:00

Don't ignore tuple locks propagated by our updates

If a tuple was locked by transaction A, and transaction B updated it,
the new version of the tuple created by B would be locked by A, yet
visible only to B; due to an oversight in HeapTupleSatisfiesUpdate, the
lock held by A wouldn't get checked if transaction B later deleted (or
key-updated) the new version of the tuple.  This might cause referential
integrity checks to give false positives (that is, allow deletes that
should have been rejected).

This is an easy oversight to have made, because prior to improved tuple
locks in commit 0ac5ad5134 it wasn't possible to have tuples created by
our own transaction that were also locked by remote transactions, and so
locks weren't even considered in that code path.

It is recommended that foreign keys be rechecked manually in bulk after
installing this update, in case some referenced rows are missing with
some referencing row remaining.

Per bug reported by Daniel Wood in
CAPweHKe5QQ1747X2c0tA=5zf4YnS2xcvGf13Opd-1Mq24rF1cQ@mail.gmail.com
This commit is contained in:
Alvaro Herrera
2013-12-18 13:31:27 -03:00
parent 65d6e4cb5c
commit 11ac4c73cb
6 changed files with 216 additions and 2 deletions

View File

@@ -0,0 +1,42 @@
# When an update propagates a preexisting lock on the updated tuple, make sure
# we don't ignore the lock in subsequent operations of the new version. (The
# version with the aborted savepoint uses a slightly different code path).
setup
{
create table parent (i int, c char(3));
create unique index parent_idx on parent (i);
insert into parent values (1, 'AAA');
create table child (i int references parent(i));
}
teardown
{
drop table child, parent;
}
session "s1"
step "s1b" { BEGIN; }
step "s1l" { INSERT INTO child VALUES (1); }
step "s1c" { COMMIT; }
session "s2"
step "s2b" { BEGIN; }
step "s2l" { INSERT INTO child VALUES (1); }
step "s2c" { COMMIT; }
session "s3"
step "s3b" { BEGIN; }
step "s3u" { UPDATE parent SET c=lower(c); } # no key update
step "s3u2" { UPDATE parent SET i = i; } # key update
step "s3svu" { SAVEPOINT f; UPDATE parent SET c = 'bbb'; ROLLBACK TO f; }
step "s3d" { DELETE FROM parent; }
step "s3c" { COMMIT; }
permutation "s1b" "s1l" "s2b" "s2l" "s3b" "s3u" "s3d" "s1c" "s2c" "s3c"
permutation "s1b" "s1l" "s2b" "s2l" "s3b" "s3u" "s3svu" "s3d" "s1c" "s2c" "s3c"
permutation "s1b" "s1l" "s2b" "s2l" "s3b" "s3u2" "s3d" "s1c" "s2c" "s3c"
permutation "s1b" "s1l" "s2b" "s2l" "s3b" "s3u2" "s3svu" "s3d" "s1c" "s2c" "s3c"
permutation "s1b" "s1l" "s3b" "s3u" "s3d" "s1c" "s3c"
permutation "s1b" "s1l" "s3b" "s3u" "s3svu" "s3d" "s1c" "s3c"
permutation "s1b" "s1l" "s3b" "s3u2" "s3d" "s1c" "s3c"
permutation "s1b" "s1l" "s3b" "s3u2" "s3svu" "s3d" "s1c" "s3c"