mirror of
https://github.com/postgres/postgres.git
synced 2025-09-03 15:22:11 +03:00
Fix EXPLAIN to handle SEARCH BREADTH FIRST queries.
The rewriter transformation for SEARCH BREADTH FIRST produces a FieldSelect on a Var of type RECORD, where the Var references the recursive union's worktable output. EXPLAIN VERBOSE failed to handle this case, because it only expected such Vars to appear in CteScans not WorkTableScans. Fix that, and add some test cases exercising EXPLAIN on SEARCH and CYCLE queries. In principle this oversight is an old bug, but it seems that the case is unreachable without SEARCH BREADTH FIRST, because the parser fails when attempting to create such a reference manually. So for today I'll just patch HEAD/v14. Someday we might find that the code portion of this patch needs to be back-patched further. Per report from Atsushi Torikoshi. Discussion: https://postgr.es/m/5bafa66ad529e11860339565c9e7c166@oss.nttdata.com
This commit is contained in:
@@ -637,13 +637,48 @@ SELECT t1.id, t2.path, t2 FROM t AS t1 JOIN t AS t2 ON
|
||||
(16 rows)
|
||||
|
||||
-- SEARCH clause
|
||||
create temp table graph0( f int, t int, label text );
|
||||
create table graph0( f int, t int, label text );
|
||||
insert into graph0 values
|
||||
(1, 2, 'arc 1 -> 2'),
|
||||
(1, 3, 'arc 1 -> 3'),
|
||||
(2, 3, 'arc 2 -> 3'),
|
||||
(1, 4, 'arc 1 -> 4'),
|
||||
(4, 5, 'arc 4 -> 5');
|
||||
explain (verbose, costs off)
|
||||
with recursive search_graph(f, t, label) as (
|
||||
select * from graph0 g
|
||||
union all
|
||||
select g.*
|
||||
from graph0 g, search_graph sg
|
||||
where g.f = sg.t
|
||||
) search depth first by f, t set seq
|
||||
select * from search_graph order by seq;
|
||||
QUERY PLAN
|
||||
----------------------------------------------------------------------------------------------
|
||||
Sort
|
||||
Output: search_graph.f, search_graph.t, search_graph.label, search_graph.seq
|
||||
Sort Key: search_graph.seq
|
||||
CTE search_graph
|
||||
-> Recursive Union
|
||||
-> Seq Scan on public.graph0 g
|
||||
Output: g.f, g.t, g.label, ARRAY[ROW(g.f, g.t)]
|
||||
-> Merge Join
|
||||
Output: g_1.f, g_1.t, g_1.label, array_cat(sg.seq, ARRAY[ROW(g_1.f, g_1.t)])
|
||||
Merge Cond: (g_1.f = sg.t)
|
||||
-> Sort
|
||||
Output: g_1.f, g_1.t, g_1.label
|
||||
Sort Key: g_1.f
|
||||
-> Seq Scan on public.graph0 g_1
|
||||
Output: g_1.f, g_1.t, g_1.label
|
||||
-> Sort
|
||||
Output: sg.seq, sg.t
|
||||
Sort Key: sg.t
|
||||
-> WorkTable Scan on search_graph sg
|
||||
Output: sg.seq, sg.t
|
||||
-> CTE Scan on search_graph
|
||||
Output: search_graph.f, search_graph.t, search_graph.label, search_graph.seq
|
||||
(22 rows)
|
||||
|
||||
with recursive search_graph(f, t, label) as (
|
||||
select * from graph0 g
|
||||
union all
|
||||
@@ -682,6 +717,41 @@ select * from search_graph order by seq;
|
||||
4 | 5 | arc 4 -> 5 | {"(4,5)"}
|
||||
(7 rows)
|
||||
|
||||
explain (verbose, costs off)
|
||||
with recursive search_graph(f, t, label) as (
|
||||
select * from graph0 g
|
||||
union all
|
||||
select g.*
|
||||
from graph0 g, search_graph sg
|
||||
where g.f = sg.t
|
||||
) search breadth first by f, t set seq
|
||||
select * from search_graph order by seq;
|
||||
QUERY PLAN
|
||||
-------------------------------------------------------------------------------------------------
|
||||
Sort
|
||||
Output: search_graph.f, search_graph.t, search_graph.label, search_graph.seq
|
||||
Sort Key: search_graph.seq
|
||||
CTE search_graph
|
||||
-> Recursive Union
|
||||
-> Seq Scan on public.graph0 g
|
||||
Output: g.f, g.t, g.label, ROW('0'::bigint, g.f, g.t)
|
||||
-> Merge Join
|
||||
Output: g_1.f, g_1.t, g_1.label, ROW(int8inc((sg.seq)."*DEPTH*"), g_1.f, g_1.t)
|
||||
Merge Cond: (g_1.f = sg.t)
|
||||
-> Sort
|
||||
Output: g_1.f, g_1.t, g_1.label
|
||||
Sort Key: g_1.f
|
||||
-> Seq Scan on public.graph0 g_1
|
||||
Output: g_1.f, g_1.t, g_1.label
|
||||
-> Sort
|
||||
Output: sg.seq, sg.t
|
||||
Sort Key: sg.t
|
||||
-> WorkTable Scan on search_graph sg
|
||||
Output: sg.seq, sg.t
|
||||
-> CTE Scan on search_graph
|
||||
Output: search_graph.f, search_graph.t, search_graph.label, search_graph.seq
|
||||
(22 rows)
|
||||
|
||||
with recursive search_graph(f, t, label) as (
|
||||
select * from graph0 g
|
||||
union all
|
||||
@@ -820,6 +890,8 @@ select * from v_search;
|
||||
4 | 5 | arc 4 -> 5
|
||||
(7 rows)
|
||||
|
||||
drop table graph0 cascade;
|
||||
NOTICE: drop cascades to view v_search
|
||||
--
|
||||
-- test cycle detection
|
||||
--
|
||||
|
@@ -349,7 +349,7 @@ SELECT t1.id, t2.path, t2 FROM t AS t1 JOIN t AS t2 ON
|
||||
|
||||
-- SEARCH clause
|
||||
|
||||
create temp table graph0( f int, t int, label text );
|
||||
create table graph0( f int, t int, label text );
|
||||
|
||||
insert into graph0 values
|
||||
(1, 2, 'arc 1 -> 2'),
|
||||
@@ -358,6 +358,16 @@ insert into graph0 values
|
||||
(1, 4, 'arc 1 -> 4'),
|
||||
(4, 5, 'arc 4 -> 5');
|
||||
|
||||
explain (verbose, costs off)
|
||||
with recursive search_graph(f, t, label) as (
|
||||
select * from graph0 g
|
||||
union all
|
||||
select g.*
|
||||
from graph0 g, search_graph sg
|
||||
where g.f = sg.t
|
||||
) search depth first by f, t set seq
|
||||
select * from search_graph order by seq;
|
||||
|
||||
with recursive search_graph(f, t, label) as (
|
||||
select * from graph0 g
|
||||
union all
|
||||
@@ -376,6 +386,16 @@ with recursive search_graph(f, t, label) as (
|
||||
) search depth first by f, t set seq
|
||||
select * from search_graph order by seq;
|
||||
|
||||
explain (verbose, costs off)
|
||||
with recursive search_graph(f, t, label) as (
|
||||
select * from graph0 g
|
||||
union all
|
||||
select g.*
|
||||
from graph0 g, search_graph sg
|
||||
where g.f = sg.t
|
||||
) search breadth first by f, t set seq
|
||||
select * from search_graph order by seq;
|
||||
|
||||
with recursive search_graph(f, t, label) as (
|
||||
select * from graph0 g
|
||||
union all
|
||||
@@ -459,6 +479,8 @@ select pg_get_viewdef('v_search');
|
||||
|
||||
select * from v_search;
|
||||
|
||||
drop table graph0 cascade;
|
||||
|
||||
--
|
||||
-- test cycle detection
|
||||
--
|
||||
|
Reference in New Issue
Block a user