From ce3054a97c78325b06e67219fe0be3535b7be272 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Tue, 14 Sep 2021 15:28:09 -0700
Subject: [PATCH v34 10/10] Test ALTER SYSTEM READ ONLY against cursors.

Add an isolation test which checks the impact of setting the system
read-only upon cursors that use a FOR UPDATE query.
---
 .../expected/cursor-prohibit-wal.out          | 157 ++++++++++++++++++
 src/test/isolation/isolation_schedule         |   1 +
 .../isolation/specs/cursor-prohibit-wal.spec  |  38 +++++
 3 files changed, 196 insertions(+)
 create mode 100644 src/test/isolation/expected/cursor-prohibit-wal.out
 create mode 100644 src/test/isolation/specs/cursor-prohibit-wal.spec

diff --git a/src/test/isolation/expected/cursor-prohibit-wal.out b/src/test/isolation/expected/cursor-prohibit-wal.out
new file mode 100644
index 0000000000..6b479143a6
--- /dev/null
+++ b/src/test/isolation/expected/cursor-prohibit-wal.out
@@ -0,0 +1,157 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1a s1b s1c s2a s2b s1d
+step s1a: DECLARE rw_cur CURSOR FOR SELECT a FROM tbl WHERE a = 5000 FOR UPDATE;
+step s1b: FETCH FORWARD ALL FROM rw_cur;
+   a
+----
+5000
+(1 row)
+
+step s1c: CLOSE ALL;
+step s2a: SELECT pg_prohibit_wal(true);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+step s2b: SELECT pg_prohibit_wal(false);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+PQconsumeInput failed: FATAL:  WAL is now prohibited
+HINT:  Sessions with open write transactions must be terminated.
+server closed the connection unexpectedly
+	This probably means the server terminated abnormally
+	before or while processing the request.
+
+The connection to the server was lost. Attempting reset: Succeeded.
+step s1d: ROLLBACK;
+
+starting permutation: s1a s1b s2a s1c s2b s1d
+step s1a: DECLARE rw_cur CURSOR FOR SELECT a FROM tbl WHERE a = 5000 FOR UPDATE;
+step s1b: FETCH FORWARD ALL FROM rw_cur;
+   a
+----
+5000
+(1 row)
+
+step s2a: SELECT pg_prohibit_wal(true);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+step s1c: CLOSE ALL;
+FATAL:  WAL is now prohibited
+FATAL:  WAL is now prohibited
+HINT:  Sessions with open write transactions must be terminated.
+server closed the connection unexpectedly
+	This probably means the server terminated abnormally
+	before or while processing the request.
+
+The connection to the server was lost. Attempting reset: Succeeded.
+step s2b: SELECT pg_prohibit_wal(false);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+s1: WARNING:  there is no transaction in progress
+step s1d: ROLLBACK;
+
+starting permutation: s1a s1b s2a s2b s1c s1d
+step s1a: DECLARE rw_cur CURSOR FOR SELECT a FROM tbl WHERE a = 5000 FOR UPDATE;
+step s1b: FETCH FORWARD ALL FROM rw_cur;
+   a
+----
+5000
+(1 row)
+
+step s2a: SELECT pg_prohibit_wal(true);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+step s2b: SELECT pg_prohibit_wal(false);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+PQconsumeInput failed: FATAL:  WAL is now prohibited
+HINT:  Sessions with open write transactions must be terminated.
+server closed the connection unexpectedly
+	This probably means the server terminated abnormally
+	before or while processing the request.
+
+The connection to the server was lost. Attempting reset: Succeeded.
+step s1c: CLOSE ALL;
+s1: WARNING:  there is no transaction in progress
+step s1d: ROLLBACK;
+
+starting permutation: s1a s2a s1b s1c s2b s1d
+step s1a: DECLARE rw_cur CURSOR FOR SELECT a FROM tbl WHERE a = 5000 FOR UPDATE;
+step s2a: SELECT pg_prohibit_wal(true);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+step s1b: FETCH FORWARD ALL FROM rw_cur;
+ERROR:  WAL is now prohibited
+step s1c: CLOSE ALL;
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step s2b: SELECT pg_prohibit_wal(false);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+step s1d: ROLLBACK;
+
+starting permutation: s1a s2a s1b s2b s1c s1d
+step s1a: DECLARE rw_cur CURSOR FOR SELECT a FROM tbl WHERE a = 5000 FOR UPDATE;
+step s2a: SELECT pg_prohibit_wal(true);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+step s1b: FETCH FORWARD ALL FROM rw_cur;
+ERROR:  WAL is now prohibited
+step s2b: SELECT pg_prohibit_wal(false);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+step s1c: CLOSE ALL;
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
+step s1d: ROLLBACK;
+
+starting permutation: s1a s2a s2b s1b s1c s1d
+step s1a: DECLARE rw_cur CURSOR FOR SELECT a FROM tbl WHERE a = 5000 FOR UPDATE;
+step s2a: SELECT pg_prohibit_wal(true);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+step s2b: SELECT pg_prohibit_wal(false);
+pg_prohibit_wal
+---------------
+               
+(1 row)
+
+step s1b: FETCH FORWARD ALL FROM rw_cur;
+   a
+----
+5000
+(1 row)
+
+step s1c: CLOSE ALL;
+step s1d: ROLLBACK;
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index f4c01006fc..fb79e010b0 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -96,3 +96,4 @@ test: plpgsql-toast
 test: truncate-conflict
 test: serializable-parallel
 test: serializable-parallel-2
+test: cursor-prohibit-wal
diff --git a/src/test/isolation/specs/cursor-prohibit-wal.spec b/src/test/isolation/specs/cursor-prohibit-wal.spec
new file mode 100644
index 0000000000..8f699a4c6e
--- /dev/null
+++ b/src/test/isolation/specs/cursor-prohibit-wal.spec
@@ -0,0 +1,38 @@
+# Test for behavior of a cursor over an index scan when the server is read-only
+# and the cursor moves over index pages that refer to dead tuples.  The key
+# point is that the server is read-only, but the scan of the index page will
+# want to hint the tuples as dead.
+# 
+# The transaction operating the cursor is intentionally read-only in its
+# behavior.  If it were to do anything that generated a transaction ID, we
+# would expect it to be terminated when the server goes read-only.
+#
+
+setup
+{
+	CREATE TABLE tbl (a integer);
+	INSERT INTO tbl SELECT * FROM generate_series(1,10000);
+}
+
+teardown
+{
+	DROP TABLE tbl;
+}
+
+session s1
+setup			{ BEGIN; }
+step s1a		{ DECLARE rw_cur CURSOR FOR SELECT a FROM tbl WHERE a = 5000 FOR UPDATE; }
+step s1b		{ FETCH FORWARD ALL FROM rw_cur; }
+step s1c		{ CLOSE ALL; }
+step s1d		{ ROLLBACK; }
+
+session s2
+step s2a		{ SELECT pg_prohibit_wal(true); }
+step s2b		{ SELECT pg_prohibit_wal(false); }
+
+permutation		s1a s1b s1c s2a s2b s1d
+permutation		s1a s1b s2a s1c s2b s1d
+permutation		s1a s1b s2a s2b s1c s1d
+permutation		s1a s2a s1b s1c s2b s1d
+permutation		s1a s2a s1b s2b s1c s1d
+permutation		s1a s2a s2b s1b s1c s1d
-- 
2.21.1 (Apple Git-122.3)

