From 934fdaaca80e981dac90cdd974f61e7d493a78bf Mon Sep 17 00:00:00 2001
From: Noah Misch <noah@leadboat.com>
Date: Tue, 20 Oct 2015 00:37:22 -0400
Subject: [PATCH] Eschew "RESET statement_timeout" in tests.

Instead, use transaction abort.  Given an unlucky bout of latency, the
timeout would cancel the RESET itself.  Buildfarm members gharial,
lapwing, mereswine, shearwater, and sungazer witness that.  Back-patch
to 9.1 (all supported versions).  The query_canceled test still could
timeout before entering its subtransaction; for whatever reason, that
has yet to happen on the buildfarm.
---
 src/test/regress/expected/plpgsql.out         | 43 +++++++++++++------
 src/test/regress/expected/prepared_xacts.out  |  6 ++-
 .../regress/expected/prepared_xacts_1.out     |  6 ++-
 src/test/regress/sql/plpgsql.sql              | 37 ++++++++++------
 src/test/regress/sql/prepared_xacts.sql       |  6 ++-
 5 files changed, 65 insertions(+), 33 deletions(-)

diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 268626ea0eb..5e742797d1d 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -2011,7 +2011,7 @@ NOTICE:  caught numeric_value_out_of_range or cardinality_violation
 (1 row)
 
 create temp table foo (f1 int);
-create function blockme() returns int as $$
+create function subxact_rollback_semantics() returns int as $$
 declare x int;
 begin
   x := 1;
@@ -2019,28 +2019,20 @@ begin
   begin
     x := x + 1;
     insert into foo values(x);
-    -- we assume this will take longer than 2 seconds:
-    select count(*) into x from tenk1 a, tenk1 b, tenk1 c;
+    raise exception 'inner';
   exception
     when others then
-      raise notice 'caught others?';
-      return -1;
-    when query_canceled then
-      raise notice 'nyeah nyeah, can''t stop me';
       x := x * 10;
   end;
   insert into foo values(x);
   return x;
 end$$ language plpgsql;
-set statement_timeout to 2000;
-select blockme();
-NOTICE:  nyeah nyeah, can't stop me
- blockme 
----------
-      20
+select subxact_rollback_semantics();
+ subxact_rollback_semantics 
+----------------------------
+                         20
 (1 row)
 
-reset statement_timeout;
 select * from foo;
  f1 
 ----
@@ -2049,6 +2041,29 @@ select * from foo;
 (2 rows)
 
 drop table foo;
+create function trap_timeout() returns void as $$
+begin
+  declare x int;
+  begin
+    -- we assume this will take longer than 2 seconds:
+    select count(*) into x from tenk1 a, tenk1 b, tenk1 c;
+  exception
+    when others then
+      raise notice 'caught others?';
+    when query_canceled then
+      raise notice 'nyeah nyeah, can''t stop me';
+  end;
+  -- Abort transaction to abandon the statement_timeout setting.  Otherwise,
+  -- the next top-level statement would be vulnerable to the timeout.
+  raise exception 'end of function';
+end$$ language plpgsql;
+begin;
+set statement_timeout to 2000;
+select trap_timeout();
+NOTICE:  nyeah nyeah, can't stop me
+ERROR:  end of function
+CONTEXT:  PL/pgSQL function trap_timeout() line 15 at RAISE
+rollback;
 -- Test for pass-by-ref values being stored in proper context
 create function test_variable_storage() returns text as $$
 declare x text;
diff --git a/src/test/regress/expected/prepared_xacts.out b/src/test/regress/expected/prepared_xacts.out
index c0b08649e8d..ef7034b5884 100644
--- a/src/test/regress/expected/prepared_xacts.out
+++ b/src/test/regress/expected/prepared_xacts.out
@@ -194,10 +194,11 @@ SELECT gid FROM pg_prepared_xacts;
 (2 rows)
 
 -- pxtest3 should be locked because of the pending DROP
+begin;
 set statement_timeout to 2000;
 SELECT * FROM pxtest3;
 ERROR:  canceling statement due to statement timeout
-reset statement_timeout;
+rollback;
 -- Disconnect, we will continue testing in a different backend
 \c -
 -- There should still be two prepared transactions
@@ -209,10 +210,11 @@ SELECT gid FROM pg_prepared_xacts;
 (2 rows)
 
 -- pxtest3 should still be locked because of the pending DROP
+begin;
 set statement_timeout to 2000;
 SELECT * FROM pxtest3;
 ERROR:  canceling statement due to statement timeout
-reset statement_timeout;
+rollback;
 -- Commit table creation
 COMMIT PREPARED 'regress-one';
 \d pxtest2
diff --git a/src/test/regress/expected/prepared_xacts_1.out b/src/test/regress/expected/prepared_xacts_1.out
index 898f278c11e..5078bf6ba98 100644
--- a/src/test/regress/expected/prepared_xacts_1.out
+++ b/src/test/regress/expected/prepared_xacts_1.out
@@ -198,13 +198,14 @@ SELECT gid FROM pg_prepared_xacts;
 (0 rows)
 
 -- pxtest3 should be locked because of the pending DROP
+begin;
 set statement_timeout to 2000;
 SELECT * FROM pxtest3;
  fff 
 -----
 (0 rows)
 
-reset statement_timeout;
+rollback;
 -- Disconnect, we will continue testing in a different backend
 \c -
 -- There should still be two prepared transactions
@@ -214,13 +215,14 @@ SELECT gid FROM pg_prepared_xacts;
 (0 rows)
 
 -- pxtest3 should still be locked because of the pending DROP
+begin;
 set statement_timeout to 2000;
 SELECT * FROM pxtest3;
  fff 
 -----
 (0 rows)
 
-reset statement_timeout;
+rollback;
 -- Commit table creation
 COMMIT PREPARED 'regress-one';
 ERROR:  prepared transaction with identifier "regress-one" does not exist
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index d76004424e5..4f27e02227b 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -1745,7 +1745,7 @@ select trap_matching_test(1);
 
 create temp table foo (f1 int);
 
-create function blockme() returns int as $$
+create function subxact_rollback_semantics() returns int as $$
 declare x int;
 begin
   x := 1;
@@ -1753,29 +1753,40 @@ begin
   begin
     x := x + 1;
     insert into foo values(x);
+    raise exception 'inner';
+  exception
+    when others then
+      x := x * 10;
+  end;
+  insert into foo values(x);
+  return x;
+end$$ language plpgsql;
+
+select subxact_rollback_semantics();
+select * from foo;
+drop table foo;
+
+create function trap_timeout() returns void as $$
+begin
+  declare x int;
+  begin
     -- we assume this will take longer than 2 seconds:
     select count(*) into x from tenk1 a, tenk1 b, tenk1 c;
   exception
     when others then
       raise notice 'caught others?';
-      return -1;
     when query_canceled then
       raise notice 'nyeah nyeah, can''t stop me';
-      x := x * 10;
   end;
-  insert into foo values(x);
-  return x;
+  -- Abort transaction to abandon the statement_timeout setting.  Otherwise,
+  -- the next top-level statement would be vulnerable to the timeout.
+  raise exception 'end of function';
 end$$ language plpgsql;
 
+begin;
 set statement_timeout to 2000;
-
-select blockme();
-
-reset statement_timeout;
-
-select * from foo;
-
-drop table foo;
+select trap_timeout();
+rollback;
 
 -- Test for pass-by-ref values being stored in proper context
 create function test_variable_storage() returns text as $$
diff --git a/src/test/regress/sql/prepared_xacts.sql b/src/test/regress/sql/prepared_xacts.sql
index 7902152775c..dfb20a18e7c 100644
--- a/src/test/regress/sql/prepared_xacts.sql
+++ b/src/test/regress/sql/prepared_xacts.sql
@@ -122,9 +122,10 @@ SELECT * FROM pxtest2;
 SELECT gid FROM pg_prepared_xacts;
 
 -- pxtest3 should be locked because of the pending DROP
+begin;
 set statement_timeout to 2000;
 SELECT * FROM pxtest3;
-reset statement_timeout;
+rollback;
 
 -- Disconnect, we will continue testing in a different backend
 \c -
@@ -133,9 +134,10 @@ reset statement_timeout;
 SELECT gid FROM pg_prepared_xacts;
 
 -- pxtest3 should still be locked because of the pending DROP
+begin;
 set statement_timeout to 2000;
 SELECT * FROM pxtest3;
-reset statement_timeout;
+rollback;
 
 -- Commit table creation
 COMMIT PREPARED 'regress-one';
-- 
GitLab