summaryrefslogtreecommitdiffstats
path: root/src/test/isolation/specs/lock-update-delete.spec
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/isolation/specs/lock-update-delete.spec')
-rw-r--r--src/test/isolation/specs/lock-update-delete.spec61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/test/isolation/specs/lock-update-delete.spec b/src/test/isolation/specs/lock-update-delete.spec
new file mode 100644
index 0000000..b9dd7d1
--- /dev/null
+++ b/src/test/isolation/specs/lock-update-delete.spec
@@ -0,0 +1,61 @@
+# This test verifies behavior when traversing an update chain during
+# locking an old version of the tuple. There are three tests here:
+# 1. update the tuple, then delete it; a second transaction locks the
+# first version. This should raise an error if the DELETE succeeds,
+# but be allowed to continue if it aborts.
+# 2. Same as (1), except that instead of deleting the tuple, we merely
+# update its key. The behavior should be the same as for (1).
+# 3. Same as (2), except that we update the tuple without modifying its
+# key. In this case, no error should be raised.
+# When run in REPEATABLE READ or SERIALIZABLE transaction isolation levels, all
+# permutations that commit s2 cause a serializability error; all permutations
+# that rollback s2 can get through.
+#
+# We use an advisory lock (which is locked during s1's setup) to let s2 obtain
+# its snapshot early and only allow it to actually traverse the update chain
+# when s1 is done creating it.
+
+setup
+{
+ DROP TABLE IF EXISTS foo;
+ CREATE TABLE foo (
+ key int PRIMARY KEY,
+ value int
+ );
+
+ INSERT INTO foo VALUES (1, 1);
+}
+
+teardown
+{
+ DROP TABLE foo;
+}
+
+session s1
+# obtain lock on the tuple, traversing its update chain
+step s1l { SELECT * FROM foo WHERE pg_advisory_xact_lock(0) IS NOT NULL AND key = 1 FOR KEY SHARE; }
+
+session s2
+setup { SELECT pg_advisory_lock(0); }
+step s2b { BEGIN; }
+step s2u { UPDATE foo SET value = 2 WHERE key = 1; }
+step s2_blocker1 { DELETE FROM foo; }
+step s2_blocker2 { UPDATE foo SET key = 2 WHERE key = 1; }
+step s2_blocker3 { UPDATE foo SET value = 2 WHERE key = 1; }
+step s2_unlock { SELECT pg_advisory_unlock(0); }
+step s2c { COMMIT; }
+step s2r { ROLLBACK; }
+
+permutation s2b s1l s2u s2_blocker1 s2_unlock s2c
+permutation s2b s1l s2u s2_blocker2 s2_unlock s2c
+permutation s2b s1l s2u s2_blocker3 s2_unlock s2c
+permutation s2b s1l s2u s2_blocker1 s2_unlock s2r
+permutation s2b s1l s2u s2_blocker2 s2_unlock s2r
+permutation s2b s1l s2u s2_blocker3 s2_unlock s2r
+
+permutation s2b s1l s2u s2_blocker1 s2c s2_unlock
+permutation s2b s1l s2u s2_blocker2 s2c s2_unlock
+permutation s2b s1l s2u s2_blocker3 s2c s2_unlock
+permutation s2b s1l s2u s2_blocker1 s2r s2_unlock
+permutation s2b s1l s2u s2_blocker2 s2r s2_unlock
+permutation s2b s1l s2u s2_blocker3 s2r s2_unlock