Skip to content

Commit 8a2228b

Browse files
committed
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
1 parent 29aecb9 commit 8a2228b

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

src/backend/optimizer/util/pathnode.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,28 @@ reparameterize_path(PlannerInfo *root, Path *path,
18091809
case T_SubqueryScan:
18101810
return create_subqueryscan_path(root, rel, path->pathkeys,
18111811
required_outer);
1812+
case T_Append:
1813+
{
1814+
AppendPath *apath = (AppendPath *) path;
1815+
List *childpaths = NIL;
1816+
ListCell *lc;
1817+
1818+
/* Reparameterize the children */
1819+
foreach(lc, apath->subpaths)
1820+
{
1821+
Path *spath = (Path *) lfirst(lc);
1822+
1823+
spath = reparameterize_path(root, spath,
1824+
required_outer,
1825+
loop_count);
1826+
if (spath == NULL)
1827+
return NULL;
1828+
childpaths = lappend(childpaths, spath);
1829+
}
1830+
return (Path *)
1831+
create_append_path(rel, childpaths,
1832+
required_outer);
1833+
}
18121834
default:
18131835
break;
18141836
}

src/test/regress/expected/join.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5153,6 +5153,25 @@ select * from
51535153
Output: 3
51545154
(11 rows)
51555155

5156+
-- check handling of nested appendrels inside LATERAL
5157+
select * from
5158+
((select 2 as v) union all (select 3 as v)) as q1
5159+
cross join lateral
5160+
((select * from
5161+
((select 4 as v) union all (select 5 as v)) as q3)
5162+
union all
5163+
(select q1.v)
5164+
) as q2;
5165+
v | v
5166+
---+---
5167+
2 | 4
5168+
2 | 5
5169+
2 | 2
5170+
3 | 4
5171+
3 | 5
5172+
3 | 3
5173+
(6 rows)
5174+
51565175
-- check we don't try to do a unique-ified semijoin with LATERAL
51575176
explain (verbose, costs off)
51585177
select * from

src/test/regress/sql/join.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,16 @@ select * from
16641664
select * from (select 3 as z offset 0) z where z.z = x.x
16651665
) zz on zz.z = y.y;
16661666

1667+
-- check handling of nested appendrels inside LATERAL
1668+
select * from
1669+
((select 2 as v) union all (select 3 as v)) as q1
1670+
cross join lateral
1671+
((select * from
1672+
((select 4 as v) union all (select 5 as v)) as q3)
1673+
union all
1674+
(select q1.v)
1675+
) as q2;
1676+
16671677
-- check we don't try to do a unique-ified semijoin with LATERAL
16681678
explain (verbose, costs off)
16691679
select * from

0 commit comments

Comments
 (0)