mirror of
https://github.com/postgres/postgres.git
synced 2025-11-25 12:03:53 +03:00
We implement ON COMMIT DELETE ROWS by truncating tables marked that way, which requires also truncating/rebuilding their indexes. But RelationTruncateIndexes asks the relcache for up-to-date copies of any index expressions, which may cause execution of eval_const_expressions on them, which can result in actual execution of subexpressions. This is a bad thing to have happening during ON COMMIT. Manuel Rigger reported that use of a SQL function resulted in crashes due to expectations that ActiveSnapshot would be set, which it isn't. The most obvious fix perhaps would be to push a snapshot during PreCommit_on_commit_actions, but I think that would just open the door to more problems: CommitTransaction explicitly expects that no user-defined code can be running at this point. Fortunately, since we know that no tuples exist to be indexed, there seems no need to use the real index expressions or predicates during RelationTruncateIndexes. We can set up dummy index expressions instead (we do need something that will expose the right data type, as there are places that build index tupdescs based on this), and just ignore predicates and exclusion constraints. In a green field it'd likely be better to reimplement ON COMMIT DELETE ROWS using the same "init fork" infrastructure used for unlogged relations. That seems impractical without catalog changes though, and even without that it'd be too big a change to back-patch. So for now do it like this. Per private report from Manuel Rigger. This has been broken forever, so back-patch to all supported branches.
168 lines
3.3 KiB
PL/PgSQL
168 lines
3.3 KiB
PL/PgSQL
--
|
|
-- TEMP
|
|
-- Test temp relations and indexes
|
|
--
|
|
|
|
-- test temp table/index masking
|
|
|
|
CREATE TABLE temptest(col int);
|
|
|
|
CREATE INDEX i_temptest ON temptest(col);
|
|
|
|
CREATE TEMP TABLE temptest(tcol int);
|
|
|
|
CREATE INDEX i_temptest ON temptest(tcol);
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
DROP INDEX i_temptest;
|
|
|
|
DROP TABLE temptest;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
DROP INDEX i_temptest;
|
|
|
|
DROP TABLE temptest;
|
|
|
|
-- test temp table selects
|
|
|
|
CREATE TABLE temptest(col int);
|
|
|
|
INSERT INTO temptest VALUES (1);
|
|
|
|
CREATE TEMP TABLE temptest(tcol float);
|
|
|
|
INSERT INTO temptest VALUES (2.1);
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
DROP TABLE temptest;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
DROP TABLE temptest;
|
|
|
|
-- test temp table deletion
|
|
|
|
CREATE TEMP TABLE temptest(col int);
|
|
|
|
\c
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
-- Test ON COMMIT DELETE ROWS
|
|
|
|
CREATE TEMP TABLE temptest(col int) ON COMMIT DELETE ROWS;
|
|
|
|
-- while we're here, verify successful truncation of index with SQL function
|
|
CREATE INDEX ON temptest(bit_length(''));
|
|
|
|
BEGIN;
|
|
INSERT INTO temptest VALUES (1);
|
|
INSERT INTO temptest VALUES (2);
|
|
|
|
SELECT * FROM temptest;
|
|
COMMIT;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
DROP TABLE temptest;
|
|
|
|
BEGIN;
|
|
CREATE TEMP TABLE temptest(col) ON COMMIT DELETE ROWS AS SELECT 1;
|
|
|
|
SELECT * FROM temptest;
|
|
COMMIT;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
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;
|
|
COMMIT;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
BEGIN;
|
|
CREATE TEMP TABLE temptest(col) ON COMMIT DROP AS SELECT 1;
|
|
|
|
SELECT * FROM temptest;
|
|
COMMIT;
|
|
|
|
SELECT * FROM temptest;
|
|
|
|
-- ON COMMIT is only allowed for TEMP
|
|
|
|
CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS;
|
|
CREATE TABLE temptest(col) ON COMMIT DELETE ROWS AS SELECT 1;
|
|
|
|
-- 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;
|
|
SELECT * FROM temptest2;
|
|
|
|
BEGIN;
|
|
CREATE TEMP TABLE temptest3(col int PRIMARY KEY) ON COMMIT DELETE ROWS;
|
|
CREATE TEMP TABLE temptest4(col int REFERENCES temptest3);
|
|
COMMIT;
|
|
|
|
-- 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;
|
|
select whoami();
|
|
|
|
-- can list temp first explicitly, but it still doesn't affect functions
|
|
set search_path = pg_temp, public;
|
|
select * from whereami;
|
|
select whoami();
|
|
|
|
-- or put it last for security
|
|
set search_path = public, pg_temp;
|
|
select * from whereami;
|
|
select whoami();
|
|
|
|
-- you can invoke a temp function explicitly, though
|
|
select pg_temp.whoami();
|
|
|
|
drop table public.whereami;
|
|
|
|
-- types in temp schema
|
|
set search_path = pg_temp, public;
|
|
create domain pg_temp.nonempty as text check (value <> '');
|
|
-- function-syntax invocation of types matches rules for functions
|
|
select nonempty('');
|
|
select pg_temp.nonempty('');
|
|
-- other syntax matches rules for tables
|
|
select ''::nonempty;
|
|
|
|
reset search_path;
|