Teach reparameterize_path() to handle AppendPaths.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Jan 2018 21:50:34 +0000 (16:50 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Jan 2018 21:50:34 +0000 (16:50 -0500)
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
src/test/regress/expected/join.out
src/test/regress/sql/join.sql

index 91295ebca498fb29232e684caba34aea8c6c6131..fe3b4582d4216e5b03977a7d7c7c1b5b3f8f6415 100644 (file)
@@ -3540,6 +3540,40 @@ reparameterize_path(PlannerInfo *root, Path *path,
                                                         spath->path.pathkeys,
                                                         required_outer);
            }
+       case T_Append:
+           {
+               AppendPath *apath = (AppendPath *) path;
+               List       *childpaths = NIL;
+               List       *partialpaths = NIL;
+               int         i;
+               ListCell   *lc;
+
+               /* Reparameterize the children */
+               i = 0;
+               foreach(lc, apath->subpaths)
+               {
+                   Path       *spath = (Path *) lfirst(lc);
+
+                   spath = reparameterize_path(root, spath,
+                                               required_outer,
+                                               loop_count);
+                   if (spath == NULL)
+                       return NULL;
+                   /* We have to re-split the regular and partial paths */
+                   if (i < apath->first_partial_path)
+                       childpaths = lappend(childpaths, spath);
+                   else
+                       partialpaths = lappend(partialpaths, spath);
+                   i++;
+               }
+               return (Path *)
+                   create_append_path(rel, childpaths, partialpaths,
+                                      required_outer,
+                                      apath->path.parallel_workers,
+                                      apath->path.parallel_aware,
+                                      apath->partitioned_rels,
+                                      -1);
+           }
        default:
            break;
    }
index 02e7d56e550057296665e6d93841e08bc75b6ad8..c50a206efb8a25c20263bab3dd759e32a414a6d2 100644 (file)
@@ -5188,6 +5188,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
index dd62c38c15ef8111fd16d6cb7475b0821d793ecb..fc84237ce92ebd11c505eb3040f56904b246e812 100644 (file)
@@ -1682,6 +1682,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