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

Commit f502849

Browse files
committed
Fix generation of EC join conditions at the wrong plan level.
get_baserel_parampathinfo previously assumed without checking that the results of generate_join_implied_equalities "necessarily satisfy join_clause_is_movable_into". This turns out to be wrong in the presence of outer joins, because the generated clauses could include Vars that mustn't be evaluated below a relevant outer join. That led to applying clauses at the wrong plan level and possibly getting incorrect query results. We must check each clause's nullable_relids, and really the right thing to do is test join_clause_is_movable_into. However, trying to fix it that way exposes an oversight in equivclass.c: it wasn't careful about marking join clauses for appendrel children with the correct clause_relids. That caused the modified get_baserel_parampathinfo code to reject some clauses it still needs to accept. (See parallel commit for HEAD/v16 for more commentary about that.) Per bug #18429 from Benoît Ryder. This misbehavior existed for a long time before commit 2489d76, so patch v12-v15 this way. Discussion: https://postgr.es/m/18429-8982d4a348cc86c6@postgresql.org
1 parent 4b0e5d6 commit f502849

File tree

4 files changed

+83
-7
lines changed

4 files changed

+83
-7
lines changed

src/backend/optimizer/path/equivclass.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,21 @@ create_join_clause(PlannerInfo *root,
14651465
rightem->em_nullable_relids),
14661466
ec->ec_min_security);
14671467

1468+
/*
1469+
* If either EM is a child, force the clause's clause_relids to include
1470+
* the relid(s) of the child rel. In normal cases it would already, but
1471+
* not if we are considering appendrel child relations with pseudoconstant
1472+
* translated variables (i.e., UNION ALL sub-selects with constant output
1473+
* items). We must do this so that join_clause_is_movable_into() will
1474+
* think that the clause should be evaluated at the correct place.
1475+
*/
1476+
if (leftem->em_is_child)
1477+
rinfo->clause_relids = bms_add_members(rinfo->clause_relids,
1478+
leftem->em_relids);
1479+
if (rightem->em_is_child)
1480+
rinfo->clause_relids = bms_add_members(rinfo->clause_relids,
1481+
rightem->em_relids);
1482+
14681483
/* Mark the clause as redundant, or not */
14691484
rinfo->parent_ec = parent_ec;
14701485

src/backend/optimizer/util/relnode.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,7 @@ get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,
12641264
ParamPathInfo *ppi;
12651265
Relids joinrelids;
12661266
List *pclauses;
1267+
List *eqclauses;
12671268
double rows;
12681269
ListCell *lc;
12691270

@@ -1297,14 +1298,24 @@ get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,
12971298
}
12981299

12991300
/*
1300-
* Add in joinclauses generated by EquivalenceClasses, too. (These
1301-
* necessarily satisfy join_clause_is_movable_into.)
1301+
* Add in joinclauses generated by EquivalenceClasses, too. In principle
1302+
* these should always satisfy join_clause_is_movable_into; but if we are
1303+
* below an outer join the clauses might contain Vars that should only be
1304+
* evaluated above the join, so we have to check.
13021305
*/
1303-
pclauses = list_concat(pclauses,
1304-
generate_join_implied_equalities(root,
1305-
joinrelids,
1306-
required_outer,
1307-
baserel));
1306+
eqclauses = generate_join_implied_equalities(root,
1307+
joinrelids,
1308+
required_outer,
1309+
baserel);
1310+
foreach(lc, eqclauses)
1311+
{
1312+
RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1313+
1314+
if (join_clause_is_movable_into(rinfo,
1315+
baserel->relids,
1316+
joinrelids))
1317+
pclauses = lappend(pclauses, rinfo);
1318+
}
13081319

13091320
/* Estimate the number of rows returned by the parameterized scan */
13101321
rows = get_parameterized_baserel_size(root, baserel, pclauses);

src/test/regress/expected/join.out

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5672,6 +5672,37 @@ select * from
56725672
3 | 3
56735673
(6 rows)
56745674

5675+
-- check for generation of join EC conditions at wrong level (bug #18429)
5676+
explain (costs off)
5677+
select * from (
5678+
select arrayd.ad, coalesce(c.hundred, 0) as h
5679+
from unnest(array[1]) as arrayd(ad)
5680+
left join lateral (
5681+
select hundred from tenk1 where unique2 = arrayd.ad
5682+
) c on true
5683+
) c2
5684+
where c2.h * c2.ad = c2.h * (c2.ad + 1);
5685+
QUERY PLAN
5686+
-------------------------------------------------------------------------------------------------------
5687+
Nested Loop Left Join
5688+
Filter: ((COALESCE(tenk1.hundred, 0) * arrayd.ad) = (COALESCE(tenk1.hundred, 0) * (arrayd.ad + 1)))
5689+
-> Function Scan on unnest arrayd
5690+
-> Index Scan using tenk1_unique2 on tenk1
5691+
Index Cond: (unique2 = arrayd.ad)
5692+
(5 rows)
5693+
5694+
select * from (
5695+
select arrayd.ad, coalesce(c.hundred, 0) as h
5696+
from unnest(array[1]) as arrayd(ad)
5697+
left join lateral (
5698+
select hundred from tenk1 where unique2 = arrayd.ad
5699+
) c on true
5700+
) c2
5701+
where c2.h * c2.ad = c2.h * (c2.ad + 1);
5702+
ad | h
5703+
----+---
5704+
(0 rows)
5705+
56755706
-- check the number of columns specified
56765707
SELECT * FROM (int8_tbl i cross join int4_tbl j) ss(a,b,c,d);
56775708
ERROR: join expression "ss" has 3 columns available but 4 columns specified

src/test/regress/sql/join.sql

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,6 +1920,25 @@ select * from
19201920
(select q1.v)
19211921
) as q2;
19221922

1923+
-- check for generation of join EC conditions at wrong level (bug #18429)
1924+
explain (costs off)
1925+
select * from (
1926+
select arrayd.ad, coalesce(c.hundred, 0) as h
1927+
from unnest(array[1]) as arrayd(ad)
1928+
left join lateral (
1929+
select hundred from tenk1 where unique2 = arrayd.ad
1930+
) c on true
1931+
) c2
1932+
where c2.h * c2.ad = c2.h * (c2.ad + 1);
1933+
select * from (
1934+
select arrayd.ad, coalesce(c.hundred, 0) as h
1935+
from unnest(array[1]) as arrayd(ad)
1936+
left join lateral (
1937+
select hundred from tenk1 where unique2 = arrayd.ad
1938+
) c on true
1939+
) c2
1940+
where c2.h * c2.ad = c2.h * (c2.ad + 1);
1941+
19231942
-- check the number of columns specified
19241943
SELECT * FROM (int8_tbl i cross join int4_tbl j) ss(a,b,c,d);
19251944

0 commit comments

Comments
 (0)