Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e76af54

Browse files
committed
Fix some issues with LATERAL(SELECT UNION ALL SELECT).
The LATERAL marking has to be propagated down to the UNION leaf queries when we pull them up. Also, fix the formerly stubbed-off set_append_rel_pathlist(). It does already have enough smarts to cope with making a parameterized Append path at need; it just has to not assume that there *must* be an unparameterized path.
1 parent 83af58f commit e76af54

File tree

4 files changed

+94
-30
lines changed

4 files changed

+94
-30
lines changed

src/backend/optimizer/path/allpaths.c

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
661661
int parentRTindex = rti;
662662
List *live_childrels = NIL;
663663
List *subpaths = NIL;
664+
bool subpaths_valid = true;
664665
List *all_child_pathkeys = NIL;
665666
List *all_child_outers = NIL;
666667
ListCell *l;
@@ -699,19 +700,21 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
699700
if (IS_DUMMY_REL(childrel))
700701
continue;
701702

702-
/* XXX need to figure out what to do for LATERAL */
703-
if (childrel->cheapest_total_path == NULL)
704-
elog(ERROR, "LATERAL within an append relation is not supported yet");
703+
/*
704+
* Child is live, so add it to the live_childrels list for use below.
705+
*/
706+
live_childrels = lappend(live_childrels, childrel);
705707

706708
/*
707-
* Child is live, so add its cheapest access path to the Append path
708-
* we are constructing for the parent.
709+
* If child has an unparameterized cheapest-total path, add that to
710+
* the unparameterized Append path we are constructing for the parent.
711+
* If not, there's no workable unparameterized path.
709712
*/
710-
subpaths = accumulate_append_subpath(subpaths,
713+
if (childrel->cheapest_total_path)
714+
subpaths = accumulate_append_subpath(subpaths,
711715
childrel->cheapest_total_path);
712-
713-
/* Remember which childrels are live, for logic below */
714-
live_childrels = lappend(live_childrels, childrel);
716+
else
717+
subpaths_valid = false;
715718

716719
/*
717720
* Collect lists of all the available path orderings and
@@ -779,17 +782,20 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
779782
}
780783

781784
/*
782-
* Next, build an unordered, unparameterized Append path for the rel.
783-
* (Note: this is correct even if we have zero or one live subpath due to
784-
* constraint exclusion.)
785+
* If we found unparameterized paths for all children, build an unordered,
786+
* unparameterized Append path for the rel. (Note: this is correct even
787+
* if we have zero or one live subpath due to constraint exclusion.)
785788
*/
786-
add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
789+
if (subpaths_valid)
790+
add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
787791

788792
/*
789-
* Build unparameterized MergeAppend paths based on the collected list of
790-
* child pathkeys.
793+
* Also build unparameterized MergeAppend paths based on the collected
794+
* list of child pathkeys.
791795
*/
792-
generate_mergeappend_paths(root, rel, live_childrels, all_child_pathkeys);
796+
if (subpaths_valid)
797+
generate_mergeappend_paths(root, rel, live_childrels,
798+
all_child_pathkeys);
793799

794800
/*
795801
* Build Append paths for each parameterization seen among the child rels.
@@ -807,11 +813,11 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
807813
foreach(l, all_child_outers)
808814
{
809815
Relids required_outer = (Relids) lfirst(l);
810-
bool ok = true;
811816
ListCell *lcr;
812817

813818
/* Select the child paths for an Append with this parameterization */
814819
subpaths = NIL;
820+
subpaths_valid = true;
815821
foreach(lcr, live_childrels)
816822
{
817823
RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr);
@@ -831,15 +837,15 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
831837
required_outer, 1.0);
832838
if (cheapest_total == NULL)
833839
{
834-
ok = false;
840+
subpaths_valid = false;
835841
break;
836842
}
837843
}
838844

839845
subpaths = accumulate_append_subpath(subpaths, cheapest_total);
840846
}
841847

842-
if (ok)
848+
if (subpaths_valid)
843849
add_path(rel, (Path *)
844850
create_append_path(rel, subpaths, required_outer));
845851
}
@@ -911,13 +917,11 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
911917
*/
912918
if (cheapest_startup == NULL || cheapest_total == NULL)
913919
{
914-
/* XXX need to figure out what to do for LATERAL */
915-
if (childrel->cheapest_total_path == NULL)
916-
elog(ERROR, "LATERAL within an append relation is not supported yet");
917-
918920
cheapest_startup = cheapest_total =
919921
childrel->cheapest_total_path;
922+
/* Assert we do have an unparameterized path for this child */
920923
Assert(cheapest_total != NULL);
924+
Assert(cheapest_total->param_info == NULL);
921925
}
922926

923927
/*

src/backend/optimizer/prep/prepjointree.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -995,20 +995,45 @@ pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte)
995995
{
996996
int varno = ((RangeTblRef *) jtnode)->rtindex;
997997
Query *subquery = rte->subquery;
998-
int rtoffset;
998+
int rtoffset = list_length(root->parse->rtable);
999999
List *rtable;
10001000

10011001
/*
1002-
* Append child RTEs to parent rtable.
1003-
*
1002+
* Make a modifiable copy of the subquery's rtable, so we can adjust
1003+
* upper-level Vars in it. There are no such Vars in the setOperations
1004+
* tree proper, so fixing the rtable should be sufficient.
1005+
*/
1006+
rtable = copyObject(subquery->rtable);
1007+
1008+
/*
10041009
* Upper-level vars in subquery are now one level closer to their parent
10051010
* than before. We don't have to worry about offsetting varnos, though,
1006-
* because any such vars must refer to stuff above the level of the query
1007-
* we are pulling into.
1011+
* because the UNION leaf queries can't cross-reference each other.
10081012
*/
1009-
rtoffset = list_length(root->parse->rtable);
1010-
rtable = copyObject(subquery->rtable);
10111013
IncrementVarSublevelsUp_rtable(rtable, -1, 1);
1014+
1015+
/*
1016+
* If the UNION ALL subquery had a LATERAL marker, propagate that to all
1017+
* its children. The individual children might or might not contain any
1018+
* actual lateral cross-references, but we have to mark the pulled-up
1019+
* child RTEs so that later planner stages will check for such.
1020+
*/
1021+
if (rte->lateral)
1022+
{
1023+
ListCell *rt;
1024+
1025+
foreach(rt, rtable)
1026+
{
1027+
RangeTblEntry *child_rte = (RangeTblEntry *) lfirst(rt);
1028+
1029+
Assert(child_rte->rtekind == RTE_SUBQUERY);
1030+
child_rte->lateral = true;
1031+
}
1032+
}
1033+
1034+
/*
1035+
* Append child RTEs to parent rtable.
1036+
*/
10121037
root->parse->rtable = list_concat(root->parse->rtable, rtable);
10131038

10141039
/*

src/test/regress/expected/join.out

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3109,6 +3109,32 @@ explain (costs off)
31093109
-> Function Scan on generate_series g
31103110
(4 rows)
31113111

3112+
-- lateral with UNION ALL subselect
3113+
explain (costs off)
3114+
select * from generate_series(100,200) g,
3115+
lateral (select * from int8_tbl a where g = q1 union all
3116+
select * from int8_tbl b where g = q2) ss;
3117+
QUERY PLAN
3118+
------------------------------------------
3119+
Nested Loop
3120+
-> Function Scan on generate_series g
3121+
-> Append
3122+
-> Seq Scan on int8_tbl a
3123+
Filter: (g.g = q1)
3124+
-> Seq Scan on int8_tbl b
3125+
Filter: (g.g = q2)
3126+
(7 rows)
3127+
3128+
select * from generate_series(100,200) g,
3129+
lateral (select * from int8_tbl a where g = q1 union all
3130+
select * from int8_tbl b where g = q2) ss;
3131+
g | q1 | q2
3132+
-----+------------------+------------------
3133+
123 | 123 | 456
3134+
123 | 123 | 4567890123456789
3135+
123 | 4567890123456789 | 123
3136+
(3 rows)
3137+
31123138
-- test some error cases where LATERAL should have been used but wasn't
31133139
select f1,g from int4_tbl a, generate_series(0, f1) g;
31143140
ERROR: column "f1" does not exist

src/test/regress/sql/join.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,15 @@ explain (costs off)
876876
explain (costs off)
877877
select count(*) from tenk1 a cross join lateral generate_series(1,two) g;
878878

879+
-- lateral with UNION ALL subselect
880+
explain (costs off)
881+
select * from generate_series(100,200) g,
882+
lateral (select * from int8_tbl a where g = q1 union all
883+
select * from int8_tbl b where g = q2) ss;
884+
select * from generate_series(100,200) g,
885+
lateral (select * from int8_tbl a where g = q1 union all
886+
select * from int8_tbl b where g = q2) ss;
887+
879888
-- test some error cases where LATERAL should have been used but wasn't
880889
select f1,g from int4_tbl a, generate_series(0, f1) g;
881890
select f1,g from int4_tbl a, generate_series(0, a.f1) g;

0 commit comments

Comments
 (0)