aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeHashjoin.c
diff options
context:
space:
mode:
authorRichard Guo <rguo@postgresql.org>2024-07-08 10:11:46 +0900
committerRichard Guo <rguo@postgresql.org>2024-07-08 10:11:46 +0900
commit0ffc0acaf3bf301ba8fd43dc0e004b8b7c9ecd3a (patch)
tree184b1f42aed4c529f96aabc623bb3a4dbe94c8a0 /src/backend/executor/nodeHashjoin.c
parent74b8e6a698025fbea5a5e22ea09d07d97188c1d6 (diff)
downloadpostgresql-0ffc0acaf3bf301ba8fd43dc0e004b8b7c9ecd3a.tar.gz
postgresql-0ffc0acaf3bf301ba8fd43dc0e004b8b7c9ecd3a.zip
Fix right-anti-joins when the inner relation is proven unique
For an inner_unique join, we always assume that the executor will stop scanning for matches after the first match. Therefore, for a mergejoin that is inner_unique and whose mergeclauses are sufficient to identify a match, we set the skip_mark_restore flag to true, indicating that the executor need not do mark/restore calls. However, merge-right-anti-join did not get this memo and continues scanning the inner side for matches after the first match. If there are duplicates in the outer scan, we may incorrectly skip matching some inner tuples, which can lead to wrong results. Here we fix this issue by ensuring that merge-right-anti-join also advances to next outer tuple after the first match in inner_unique cases. This also saves cycles by avoiding unnecessary scanning of inner tuples after the first match. Although hash-right-anti-join does not suffer from this wrong results issue, we apply the same change to it as well, to help save cycles for the same reason. Per bug #18522 from Antti Lampinen, and bug #18526 from Feliphe Pozzer. Back-patch to v16 where right-anti-join was introduced. Author: Richard Guo Discussion: https://postgr.es/m/18522-c7a8956126afdfd0@postgresql.org
Diffstat (limited to 'src/backend/executor/nodeHashjoin.c')
-rw-r--r--src/backend/executor/nodeHashjoin.c21
1 files changed, 11 insertions, 10 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);