aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeHashjoin.c21
-rw-r--r--src/backend/executor/nodeMergejoin.c21
-rw-r--r--src/test/regress/expected/join.out54
-rw-r--r--src/test/regress/sql/join.sql24
4 files changed, 100 insertions, 20 deletions
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index c46764023df..5429e687342 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -573,20 +573,21 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel)
}
/*
- * In a right-antijoin, we never return a matched tuple.
- * And we need to stay on the current outer tuple to
- * continue scanning the inner side for matches.
+ * If we only need to consider the first matching inner
+ * tuple, then advance to next outer tuple after we've
+ * processed this one.
*/
- if (node->js.jointype == JOIN_RIGHT_ANTI)
- continue;
+ if (node->js.single_match)
+ node->hj_JoinState = HJ_NEED_NEW_OUTER;
/*
- * If we only need to join to the first matching inner
- * tuple, then consider returning this one, but after that
- * continue with next outer tuple.
+ * In a right-antijoin, we never return a matched tuple.
+ * If it's not an inner_unique join, we need to stay on
+ * the current outer tuple to continue scanning the inner
+ * side for matches.
*/
- if (node->js.single_match)
- node->hj_JoinState = HJ_NEED_NEW_OUTER;
+ if (node->js.jointype == JOIN_RIGHT_ANTI)
+ continue;
if (otherqual == NULL || ExecQual(otherqual, econtext))
return ExecProject(node->js.ps.ps_ProjInfo);
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 4fb34e35371..29c54fcd753 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -805,20 +805,21 @@ ExecMergeJoin(PlanState *pstate)
}
/*
- * In a right-antijoin, we never return a matched tuple.
- * And we need to stay on the current outer tuple to
- * continue scanning the inner side for matches.
+ * If we only need to consider the first matching inner
+ * tuple, then advance to next outer tuple after we've
+ * processed this one.
*/
- if (node->js.jointype == JOIN_RIGHT_ANTI)
- break;
+ if (node->js.single_match)
+ node->mj_JoinState = EXEC_MJ_NEXTOUTER;
/*
- * If we only need to join to the first matching inner
- * tuple, then consider returning this one, but after that
- * continue with next outer tuple.
+ * In a right-antijoin, we never return a matched tuple.
+ * If it's not an inner_unique join, we need to stay on
+ * the current outer tuple to continue scanning the inner
+ * side for matches.
*/
- if (node->js.single_match)
- node->mj_JoinState = EXEC_MJ_NEXTOUTER;
+ if (node->js.jointype == JOIN_RIGHT_ANTI)
+ break;
qualResult = (otherqual == NULL ||
ExecQual(otherqual, econtext));
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 9142dab171f..53f70d72ed6 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -2927,6 +2927,60 @@ select tt1.*, tt2.* from tt2 right join tt1 on tt1.joincol = tt2.joincol;
reset enable_hashjoin;
reset enable_nestloop;
--
+-- regression test for bug #18522 (merge-right-anti-join in inner_unique cases)
+--
+create temp table tbl_ra(a int unique, b int);
+insert into tbl_ra select i, i%100 from generate_series(1,1000)i;
+create index on tbl_ra (b);
+analyze tbl_ra;
+set enable_hashjoin to off;
+set enable_nestloop to off;
+-- ensure we get a merge right anti join
+explain (costs off)
+select * from tbl_ra t1
+where not exists (select 1 from tbl_ra t2 where t2.b = t1.a) and t1.b < 2;
+ QUERY PLAN
+-------------------------------------------------------
+ Merge Right Anti Join
+ Merge Cond: (t2.b = t1.a)
+ -> Index Only Scan using tbl_ra_b_idx on tbl_ra t2
+ -> Sort
+ Sort Key: t1.a
+ -> Bitmap Heap Scan on tbl_ra t1
+ Recheck Cond: (b < 2)
+ -> Bitmap Index Scan on tbl_ra_b_idx
+ Index Cond: (b < 2)
+(9 rows)
+
+-- and check we get the expected results
+select * from tbl_ra t1
+where not exists (select 1 from tbl_ra t2 where t2.b = t1.a) and t1.b < 2;
+ a | b
+------+---
+ 100 | 0
+ 101 | 1
+ 200 | 0
+ 201 | 1
+ 300 | 0
+ 301 | 1
+ 400 | 0
+ 401 | 1
+ 500 | 0
+ 501 | 1
+ 600 | 0
+ 601 | 1
+ 700 | 0
+ 701 | 1
+ 800 | 0
+ 801 | 1
+ 900 | 0
+ 901 | 1
+ 1000 | 0
+(19 rows)
+
+reset enable_hashjoin;
+reset enable_nestloop;
+--
-- regression test for bug #13908 (hash join with skew tuples & nbatch increase)
--
set work_mem to '64kB';
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index e3d26520832..d81ff63be53 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -694,6 +694,30 @@ reset enable_hashjoin;
reset enable_nestloop;
--
+-- regression test for bug #18522 (merge-right-anti-join in inner_unique cases)
+--
+
+create temp table tbl_ra(a int unique, b int);
+insert into tbl_ra select i, i%100 from generate_series(1,1000)i;
+create index on tbl_ra (b);
+analyze tbl_ra;
+
+set enable_hashjoin to off;
+set enable_nestloop to off;
+
+-- ensure we get a merge right anti join
+explain (costs off)
+select * from tbl_ra t1
+where not exists (select 1 from tbl_ra t2 where t2.b = t1.a) and t1.b < 2;
+
+-- and check we get the expected results
+select * from tbl_ra t1
+where not exists (select 1 from tbl_ra t2 where t2.b = t1.a) and t1.b < 2;
+
+reset enable_hashjoin;
+reset enable_nestloop;
+
+--
-- regression test for bug #13908 (hash join with skew tuples & nbatch increase)
--