postgres.git / summary / log / commit / refs

commit    8a2228b2f5dc7a52590cef97bf496fcf143db6de
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Tue Jan 23 21:50:35 2018 +0000

    Teach reparameterize_path() to handle AppendPaths.
    
    If we're inside a lateral subquery, there may be no unparameterized paths
    for a particular child relation of an appendrel, in which case we *must*
    be able to create similarly-parameterized paths for each other child
    relation, else the planner will fail with "could not devise a query plan
    for the given query".  This means that there are situations where we'd
    better be able to reparameterize at least one path for each child.
    
    This calls into question the assumption in reparameterize_path() that
    it can just punt if it feels like it.  However, the only case that is
    known broken right now is where the child is itself an appendrel so that
    all its paths are AppendPaths.  (I think possibly I disregarded that in
    the original coding on the theory that nested appendrels would get folded
    together --- but that only happens *after* reparameterize_path(), so it's
    not excused from handling a child AppendPath.)  Given that this code's been
    like this since 9.3 when LATERAL was introduced, it seems likely we'd have
    heard of other cases by now if there were a larger problem.
    
    Per report from Elvis Pranskevichus.  Back-patch to 9.3.
    
    Discussion: https://postgr.es/m/5981018.zdth1YWmNy@hammer.magicstack.net


src/backend/optimizer/util/pathnode.c | 22 ++++++++++++++++++++++ src/test/regress/expected/join.out | 19 +++++++++++++++++++ src/test/regress/sql/join.sql | 10 ++++++++++ 3 files changed, 51 insertions(+) diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 972e3b0810a..e74aa094c02 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -1809,6 +1809,28 @@ reparameterize_path(PlannerInfo *root, Path *path, case T_SubqueryScan: return create_subqueryscan_path(root, rel, path->pathkeys, required_outer); + case T_Append: + { + AppendPath *apath = (AppendPath *) path; + List *childpaths = NIL; + ListCell *lc; + + /* Reparameterize the children */ + foreach(lc, apath->subpaths) + { + Path *spath = (Path *) lfirst(lc); + + spath = reparameterize_path(root, spath, + required_outer, + loop_count); + if (spath == NULL) + return NULL; + childpaths = lappend(childpaths, spath); + } + return (Path *) + create_append_path(rel, childpaths, + required_outer); + } default: break; } diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index d71da0b8137..be6e5468648 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -5153,6 +5153,25 @@ select * from Output: 3 (11 rows) +-- check handling of nested appendrels inside LATERAL +select * from + ((select 2 as v) union all (select 3 as v)) as q1 + cross join lateral + ((select * from + ((select 4 as v) union all (select 5 as v)) as q3) + union all + (select q1.v) + ) as q2; + v | v +---+--- + 2 | 4 + 2 | 5 + 2 | 2 + 3 | 4 + 3 | 5 + 3 | 3 +(6 rows) + -- check we don't try to do a unique-ified semijoin with LATERAL explain (verbose, costs off) select * from diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index fd05f5c8a32..b29aecba38d 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -1664,6 +1664,16 @@ select * from select * from (select 3 as z offset 0) z where z.z = x.x ) zz on zz.z = y.y; +-- check handling of nested appendrels inside LATERAL +select * from + ((select 2 as v) union all (select 3 as v)) as q1 + cross join lateral + ((select * from + ((select 4 as v) union all (select 5 as v)) as q3) + union all + (select q1.v) + ) as q2; + -- check we don't try to do a unique-ified semijoin with LATERAL explain (verbose, costs off) select * from [parent: 29aecb94a3d9]