From 3590a10e5a891fd93e83318c5b0082eae1d98333 Mon Sep 17 00:00:00 2001 From: Richard Guo Date: Thu, 24 Jun 2021 16:58:44 +0800 Subject: [PATCH] Using each rel as both outer and inner for anti joins --- src/backend/commands/explain.c | 3 +++ src/backend/executor/nodeHashjoin.c | 4 +++- src/backend/optimizer/path/joinpath.c | 7 +++++++ src/backend/optimizer/path/joinrels.c | 3 +++ src/include/nodes/nodes.h | 4 +++- 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index e81b990092..a9f6ebf1f3 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -1517,6 +1517,9 @@ ExplainNode(PlanState *planstate, List *ancestors, case JOIN_ANTI: jointype = "Anti"; break; + case JOIN_RIGHT_ANTI: + jointype = "Right Anti"; + break; default: jointype = "???"; break; diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 510bdd39ad..0e901c9d53 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -476,7 +476,8 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel) } /* In an antijoin, we never return a matched tuple */ - if (node->js.jointype == JOIN_ANTI) + if (node->js.jointype == JOIN_ANTI || + node->js.jointype == JOIN_RIGHT_ANTI) { node->hj_JoinState = HJ_NEED_NEW_OUTER; continue; @@ -694,6 +695,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; diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index b67b517770..e91293ff54 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -1110,6 +1110,9 @@ sort_inner_and_outer(PlannerInfo *root, List *all_pathkeys; ListCell *l; + if (jointype == JOIN_RIGHT_ANTI) + return; + /* * We only consider the cheapest-total-cost input paths, since we are * assuming here that a sort is required. We will consider @@ -1559,6 +1562,9 @@ match_unsorted_outer(PlannerInfo *root, Path *matpath = NULL; ListCell *lc1; + if (jointype == JOIN_RIGHT_ANTI) + return; + /* * Nestloop only supports inner, left, semi, and anti joins. Also, if we * are doing a right or full mergejoin, we must use *all* the mergeclauses @@ -2100,6 +2106,7 @@ hash_inner_and_outer(PlannerInfo *root, save_jointype != JOIN_UNIQUE_OUTER && save_jointype != JOIN_FULL && save_jointype != JOIN_RIGHT && + save_jointype != JOIN_RIGHT_ANTI && outerrel->partial_pathlist != NIL && bms_is_empty(joinrel->lateral_relids)) { diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 0dbe2ac726..194f820c2f 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -915,6 +915,9 @@ populate_joinrel_with_paths(PlannerInfo *root, RelOptInfo *rel1, add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_ANTI, sjinfo, restrictlist); + add_paths_to_joinrel(root, joinrel, rel2, rel1, + JOIN_RIGHT_ANTI, sjinfo, + restrictlist); break; default: /* other values not expected here */ diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index d9e417bcd7..7c07792e56 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -725,6 +725,7 @@ typedef enum JoinType */ JOIN_SEMI, /* 1 copy of each LHS row that has match(es) */ JOIN_ANTI, /* 1 copy of each LHS row that has no match */ + JOIN_RIGHT_ANTI, /* 1 copy of each RHS row that has no match */ /* * These codes are used internally in the planner, but are not supported @@ -757,7 +758,8 @@ typedef enum JoinType ((1 << JOIN_LEFT) | \ (1 << JOIN_FULL) | \ (1 << JOIN_RIGHT) | \ - (1 << JOIN_ANTI))) != 0) + (1 << JOIN_ANTI) | \ + (1 << JOIN_RIGHT_ANTI))) != 0) /* * AggStrategy - -- 2.31.0