Skip to content

Commit 8a4fdce

Browse files
committed
Fix thinko in new logic about pushing down non-nullability constraints:
constraints appearing in outer-join qualification clauses are restricted as to when and where they can be pushed down. Add regression test to catch future errors in this area.
1 parent ec8f0e8 commit 8a4fdce

File tree

3 files changed

+192
-8
lines changed

3 files changed

+192
-8
lines changed

src/backend/optimizer/prep/prepjointree.c

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*
1717
*
1818
* IDENTIFICATION
19-
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.5 2003/02/09 23:57:19 tgl Exp $
19+
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.6 2003/02/10 17:08:50 tgl Exp $
2020
*
2121
*-------------------------------------------------------------------------
2222
*/
@@ -694,23 +694,45 @@ reduce_outer_joins_pass2(Node *jtnode,
694694
/* Only recurse if there's more to do below here */
695695
if (left_state->contains_outer || right_state->contains_outer)
696696
{
697+
Relids local_nonnullable;
697698
Relids pass_nonnullable;
698699

699700
/*
700-
* Scan join quals to see if we can add any nonnullability
701-
* constraints. (Okay to do this even if join is still outer.)
701+
* If this join is (now) inner, we can add any nonnullability
702+
* constraints its quals provide to those we got from above.
703+
* But if it is outer, we can only pass down the local constraints
704+
* into the nullable side, because an outer join never eliminates
705+
* any rows from its non-nullable side. If it's a FULL join then
706+
* it doesn't eliminate anything from either side.
702707
*/
703-
pass_nonnullable = find_nonnullable_rels(j->quals, true);
704-
pass_nonnullable = bms_add_members(pass_nonnullable,
705-
nonnullable_rels);
706-
/* And recurse as needed */
708+
if (jointype != JOIN_FULL)
709+
{
710+
local_nonnullable = find_nonnullable_rels(j->quals, true);
711+
local_nonnullable = bms_add_members(local_nonnullable,
712+
nonnullable_rels);
713+
}
714+
else
715+
local_nonnullable = NULL; /* no use in calculating it */
716+
707717
if (left_state->contains_outer)
718+
{
719+
if (jointype == JOIN_INNER || jointype == JOIN_RIGHT)
720+
pass_nonnullable = local_nonnullable;
721+
else
722+
pass_nonnullable = nonnullable_rels;
708723
reduce_outer_joins_pass2(j->larg, left_state, parse,
709724
pass_nonnullable);
725+
}
710726
if (right_state->contains_outer)
727+
{
728+
if (jointype == JOIN_INNER || jointype == JOIN_LEFT)
729+
pass_nonnullable = local_nonnullable;
730+
else
731+
pass_nonnullable = nonnullable_rels;
711732
reduce_outer_joins_pass2(j->rarg, right_state, parse,
712733
pass_nonnullable);
713-
bms_free(pass_nonnullable);
734+
}
735+
bms_free(local_nonnullable);
714736
}
715737
}
716738
else

src/test/regress/expected/join.out

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2004,6 +2004,129 @@ NATURAL FULL JOIN
20042004
dd | | 42 | 2 |
20052005
(4 rows)
20062006

2007+
-- Test for propagation of nullability constraints into sub-joins
2008+
create temp table x (x1 int, x2 int);
2009+
insert into x values (1,11);
2010+
insert into x values (2,22);
2011+
insert into x values (3,null);
2012+
insert into x values (4,44);
2013+
insert into x values (5,null);
2014+
create temp table y (y1 int, y2 int);
2015+
insert into y values (1,111);
2016+
insert into y values (2,222);
2017+
insert into y values (3,333);
2018+
insert into y values (4,null);
2019+
select * from x;
2020+
x1 | x2
2021+
----+----
2022+
1 | 11
2023+
2 | 22
2024+
3 |
2025+
4 | 44
2026+
5 |
2027+
(5 rows)
2028+
2029+
select * from y;
2030+
y1 | y2
2031+
----+-----
2032+
1 | 111
2033+
2 | 222
2034+
3 | 333
2035+
4 |
2036+
(4 rows)
2037+
2038+
select * from x left join y on (x1 = y1 and x2 is not null);
2039+
x1 | x2 | y1 | y2
2040+
----+----+----+-----
2041+
1 | 11 | 1 | 111
2042+
2 | 22 | 2 | 222
2043+
3 | | |
2044+
4 | 44 | 4 |
2045+
5 | | |
2046+
(5 rows)
2047+
2048+
select * from x left join y on (x1 = y1 and y2 is not null);
2049+
x1 | x2 | y1 | y2
2050+
----+----+----+-----
2051+
1 | 11 | 1 | 111
2052+
2 | 22 | 2 | 222
2053+
3 | | 3 | 333
2054+
4 | 44 | |
2055+
5 | | |
2056+
(5 rows)
2057+
2058+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
2059+
on (x1 = xx1);
2060+
x1 | x2 | y1 | y2 | xx1 | xx2
2061+
----+----+----+-----+-----+-----
2062+
1 | 11 | 1 | 111 | 1 | 11
2063+
2 | 22 | 2 | 222 | 2 | 22
2064+
3 | | 3 | 333 | 3 |
2065+
4 | 44 | 4 | | 4 | 44
2066+
5 | | | | 5 |
2067+
(5 rows)
2068+
2069+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
2070+
on (x1 = xx1 and x2 is not null);
2071+
x1 | x2 | y1 | y2 | xx1 | xx2
2072+
----+----+----+-----+-----+-----
2073+
1 | 11 | 1 | 111 | 1 | 11
2074+
2 | 22 | 2 | 222 | 2 | 22
2075+
3 | | 3 | 333 | |
2076+
4 | 44 | 4 | | 4 | 44
2077+
5 | | | | |
2078+
(5 rows)
2079+
2080+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
2081+
on (x1 = xx1 and y2 is not null);
2082+
x1 | x2 | y1 | y2 | xx1 | xx2
2083+
----+----+----+-----+-----+-----
2084+
1 | 11 | 1 | 111 | 1 | 11
2085+
2 | 22 | 2 | 222 | 2 | 22
2086+
3 | | 3 | 333 | 3 |
2087+
4 | 44 | 4 | | |
2088+
5 | | | | |
2089+
(5 rows)
2090+
2091+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
2092+
on (x1 = xx1 and xx2 is not null);
2093+
x1 | x2 | y1 | y2 | xx1 | xx2
2094+
----+----+----+-----+-----+-----
2095+
1 | 11 | 1 | 111 | 1 | 11
2096+
2 | 22 | 2 | 222 | 2 | 22
2097+
3 | | 3 | 333 | |
2098+
4 | 44 | 4 | | 4 | 44
2099+
5 | | | | |
2100+
(5 rows)
2101+
2102+
-- these should NOT give the same answers as above
2103+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
2104+
on (x1 = xx1) where (x2 is not null);
2105+
x1 | x2 | y1 | y2 | xx1 | xx2
2106+
----+----+----+-----+-----+-----
2107+
1 | 11 | 1 | 111 | 1 | 11
2108+
2 | 22 | 2 | 222 | 2 | 22
2109+
4 | 44 | 4 | | 4 | 44
2110+
(3 rows)
2111+
2112+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
2113+
on (x1 = xx1) where (y2 is not null);
2114+
x1 | x2 | y1 | y2 | xx1 | xx2
2115+
----+----+----+-----+-----+-----
2116+
1 | 11 | 1 | 111 | 1 | 11
2117+
2 | 22 | 2 | 222 | 2 | 22
2118+
3 | | 3 | 333 | 3 |
2119+
(3 rows)
2120+
2121+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
2122+
on (x1 = xx1) where (xx2 is not null);
2123+
x1 | x2 | y1 | y2 | xx1 | xx2
2124+
----+----+----+-----+-----+-----
2125+
1 | 11 | 1 | 111 | 1 | 11
2126+
2 | 22 | 2 | 222 | 2 | 22
2127+
4 | 44 | 4 | | 4 | 44
2128+
(3 rows)
2129+
20072130
--
20082131
-- Clean up
20092132
--

src/test/regress/sql/join.sql

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,45 @@ NATURAL FULL JOIN
292292
(SELECT name, n as s3_n FROM t3) as s3
293293
) ss2;
294294

295+
296+
-- Test for propagation of nullability constraints into sub-joins
297+
298+
create temp table x (x1 int, x2 int);
299+
insert into x values (1,11);
300+
insert into x values (2,22);
301+
insert into x values (3,null);
302+
insert into x values (4,44);
303+
insert into x values (5,null);
304+
305+
create temp table y (y1 int, y2 int);
306+
insert into y values (1,111);
307+
insert into y values (2,222);
308+
insert into y values (3,333);
309+
insert into y values (4,null);
310+
311+
select * from x;
312+
select * from y;
313+
314+
select * from x left join y on (x1 = y1 and x2 is not null);
315+
select * from x left join y on (x1 = y1 and y2 is not null);
316+
317+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
318+
on (x1 = xx1);
319+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
320+
on (x1 = xx1 and x2 is not null);
321+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
322+
on (x1 = xx1 and y2 is not null);
323+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
324+
on (x1 = xx1 and xx2 is not null);
325+
-- these should NOT give the same answers as above
326+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
327+
on (x1 = xx1) where (x2 is not null);
328+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
329+
on (x1 = xx1) where (y2 is not null);
330+
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
331+
on (x1 = xx1) where (xx2 is not null);
332+
333+
295334
--
296335
-- Clean up
297336
--

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy