From a50723ddec935dc3182e641aa7fe84e78fb2d857 Mon Sep 17 00:00:00 2001
From: Amul Sul <sulamul@gmail.com>
Date: Thu, 23 Nov 2017 16:30:03 +0530
Subject: [PATCH 2/2] isolation tests v1

v1:
 Added isolation tests to hit an error in the following functions:
 1. ExecUpdate  	-> specs/partition-key-update-1
 2. ExecDelete		-> specs/partition-key-update-1
 3. GetTupleForTrigger	-> specs/partition-key-update-2
 4. ExecLockRows	-> specs/partition-key-update-3

TODOs:
 Tests for the following function yet to add.
 1. EvalPlanQualFetch
 2. ExecOnConflictUpdate
 3. RelationFindReplTupleByIndex
 4. RelationFindReplTupleSeq
---
 .../isolation/expected/partition-key-update-1.out  | 35 +++++++++++++++++++
 .../isolation/expected/partition-key-update-2.out  | 18 ++++++++++
 .../isolation/expected/partition-key-update-3.out  |  8 +++++
 src/test/isolation/isolation_schedule              |  3 ++
 .../isolation/specs/partition-key-update-1.spec    | 37 ++++++++++++++++++++
 .../isolation/specs/partition-key-update-2.spec    | 39 ++++++++++++++++++++++
 .../isolation/specs/partition-key-update-3.spec    | 30 +++++++++++++++++
 7 files changed, 170 insertions(+)
 create mode 100644 src/test/isolation/expected/partition-key-update-1.out
 create mode 100644 src/test/isolation/expected/partition-key-update-2.out
 create mode 100644 src/test/isolation/expected/partition-key-update-3.out
 create mode 100644 src/test/isolation/specs/partition-key-update-1.spec
 create mode 100644 src/test/isolation/specs/partition-key-update-2.spec
 create mode 100644 src/test/isolation/specs/partition-key-update-3.spec

diff --git a/src/test/isolation/expected/partition-key-update-1.out b/src/test/isolation/expected/partition-key-update-1.out
new file mode 100644
index 0000000000..27820ea900
--- /dev/null
+++ b/src/test/isolation/expected/partition-key-update-1.out
@@ -0,0 +1,35 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1u s1c s2u
+step s1u: UPDATE foo SET a=2 WHERE a=1;
+step s1c: COMMIT;
+step s2u: UPDATE foo SET b='EFG' WHERE a=1;
+
+starting permutation: s1u s2u s1c
+step s1u: UPDATE foo SET a=2 WHERE a=1;
+step s2u: UPDATE foo SET b='EFG' WHERE a=1; <waiting ...>
+step s1c: COMMIT;
+step s2u: <... completed>
+error in steps s1c s2u: ERROR:  tuple to be updated was already moved to an another partition due to concurrent update
+
+starting permutation: s2u s1u s1c
+step s2u: UPDATE foo SET b='EFG' WHERE a=1;
+step s1u: UPDATE foo SET a=2 WHERE a=1;
+step s1c: COMMIT;
+
+starting permutation: s1u s1c s2d
+step s1u: UPDATE foo SET a=2 WHERE a=1;
+step s1c: COMMIT;
+step s2d: DELETE FROM foo WHERE a=1;
+
+starting permutation: s1u s2d s1c
+step s1u: UPDATE foo SET a=2 WHERE a=1;
+step s2d: DELETE FROM foo WHERE a=1; <waiting ...>
+step s1c: COMMIT;
+step s2d: <... completed>
+error in steps s1c s2d: ERROR:  tuple to be updated was already moved to an another partition due to concurrent update
+
+starting permutation: s2d s1u s1c
+step s2d: DELETE FROM foo WHERE a=1;
+step s1u: UPDATE foo SET a=2 WHERE a=1;
+step s1c: COMMIT;
diff --git a/src/test/isolation/expected/partition-key-update-2.out b/src/test/isolation/expected/partition-key-update-2.out
new file mode 100644
index 0000000000..afe9415ea4
--- /dev/null
+++ b/src/test/isolation/expected/partition-key-update-2.out
@@ -0,0 +1,18 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1u s1c s2u
+step s1u: UPDATE foo SET b='EFG' WHERE a=1;
+step s1c: COMMIT;
+step s2u: UPDATE foo SET b='XYZ' WHERE a=1;
+
+starting permutation: s1u s2u s1c
+step s1u: UPDATE foo SET b='EFG' WHERE a=1;
+step s2u: UPDATE foo SET b='XYZ' WHERE a=1; <waiting ...>
+step s1c: COMMIT;
+step s2u: <... completed>
+error in steps s1c s2u: ERROR:  tuple to be updated was already moved to an another partition due to concurrent update
+
+starting permutation: s2u s1u s1c
+step s2u: UPDATE foo SET b='XYZ' WHERE a=1;
+step s1u: UPDATE foo SET b='EFG' WHERE a=1;
+step s1c: COMMIT;
diff --git a/src/test/isolation/expected/partition-key-update-3.out b/src/test/isolation/expected/partition-key-update-3.out
new file mode 100644
index 0000000000..63714a0cf6
--- /dev/null
+++ b/src/test/isolation/expected/partition-key-update-3.out
@@ -0,0 +1,8 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1u3 s2i s1c
+step s1u3: UPDATE foo_r SET a=11 WHERE a=7 AND b = 'ABC';
+step s2i: INSERT INTO bar VALUES(7); <waiting ...>
+step s1c: COMMIT;
+step s2i: <... completed>
+error in steps s1c s2i: ERROR:  tuple to be locked was already moved to an another partition due to concurrent update
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 32c965b2a0..e9a94996b4 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -62,3 +62,6 @@ test: sequence-ddl
 test: async-notify
 test: vacuum-reltuples
 test: timeouts
+test: partition-key-update-1
+test: partition-key-update-2
+test: partition-key-update-3
diff --git a/src/test/isolation/specs/partition-key-update-1.spec b/src/test/isolation/specs/partition-key-update-1.spec
new file mode 100644
index 0000000000..db76c9a9b5
--- /dev/null
+++ b/src/test/isolation/specs/partition-key-update-1.spec
@@ -0,0 +1,37 @@
+# Concurrency error from ExecUpdate and ExecDelete.
+
+# Throw an error to indicate that the targeted row has been already moved to
+# another partition in the case of concurrency where a session trying to
+# update/delete a row that's locked for a concurrent update by the another
+# session cause tuple movement to the another partition due update of partition
+# key.
+
+setup
+{
+  CREATE TABLE foo (a int, b text) PARTITION BY LIST(a);
+  CREATE TABLE foo1 PARTITION OF foo FOR VALUES IN (1);
+  CREATE TABLE foo2 PARTITION OF foo FOR VALUES IN (2);
+  INSERT INTO foo VALUES (1, 'ABC');
+}
+
+teardown
+{
+  DROP TABLE foo;
+}
+
+session "s1"
+setup		{ BEGIN; }
+step "s1u"	{ UPDATE foo SET a=2 WHERE a=1; }
+step "s1c"	{ COMMIT; }
+
+session "s2"
+step "s2u"	{ UPDATE foo SET b='EFG' WHERE a=1; }
+step "s2d"	{ DELETE FROM foo WHERE a=1; }
+
+permutation "s1u" "s1c" "s2u"
+permutation "s1u" "s2u" "s1c"
+permutation "s2u" "s1u" "s1c"
+
+permutation "s1u" "s1c" "s2d"
+permutation "s1u" "s2d" "s1c"
+permutation "s2d" "s1u" "s1c"
diff --git a/src/test/isolation/specs/partition-key-update-2.spec b/src/test/isolation/specs/partition-key-update-2.spec
new file mode 100644
index 0000000000..b09e76ce21
--- /dev/null
+++ b/src/test/isolation/specs/partition-key-update-2.spec
@@ -0,0 +1,39 @@
+# Concurrency error from GetTupleForTrigger
+
+# Like partition-key-update-1.spec, throw an error where a session trying to
+# update a row that has been moved to another partition due to a concurrent
+# update by other seesion.
+
+setup
+{
+  CREATE TABLE foo (a int, b text) PARTITION BY LIST(a);
+  CREATE TABLE foo1 PARTITION OF foo FOR VALUES IN (1);
+  CREATE TABLE foo2 PARTITION OF foo FOR VALUES IN (2);
+  INSERT INTO foo VALUES (1, 'ABC');
+  CREATE FUNCTION func_foo_mod_a() RETURNS TRIGGER AS $$
+    BEGIN
+	  NEW.a = 2; -- This is changing partition key column.
+   RETURN NEW;
+  END $$ LANGUAGE PLPGSQL;
+  CREATE TRIGGER foo_mod_a BEFORE UPDATE ON foo1
+   FOR EACH ROW EXECUTE PROCEDURE func_foo_mod_a();
+}
+
+teardown
+{
+  DROP TRIGGER foo_mod_a ON foo1;
+  DROP FUNCTION func_foo_mod_a();
+  DROP TABLE foo;
+}
+
+session "s1"
+setup		{ BEGIN; }
+step "s1u"	{ UPDATE foo SET b='EFG' WHERE a=1; }
+step "s1c"	{ COMMIT; }
+
+session "s2"
+step "s2u"	{ UPDATE foo SET b='XYZ' WHERE a=1; }
+
+permutation "s1u" "s1c" "s2u"
+permutation "s1u" "s2u" "s1c"
+permutation "s2u" "s1u" "s1c"
diff --git a/src/test/isolation/specs/partition-key-update-3.spec b/src/test/isolation/specs/partition-key-update-3.spec
new file mode 100644
index 0000000000..c1f547d9ba
--- /dev/null
+++ b/src/test/isolation/specs/partition-key-update-3.spec
@@ -0,0 +1,30 @@
+# Concurrency error from ExecLockRows
+
+# Like partition-key-update-1.spec, throw an error where a session trying to
+# lock a row that has been moved to another partition due to a concurrent
+# update by other seesion.
+
+setup
+{
+  CREATE TABLE foo_r (a int, b text) PARTITION BY RANGE(a);
+  CREATE TABLE foo_r1 PARTITION OF foo_r FOR VALUES FROM (1) TO (10);
+  CREATE TABLE foo_r2 PARTITION OF foo_r FOR VALUES FROM (10) TO (20);
+  INSERT INTO foo_r VALUES(7, 'ABC');
+  CREATE UNIQUE INDEX foo_r1_a_unique ON foo_r1 (a);
+  CREATE TABLE bar (a int REFERENCES foo_r1(a));
+}
+
+teardown
+{
+  DROP TABLE bar, foo_r;
+}
+
+session "s1"
+setup		{ BEGIN; }
+step "s1u3"	{ UPDATE foo_r SET a=11 WHERE a=7 AND b = 'ABC'; }
+step "s1c"	{ COMMIT; }
+
+session "s2"
+step "s2i"	{ INSERT INTO bar VALUES(7); }
+
+permutation "s1u3" "s2i" "s1c"
-- 
2.14.1

