PG17 compatibility: add helper function for EXPLAIN diffs in scalar subquery output (#7757)

PG17 changed how scalar subquery outputs appear in EXPLAIN output (*).
This commit changes impacted regress goldfiles to the PG17 format, and
adds a helper function to covert pre-PG17 plans to the PG17 format. The
conversion is required when testing Citus on pgversions prior to 17. The
helper function can and should be removed when 17 becomes the minimum
supported version.

(*)
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=fd0398fcb
pull/7922/head
Colm 2024-11-21 19:22:30 +00:00 committed by naisila
parent 81bda6fb8e
commit 4c080c48cd
15 changed files with 256 additions and 63 deletions

View File

@ -12,6 +12,7 @@ SELECT create_distributed_table('stock','s_w_id');
(1 row) (1 row)
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
@ -19,15 +20,16 @@ where s_order_cnt > (select sum(s_order_cnt) * .005 as where_query from stock)
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock) having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Sort Sort
Sort Key: remote_scan.s_i_id Sort Key: remote_scan.s_i_id
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> HashAggregate -> HashAggregate
Group Key: remote_scan.s_i_id Group Key: remote_scan.s_i_id
Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > $0) Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > (InitPlan 1).col1)
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
-> Distributed Subplan XXX_1 -> Distributed Subplan XXX_1
-> Aggregate -> Aggregate
@ -53,27 +55,29 @@ order by s_i_id;
Node: host=localhost port=xxxxx dbname=regression Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate -> HashAggregate
Group Key: stock.s_i_id Group Key: stock.s_i_id
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> Seq Scan on stock_1640000 stock -> Seq Scan on stock_1640000 stock
Filter: ((s_order_cnt)::numeric > $0) Filter: ((s_order_cnt)::numeric > (InitPlan 1).col1)
(36 rows) (36 rows)
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock) having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Sort Sort
Sort Key: remote_scan.s_i_id Sort Key: remote_scan.s_i_id
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> HashAggregate -> HashAggregate
Group Key: remote_scan.s_i_id Group Key: remote_scan.s_i_id
Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > $0) Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > (InitPlan 1).col1)
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
-> Distributed Subplan XXX_1 -> Distributed Subplan XXX_1
-> Aggregate -> Aggregate
@ -93,17 +97,19 @@ order by s_i_id;
-> Seq Scan on stock_1640000 stock -> Seq Scan on stock_1640000 stock
(24 rows) (24 rows)
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock); having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock);
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
HashAggregate HashAggregate
Group Key: remote_scan.s_i_id Group Key: remote_scan.s_i_id
Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > $0) Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > (InitPlan 1).col1)
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
-> Distributed Subplan XXX_1 -> Distributed Subplan XXX_1
@ -124,24 +130,26 @@ having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from st
-> Seq Scan on stock_1640000 stock -> Seq Scan on stock_1640000 stock
(22 rows) (22 rows)
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false) explain (costs false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock s from stock s
group by s_i_id group by s_i_id
having (select true) having (select true)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Sort Sort
Sort Key: remote_scan.s_i_id Sort Key: remote_scan.s_i_id
InitPlan 1 (returns $0) InitPlan 1
-> Result -> Result
-> HashAggregate -> HashAggregate
Group Key: remote_scan.s_i_id Group Key: remote_scan.s_i_id
-> Result -> Result
One-Time Filter: $0 One-Time Filter: (InitPlan 1).col1
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
Filter: $0 Filter: (InitPlan 1).col1
Task Count: 4 Task Count: 4
Tasks Shown: One of 4 Tasks Shown: One of 4
-> Task -> Task
@ -151,21 +159,23 @@ order by s_i_id;
-> Seq Scan on stock_1640000 s -> Seq Scan on stock_1640000 s
(17 rows) (17 rows)
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false) explain (costs false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock s from stock s
group by s_i_id group by s_i_id
having (select true); having (select true);
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
HashAggregate HashAggregate
Group Key: remote_scan.s_i_id Group Key: remote_scan.s_i_id
InitPlan 1 (returns $0) InitPlan 1
-> Result -> Result
-> Result -> Result
One-Time Filter: $0 One-Time Filter: (InitPlan 1).col1
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
Filter: $0 Filter: (InitPlan 1).col1
Task Count: 4 Task Count: 4
Tasks Shown: One of 4 Tasks Shown: One of 4
-> Task -> Task

View File

@ -16,6 +16,7 @@ SELECT create_distributed_table('stock','s_w_id');
\c - - - :worker_1_port \c - - - :worker_1_port
SET search_path = ch_bench_having; SET search_path = ch_bench_having;
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
@ -23,15 +24,16 @@ where s_order_cnt > (select sum(s_order_cnt) * .005 as where_query from stock)
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock) having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Sort Sort
Sort Key: remote_scan.s_i_id Sort Key: remote_scan.s_i_id
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> HashAggregate -> HashAggregate
Group Key: remote_scan.s_i_id Group Key: remote_scan.s_i_id
Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > $0) Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > (InitPlan 1).col1)
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
-> Distributed Subplan XXX_1 -> Distributed Subplan XXX_1
-> Aggregate -> Aggregate
@ -57,27 +59,29 @@ order by s_i_id;
Node: host=localhost port=xxxxx dbname=regression Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate -> HashAggregate
Group Key: stock.s_i_id Group Key: stock.s_i_id
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> Seq Scan on stock_1640000 stock -> Seq Scan on stock_1640000 stock
Filter: ((s_order_cnt)::numeric > $0) Filter: ((s_order_cnt)::numeric > (InitPlan 1).col1)
(36 rows) (36 rows)
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock) having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Sort Sort
Sort Key: remote_scan.s_i_id Sort Key: remote_scan.s_i_id
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> HashAggregate -> HashAggregate
Group Key: remote_scan.s_i_id Group Key: remote_scan.s_i_id
Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > $0) Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > (InitPlan 1).col1)
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
-> Distributed Subplan XXX_1 -> Distributed Subplan XXX_1
-> Aggregate -> Aggregate
@ -97,17 +101,19 @@ order by s_i_id;
-> Seq Scan on stock_1640000 stock -> Seq Scan on stock_1640000 stock
(24 rows) (24 rows)
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock); having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock);
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
HashAggregate HashAggregate
Group Key: remote_scan.s_i_id Group Key: remote_scan.s_i_id
Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > $0) Filter: ((pg_catalog.sum(remote_scan.worker_column_3))::bigint > (InitPlan 1).col1)
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
-> Distributed Subplan XXX_1 -> Distributed Subplan XXX_1
@ -128,24 +134,26 @@ having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from st
-> Seq Scan on stock_1640000 stock -> Seq Scan on stock_1640000 stock
(22 rows) (22 rows)
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false) explain (costs false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock s from stock s
group by s_i_id group by s_i_id
having (select true) having (select true)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Sort Sort
Sort Key: remote_scan.s_i_id Sort Key: remote_scan.s_i_id
InitPlan 1 (returns $0) InitPlan 1
-> Result -> Result
-> HashAggregate -> HashAggregate
Group Key: remote_scan.s_i_id Group Key: remote_scan.s_i_id
-> Result -> Result
One-Time Filter: $0 One-Time Filter: (InitPlan 1).col1
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
Filter: $0 Filter: (InitPlan 1).col1
Task Count: 4 Task Count: 4
Tasks Shown: One of 4 Tasks Shown: One of 4
-> Task -> Task
@ -155,20 +163,22 @@ order by s_i_id;
-> Seq Scan on stock_1640000 s -> Seq Scan on stock_1640000 s
(17 rows) (17 rows)
SELECT public.explain_with_pg17_initplan_format($Q$
explain select s_i_id, sum(s_order_cnt) as ordercount explain select s_i_id, sum(s_order_cnt) as ordercount
from stock s from stock s
group by s_i_id group by s_i_id
having (select true); having (select true);
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
HashAggregate (cost=500.01..503.01 rows=200 width=12) HashAggregate (cost=500.01..503.01 rows=200 width=12)
Group Key: remote_scan.s_i_id Group Key: remote_scan.s_i_id
InitPlan 1 (returns $0) InitPlan 1
-> Result (cost=0.00..0.01 rows=1 width=1) -> Result (cost=0.00..0.01 rows=1 width=1)
-> Result (cost=0.00..0.00 rows=100000 width=12) -> Result (cost=0.00..0.00 rows=100000 width=12)
One-Time Filter: $0 One-Time Filter: (InitPlan 1).col1
-> Custom Scan (Citus Adaptive) (cost=0.00..0.00 rows=100000 width=12) -> Custom Scan (Citus Adaptive) (cost=0.00..0.00 rows=100000 width=12)
Filter: $0 Filter: (InitPlan 1).col1
Task Count: 4 Task Count: 4
Tasks Shown: One of 4 Tasks Shown: One of 4
-> Task -> Task

View File

@ -22,6 +22,7 @@ HAVING (
(3 rows) (3 rows)
-- lets pin the plan in the test as well -- lets pin the plan in the test as well
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
SELECT count(*), SELECT count(*),
o_orderstatus o_orderstatus
@ -31,16 +32,17 @@ HAVING (
SELECT count(*) SELECT count(*)
FROM customer FROM customer
) > 0; ) > 0;
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
HashAggregate HashAggregate
Group Key: remote_scan.o_orderstatus Group Key: remote_scan.o_orderstatus
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> Result -> Result
One-Time Filter: ($0 > 0) One-Time Filter: ((InitPlan 1).col1 > 0)
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
Filter: ($0 > 0) Filter: ((InitPlan 1).col1 > 0)
-> Distributed Subplan XXX_1 -> Distributed Subplan XXX_1
-> Custom Scan (Citus Adaptive) -> Custom Scan (Citus Adaptive)
Task Count: 1 Task Count: 1

View File

@ -1456,25 +1456,27 @@ Custom Scan (Citus INSERT ... SELECT)
INSERT/SELECT method: pull to coordinator INSERT/SELECT method: pull to coordinator
-> Function Scan on generate_series s -> Function Scan on generate_series s
-- WHERE EXISTS forces pg12 to materialize cte -- WHERE EXISTS forces pg12 to materialize cte
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
WITH cte1 AS (SELECT s FROM generate_series(1,10) s) WITH cte1 AS (SELECT s FROM generate_series(1,10) s)
INSERT INTO lineitem_hash_part INSERT INTO lineitem_hash_part
WITH cte1 AS (SELECT * FROM cte1 WHERE EXISTS (SELECT * FROM cte1) LIMIT 5) WITH cte1 AS (SELECT * FROM cte1 WHERE EXISTS (SELECT * FROM cte1) LIMIT 5)
SELECT s FROM cte1 WHERE EXISTS (SELECT * FROM cte1); SELECT s FROM cte1 WHERE EXISTS (SELECT * FROM cte1);
$Q$);
Custom Scan (Citus INSERT ... SELECT) Custom Scan (Citus INSERT ... SELECT)
INSERT/SELECT method: pull to coordinator INSERT/SELECT method: pull to coordinator
-> Result -> Result
One-Time Filter: $3 One-Time Filter: (InitPlan 4).col1
CTE cte1 CTE cte1
-> Function Scan on generate_series s -> Function Scan on generate_series s
CTE cte1 CTE cte1
-> Limit -> Limit
InitPlan 2 (returns $1) InitPlan 2
-> CTE Scan on cte1 cte1_1 -> CTE Scan on cte1 cte1_1
-> Result -> Result
One-Time Filter: $1 One-Time Filter: (InitPlan 2).col1
-> CTE Scan on cte1 cte1_2 -> CTE Scan on cte1 cte1_2
InitPlan 4 (returns $3) InitPlan 4
-> CTE Scan on cte1 cte1_3 -> CTE Scan on cte1 cte1_3
-> CTE Scan on cte1 -> CTE Scan on cte1
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
@ -2425,9 +2427,11 @@ Aggregate (actual rows=1 loops=1)
Sort Key: ref_table.a Sort Key: ref_table.a
Sort Method: quicksort Memory: 25kB Sort Method: quicksort Memory: 25kB
-> Seq Scan on ref_table_570021 ref_table (actual rows=10 loops=1) -> Seq Scan on ref_table_570021 ref_table (actual rows=10 loops=1)
EXPLAIN :default_analyze_flags SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (ANALYZE on, COSTS off, TIMING off, SUMMARY off)
SELECT count(distinct a) FROM dist_table SELECT count(distinct a) FROM dist_table
WHERE EXISTS(SELECT random() < 2 FROM dist_table NATURAL JOIN ref_table); WHERE EXISTS(SELECT random() < 2 FROM dist_table NATURAL JOIN ref_table);
$Q$);
Aggregate (actual rows=1 loops=1) Aggregate (actual rows=1 loops=1)
-> Custom Scan (Citus Adaptive) (actual rows=4 loops=1) -> Custom Scan (Citus Adaptive) (actual rows=4 loops=1)
-> Distributed Subplan XXX_1 -> Distributed Subplan XXX_1
@ -2457,13 +2461,13 @@ Aggregate (actual rows=1 loops=1)
Tuple data received from node: 8 bytes Tuple data received from node: 8 bytes
Node: host=localhost port=xxxxx dbname=regression Node: host=localhost port=xxxxx dbname=regression
-> Aggregate (actual rows=1 loops=1) -> Aggregate (actual rows=1 loops=1)
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result (actual rows=1 loops=1) -> Function Scan on read_intermediate_result intermediate_result (actual rows=1 loops=1)
-> Sort (actual rows=4 loops=1) -> Sort (actual rows=4 loops=1)
Sort Key: dist_table.a Sort Key: dist_table.a
Sort Method: quicksort Memory: 25kB Sort Method: quicksort Memory: 25kB
-> Result (actual rows=4 loops=1) -> Result (actual rows=4 loops=1)
One-Time Filter: $0 One-Time Filter: (InitPlan 1).col1
-> Seq Scan on dist_table_570017 dist_table (actual rows=4 loops=1) -> Seq Scan on dist_table_570017 dist_table (actual rows=4 loops=1)
BEGIN; BEGIN;
EXPLAIN :default_analyze_flags EXPLAIN :default_analyze_flags

View File

@ -1456,25 +1456,27 @@ Custom Scan (Citus INSERT ... SELECT)
INSERT/SELECT method: pull to coordinator INSERT/SELECT method: pull to coordinator
-> Function Scan on generate_series s -> Function Scan on generate_series s
-- WHERE EXISTS forces pg12 to materialize cte -- WHERE EXISTS forces pg12 to materialize cte
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
WITH cte1 AS (SELECT s FROM generate_series(1,10) s) WITH cte1 AS (SELECT s FROM generate_series(1,10) s)
INSERT INTO lineitem_hash_part INSERT INTO lineitem_hash_part
WITH cte1 AS (SELECT * FROM cte1 WHERE EXISTS (SELECT * FROM cte1) LIMIT 5) WITH cte1 AS (SELECT * FROM cte1 WHERE EXISTS (SELECT * FROM cte1) LIMIT 5)
SELECT s FROM cte1 WHERE EXISTS (SELECT * FROM cte1); SELECT s FROM cte1 WHERE EXISTS (SELECT * FROM cte1);
$Q$);
Custom Scan (Citus INSERT ... SELECT) Custom Scan (Citus INSERT ... SELECT)
INSERT/SELECT method: pull to coordinator INSERT/SELECT method: pull to coordinator
-> Result -> Result
One-Time Filter: $3 One-Time Filter: (InitPlan 4).col1
CTE cte1 CTE cte1
-> Function Scan on generate_series s -> Function Scan on generate_series s
CTE cte1 CTE cte1
-> Limit -> Limit
InitPlan 2 (returns $1) InitPlan 2
-> CTE Scan on cte1 cte1_1 -> CTE Scan on cte1 cte1_1
-> Result -> Result
One-Time Filter: $1 One-Time Filter: (InitPlan 2).col1
-> CTE Scan on cte1 cte1_2 -> CTE Scan on cte1 cte1_2
InitPlan 4 (returns $3) InitPlan 4
-> CTE Scan on cte1 cte1_3 -> CTE Scan on cte1 cte1_3
-> CTE Scan on cte1 -> CTE Scan on cte1
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
@ -2420,9 +2422,11 @@ Aggregate (actual rows=1 loops=1)
Sort Key: ref_table.a Sort Key: ref_table.a
Sort Method: quicksort Memory: 25kB Sort Method: quicksort Memory: 25kB
-> Seq Scan on ref_table_570021 ref_table (actual rows=10 loops=1) -> Seq Scan on ref_table_570021 ref_table (actual rows=10 loops=1)
EXPLAIN :default_analyze_flags SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (ANALYZE on, COSTS off, TIMING off, SUMMARY off)
SELECT count(distinct a) FROM dist_table SELECT count(distinct a) FROM dist_table
WHERE EXISTS(SELECT random() < 2 FROM dist_table NATURAL JOIN ref_table); WHERE EXISTS(SELECT random() < 2 FROM dist_table NATURAL JOIN ref_table);
$Q$);
Aggregate (actual rows=1 loops=1) Aggregate (actual rows=1 loops=1)
-> Custom Scan (Citus Adaptive) (actual rows=4 loops=1) -> Custom Scan (Citus Adaptive) (actual rows=4 loops=1)
-> Distributed Subplan XXX_1 -> Distributed Subplan XXX_1
@ -2452,10 +2456,10 @@ Aggregate (actual rows=1 loops=1)
Tuple data received from node: 8 bytes Tuple data received from node: 8 bytes
Node: host=localhost port=xxxxx dbname=regression Node: host=localhost port=xxxxx dbname=regression
-> Aggregate (actual rows=1 loops=1) -> Aggregate (actual rows=1 loops=1)
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result (actual rows=1 loops=1) -> Function Scan on read_intermediate_result intermediate_result (actual rows=1 loops=1)
-> Result (actual rows=4 loops=1) -> Result (actual rows=4 loops=1)
One-Time Filter: $0 One-Time Filter: (InitPlan 1).col1
-> Seq Scan on dist_table_570017 dist_table (actual rows=4 loops=1) -> Seq Scan on dist_table_570017 dist_table (actual rows=4 loops=1)
BEGIN; BEGIN;
EXPLAIN :default_analyze_flags EXPLAIN :default_analyze_flags

View File

@ -1574,9 +1574,11 @@ ALTER TABLE reference_table_test ADD COLUMN value_dummy INT;
INSERT INTO reference_table_test VALUES (2, 2.0, '2', '2016-12-02'); INSERT INTO reference_table_test VALUES (2, 2.0, '2', '2016-12-02');
ROLLBACK; ROLLBACK;
-- Previous issue failed to rename reference tables in subqueries -- Previous issue failed to rename reference tables in subqueries
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) SELECT value_1, count(*) FROM colocated_table_test GROUP BY value_1 EXPLAIN (COSTS OFF) SELECT value_1, count(*) FROM colocated_table_test GROUP BY value_1
HAVING (SELECT rt.value_2 FROM reference_table_test rt where rt.value_2 = 2) > 0 HAVING (SELECT rt.value_2 FROM reference_table_test rt where rt.value_2 = 2) > 0
ORDER BY 1; ORDER BY 1;
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Sort Sort
@ -1596,10 +1598,10 @@ ORDER BY 1;
Node: host=localhost port=xxxxx dbname=regression Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate -> HashAggregate
Group Key: colocated_table_test.value_1 Group Key: colocated_table_test.value_1
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> Result -> Result
One-Time Filter: ($0 > '0'::double precision) One-Time Filter: ((InitPlan 1).col1 > '0'::double precision)
-> Seq Scan on colocated_table_test_1250005 colocated_table_test -> Seq Scan on colocated_table_test_1250005 colocated_table_test
(22 rows) (22 rows)

View File

@ -973,8 +973,10 @@ SELECT create_reference_table('keyvalref');
(1 row) (1 row)
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyvalref GROUP BY key); SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyvalref GROUP BY key);
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (Citus Adaptive) Custom Scan (Citus Adaptive)
@ -993,15 +995,17 @@ SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value)
Node: host=localhost port=xxxxx dbname=regression Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate -> HashAggregate
Group Key: keyval1.key Group Key: keyval1.key
Filter: (sum(keyval1.value) > $0) Filter: (sum(keyval1.value) > (InitPlan 1).col1)
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> Seq Scan on keyval1_xxxxxxx keyval1 -> Seq Scan on keyval1_xxxxxxx keyval1
(20 rows) (20 rows)
-- For some reason 'ORDER BY 1 DESC LIMIT 1' triggers recursive planning -- For some reason 'ORDER BY 1 DESC LIMIT 1' triggers recursive planning
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyvalref GROUP BY key ORDER BY 1 DESC LIMIT 1); SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyvalref GROUP BY key ORDER BY 1 DESC LIMIT 1);
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (Citus Adaptive) Custom Scan (Citus Adaptive)
@ -1023,14 +1027,16 @@ SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value)
Node: host=localhost port=xxxxx dbname=regression Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate -> HashAggregate
Group Key: keyval1.key Group Key: keyval1.key
Filter: (sum(keyval1.value) > $0) Filter: (sum(keyval1.value) > (InitPlan 1).col1)
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> Seq Scan on keyval1_xxxxxxx keyval1 -> Seq Scan on keyval1_xxxxxxx keyval1
(23 rows) (23 rows)
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyval2 GROUP BY key ORDER BY 1 DESC LIMIT 1); SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyval2 GROUP BY key ORDER BY 1 DESC LIMIT 1);
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (Citus Adaptive) Custom Scan (Citus Adaptive)
@ -1055,14 +1061,16 @@ SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value)
Node: host=localhost port=xxxxx dbname=regression Node: host=localhost port=xxxxx dbname=regression
-> HashAggregate -> HashAggregate
Group Key: keyval1.key Group Key: keyval1.key
Filter: (sum(keyval1.value) > $0) Filter: (sum(keyval1.value) > (InitPlan 1).col1)
InitPlan 1 (returns $0) InitPlan 1
-> Function Scan on read_intermediate_result intermediate_result -> Function Scan on read_intermediate_result intermediate_result
-> Seq Scan on keyval1_xxxxxxx keyval1 -> Seq Scan on keyval1_xxxxxxx keyval1
(26 rows) (26 rows)
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
SELECT count(*) FROM keyval1 k1 WHERE k1.key = 2 HAVING sum(value) > (SELECT sum(value) FROM keyval2 k2 WHERE k2.key = 2 ORDER BY 1 DESC LIMIT 1); SELECT count(*) FROM keyval1 k1 WHERE k1.key = 2 HAVING sum(value) > (SELECT sum(value) FROM keyval2 k2 WHERE k2.key = 2 ORDER BY 1 DESC LIMIT 1);
$Q$) as "QUERY PLAN";
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------- ---------------------------------------------------------------------
Custom Scan (Citus Adaptive) Custom Scan (Citus Adaptive)
@ -1071,8 +1079,8 @@ SELECT count(*) FROM keyval1 k1 WHERE k1.key = 2 HAVING sum(value) > (SELECT sum
-> Task -> Task
Node: host=localhost port=xxxxx dbname=regression Node: host=localhost port=xxxxx dbname=regression
-> Aggregate -> Aggregate
Filter: (sum(k1.value) > $0) Filter: (sum(k1.value) > (InitPlan 1).col1)
InitPlan 1 (returns $0) InitPlan 1
-> Limit -> Limit
-> Sort -> Sort
Sort Key: (sum(k2.value)) DESC Sort Key: (sum(k2.value)) DESC

View File

@ -639,3 +639,62 @@ BEGIN
END LOOP; END LOOP;
END; END;
$func$ LANGUAGE plpgsql; $func$ LANGUAGE plpgsql;
CREATE or REPLACE FUNCTION initplan_references_to_pg17(text) returns text AS $$
DECLARE
expr_parts text[];
initplan_refs text[];
n_initplan_refs int = 0;
i int := 1;
rv text := '';
expr_part text;
BEGIN
-- Split the line on each $x; there must be at least one
-- For example 'foo = $0 and bar < $1' is split to: [ 'foo =', 'bar <' ]
expr_parts := regexp_split_to_array($1, '\$\d+');
-- Construct the PG17 formatted names in the given text
-- for example 'foo = $0 and bar < $1' yields [ '(InitPlan1).col1', '(InitPlan2).col1' ]
initplan_refs := ARRAY(select '(InitPlan ' || substr(x[1],2)::int + 1 || ').col1' from regexp_matches($1, '\$\d', 'g') x);
n_initplan_refs := array_length(initplan_refs, 1);
-- Combine expression parts with PG17 formatted names
FOREACH expr_part IN ARRAY expr_parts
LOOP
rv := rv || expr_part;
-- There should be more expr parts than init plan refs so
-- check init plan refs boundary each time
IF i <= n_initplan_refs THEN
rv := rv || initplan_refs[i];
END IF;
i := i + 1;
END LOOP;
RETURN rv;
END;
$$ LANGUAGE plpgsql;
-- This function formats EXPLAIN output to conform to how PG17 EXPLAIN shows
-- scalar subquery outputs if the pg version is less than 17 (*). When 17
-- becomes the minimum supported pgversion this function can be retired.
--
-- (*) https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=fd0398fcb
CREATE OR REPLACE FUNCTION explain_with_pg17_initplan_format(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$
DECLARE
pgversion int = 0;
BEGIN
pgversion = substring(version(), '\d+')::int ;
FOR query_plan IN execute explain_command LOOP
IF pgversion < 17 THEN
-- Two types of format changes are needed:
-- 1) 'Init Plan 1 (returns $0)' becomes just 'Init Plan 1'
-- 2) 'foo = $0' becomes 'foo = (InitPlan 1).col1'
IF query_plan ~ 'InitPlan \d \(returns' THEN
query_plan = regexp_replace(query_plan, '\(returns \$\d\)', '', 'g');
ELSIF query_plan ~ '\$\d' THEN
-- This line contains at least one InitPlan reference
-- Replace it to have PG17 style InitPlan references
query_plan = public.initplan_references_to_pg17(query_plan);
END IF;
END IF;
RETURN NEXT;
END LOOP;
END; $$ language plpgsql;

View File

@ -10,6 +10,7 @@ CREATE TABLE stock (
SELECT create_distributed_table('stock','s_w_id'); SELECT create_distributed_table('stock','s_w_id');
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
@ -17,33 +18,41 @@ where s_order_cnt > (select sum(s_order_cnt) * .005 as where_query from stock)
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock) having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock) having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock); having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock);
$Q$) as "QUERY PLAN";
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false) explain (costs false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock s from stock s
group by s_i_id group by s_i_id
having (select true) having (select true)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false) explain (costs false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock s from stock s
group by s_i_id group by s_i_id
having (select true); having (select true);
$Q$) as "QUERY PLAN";
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock

View File

@ -15,6 +15,7 @@ SELECT create_distributed_table('stock','s_w_id');
\c - - - :worker_1_port \c - - - :worker_1_port
SET search_path = ch_bench_having; SET search_path = ch_bench_having;
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
@ -22,32 +23,40 @@ where s_order_cnt > (select sum(s_order_cnt) * .005 as where_query from stock)
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock) having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock) having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false, summary false, timing false) explain (costs false, summary false, timing false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock
group by s_i_id group by s_i_id
having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock); having sum(s_order_cnt) > (select max(s_order_cnt) - 3 as having_query from stock);
$Q$) as "QUERY PLAN";
SELECT public.explain_with_pg17_initplan_format($Q$
explain (costs false) explain (costs false)
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock s from stock s
group by s_i_id group by s_i_id
having (select true) having (select true)
order by s_i_id; order by s_i_id;
$Q$) as "QUERY PLAN";
SELECT public.explain_with_pg17_initplan_format($Q$
explain select s_i_id, sum(s_order_cnt) as ordercount explain select s_i_id, sum(s_order_cnt) as ordercount
from stock s from stock s
group by s_i_id group by s_i_id
having (select true); having (select true);
$Q$) as "QUERY PLAN";
select s_i_id, sum(s_order_cnt) as ordercount select s_i_id, sum(s_order_cnt) as ordercount
from stock from stock

View File

@ -16,6 +16,7 @@ HAVING (
) > 0; ) > 0;
-- lets pin the plan in the test as well -- lets pin the plan in the test as well
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
SELECT count(*), SELECT count(*),
o_orderstatus o_orderstatus
@ -25,3 +26,4 @@ HAVING (
SELECT count(*) SELECT count(*)
FROM customer FROM customer
) > 0; ) > 0;
$Q$) as "QUERY PLAN";

View File

@ -630,11 +630,13 @@ INSERT INTO lineitem_hash_part (l_orderkey)
SELECT s FROM generate_series(1,5) s; SELECT s FROM generate_series(1,5) s;
-- WHERE EXISTS forces pg12 to materialize cte -- WHERE EXISTS forces pg12 to materialize cte
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
WITH cte1 AS (SELECT s FROM generate_series(1,10) s) WITH cte1 AS (SELECT s FROM generate_series(1,10) s)
INSERT INTO lineitem_hash_part INSERT INTO lineitem_hash_part
WITH cte1 AS (SELECT * FROM cte1 WHERE EXISTS (SELECT * FROM cte1) LIMIT 5) WITH cte1 AS (SELECT * FROM cte1 WHERE EXISTS (SELECT * FROM cte1) LIMIT 5)
SELECT s FROM cte1 WHERE EXISTS (SELECT * FROM cte1); SELECT s FROM cte1 WHERE EXISTS (SELECT * FROM cte1);
$Q$);
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
INSERT INTO lineitem_hash_part INSERT INTO lineitem_hash_part
@ -949,9 +951,11 @@ SELECT count(distinct a) from r NATURAL JOIN ref_table;
EXPLAIN :default_analyze_flags EXPLAIN :default_analyze_flags
SELECT count(distinct a) FROM (SELECT GREATEST(random(), 2) r, a FROM dist_table) t NATURAL JOIN ref_table; SELECT count(distinct a) FROM (SELECT GREATEST(random(), 2) r, a FROM dist_table) t NATURAL JOIN ref_table;
EXPLAIN :default_analyze_flags SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (ANALYZE on, COSTS off, TIMING off, SUMMARY off)
SELECT count(distinct a) FROM dist_table SELECT count(distinct a) FROM dist_table
WHERE EXISTS(SELECT random() < 2 FROM dist_table NATURAL JOIN ref_table); WHERE EXISTS(SELECT random() < 2 FROM dist_table NATURAL JOIN ref_table);
$Q$);
BEGIN; BEGIN;
EXPLAIN :default_analyze_flags EXPLAIN :default_analyze_flags

View File

@ -993,9 +993,11 @@ INSERT INTO reference_table_test VALUES (2, 2.0, '2', '2016-12-02');
ROLLBACK; ROLLBACK;
-- Previous issue failed to rename reference tables in subqueries -- Previous issue failed to rename reference tables in subqueries
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) SELECT value_1, count(*) FROM colocated_table_test GROUP BY value_1 EXPLAIN (COSTS OFF) SELECT value_1, count(*) FROM colocated_table_test GROUP BY value_1
HAVING (SELECT rt.value_2 FROM reference_table_test rt where rt.value_2 = 2) > 0 HAVING (SELECT rt.value_2 FROM reference_table_test rt where rt.value_2 = 2) > 0
ORDER BY 1; ORDER BY 1;
$Q$) as "QUERY PLAN";
WITH a as (SELECT rt.value_2 FROM reference_table_test rt where rt.value_2 = 2) WITH a as (SELECT rt.value_2 FROM reference_table_test rt where rt.value_2 = 2)
SELECT ct.value_1, count(*) FROM colocated_table_test ct join a on ct.value_1 = a.value_2 SELECT ct.value_1, count(*) FROM colocated_table_test ct join a on ct.value_1 = a.value_2

View File

@ -665,18 +665,26 @@ SELECT create_distributed_table('keyval2', 'key');
CREATE TABLE keyvalref (key int, value int); CREATE TABLE keyvalref (key int, value int);
SELECT create_reference_table('keyvalref'); SELECT create_reference_table('keyvalref');
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyvalref GROUP BY key); SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyvalref GROUP BY key);
$Q$) as "QUERY PLAN";
-- For some reason 'ORDER BY 1 DESC LIMIT 1' triggers recursive planning -- For some reason 'ORDER BY 1 DESC LIMIT 1' triggers recursive planning
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyvalref GROUP BY key ORDER BY 1 DESC LIMIT 1); SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyvalref GROUP BY key ORDER BY 1 DESC LIMIT 1);
$Q$) as "QUERY PLAN";
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyval2 GROUP BY key ORDER BY 1 DESC LIMIT 1); SELECT count(*) FROM keyval1 GROUP BY key HAVING sum(value) > (SELECT sum(value) FROM keyval2 GROUP BY key ORDER BY 1 DESC LIMIT 1);
$Q$) as "QUERY PLAN";
SELECT public.explain_with_pg17_initplan_format($Q$
EXPLAIN (COSTS OFF) EXPLAIN (COSTS OFF)
SELECT count(*) FROM keyval1 k1 WHERE k1.key = 2 HAVING sum(value) > (SELECT sum(value) FROM keyval2 k2 WHERE k2.key = 2 ORDER BY 1 DESC LIMIT 1); SELECT count(*) FROM keyval1 k1 WHERE k1.key = 2 HAVING sum(value) > (SELECT sum(value) FROM keyval2 k2 WHERE k2.key = 2 ORDER BY 1 DESC LIMIT 1);
$Q$) as "QUERY PLAN";
-- Simple join subquery pushdown -- Simple join subquery pushdown
SELECT SELECT

View File

@ -666,3 +666,63 @@ BEGIN
END LOOP; END LOOP;
END; END;
$func$ LANGUAGE plpgsql; $func$ LANGUAGE plpgsql;
CREATE or REPLACE FUNCTION initplan_references_to_pg17(text) returns text AS $$
DECLARE
expr_parts text[];
initplan_refs text[];
n_initplan_refs int = 0;
i int := 1;
rv text := '';
expr_part text;
BEGIN
-- Split the line on each $x; there must be at least one
-- For example 'foo = $0 and bar < $1' is split to: [ 'foo =', 'bar <' ]
expr_parts := regexp_split_to_array($1, '\$\d+');
-- Construct the PG17 formatted names in the given text
-- for example 'foo = $0 and bar < $1' yields [ '(InitPlan1).col1', '(InitPlan2).col1' ]
initplan_refs := ARRAY(select '(InitPlan ' || substr(x[1],2)::int + 1 || ').col1' from regexp_matches($1, '\$\d', 'g') x);
n_initplan_refs := array_length(initplan_refs, 1);
-- Combine expression parts with PG17 formatted names
FOREACH expr_part IN ARRAY expr_parts
LOOP
rv := rv || expr_part;
-- There should be more expr parts than init plan refs so
-- check init plan refs boundary each time
IF i <= n_initplan_refs THEN
rv := rv || initplan_refs[i];
END IF;
i := i + 1;
END LOOP;
RETURN rv;
END;
$$ LANGUAGE plpgsql;
-- This function formats EXPLAIN output to conform to how PG17 EXPLAIN shows
-- scalar subquery outputs if the pg version is less than 17 (*). When 17
-- becomes the minimum supported pgversion this function can be retired.
--
-- (*) https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=fd0398fcb
CREATE OR REPLACE FUNCTION explain_with_pg17_initplan_format(explain_command text, out query_plan text)
RETURNS SETOF TEXT AS $$
DECLARE
pgversion int = 0;
BEGIN
pgversion = substring(version(), '\d+')::int ;
FOR query_plan IN execute explain_command LOOP
IF pgversion < 17 THEN
-- Two types of format changes are needed:
-- 1) 'Init Plan 1 (returns $0)' becomes just 'Init Plan 1'
-- 2) 'foo = $0' becomes 'foo = (InitPlan 1).col1'
IF query_plan ~ 'InitPlan \d \(returns' THEN
query_plan = regexp_replace(query_plan, '\(returns \$\d\)', '', 'g');
ELSIF query_plan ~ '\$\d' THEN
-- This line contains at least one InitPlan reference
-- Replace it to have PG17 style InitPlan references
query_plan = public.initplan_references_to_pg17(query_plan);
END IF;
END IF;
RETURN NEXT;
END LOOP;
END; $$ language plpgsql;