diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-08-14 18:48:00 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-08-14 18:48:00 +0000 |
commit | e006a24ad152b3faec748afe8c1ff0829699b2e6 (patch) | |
tree | d00e01d25270b4b04aac3c723b9e440a56d8a085 /src/backend/executor/nodeNestloop.c | |
parent | ef1c807c25b47960aa86cd185fb74371e88d0cbf (diff) | |
download | postgresql-e006a24ad152b3faec748afe8c1ff0829699b2e6.tar.gz postgresql-e006a24ad152b3faec748afe8c1ff0829699b2e6.zip |
Implement SEMI and ANTI joins in the planner and executor. (Semijoins replace
the old JOIN_IN code, but antijoins are new functionality.) Teach the planner
to convert appropriate EXISTS and NOT EXISTS subqueries into semi and anti
joins respectively. Also, LEFT JOINs with suitable upper-level IS NULL
filters are recognized as being anti joins. Unify the InClauseInfo and
OuterJoinInfo infrastructure into "SpecialJoinInfo". With that change,
it becomes possible to associate a SpecialJoinInfo with every join attempt,
which permits some cleanup of join selectivity estimation. That needs to be
taken much further than this patch does, but the next step is to change the
API for oprjoin selectivity functions, which seems like material for a
separate patch. So for the moment the output size estimates for semi and
especially anti joins are quite bogus.
Diffstat (limited to 'src/backend/executor/nodeNestloop.c')
-rw-r--r-- | src/backend/executor/nodeNestloop.c | 60 |
1 files changed, 31 insertions, 29 deletions
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index 78216212ff5..c6a33228582 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.46 2008/01/01 19:45:49 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.47 2008/08/14 18:47:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -102,15 +102,6 @@ ExecNestLoop(NestLoopState *node) } /* - * If we're doing an IN join, we want to return at most one row per outer - * tuple; so we can stop scanning the inner scan if we matched on the - * previous try. - */ - if (node->js.jointype == JOIN_IN && - node->nl_MatchedOuter) - node->nl_NeedNewOuter = true; - - /* * Reset per-tuple memory context to free any expression evaluation * storage allocated in the previous tuple cycle. Note this can't happen * until we're done projecting out tuples from a join tuple. @@ -177,7 +168,8 @@ ExecNestLoop(NestLoopState *node) node->nl_NeedNewOuter = true; if (!node->nl_MatchedOuter && - node->js.jointype == JOIN_LEFT) + (node->js.jointype == JOIN_LEFT || + node->js.jointype == JOIN_ANTI)) { /* * We are doing an outer join and there were no join matches @@ -189,7 +181,7 @@ ExecNestLoop(NestLoopState *node) ENL1_printf("testing qualification for outer-join tuple"); - if (ExecQual(otherqual, econtext, false)) + if (otherqual == NIL || ExecQual(otherqual, econtext, false)) { /* * qualification was satisfied so we project and return @@ -232,30 +224,39 @@ ExecNestLoop(NestLoopState *node) { node->nl_MatchedOuter = true; - if (otherqual == NIL || ExecQual(otherqual, econtext, false)) + /* In an antijoin, we never return a matched tuple */ + if (node->js.jointype == JOIN_ANTI) + node->nl_NeedNewOuter = true; + else { /* - * qualification was satisfied so we project and return the - * slot containing the result tuple using ExecProject(). + * In a semijoin, we'll consider returning the first match, + * but after that we're done with this outer tuple. */ - TupleTableSlot *result; - ExprDoneCond isDone; + if (node->js.jointype == JOIN_SEMI) + node->nl_NeedNewOuter = true; + if (otherqual == NIL || ExecQual(otherqual, econtext, false)) + { + /* + * qualification was satisfied so we project and return + * the slot containing the result tuple using + * ExecProject(). + */ + TupleTableSlot *result; + ExprDoneCond isDone; - ENL1_printf("qualification succeeded, projecting tuple"); + ENL1_printf("qualification succeeded, projecting tuple"); - result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); + result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; + if (isDone != ExprEndResult) + { + node->js.ps.ps_TupFromTlist = + (isDone == ExprMultipleResult); + return result; + } } } - - /* If we didn't return a tuple, may need to set NeedNewOuter */ - if (node->js.jointype == JOIN_IN) - node->nl_NeedNewOuter = true; } /* @@ -333,9 +334,10 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) switch (node->join.jointype) { case JOIN_INNER: - case JOIN_IN: + case JOIN_SEMI: break; case JOIN_LEFT: + case JOIN_ANTI: nlstate->nl_NullInnerTupleSlot = ExecInitNullTupleSlot(estate, ExecGetResultType(innerPlanState(nlstate))); |