chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
--
|
||||
-- Tests to exercise the plan caching/invalidation mechanism
|
||||
--
|
||||
|
||||
CREATE TEMP TABLE pcachetest AS SELECT * FROM int8_tbl;
|
||||
|
||||
-- create and use a cached plan
|
||||
PREPARE prepstmt AS SELECT * FROM pcachetest;
|
||||
|
||||
EXECUTE prepstmt;
|
||||
|
||||
-- and one with parameters
|
||||
PREPARE prepstmt2(bigint) AS SELECT * FROM pcachetest WHERE q1 = $1;
|
||||
|
||||
EXECUTE prepstmt2(123);
|
||||
|
||||
-- invalidate the plans and see what happens
|
||||
DROP TABLE pcachetest;
|
||||
|
||||
EXECUTE prepstmt;
|
||||
EXECUTE prepstmt2(123);
|
||||
|
||||
-- recreate the temp table (this demonstrates that the raw plan is
|
||||
-- purely textual and doesn't depend on OIDs, for instance)
|
||||
CREATE TEMP TABLE pcachetest AS SELECT * FROM int8_tbl ORDER BY 2;
|
||||
|
||||
EXECUTE prepstmt;
|
||||
EXECUTE prepstmt2(123);
|
||||
|
||||
-- prepared statements should prevent change in output tupdesc,
|
||||
-- since clients probably aren't expecting that to change on the fly
|
||||
ALTER TABLE pcachetest ADD COLUMN q3 bigint;
|
||||
|
||||
EXECUTE prepstmt;
|
||||
EXECUTE prepstmt2(123);
|
||||
|
||||
-- but we're nice guys and will let you undo your mistake
|
||||
ALTER TABLE pcachetest DROP COLUMN q3;
|
||||
|
||||
EXECUTE prepstmt;
|
||||
EXECUTE prepstmt2(123);
|
||||
|
||||
-- Try it with a view, which isn't directly used in the resulting plan
|
||||
-- but should trigger invalidation anyway
|
||||
CREATE TEMP VIEW pcacheview AS
|
||||
SELECT * FROM pcachetest;
|
||||
|
||||
PREPARE vprep AS SELECT * FROM pcacheview;
|
||||
|
||||
EXECUTE vprep;
|
||||
|
||||
CREATE OR REPLACE TEMP VIEW pcacheview AS
|
||||
SELECT q1, q2/2 AS q2 FROM pcachetest;
|
||||
|
||||
EXECUTE vprep;
|
||||
|
||||
-- Check basic SPI plan invalidation
|
||||
|
||||
create function cache_test(int) returns int as $$
|
||||
declare total int;
|
||||
begin
|
||||
create temp table t1(f1 int);
|
||||
insert into t1 values($1);
|
||||
insert into t1 values(11);
|
||||
insert into t1 values(12);
|
||||
insert into t1 values(13);
|
||||
select sum(f1) into total from t1;
|
||||
drop table t1;
|
||||
return total;
|
||||
end
|
||||
$$ language plpgsql;
|
||||
|
||||
select cache_test(1);
|
||||
select cache_test(2);
|
||||
select cache_test(3);
|
||||
|
||||
-- Check invalidation of plpgsql "simple expression"
|
||||
|
||||
create temp view v1 as
|
||||
select 2+2 as f1;
|
||||
|
||||
create function cache_test_2() returns int as $$
|
||||
begin
|
||||
return f1 from v1;
|
||||
end$$ language plpgsql;
|
||||
|
||||
select cache_test_2();
|
||||
|
||||
create or replace temp view v1 as
|
||||
select 2+2+4 as f1;
|
||||
select cache_test_2();
|
||||
|
||||
create or replace temp view v1 as
|
||||
select 2+2+4+(select max(unique1) from tenk1) as f1;
|
||||
select cache_test_2();
|
||||
|
||||
--- Check that change of search_path is honored when re-using cached plan
|
||||
|
||||
create schema s1
|
||||
create table abc (f1 int);
|
||||
|
||||
create schema s2
|
||||
create table abc (f1 int);
|
||||
|
||||
insert into s1.abc values(123);
|
||||
insert into s2.abc values(456);
|
||||
|
||||
set search_path = s1;
|
||||
|
||||
prepare p1 as select f1 from abc;
|
||||
|
||||
execute p1;
|
||||
|
||||
set search_path = s2;
|
||||
|
||||
select f1 from abc;
|
||||
|
||||
execute p1;
|
||||
|
||||
alter table s1.abc add column f2 float8; -- force replan
|
||||
|
||||
execute p1;
|
||||
|
||||
drop schema s1 cascade;
|
||||
drop schema s2 cascade;
|
||||
|
||||
reset search_path;
|
||||
|
||||
-- Check that invalidation deals with regclass constants
|
||||
|
||||
create temp sequence seq;
|
||||
|
||||
prepare p2 as select nextval('seq');
|
||||
|
||||
execute p2;
|
||||
|
||||
drop sequence seq;
|
||||
|
||||
create temp sequence seq;
|
||||
|
||||
execute p2;
|
||||
|
||||
-- Check DDL via SPI, immediately followed by SPI plan re-use
|
||||
-- (bug in original coding)
|
||||
|
||||
create function cachebug() returns void as $$
|
||||
declare r int;
|
||||
begin
|
||||
drop table if exists temptable cascade;
|
||||
create temp table temptable as select * from generate_series(1,3) as f1;
|
||||
create temp view vv as select * from temptable;
|
||||
for r in select * from vv loop
|
||||
raise notice '%', r;
|
||||
end loop;
|
||||
end$$ language plpgsql;
|
||||
|
||||
select cachebug();
|
||||
select cachebug();
|
||||
|
||||
-- Check that addition or removal of any partition is correctly dealt with by
|
||||
-- default partition table when it is being used in prepared statement.
|
||||
create table pc_list_parted (a int) partition by list(a);
|
||||
create table pc_list_part_null partition of pc_list_parted for values in (null);
|
||||
create table pc_list_part_1 partition of pc_list_parted for values in (1);
|
||||
create table pc_list_part_def partition of pc_list_parted default;
|
||||
prepare pstmt_def_insert (int) as insert into pc_list_part_def values($1);
|
||||
-- should fail
|
||||
execute pstmt_def_insert(null);
|
||||
execute pstmt_def_insert(1);
|
||||
create table pc_list_part_2 partition of pc_list_parted for values in (2);
|
||||
execute pstmt_def_insert(2);
|
||||
alter table pc_list_parted detach partition pc_list_part_null;
|
||||
-- should be ok
|
||||
execute pstmt_def_insert(null);
|
||||
drop table pc_list_part_1;
|
||||
-- should be ok
|
||||
execute pstmt_def_insert(1);
|
||||
drop table pc_list_parted, pc_list_part_null;
|
||||
deallocate pstmt_def_insert;
|
||||
|
||||
-- Test plan_cache_mode
|
||||
|
||||
create table test_mode (a int);
|
||||
insert into test_mode select 1 from generate_series(1,1000) union all select 2;
|
||||
create index on test_mode (a);
|
||||
analyze test_mode;
|
||||
|
||||
prepare test_mode_pp (int) as select count(*) from test_mode where a = $1;
|
||||
select name, generic_plans, custom_plans from pg_prepared_statements
|
||||
where name = 'test_mode_pp';
|
||||
|
||||
-- up to 5 executions, custom plan is used
|
||||
set plan_cache_mode to auto;
|
||||
explain (costs off) execute test_mode_pp(2);
|
||||
select name, generic_plans, custom_plans from pg_prepared_statements
|
||||
where name = 'test_mode_pp';
|
||||
|
||||
-- force generic plan
|
||||
set plan_cache_mode to force_generic_plan;
|
||||
explain (costs off) execute test_mode_pp(2);
|
||||
select name, generic_plans, custom_plans from pg_prepared_statements
|
||||
where name = 'test_mode_pp';
|
||||
|
||||
-- get to generic plan by 5 executions
|
||||
set plan_cache_mode to auto;
|
||||
execute test_mode_pp(1); -- 1x
|
||||
execute test_mode_pp(1); -- 2x
|
||||
execute test_mode_pp(1); -- 3x
|
||||
execute test_mode_pp(1); -- 4x
|
||||
select name, generic_plans, custom_plans from pg_prepared_statements
|
||||
where name = 'test_mode_pp';
|
||||
execute test_mode_pp(1); -- 5x
|
||||
select name, generic_plans, custom_plans from pg_prepared_statements
|
||||
where name = 'test_mode_pp';
|
||||
|
||||
-- we should now get a really bad plan
|
||||
explain (costs off) execute test_mode_pp(2);
|
||||
|
||||
-- but we can force a custom plan
|
||||
set plan_cache_mode to force_custom_plan;
|
||||
explain (costs off) execute test_mode_pp(2);
|
||||
select name, generic_plans, custom_plans from pg_prepared_statements
|
||||
where name = 'test_mode_pp';
|
||||
|
||||
drop table test_mode;
|
||||
Reference in New Issue
Block a user