2000-01-09 04:48:39 +01:00
|
|
|
--
|
|
|
|
-- TEMP
|
|
|
|
-- Test temp relations and indexes
|
|
|
|
--
|
|
|
|
-- test temp table/index masking
|
|
|
|
CREATE TABLE temptest(col int);
|
|
|
|
CREATE INDEX i_temptest ON temptest(col);
|
2002-11-11 23:19:25 +01:00
|
|
|
CREATE TEMP TABLE temptest(tcol int);
|
|
|
|
CREATE INDEX i_temptest ON temptest(tcol);
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
tcol
|
|
|
|
------
|
|
|
|
(0 rows)
|
|
|
|
|
2000-01-09 04:48:39 +01:00
|
|
|
DROP INDEX i_temptest;
|
|
|
|
DROP TABLE temptest;
|
2002-11-11 23:19:25 +01:00
|
|
|
SELECT * FROM temptest;
|
|
|
|
col
|
|
|
|
-----
|
|
|
|
(0 rows)
|
|
|
|
|
2000-01-09 04:48:39 +01:00
|
|
|
DROP INDEX i_temptest;
|
|
|
|
DROP TABLE temptest;
|
|
|
|
-- test temp table selects
|
|
|
|
CREATE TABLE temptest(col int);
|
|
|
|
INSERT INTO temptest VALUES (1);
|
2002-11-11 23:19:25 +01:00
|
|
|
CREATE TEMP TABLE temptest(tcol float);
|
|
|
|
INSERT INTO temptest VALUES (2.1);
|
2000-01-09 04:48:39 +01:00
|
|
|
SELECT * FROM temptest;
|
2002-11-11 23:19:25 +01:00
|
|
|
tcol
|
|
|
|
------
|
|
|
|
2.1
|
1999-02-02 04:45:56 +01:00
|
|
|
(1 row)
|
|
|
|
|
2000-01-09 04:48:39 +01:00
|
|
|
DROP TABLE temptest;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
col
|
|
|
|
-----
|
|
|
|
1
|
1999-02-02 04:45:56 +01:00
|
|
|
(1 row)
|
|
|
|
|
2000-01-09 04:48:39 +01:00
|
|
|
DROP TABLE temptest;
|
|
|
|
-- test temp table deletion
|
2002-11-11 23:19:25 +01:00
|
|
|
CREATE TEMP TABLE temptest(col int);
|
2008-07-03 18:01:10 +02:00
|
|
|
\c
|
2000-01-09 04:48:39 +01:00
|
|
|
SELECT * FROM temptest;
|
2003-07-21 03:59:11 +02:00
|
|
|
ERROR: relation "temptest" does not exist
|
2008-09-01 22:42:46 +02:00
|
|
|
LINE 1: SELECT * FROM temptest;
|
|
|
|
^
|
2002-11-11 23:19:25 +01:00
|
|
|
-- Test ON COMMIT DELETE ROWS
|
|
|
|
CREATE TEMP TABLE temptest(col int) ON COMMIT DELETE ROWS;
|
|
|
|
BEGIN;
|
|
|
|
INSERT INTO temptest VALUES (1);
|
|
|
|
INSERT INTO temptest VALUES (2);
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
col
|
|
|
|
-----
|
|
|
|
1
|
|
|
|
2
|
|
|
|
(2 rows)
|
|
|
|
|
|
|
|
COMMIT;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
col
|
|
|
|
-----
|
|
|
|
(0 rows)
|
|
|
|
|
2006-02-19 01:04:28 +01:00
|
|
|
DROP TABLE temptest;
|
|
|
|
BEGIN;
|
|
|
|
CREATE TEMP TABLE temptest(col) ON COMMIT DELETE ROWS AS SELECT 1;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
col
|
|
|
|
-----
|
|
|
|
1
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
COMMIT;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
col
|
|
|
|
-----
|
|
|
|
(0 rows)
|
|
|
|
|
2002-11-11 23:19:25 +01:00
|
|
|
DROP TABLE temptest;
|
|
|
|
-- Test ON COMMIT DROP
|
|
|
|
BEGIN;
|
|
|
|
CREATE TEMP TABLE temptest(col int) ON COMMIT DROP;
|
|
|
|
INSERT INTO temptest VALUES (1);
|
|
|
|
INSERT INTO temptest VALUES (2);
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
col
|
|
|
|
-----
|
|
|
|
1
|
|
|
|
2
|
|
|
|
(2 rows)
|
|
|
|
|
2006-02-19 01:04:28 +01:00
|
|
|
COMMIT;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
ERROR: relation "temptest" does not exist
|
2008-09-01 22:42:46 +02:00
|
|
|
LINE 1: SELECT * FROM temptest;
|
|
|
|
^
|
2006-02-19 01:04:28 +01:00
|
|
|
BEGIN;
|
|
|
|
CREATE TEMP TABLE temptest(col) ON COMMIT DROP AS SELECT 1;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
col
|
|
|
|
-----
|
|
|
|
1
|
|
|
|
(1 row)
|
|
|
|
|
2002-11-11 23:19:25 +01:00
|
|
|
COMMIT;
|
|
|
|
SELECT * FROM temptest;
|
2003-07-21 03:59:11 +02:00
|
|
|
ERROR: relation "temptest" does not exist
|
2008-09-01 22:42:46 +02:00
|
|
|
LINE 1: SELECT * FROM temptest;
|
|
|
|
^
|
2002-11-11 23:19:25 +01:00
|
|
|
-- ON COMMIT is only allowed for TEMP
|
|
|
|
CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS;
|
2003-09-25 08:58:07 +02:00
|
|
|
ERROR: ON COMMIT can only be used on temporary tables
|
2006-02-19 01:04:28 +01:00
|
|
|
CREATE TABLE temptest(col) ON COMMIT DELETE ROWS AS SELECT 1;
|
|
|
|
ERROR: ON COMMIT can only be used on temporary tables
|
2005-01-27 04:19:37 +01:00
|
|
|
-- Test foreign keys
|
|
|
|
BEGIN;
|
|
|
|
CREATE TEMP TABLE temptest1(col int PRIMARY KEY);
|
|
|
|
CREATE TEMP TABLE temptest2(col int REFERENCES temptest1)
|
|
|
|
ON COMMIT DELETE ROWS;
|
|
|
|
INSERT INTO temptest1 VALUES (1);
|
|
|
|
INSERT INTO temptest2 VALUES (1);
|
|
|
|
COMMIT;
|
|
|
|
SELECT * FROM temptest1;
|
|
|
|
col
|
|
|
|
-----
|
|
|
|
1
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
SELECT * FROM temptest2;
|
|
|
|
col
|
|
|
|
-----
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
BEGIN;
|
|
|
|
CREATE TEMP TABLE temptest3(col int PRIMARY KEY) ON COMMIT DELETE ROWS;
|
|
|
|
CREATE TEMP TABLE temptest4(col int REFERENCES temptest3);
|
|
|
|
COMMIT;
|
|
|
|
ERROR: unsupported ON COMMIT and foreign key combination
|
2006-06-29 18:07:29 +02:00
|
|
|
DETAIL: Table "temptest4" references "temptest3", but they do not have the same ON COMMIT setting.
|
2007-04-20 04:37:38 +02:00
|
|
|
-- Test manipulation of temp schema's placement in search path
|
|
|
|
create table public.whereami (f1 text);
|
|
|
|
insert into public.whereami values ('public');
|
|
|
|
create temp table whereami (f1 text);
|
|
|
|
insert into whereami values ('temp');
|
|
|
|
create function public.whoami() returns text
|
|
|
|
as $$select 'public'::text$$ language sql;
|
|
|
|
create function pg_temp.whoami() returns text
|
|
|
|
as $$select 'temp'::text$$ language sql;
|
|
|
|
-- default should have pg_temp implicitly first, but only for tables
|
|
|
|
select * from whereami;
|
|
|
|
f1
|
|
|
|
------
|
|
|
|
temp
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select whoami();
|
|
|
|
whoami
|
|
|
|
--------
|
|
|
|
public
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- can list temp first explicitly, but it still doesn't affect functions
|
|
|
|
set search_path = pg_temp, public;
|
|
|
|
select * from whereami;
|
|
|
|
f1
|
|
|
|
------
|
|
|
|
temp
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select whoami();
|
|
|
|
whoami
|
|
|
|
--------
|
|
|
|
public
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- or put it last for security
|
|
|
|
set search_path = public, pg_temp;
|
|
|
|
select * from whereami;
|
|
|
|
f1
|
|
|
|
--------
|
|
|
|
public
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
select whoami();
|
|
|
|
whoami
|
|
|
|
--------
|
|
|
|
public
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- you can invoke a temp function explicitly, though
|
|
|
|
select pg_temp.whoami();
|
|
|
|
whoami
|
|
|
|
--------
|
|
|
|
temp
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
drop table public.whereami;
|
2018-11-05 01:14:33 +01:00
|
|
|
-- For partitioned temp tables, ON COMMIT actions ignore storage-less
|
|
|
|
-- partitioned tables.
|
|
|
|
begin;
|
|
|
|
create temp table temp_parted_oncommit (a int)
|
|
|
|
partition by list (a) on commit delete rows;
|
|
|
|
create temp table temp_parted_oncommit_1
|
|
|
|
partition of temp_parted_oncommit
|
|
|
|
for values in (1) on commit delete rows;
|
|
|
|
insert into temp_parted_oncommit values (1);
|
|
|
|
commit;
|
|
|
|
-- partitions are emptied by the previous commit
|
|
|
|
select * from temp_parted_oncommit;
|
|
|
|
a
|
|
|
|
---
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
drop table temp_parted_oncommit;
|
2018-11-09 02:03:22 +01:00
|
|
|
-- Check dependencies between ON COMMIT actions with a partitioned
|
|
|
|
-- table and its partitions. Using ON COMMIT DROP on a parent removes
|
|
|
|
-- the whole set.
|
|
|
|
begin;
|
|
|
|
create temp table temp_parted_oncommit_test (a int)
|
|
|
|
partition by list (a) on commit drop;
|
|
|
|
create temp table temp_parted_oncommit_test1
|
|
|
|
partition of temp_parted_oncommit_test
|
|
|
|
for values in (1) on commit delete rows;
|
|
|
|
create temp table temp_parted_oncommit_test2
|
|
|
|
partition of temp_parted_oncommit_test
|
|
|
|
for values in (2) on commit drop;
|
|
|
|
insert into temp_parted_oncommit_test values (1), (2);
|
|
|
|
commit;
|
|
|
|
-- no relations remain in this case.
|
|
|
|
select relname from pg_class where relname like 'temp_parted_oncommit_test%';
|
|
|
|
relname
|
|
|
|
---------
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
-- Using ON COMMIT DELETE on a partitioned table does not remove
|
|
|
|
-- all rows if partitions preserve their data.
|
|
|
|
begin;
|
|
|
|
create temp table temp_parted_oncommit_test (a int)
|
|
|
|
partition by list (a) on commit delete rows;
|
|
|
|
create temp table temp_parted_oncommit_test1
|
|
|
|
partition of temp_parted_oncommit_test
|
|
|
|
for values in (1) on commit preserve rows;
|
|
|
|
create temp table temp_parted_oncommit_test2
|
|
|
|
partition of temp_parted_oncommit_test
|
|
|
|
for values in (2) on commit drop;
|
|
|
|
insert into temp_parted_oncommit_test values (1), (2);
|
|
|
|
commit;
|
|
|
|
-- Data from the remaining partition is still here as its rows are
|
|
|
|
-- preserved.
|
|
|
|
select * from temp_parted_oncommit_test;
|
|
|
|
a
|
|
|
|
---
|
|
|
|
1
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
-- two relations remain in this case.
|
|
|
|
select relname from pg_class where relname like 'temp_parted_oncommit_test%';
|
|
|
|
relname
|
|
|
|
----------------------------
|
|
|
|
temp_parted_oncommit_test
|
|
|
|
temp_parted_oncommit_test1
|
|
|
|
(2 rows)
|
|
|
|
|
|
|
|
drop table temp_parted_oncommit_test;
|
|
|
|
-- Check dependencies between ON COMMIT actions with inheritance trees.
|
|
|
|
-- Using ON COMMIT DROP on a parent removes the whole set.
|
|
|
|
begin;
|
|
|
|
create temp table temp_inh_oncommit_test (a int) on commit drop;
|
|
|
|
create temp table temp_inh_oncommit_test1 ()
|
|
|
|
inherits(temp_inh_oncommit_test) on commit delete rows;
|
|
|
|
insert into temp_inh_oncommit_test1 values (1);
|
|
|
|
commit;
|
|
|
|
-- no relations remain in this case
|
|
|
|
select relname from pg_class where relname like 'temp_inh_oncommit_test%';
|
|
|
|
relname
|
|
|
|
---------
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
-- Data on the parent is removed, and the child goes away.
|
|
|
|
begin;
|
|
|
|
create temp table temp_inh_oncommit_test (a int) on commit delete rows;
|
|
|
|
create temp table temp_inh_oncommit_test1 ()
|
|
|
|
inherits(temp_inh_oncommit_test) on commit drop;
|
|
|
|
insert into temp_inh_oncommit_test1 values (1);
|
|
|
|
insert into temp_inh_oncommit_test values (1);
|
|
|
|
commit;
|
|
|
|
select * from temp_inh_oncommit_test;
|
|
|
|
a
|
|
|
|
---
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
-- one relation remains
|
|
|
|
select relname from pg_class where relname like 'temp_inh_oncommit_test%';
|
|
|
|
relname
|
|
|
|
------------------------
|
|
|
|
temp_inh_oncommit_test
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
drop table temp_inh_oncommit_test;
|
Restrict the use of temporary namespace in two-phase transactions
Attempting to use a temporary table within a two-phase transaction is
forbidden for ages. However, there have been uncovered grounds for
a couple of other object types and commands which work on temporary
objects with two-phase commit. In short, trying to create, lock or drop
an object on a temporary schema should not be authorized within a
two-phase transaction, as it would cause its state to create
dependencies with other sessions, causing all sorts of side effects with
the existing session or other sessions spawned later on trying to use
the same temporary schema name.
Regression tests are added to cover all the grounds found, the original
report mentioned function creation, but monitoring closer there are many
other patterns with LOCK, DROP or CREATE EXTENSION which are involved.
One of the symptoms resulting in combining both is that the session
which used the temporary schema is not able to shut down completely,
waiting for being able to drop the temporary schema, something that it
cannot complete because of the two-phase transaction involved with
temporary objects. In this case the client is able to disconnect but
the session remains alive on the backend-side, potentially blocking
connection backend slots from being used. Other problems reported could
also involve server crashes.
This is back-patched down to v10, which is where 9b013dc has introduced
MyXactFlags, something that this patch relies on.
Reported-by: Alexey Bashtanov
Author: Michael Paquier
Reviewed-by: Masahiko Sawada
Discussion: https://postgr.es/m/5d910e2e-0db8-ec06-dd5f-baec420513c3@imap.cc
Backpatch-through: 10
2019-01-18 01:21:44 +01:00
|
|
|
-- Tests with two-phase commit
|
|
|
|
-- Transactions creating objects in a temporary namespace cannot be used
|
|
|
|
-- with two-phase commit.
|
|
|
|
-- These cases generate errors about temporary namespace.
|
|
|
|
-- Function creation
|
|
|
|
begin;
|
|
|
|
create function pg_temp.twophase_func() returns void as
|
|
|
|
$$ select '2pc_func'::text $$ language sql;
|
|
|
|
prepare transaction 'twophase_func';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary namespace
|
|
|
|
-- Function drop
|
|
|
|
create function pg_temp.twophase_func() returns void as
|
|
|
|
$$ select '2pc_func'::text $$ language sql;
|
|
|
|
begin;
|
|
|
|
drop function pg_temp.twophase_func();
|
|
|
|
prepare transaction 'twophase_func';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary namespace
|
|
|
|
-- Operator creation
|
|
|
|
begin;
|
|
|
|
create operator pg_temp.@@ (leftarg = int4, rightarg = int4, procedure = int4mi);
|
|
|
|
prepare transaction 'twophase_operator';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary namespace
|
|
|
|
-- These generate errors about temporary tables.
|
|
|
|
begin;
|
|
|
|
create type pg_temp.twophase_type as (a int);
|
|
|
|
prepare transaction 'twophase_type';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary tables
|
|
|
|
begin;
|
|
|
|
create view pg_temp.twophase_view as select 1;
|
|
|
|
prepare transaction 'twophase_view';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary tables
|
|
|
|
begin;
|
|
|
|
create sequence pg_temp.twophase_seq;
|
|
|
|
prepare transaction 'twophase_sequence';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary tables
|
|
|
|
-- Temporary tables cannot be used with two-phase commit.
|
|
|
|
create temp table twophase_tab (a int);
|
|
|
|
begin;
|
|
|
|
select a from twophase_tab;
|
|
|
|
a
|
|
|
|
---
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
prepare transaction 'twophase_tab';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary tables
|
|
|
|
begin;
|
|
|
|
insert into twophase_tab values (1);
|
|
|
|
prepare transaction 'twophase_tab';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary tables
|
|
|
|
begin;
|
|
|
|
lock twophase_tab in access exclusive mode;
|
|
|
|
prepare transaction 'twophase_tab';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary tables
|
|
|
|
begin;
|
|
|
|
drop table twophase_tab;
|
|
|
|
prepare transaction 'twophase_tab';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary tables
|
|
|
|
-- Corner case: current_schema may create a temporary schema if namespace
|
|
|
|
-- creation is pending, so check after that. First reset the connection
|
2019-01-18 02:51:39 +01:00
|
|
|
-- to remove the temporary namespace, and make sure that non-parallel plans
|
|
|
|
-- are used.
|
Restrict the use of temporary namespace in two-phase transactions
Attempting to use a temporary table within a two-phase transaction is
forbidden for ages. However, there have been uncovered grounds for
a couple of other object types and commands which work on temporary
objects with two-phase commit. In short, trying to create, lock or drop
an object on a temporary schema should not be authorized within a
two-phase transaction, as it would cause its state to create
dependencies with other sessions, causing all sorts of side effects with
the existing session or other sessions spawned later on trying to use
the same temporary schema name.
Regression tests are added to cover all the grounds found, the original
report mentioned function creation, but monitoring closer there are many
other patterns with LOCK, DROP or CREATE EXTENSION which are involved.
One of the symptoms resulting in combining both is that the session
which used the temporary schema is not able to shut down completely,
waiting for being able to drop the temporary schema, something that it
cannot complete because of the two-phase transaction involved with
temporary objects. In this case the client is able to disconnect but
the session remains alive on the backend-side, potentially blocking
connection backend slots from being used. Other problems reported could
also involve server crashes.
This is back-patched down to v10, which is where 9b013dc has introduced
MyXactFlags, something that this patch relies on.
Reported-by: Alexey Bashtanov
Author: Michael Paquier
Reviewed-by: Masahiko Sawada
Discussion: https://postgr.es/m/5d910e2e-0db8-ec06-dd5f-baec420513c3@imap.cc
Backpatch-through: 10
2019-01-18 01:21:44 +01:00
|
|
|
\c -
|
2019-01-18 02:51:39 +01:00
|
|
|
SET max_parallel_workers = 0;
|
|
|
|
SET max_parallel_workers_per_gather = 0;
|
Restrict the use of temporary namespace in two-phase transactions
Attempting to use a temporary table within a two-phase transaction is
forbidden for ages. However, there have been uncovered grounds for
a couple of other object types and commands which work on temporary
objects with two-phase commit. In short, trying to create, lock or drop
an object on a temporary schema should not be authorized within a
two-phase transaction, as it would cause its state to create
dependencies with other sessions, causing all sorts of side effects with
the existing session or other sessions spawned later on trying to use
the same temporary schema name.
Regression tests are added to cover all the grounds found, the original
report mentioned function creation, but monitoring closer there are many
other patterns with LOCK, DROP or CREATE EXTENSION which are involved.
One of the symptoms resulting in combining both is that the session
which used the temporary schema is not able to shut down completely,
waiting for being able to drop the temporary schema, something that it
cannot complete because of the two-phase transaction involved with
temporary objects. In this case the client is able to disconnect but
the session remains alive on the backend-side, potentially blocking
connection backend slots from being used. Other problems reported could
also involve server crashes.
This is back-patched down to v10, which is where 9b013dc has introduced
MyXactFlags, something that this patch relies on.
Reported-by: Alexey Bashtanov
Author: Michael Paquier
Reviewed-by: Masahiko Sawada
Discussion: https://postgr.es/m/5d910e2e-0db8-ec06-dd5f-baec420513c3@imap.cc
Backpatch-through: 10
2019-01-18 01:21:44 +01:00
|
|
|
SET search_path TO 'pg_temp';
|
|
|
|
BEGIN;
|
|
|
|
SELECT current_schema() ~ 'pg_temp' AS is_temp_schema;
|
|
|
|
is_temp_schema
|
|
|
|
----------------
|
|
|
|
t
|
|
|
|
(1 row)
|
|
|
|
|
|
|
|
PREPARE TRANSACTION 'twophase_search';
|
|
|
|
ERROR: cannot PREPARE a transaction that has operated on temporary namespace
|