summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2015-04-04 19:55:15 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2015-04-04 19:55:15 -0400
commitb7d493bf78328fbb450e9db56a60e536a6fb6bbf (patch)
tree191ff42dfeb55f66a27ac26bbc4cb91e5cb1379b /src/test
parent0aff9d8338d6fa6b9ef2439c7c0b4aa3ad4a4651 (diff)
Fix incorrect matching of subexpressions in outer-join plan nodes.
Previously we would re-use input subexpressions in all expression trees attached to a Join plan node. However, if it's an outer join and the subexpression appears in the nullable-side input, this is potentially incorrect for apparently-matching subexpressions that came from above the outer join (ie, targetlist and qpqual expressions), because the executor will treat the subexpression value as NULL when maybe it should not be. The case is fairly hard to hit because (a) you need a non-strict subexpression (else NULL is correct), and (b) we don't usually compute expressions in the outputs of non-toplevel plan nodes. But we might do so if the expressions are sort keys for a mergejoin, for example. Probably in the long run we should make a more explicit distinction between Vars appearing above and below an outer join, but that will be a major planner redesign and not at all back-patchable. For the moment, just hack set_join_references so that it will not match any non-Var expressions coming from nullable inputs to expressions that came from above the join. (This is somewhat overkill, in that a strict expression could still be matched, but it doesn't seem worth the effort to check that.) Per report from Qingqing Zhou. The added regression test case is based on his example. This has been broken for a very long time, so back-patch to all active branches.
Diffstat (limited to 'src/test')
-rw-r--r--src/test/regress/expected/join.out48
-rw-r--r--src/test/regress/sql/join.sql20
2 files changed, 68 insertions, 0 deletions
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 9c93969b3fc..b484620dba1 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -3106,6 +3106,54 @@ explain (costs off)
(6 rows)
--
+-- test that quals attached to an outer join have correct semantics,
+-- specifically that they don't re-use expressions computed below the join;
+-- we force a mergejoin so that coalesce(b.q1, 1) appears as a join input
+--
+set enable_hashjoin to off;
+set enable_nestloop to off;
+explain (verbose, costs off)
+ select a.q2, b.q1
+ from int8_tbl a left join int8_tbl b on a.q2 = coalesce(b.q1, 1)
+ where coalesce(b.q1, 1) > 0;
+ QUERY PLAN
+-------------------------------------------------------
+ Merge Left Join
+ Output: a.q2, b.q1
+ Merge Cond: (a.q2 = (COALESCE(b.q1, 1::bigint)))
+ Filter: (COALESCE(b.q1, 1::bigint) > 0)
+ -> Sort
+ Output: a.q2
+ Sort Key: a.q2
+ -> Seq Scan on public.int8_tbl a
+ Output: a.q2
+ -> Sort
+ Output: b.q1, (COALESCE(b.q1, 1::bigint))
+ Sort Key: (COALESCE(b.q1, 1::bigint))
+ -> Seq Scan on public.int8_tbl b
+ Output: b.q1, COALESCE(b.q1, 1::bigint)
+(14 rows)
+
+select a.q2, b.q1
+ from int8_tbl a left join int8_tbl b on a.q2 = coalesce(b.q1, 1)
+ where coalesce(b.q1, 1) > 0;
+ q2 | q1
+-------------------+------------------
+ -4567890123456789 |
+ 123 | 123
+ 123 | 123
+ 456 |
+ 4567890123456789 | 4567890123456789
+ 4567890123456789 | 4567890123456789
+ 4567890123456789 | 4567890123456789
+ 4567890123456789 | 4567890123456789
+ 4567890123456789 | 4567890123456789
+ 4567890123456789 | 4567890123456789
+(10 rows)
+
+reset enable_hashjoin;
+reset enable_nestloop;
+--
-- test join removal
--
begin;
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index f2fa6e8c789..39a701a9e02 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -908,6 +908,26 @@ explain (costs off)
select * from tenk1 a full join tenk1 b using(unique2) where unique2 = 42;
--
+-- test that quals attached to an outer join have correct semantics,
+-- specifically that they don't re-use expressions computed below the join;
+-- we force a mergejoin so that coalesce(b.q1, 1) appears as a join input
+--
+
+set enable_hashjoin to off;
+set enable_nestloop to off;
+
+explain (verbose, costs off)
+ select a.q2, b.q1
+ from int8_tbl a left join int8_tbl b on a.q2 = coalesce(b.q1, 1)
+ where coalesce(b.q1, 1) > 0;
+select a.q2, b.q1
+ from int8_tbl a left join int8_tbl b on a.q2 = coalesce(b.q1, 1)
+ where coalesce(b.q1, 1) > 0;
+
+reset enable_hashjoin;
+reset enable_nestloop;
+
+--
-- test join removal
--