int parentRTindex = rti;
List *live_childrels = NIL;
List *subpaths = NIL;
+ bool subpaths_valid = true;
List *all_child_pathkeys = NIL;
List *all_child_outers = NIL;
ListCell *l;
if (IS_DUMMY_REL(childrel))
continue;
- /* XXX need to figure out what to do for LATERAL */
- if (childrel->cheapest_total_path == NULL)
- elog(ERROR, "LATERAL within an append relation is not supported yet");
+ /*
+ * Child is live, so add it to the live_childrels list for use below.
+ */
+ live_childrels = lappend(live_childrels, childrel);
/*
- * Child is live, so add its cheapest access path to the Append path
- * we are constructing for the parent.
+ * If child has an unparameterized cheapest-total path, add that to
+ * the unparameterized Append path we are constructing for the parent.
+ * If not, there's no workable unparameterized path.
*/
- subpaths = accumulate_append_subpath(subpaths,
+ if (childrel->cheapest_total_path)
+ subpaths = accumulate_append_subpath(subpaths,
childrel->cheapest_total_path);
-
- /* Remember which childrels are live, for logic below */
- live_childrels = lappend(live_childrels, childrel);
+ else
+ subpaths_valid = false;
/*
* Collect lists of all the available path orderings and
}
/*
- * Next, build an unordered, unparameterized Append path for the rel.
- * (Note: this is correct even if we have zero or one live subpath due to
- * constraint exclusion.)
+ * If we found unparameterized paths for all children, build an unordered,
+ * unparameterized Append path for the rel. (Note: this is correct even
+ * if we have zero or one live subpath due to constraint exclusion.)
*/
- add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
+ if (subpaths_valid)
+ add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
/*
- * Build unparameterized MergeAppend paths based on the collected list of
- * child pathkeys.
+ * Also build unparameterized MergeAppend paths based on the collected
+ * list of child pathkeys.
*/
- generate_mergeappend_paths(root, rel, live_childrels, all_child_pathkeys);
+ if (subpaths_valid)
+ generate_mergeappend_paths(root, rel, live_childrels,
+ all_child_pathkeys);
/*
* Build Append paths for each parameterization seen among the child rels.
foreach(l, all_child_outers)
{
Relids required_outer = (Relids) lfirst(l);
- bool ok = true;
ListCell *lcr;
/* Select the child paths for an Append with this parameterization */
subpaths = NIL;
+ subpaths_valid = true;
foreach(lcr, live_childrels)
{
RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr);
required_outer, 1.0);
if (cheapest_total == NULL)
{
- ok = false;
+ subpaths_valid = false;
break;
}
}
subpaths = accumulate_append_subpath(subpaths, cheapest_total);
}
- if (ok)
+ if (subpaths_valid)
add_path(rel, (Path *)
create_append_path(rel, subpaths, required_outer));
}
*/
if (cheapest_startup == NULL || cheapest_total == NULL)
{
- /* XXX need to figure out what to do for LATERAL */
- if (childrel->cheapest_total_path == NULL)
- elog(ERROR, "LATERAL within an append relation is not supported yet");
-
cheapest_startup = cheapest_total =
childrel->cheapest_total_path;
+ /* Assert we do have an unparameterized path for this child */
Assert(cheapest_total != NULL);
+ Assert(cheapest_total->param_info == NULL);
}
/*
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
Query *subquery = rte->subquery;
- int rtoffset;
+ int rtoffset = list_length(root->parse->rtable);
List *rtable;
/*
- * Append child RTEs to parent rtable.
- *
+ * Make a modifiable copy of the subquery's rtable, so we can adjust
+ * upper-level Vars in it. There are no such Vars in the setOperations
+ * tree proper, so fixing the rtable should be sufficient.
+ */
+ rtable = copyObject(subquery->rtable);
+
+ /*
* Upper-level vars in subquery are now one level closer to their parent
* than before. We don't have to worry about offsetting varnos, though,
- * because any such vars must refer to stuff above the level of the query
- * we are pulling into.
+ * because the UNION leaf queries can't cross-reference each other.
*/
- rtoffset = list_length(root->parse->rtable);
- rtable = copyObject(subquery->rtable);
IncrementVarSublevelsUp_rtable(rtable, -1, 1);
+
+ /*
+ * If the UNION ALL subquery had a LATERAL marker, propagate that to all
+ * its children. The individual children might or might not contain any
+ * actual lateral cross-references, but we have to mark the pulled-up
+ * child RTEs so that later planner stages will check for such.
+ */
+ if (rte->lateral)
+ {
+ ListCell *rt;
+
+ foreach(rt, rtable)
+ {
+ RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(rt);
+
+ Assert(child_rte->rtekind == RTE_SUBQUERY);
+ child_rte->lateral = true;
+ }
+ }
+
+ /*
+ * Append child RTEs to parent rtable.
+ */
root->parse->rtable = list_concat(root->parse->rtable, rtable);
/*
-> Function Scan on generate_series g
(4 rows)
+-- lateral with UNION ALL subselect
+explain (costs off)
+ select * from generate_series(100,200) g,
+ lateral (select * from int8_tbl a where g = q1 union all
+ select * from int8_tbl b where g = q2) ss;
+ QUERY PLAN
+------------------------------------------
+ Nested Loop
+ -> Function Scan on generate_series g
+ -> Append
+ -> Seq Scan on int8_tbl a
+ Filter: (g.g = q1)
+ -> Seq Scan on int8_tbl b
+ Filter: (g.g = q2)
+(7 rows)
+
+select * from generate_series(100,200) g,
+ lateral (select * from int8_tbl a where g = q1 union all
+ select * from int8_tbl b where g = q2) ss;
+ g | q1 | q2
+-----+------------------+------------------
+ 123 | 123 | 456
+ 123 | 123 | 4567890123456789
+ 123 | 4567890123456789 | 123
+(3 rows)
+
-- test some error cases where LATERAL should have been used but wasn't
select f1,g from int4_tbl a, generate_series(0, f1) g;
ERROR: column "f1" does not exist
explain (costs off)
select count(*) from tenk1 a cross join lateral generate_series(1,two) g;
+-- lateral with UNION ALL subselect
+explain (costs off)
+ select * from generate_series(100,200) g,
+ lateral (select * from int8_tbl a where g = q1 union all
+ select * from int8_tbl b where g = q2) ss;
+select * from generate_series(100,200) g,
+ lateral (select * from int8_tbl a where g = q1 union all
+ select * from int8_tbl b where g = q2) ss;
+
-- test some error cases where LATERAL should have been used but wasn't
select f1,g from int4_tbl a, generate_series(0, f1) g;
select f1,g from int4_tbl a, generate_series(0, a.f1) g;