aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeHashjoin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeHashjoin.c')
-rw-r--r--src/backend/executor/nodeHashjoin.c35
1 files changed, 23 insertions, 12 deletions
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 52ed05c6f5a..0a3f32f731d 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -86,7 +86,7 @@
* PHJ_BATCH_ALLOCATE* -- one allocates buckets
* PHJ_BATCH_LOAD -- all load the hash table from disk
* PHJ_BATCH_PROBE -- all probe
- * PHJ_BATCH_SCAN* -- one does full/right unmatched scan
+ * PHJ_BATCH_SCAN* -- one does right/right-anti/full unmatched scan
* PHJ_BATCH_FREE* -- one frees memory
*
* Batch 0 is a special case, because it starts out in phase
@@ -228,10 +228,10 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel)
/*
* If the outer relation is completely empty, and it's not
- * right/full join, we can quit without building the hash
- * table. However, for an inner join it is only a win to
- * check this when the outer relation's startup cost is less
- * than the projected cost of building the hash table.
+ * right/right-anti/full join, we can quit without building
+ * the hash table. However, for an inner join it is only a
+ * win to check this when the outer relation's startup cost is
+ * less than the projected cost of building the hash table.
* Otherwise it's best to build the hash table first and see
* if the inner relation is empty. (When it's a left join, we
* should always make this check, since we aren't going to be
@@ -520,6 +520,14 @@ 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 (node->js.jointype == JOIN_RIGHT_ANTI)
+ continue;
+
+ /*
* 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.
@@ -564,9 +572,10 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel)
case HJ_FILL_INNER_TUPLES:
/*
- * We have finished a batch, but we are doing right/full join,
- * so any unmatched inner tuples in the hashtable have to be
- * emitted before we continue to the next batch.
+ * We have finished a batch, but we are doing
+ * right/right-anti/full join, so any unmatched inner tuples
+ * in the hashtable have to be emitted before we continue to
+ * the next batch.
*/
if (!(parallel ? ExecParallelScanHashTableForUnmatched(node, econtext)
: ExecScanHashTableForUnmatched(node, econtext)))
@@ -732,6 +741,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
break;
case JOIN_RIGHT:
+ case JOIN_RIGHT_ANTI:
hjstate->hj_NullOuterTupleSlot =
ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
break;
@@ -1027,8 +1037,9 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
* side, but there are exceptions:
*
* 1. In a left/full outer join, we have to process outer batches even if
- * the inner batch is empty. Similarly, in a right/full outer join, we
- * have to process inner batches even if the outer batch is empty.
+ * the inner batch is empty. Similarly, in a right/right-anti/full outer
+ * join, we have to process inner batches even if the outer batch is
+ * empty.
*
* 2. If we have increased nbatch since the initial estimate, we have to
* scan inner batches since they might contain tuples that need to be
@@ -1349,8 +1360,8 @@ ExecReScanHashJoin(HashJoinState *node)
/*
* Okay to reuse the hash table; needn't rescan inner, either.
*
- * However, if it's a right/full join, we'd better reset the
- * inner-tuple match flags contained in the table.
+ * However, if it's a right/right-anti/full join, we'd better
+ * reset the inner-tuple match flags contained in the table.
*/
if (HJ_FILL_INNER(node))
ExecHashTableResetMatchFlags(node->hj_HashTable);