From df66ff9304da898ffe804c934e1c2fc3a8829a54 Mon Sep 17 00:00:00 2001
From: Amul Sul <sulamul@gmail.com>
Date: Fri, 12 Jan 2018 11:30:40 +0530
Subject: [PATCH 2/2] isolation tests v3

v3:
 - Rebase on "UPDATE of partition key v35" patch[2] and
  latest maste head[3].

v2:
 - Error message changed.
 - Can't add isolation test[1] for
 	RelationFindReplTupleByIndex & RelationFindReplTupleSeq
 - In ExecOnConflictUpdate, the error report is converted to assert
   check.

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

 ------------
  References:
 ------------
 1] https://postgr.es/m/CA+TgmoYsMRo2PHFTGUFifv4ZSCZ9LNJASbOyb=9it2=UA4j4vw@mail.gmail.com
 2] https://postgr.es/m/CAJ3gD9dixkkMzNnnP1CaZ1H17-U17ok_sVbjZZo+wnB=rJH6yg@mail.gmail.com
 3] Commit id bdb70c12b3a2e69eec6e51411df60d9f43ecc841
---
 .../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..c33960a0d2
--- /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 locked was already moved to 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 locked was already moved to 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..195ec4cedf
--- /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 locked was already moved to 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..1922bdce46
--- /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 another partition due to concurrent update
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index befe676816..3545b1b758 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -65,3 +65,6 @@ test: async-notify
 test: vacuum-reltuples
 test: timeouts
 test: vacuum-concurrent-drop
+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

