blob: 06959f3132e6a6403a3db754987a74f186661f7a [file] [log] [blame]
-- Here we ensure that we clean up resource queue in-memory state gracefully
-- in the face of deadlocks and statement cancellations, when there is more than
-- one active portal in the session.
0:CREATE RESOURCE QUEUE rq_multi_portal WITH (active_statements = 2);
0:CREATE ROLE role_multi_portal RESOURCE QUEUE rq_multi_portal;
1:SET ROLE role_multi_portal;
2:SET ROLE role_multi_portal;
--
-- Scenario 1:
-- Multiple explicit cursors active in the same session with a deadlock.
--
1:BEGIN;
1:DECLARE c1 CURSOR FOR SELECT 1;
2:BEGIN;
2:DECLARE c2 CURSOR FOR SELECT 1;
-- There should be 2 active statements.
0:SELECT rsqcountlimit, rsqcountvalue FROM pg_resqueue_status WHERE rsqname = 'rq_multi_portal';
-- This should block as it will exceed the active statements limit.
1&:DECLARE c3 CURSOR FOR SELECT 1;
-- There should be 2 active statements.
0:SELECT rsqcountlimit, rsqcountvalue FROM pg_resqueue_status WHERE rsqname = 'rq_multi_portal';
-- This should cause a deadlock.
2:DECLARE c4 CURSOR FOR SELECT 1;
-- After the deadlock report, one session should have ERRORed out with the
-- deadlock report and aborted, while the other session should remain active
-- and idle in transaction. The active statement count should be 2, contributed
-- to by the session that is idle in transaction.
0:SELECT rsqcountlimit, rsqcountvalue FROM pg_resqueue_status WHERE rsqname = 'rq_multi_portal';
0:SELECT count(*) from pg_stat_activity WHERE query LIKE 'DECLARE c% CURSOR FOR SELECT 1;'
AND state = 'idle in transaction';
0:SELECT count(*) from pg_stat_activity WHERE query LIKE 'DECLARE c% CURSOR FOR SELECT 1;'
AND state = 'idle in transaction (aborted)';
-- After ending the transactions, there should be 0 active statements.
1<:
1:END;
2:END;
0:SELECT rsqcountlimit, rsqcountvalue FROM pg_resqueue_status WHERE rsqname = 'rq_multi_portal';
--
-- Scenario 2:
-- Multiple explicit cursors active in the same session with a self deadlock.
--
1:BEGIN;
1:DECLARE c1 CURSOR FOR SELECT 1;
1:DECLARE c2 CURSOR FOR SELECT 1;
-- There should be 2 active statements.
0:SELECT rsqcountlimit, rsqcountvalue FROM pg_resqueue_status WHERE rsqname = 'rq_multi_portal';
-- This should cause a self-deadlock and session 1 should error out, aborting
-- its transaction.
1:DECLARE c3 CURSOR FOR SELECT 1;
-- There should be 0 active statements following the transaction abort.
0:SELECT rsqcountlimit, rsqcountvalue FROM pg_resqueue_status WHERE rsqname = 'rq_multi_portal';
1:END;
--
-- Scenario 3:
-- Multiple explicit cursors active in the same session with cancellation.
--
1:BEGIN;
1:DECLARE c1 CURSOR FOR SELECT 1;
2:BEGIN;
2:DECLARE c2 CURSOR FOR SELECT 1;
-- This should block as it will exceed the active statements limit.
1&:DECLARE c3 CURSOR FOR SELECT 1;
-- There should be 2 active statements.
0:SELECT rsqcountlimit, rsqcountvalue FROM pg_resqueue_status WHERE rsqname = 'rq_multi_portal';
-- Cancel session 1's transaction.
0:SELECT pg_cancel_backend(pid) FROM pg_stat_activity
WHERE query = 'DECLARE c3 CURSOR FOR SELECT 1;';
-- There should now only be one active statement, following the abort of session
-- 1's transaction. The active statement is contributed by session 2.
0:SELECT rsqcountlimit, rsqcountvalue FROM pg_resqueue_status WHERE rsqname = 'rq_multi_portal';
0:SELECT query, state from pg_stat_activity
WHERE query = 'DECLARE c2 CURSOR FOR SELECT 1;';
-- After ending the transactions, there should be 0 active statements.
1<:
1:END;
2:END;
0:SELECT rsqcountlimit, rsqcountvalue FROM pg_resqueue_status WHERE rsqname = 'rq_multi_portal';
-- Cleanup
0:DROP ROLE role_multi_portal;
0:DROP RESOURCE QUEUE rq_multi_portal;