2 -- Tests to exercise the plan caching/invalidation mechanism
4 CREATE TEMP TABLE pcachetest AS SELECT * FROM int8_tbl;
5 -- create and use a cached plan
6 PREPARE prepstmt AS SELECT * FROM pcachetest;
9 ------------------+-------------------
11 123 | 4567890123456789
12 4567890123456789 | 123
13 4567890123456789 | 4567890123456789
14 4567890123456789 | -4567890123456789
17 -- and one with parameters
18 PREPARE prepstmt2(bigint) AS SELECT * FROM pcachetest WHERE q1 = $1;
19 EXECUTE prepstmt2(123);
21 -----+------------------
23 123 | 4567890123456789
26 -- invalidate the plans and see what happens
27 DROP TABLE pcachetest;
29 ERROR: relation "pcachetest" does not exist
30 EXECUTE prepstmt2(123);
31 ERROR: relation "pcachetest" does not exist
32 -- recreate the temp table (this demonstrates that the raw plan is
33 -- purely textual and doesn't depend on OIDs, for instance)
34 CREATE TEMP TABLE pcachetest AS SELECT * FROM int8_tbl ORDER BY 2;
37 ------------------+-------------------
38 4567890123456789 | -4567890123456789
39 4567890123456789 | 123
41 123 | 4567890123456789
42 4567890123456789 | 4567890123456789
45 EXECUTE prepstmt2(123);
47 -----+------------------
49 123 | 4567890123456789
52 -- prepared statements should prevent change in output tupdesc,
53 -- since clients probably aren't expecting that to change on the fly
54 ALTER TABLE pcachetest ADD COLUMN q3 bigint;
56 ERROR: cached plan must not change result type
57 EXECUTE prepstmt2(123);
58 ERROR: cached plan must not change result type
59 -- but we're nice guys and will let you undo your mistake
60 ALTER TABLE pcachetest DROP COLUMN q3;
63 ------------------+-------------------
64 4567890123456789 | -4567890123456789
65 4567890123456789 | 123
67 123 | 4567890123456789
68 4567890123456789 | 4567890123456789
71 EXECUTE prepstmt2(123);
73 -----+------------------
75 123 | 4567890123456789
78 -- Try it with a view, which isn't directly used in the resulting plan
79 -- but should trigger invalidation anyway
80 CREATE TEMP VIEW pcacheview AS
81 SELECT * FROM pcachetest;
82 PREPARE vprep AS SELECT * FROM pcacheview;
85 ------------------+-------------------
86 4567890123456789 | -4567890123456789
87 4567890123456789 | 123
89 123 | 4567890123456789
90 4567890123456789 | 4567890123456789
93 CREATE OR REPLACE TEMP VIEW pcacheview AS
94 SELECT q1, q2/2 AS q2 FROM pcachetest;
97 ------------------+-------------------
98 4567890123456789 | -2283945061728394
101 123 | 2283945061728394
102 4567890123456789 | 2283945061728394
105 -- Check basic SPI plan invalidation
106 create function cache_test(int) returns int as $$
109 create temp table t1(f1 int);
110 insert into t1 values($1);
111 insert into t1 values(11);
112 insert into t1 values(12);
113 insert into t1 values(13);
114 select sum(f1) into total from t1;
119 select cache_test(1);
125 select cache_test(2);
131 select cache_test(3);
137 -- Check invalidation of plpgsql "simple expression"
138 create temp view v1 as
140 create function cache_test_2() returns int as $$
143 end$$ language plpgsql;
144 select cache_test_2();
150 create or replace temp view v1 as
152 select cache_test_2();
158 create or replace temp view v1 as
159 select 2+2+4+(select max(unique1) from tenk1) as f1;
160 select cache_test_2();
166 --- Check that change of search_path is honored when re-using cached plan
168 create table abc (f1 int);
170 create table abc (f1 int);
171 insert into s1.abc values(123);
172 insert into s2.abc values(456);
173 set search_path = s1;
174 prepare p1 as select f1 from abc;
181 set search_path = s2;
194 alter table s1.abc add column f2 float8; -- force replan
201 drop schema s1 cascade;
202 NOTICE: drop cascades to table s1.abc
203 drop schema s2 cascade;
204 NOTICE: drop cascades to table abc
206 -- Check that invalidation deals with regclass constants
207 create temp sequence seq;
208 prepare p2 as select nextval('seq');
216 create temp sequence seq;
223 -- Check DDL via SPI, immediately followed by SPI plan re-use
224 -- (bug in original coding)
225 create function cachebug() returns void as $$
228 drop table if exists temptable cascade;
229 create temp table temptable as select * from generate_series(1,3) as f1;
230 create temp view vv as select * from temptable;
231 for r in select * from vv loop
234 end$$ language plpgsql;
236 NOTICE: table "temptable" does not exist, skipping
246 NOTICE: drop cascades to view vv
255 -- Check that addition or removal of any partition is correctly dealt with by
256 -- default partition table when it is being used in prepared statement.
257 create table pc_list_parted (a int) partition by list(a);
258 create table pc_list_part_null partition of pc_list_parted for values in (null);
259 create table pc_list_part_1 partition of pc_list_parted for values in (1);
260 create table pc_list_part_def partition of pc_list_parted default;
261 prepare pstmt_def_insert (int) as insert into pc_list_part_def values($1);
263 execute pstmt_def_insert(null);
264 ERROR: new row for relation "pc_list_part_def" violates partition constraint
265 DETAIL: Failing row contains (null).
266 execute pstmt_def_insert(1);
267 ERROR: new row for relation "pc_list_part_def" violates partition constraint
268 DETAIL: Failing row contains (1).
269 create table pc_list_part_2 partition of pc_list_parted for values in (2);
270 execute pstmt_def_insert(2);
271 ERROR: new row for relation "pc_list_part_def" violates partition constraint
272 DETAIL: Failing row contains (2).
273 alter table pc_list_parted detach partition pc_list_part_null;
275 execute pstmt_def_insert(null);
276 drop table pc_list_part_1;
278 execute pstmt_def_insert(1);
279 drop table pc_list_parted, pc_list_part_null;
280 deallocate pstmt_def_insert;
281 -- Test plan_cache_mode
282 create table test_mode (a int);
283 insert into test_mode select 1 from generate_series(1,1000) union all select 2;
284 create index on test_mode (a);
286 prepare test_mode_pp (int) as select count(*) from test_mode where a = $1;
287 select name, generic_plans, custom_plans from pg_prepared_statements
288 where name = 'test_mode_pp';
289 name | generic_plans | custom_plans
290 --------------+---------------+--------------
294 -- up to 5 executions, custom plan is used
295 set plan_cache_mode to auto;
296 explain (costs off) execute test_mode_pp(2);
298 ----------------------------------------------------------
300 -> Index Only Scan using test_mode_a_idx on test_mode
304 select name, generic_plans, custom_plans from pg_prepared_statements
305 where name = 'test_mode_pp';
306 name | generic_plans | custom_plans
307 --------------+---------------+--------------
311 -- force generic plan
312 set plan_cache_mode to force_generic_plan;
313 explain (costs off) execute test_mode_pp(2);
315 -----------------------------
317 -> Seq Scan on test_mode
321 select name, generic_plans, custom_plans from pg_prepared_statements
322 where name = 'test_mode_pp';
323 name | generic_plans | custom_plans
324 --------------+---------------+--------------
328 -- get to generic plan by 5 executions
329 set plan_cache_mode to auto;
330 execute test_mode_pp(1); -- 1x
336 execute test_mode_pp(1); -- 2x
342 execute test_mode_pp(1); -- 3x
348 execute test_mode_pp(1); -- 4x
354 select name, generic_plans, custom_plans from pg_prepared_statements
355 where name = 'test_mode_pp';
356 name | generic_plans | custom_plans
357 --------------+---------------+--------------
361 execute test_mode_pp(1); -- 5x
367 select name, generic_plans, custom_plans from pg_prepared_statements
368 where name = 'test_mode_pp';
369 name | generic_plans | custom_plans
370 --------------+---------------+--------------
374 -- we should now get a really bad plan
375 explain (costs off) execute test_mode_pp(2);
377 -----------------------------
379 -> Seq Scan on test_mode
383 -- but we can force a custom plan
384 set plan_cache_mode to force_custom_plan;
385 explain (costs off) execute test_mode_pp(2);
387 ----------------------------------------------------------
389 -> Index Only Scan using test_mode_a_idx on test_mode
393 select name, generic_plans, custom_plans from pg_prepared_statements
394 where name = 'test_mode_pp';
395 name | generic_plans | custom_plans
396 --------------+---------------+--------------
400 drop table test_mode;