Commit f4abd024 authored by Tom Lane's avatar Tom Lane

Support flattening of empty-FROM subqueries and one-row VALUES tables.

We can't handle this in the general case due to limitations of the
planner's data representations; but we can allow it in many useful cases,
by being careful to flatten only when we are pulling a single-row subquery
up into a FROM (or, equivalently, inner JOIN) node that will still have at
least one remaining relation child.  Per discussion of an example from
Kyotaro Horiguchi.
parent b746d0c3
......@@ -1762,6 +1762,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
WRITE_BOOL_FIELD(hasInheritedTarget);
WRITE_BOOL_FIELD(hasJoinRTEs);
WRITE_BOOL_FIELD(hasLateralRTEs);
WRITE_BOOL_FIELD(hasDeletedRTEs);
WRITE_BOOL_FIELD(hasHavingQual);
WRITE_BOOL_FIELD(hasPseudoConstantQuals);
WRITE_BOOL_FIELD(hasRecursion);
......
......@@ -352,8 +352,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
* Check to see if any subqueries in the jointree can be merged into this
* query.
*/
parse->jointree = (FromExpr *)
pull_up_subqueries(root, (Node *) parse->jointree);
pull_up_subqueries(root);
/*
* If this is a simple UNION ALL query, flatten it into an appendrel. We
......
This diff is collapsed.
......@@ -244,6 +244,7 @@ typedef struct PlannerInfo
* inheritance child rel */
bool hasJoinRTEs; /* true if any RTEs are RTE_JOIN kind */
bool hasLateralRTEs; /* true if any RTEs are marked LATERAL */
bool hasDeletedRTEs; /* true if any RTE was deleted from jointree */
bool hasHavingQual; /* true if havingQual was non-null */
bool hasPseudoConstantQuals; /* true if any RestrictInfo has
* pseudoconstant = true */
......
......@@ -23,7 +23,7 @@
*/
extern void pull_up_sublinks(PlannerInfo *root);
extern void inline_set_returning_functions(PlannerInfo *root);
extern Node *pull_up_subqueries(PlannerInfo *root, Node *jtnode);
extern void pull_up_subqueries(PlannerInfo *root);
extern void flatten_simple_union_all(PlannerInfo *root);
extern void reduce_outer_joins(PlannerInfo *root);
extern Relids get_relids_in_jointree(Node *jtnode, bool include_joins);
......
......@@ -3634,6 +3634,26 @@ explain (costs off)
select count(*) from tenk1 a,
tenk1 b join lateral (values(a.unique1)) ss(x) on b.unique2 = ss.x;
QUERY PLAN
------------------------------------------------------------
Aggregate
-> Merge Join
Merge Cond: (a.unique1 = b.unique2)
-> Index Only Scan using tenk1_unique1 on tenk1 a
-> Index Only Scan using tenk1_unique2 on tenk1 b
(5 rows)
select count(*) from tenk1 a,
tenk1 b join lateral (values(a.unique1)) ss(x) on b.unique2 = ss.x;
count
-------
10000
(1 row)
-- lateral with VALUES, no flattening possible
explain (costs off)
select count(*) from tenk1 a,
tenk1 b join lateral (values(a.unique1),(-1)) ss(x) on b.unique2 = ss.x;
QUERY PLAN
------------------------------------------------------------------
Aggregate
-> Hash Join
......@@ -3646,7 +3666,7 @@ explain (costs off)
(8 rows)
select count(*) from tenk1 a,
tenk1 b join lateral (values(a.unique1)) ss(x) on b.unique2 = ss.x;
tenk1 b join lateral (values(a.unique1),(-1)) ss(x) on b.unique2 = ss.x;
count
-------
10000
......@@ -4214,7 +4234,7 @@ select * from
cross join
lateral (select q1, coalesce(ss1.x,q2) as y from int8_tbl d) ss2
) on c.q2 = ss2.q1,
lateral (select ss2.y) ss3;
lateral (select ss2.y offset 0) ss3;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop
......@@ -4296,9 +4316,9 @@ select c.*,a.*,ss1.q1,ss2.q1,ss3.* from
-- check processing of postponed quals (bug #9041)
explain (verbose, costs off)
select * from
(select 1 as x) x cross join (select 2 as y) y
(select 1 as x offset 0) x cross join (select 2 as y offset 0) y
left join lateral (
select * from (select 3 as z) z where z.z = x.x
select * from (select 3 as z offset 0) z where z.z = x.x
) zz on zz.z = y.y;
QUERY PLAN
----------------------------------------------
......
......@@ -2034,7 +2034,7 @@ select x from int8_tbl, extractq2(int8_tbl) f(x);
(5 rows)
create function extractq2_2(t int8_tbl) returns table(ret1 int8) as $$
select extractq2(t)
select extractq2(t) offset 0
$$ language sql immutable;
explain (verbose, costs off)
select x from int8_tbl, extractq2_2(int8_tbl) f(x);
......@@ -2058,3 +2058,25 @@ select x from int8_tbl, extractq2_2(int8_tbl) f(x);
-4567890123456789
(5 rows)
-- without the "offset 0", this function gets optimized quite differently
create function extractq2_2_opt(t int8_tbl) returns table(ret1 int8) as $$
select extractq2(t)
$$ language sql immutable;
explain (verbose, costs off)
select x from int8_tbl, extractq2_2_opt(int8_tbl) f(x);
QUERY PLAN
-----------------------------
Seq Scan on public.int8_tbl
Output: int8_tbl.q2
(2 rows)
select x from int8_tbl, extractq2_2_opt(int8_tbl) f(x);
x
-------------------
456
4567890123456789
123
4567890123456789
-4567890123456789
(5 rows)
......@@ -1137,6 +1137,13 @@ explain (costs off)
select count(*) from tenk1 a,
tenk1 b join lateral (values(a.unique1)) ss(x) on b.unique2 = ss.x;
-- lateral with VALUES, no flattening possible
explain (costs off)
select count(*) from tenk1 a,
tenk1 b join lateral (values(a.unique1),(-1)) ss(x) on b.unique2 = ss.x;
select count(*) from tenk1 a,
tenk1 b join lateral (values(a.unique1),(-1)) ss(x) on b.unique2 = ss.x;
-- lateral injecting a strange outer join condition
explain (costs off)
select * from int8_tbl a,
......@@ -1247,7 +1254,7 @@ select * from
cross join
lateral (select q1, coalesce(ss1.x,q2) as y from int8_tbl d) ss2
) on c.q2 = ss2.q1,
lateral (select ss2.y) ss3;
lateral (select ss2.y offset 0) ss3;
-- case that breaks the old ph_may_need optimization
explain (verbose, costs off)
......@@ -1265,9 +1272,9 @@ select c.*,a.*,ss1.q1,ss2.q1,ss3.* from
-- check processing of postponed quals (bug #9041)
explain (verbose, costs off)
select * from
(select 1 as x) x cross join (select 2 as y) y
(select 1 as x offset 0) x cross join (select 2 as y offset 0) y
left join lateral (
select * from (select 3 as z) z where z.z = x.x
select * from (select 3 as z offset 0) z where z.z = x.x
) zz on zz.z = y.y;
-- test some error cases where LATERAL should have been used but wasn't
......
......@@ -621,10 +621,21 @@ select x from int8_tbl, extractq2(int8_tbl) f(x);
select x from int8_tbl, extractq2(int8_tbl) f(x);
create function extractq2_2(t int8_tbl) returns table(ret1 int8) as $$
select extractq2(t)
select extractq2(t) offset 0
$$ language sql immutable;
explain (verbose, costs off)
select x from int8_tbl, extractq2_2(int8_tbl) f(x);
select x from int8_tbl, extractq2_2(int8_tbl) f(x);
-- without the "offset 0", this function gets optimized quite differently
create function extractq2_2_opt(t int8_tbl) returns table(ret1 int8) as $$
select extractq2(t)
$$ language sql immutable;
explain (verbose, costs off)
select x from int8_tbl, extractq2_2_opt(int8_tbl) f(x);
select x from int8_tbl, extractq2_2_opt(int8_tbl) f(x);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment