-- Cases around DROP SCHEMA of the session's own pg_temp_N. -- Run as a superuser in a scratch database: psql -X -f temp_schema_drop_cases.sql -- Each case starts a new session (\c -). "expected" is master's behavior, -- or what should happen where master is broken. \set VERBOSITY terse \pset footer off \echo \echo == 1. drop committed, then other temp objects \echo expected: all created, nothing pointing to a missing schema \echo (master: errors, and rows left in pg_class/pg_type) \c - CREATE TEMP TABLE z(a int); SELECT pg_my_temp_schema()::regnamespace AS s \gset DROP SCHEMA :s CASCADE; CREATE TYPE pg_temp.ty AS (a int); CREATE DOMAIN pg_temp.dom AS int; CREATE FUNCTION pg_temp.eq3(int, int) RETURNS bool LANGUAGE sql AS 'SELECT $1 = $2'; CREATE OPERATOR pg_temp.=== (LEFTARG = int, RIGHTARG = int, FUNCTION = pg_temp.eq3); CREATE TEMP TABLE ser(id serial PRIMARY KEY, b int); CREATE INDEX ON ser(b); CREATE STATISTICS pg_temp.st ON id, b FROM ser; SELECT EXISTS (SELECT 1 FROM pg_namespace WHERE oid = pg_my_temp_schema()) AS temp_schema_exists, (SELECT count(*) FROM pg_class c WHERE NOT EXISTS (SELECT 1 FROM pg_namespace n WHERE n.oid = c.relnamespace)) AS dangling_class, (SELECT count(*) FROM pg_type t WHERE NOT EXISTS (SELECT 1 FROM pg_namespace n WHERE n.oid = t.typnamespace)) AS dangling_type; \echo \echo == 2. drop rolled back \echo expected: keep has 3 rows, before and after the next CREATE TEMP TABLE \c - CREATE TEMP TABLE keep(a int); INSERT INTO keep VALUES (1), (2), (3); SELECT pg_my_temp_schema()::regnamespace AS s \gset BEGIN; DROP SCHEMA :s CASCADE; CREATE TEMP TABLE t(a int); ROLLBACK; SELECT count(*) AS keep_rows FROM keep; CREATE TEMP TABLE t2(a int); SELECT count(*) AS keep_rows FROM keep; \echo \echo == 3. drop undone by ROLLBACK TO SAVEPOINT \echo expected: keep has 3 rows, before and after the next CREATE TEMP TABLE \c - CREATE TEMP TABLE keep(a int); INSERT INTO keep VALUES (1), (2), (3); SELECT pg_my_temp_schema()::regnamespace AS s \gset BEGIN; SAVEPOINT sp; DROP SCHEMA :s CASCADE; CREATE TEMP TABLE t(a int); ROLLBACK TO sp; COMMIT; SELECT count(*) AS keep_rows FROM keep; CREATE TEMP TABLE t2(a int); SELECT count(*) AS keep_rows FROM keep; \echo \echo == 4. temp schema created, dropped and rolled back in one transaction \echo expected: c has 1 row, temp schema exists \c - BEGIN; CREATE TEMP TABLE a(x int); SELECT pg_my_temp_schema()::regnamespace AS s \gset DROP SCHEMA :s CASCADE; CREATE TEMP TABLE b(x int); ROLLBACK; CREATE TEMP TABLE c(x int); INSERT INTO c VALUES (1); SELECT count(*) AS c_rows, EXISTS (SELECT 1 FROM pg_namespace WHERE oid = pg_my_temp_schema()) AS temp_schema_exists; \echo \echo == 5. drop committed, then an aborted CREATE TEMP TABLE, then another \echo expected: c has 1 row, temp schema exists (master: it doesn't) \c - CREATE TEMP TABLE a(x int); SELECT pg_my_temp_schema()::regnamespace AS s \gset DROP SCHEMA :s CASCADE; BEGIN; CREATE TEMP TABLE b(x int); ROLLBACK; CREATE TEMP TABLE c(x int); INSERT INTO c VALUES (1); SELECT count(*) AS c_rows, EXISTS (SELECT 1 FROM pg_namespace WHERE oid = pg_my_temp_schema()) AS temp_schema_exists; \echo \echo == 6. drop undone by ROLLBACK TO an outer savepoint, a savepoint released in between \echo expected: keep has 3 rows \c - CREATE TEMP TABLE keep(x int); INSERT INTO keep VALUES (1), (2), (3); SELECT pg_my_temp_schema()::regnamespace AS s \gset BEGIN; SAVEPOINT a; SAVEPOINT b; DROP SCHEMA :s CASCADE; SAVEPOINT c; CREATE TEMP TABLE t(x int); RELEASE c; ROLLBACK TO b; CREATE TEMP TABLE t2(x int); COMMIT; SELECT count(*) AS keep_rows FROM keep; \echo \echo == 7. drop released from a savepoint, then the transaction rolled back \echo expected: keep has 3 rows, before and after the next CREATE TEMP TABLE \c - CREATE TEMP TABLE keep(x int); INSERT INTO keep VALUES (1), (2), (3); SELECT pg_my_temp_schema()::regnamespace AS s \gset BEGIN; SAVEPOINT a; DROP SCHEMA :s CASCADE; CREATE TEMP TABLE t(x int); RELEASE a; ROLLBACK; SELECT count(*) AS keep_rows FROM keep; CREATE TEMP TABLE t3(x int); SELECT count(*) AS keep_rows FROM keep; \echo \echo == 8. a table whose pg_namespace row is gone, and a same-named table in public \echo expected: no crash; the round trip must not land on public.x \echo (master: pg_identify_object crashes, and the round trip returns public.x) \echo This one deletes a catalog row: run it in a database you can throw away. \c - CREATE SCHEMA gone; CREATE TABLE gone.x(a int); CREATE TABLE public.x(b text); SELECT oid AS xoid FROM pg_class WHERE relnamespace = 'gone'::regnamespace AND relname = 'x' \gset SET allow_system_table_mods = on; DELETE FROM pg_namespace WHERE nspname = 'gone'; RESET allow_system_table_mods; SELECT :xoid AS gone_x_oid, 'public.x'::regclass::oid AS public_x_oid; SELECT (pg_identify_object_as_address('pg_class'::regclass, :xoid, 0)).object_names; SELECT objid AS round_trip_oid FROM pg_get_object_address('table', (pg_identify_object_as_address('pg_class'::regclass, :xoid, 0)).object_names, '{}'); SELECT pg_identify_object('pg_class'::regclass, :xoid, 0);