diff options
Diffstat (limited to 'src/backend/executor/nodeNestloop.c')
-rw-r--r-- | src/backend/executor/nodeNestloop.c | 418 |
1 files changed, 0 insertions, 418 deletions
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c deleted file mode 100644 index 2bd26938fcc..00000000000 --- a/src/backend/executor/nodeNestloop.c +++ /dev/null @@ -1,418 +0,0 @@ -/*------------------------------------------------------------------------- - * - * nodeNestloop.c - * routines to support nest-loop joins - * - * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.26 2002/06/20 20:29:28 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -/* - * INTERFACE ROUTINES - * ExecNestLoop - process a nestloop join of two plans - * ExecInitNestLoop - initialize the join - * ExecEndNestLoop - shut down the join - */ - -#include "postgres.h" - -#include "executor/execdebug.h" -#include "executor/nodeNestloop.h" -#include "utils/memutils.h" - - -/* ---------------------------------------------------------------- - * ExecNestLoop(node) - * - * old comments - * Returns the tuple joined from inner and outer tuples which - * satisfies the qualification clause. - * - * It scans the inner relation to join with current outer tuple. - * - * If none is found, next tuple from the outer relation is retrieved - * and the inner relation is scanned from the beginning again to join - * with the outer tuple. - * - * NULL is returned if all the remaining outer tuples are tried and - * all fail to join with the inner tuples. - * - * NULL is also returned if there is no tuple from inner relation. - * - * Conditions: - * -- outerTuple contains current tuple from outer relation and - * the right son(inner relation) maintains "cursor" at the tuple - * returned previously. - * This is achieved by maintaining a scan position on the outer - * relation. - * - * Initial States: - * -- the outer child and the inner child - * are prepared to return the first tuple. - * ---------------------------------------------------------------- - */ -TupleTableSlot * -ExecNestLoop(NestLoop *node) -{ - NestLoopState *nlstate; - Plan *innerPlan; - Plan *outerPlan; - TupleTableSlot *outerTupleSlot; - TupleTableSlot *innerTupleSlot; - List *joinqual; - List *otherqual; - ExprContext *econtext; - - /* - * get information from the node - */ - ENL1_printf("getting info from node"); - - nlstate = node->nlstate; - joinqual = node->join.joinqual; - otherqual = node->join.plan.qual; - outerPlan = outerPlan((Plan *) node); - innerPlan = innerPlan((Plan *) node); - econtext = nlstate->jstate.cs_ExprContext; - - /* - * get the current outer tuple - */ - outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot; - econtext->ecxt_outertuple = outerTupleSlot; - - /* - * Check to see if we're still projecting out tuples from a previous - * join tuple (because there is a function-returning-set in the - * projection expressions). If so, try to project another one. - */ - if (nlstate->jstate.cs_TupFromTlist) - { - TupleTableSlot *result; - ExprDoneCond isDone; - - result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone); - if (isDone == ExprMultipleResult) - return result; - /* Done with that source tuple... */ - nlstate->jstate.cs_TupFromTlist = false; - } - - /* - * 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. - */ - ResetExprContext(econtext); - - /* - * Ok, everything is setup for the join so now loop until we return a - * qualifying join tuple. - */ - ENL1_printf("entering main loop"); - - for (;;) - { - /* - * If we don't have an outer tuple, get the next one and reset the - * inner scan. - */ - if (nlstate->nl_NeedNewOuter) - { - ENL1_printf("getting new outer tuple"); - outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node); - - /* - * if there are no more outer tuples, then the join is - * complete.. - */ - if (TupIsNull(outerTupleSlot)) - { - ENL1_printf("no outer tuple, ending join"); - return NULL; - } - - ENL1_printf("saving new outer tuple information"); - nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot; - econtext->ecxt_outertuple = outerTupleSlot; - nlstate->nl_NeedNewOuter = false; - nlstate->nl_MatchedOuter = false; - - /* - * now rescan the inner plan - */ - ENL1_printf("rescanning inner plan"); - - /* - * The scan key of the inner plan might depend on the current - * outer tuple (e.g. in index scans), that's why we pass our - * expr context. - */ - ExecReScan(innerPlan, econtext, (Plan *) node); - } - - /* - * we have an outerTuple, try to get the next inner tuple. - */ - ENL1_printf("getting new inner tuple"); - - innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node); - econtext->ecxt_innertuple = innerTupleSlot; - - if (TupIsNull(innerTupleSlot)) - { - ENL1_printf("no inner tuple, need new outer tuple"); - - nlstate->nl_NeedNewOuter = true; - - if (!nlstate->nl_MatchedOuter && - node->join.jointype == JOIN_LEFT) - { - /* - * We are doing an outer join and there were no join - * matches for this outer tuple. Generate a fake join - * tuple with nulls for the inner tuple, and return it if - * it passes the non-join quals. - */ - econtext->ecxt_innertuple = nlstate->nl_NullInnerTupleSlot; - - ENL1_printf("testing qualification for outer-join tuple"); - - if (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"); - - result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - nlstate->jstate.cs_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } - } - - /* - * Otherwise just return to top of loop for a new outer tuple. - */ - continue; - } - - /* - * at this point we have a new pair of inner and outer tuples so - * we test the inner and outer tuples to see if they satisfy the - * node's qualification. - * - * Only the joinquals determine MatchedOuter status, but all quals - * must pass to actually return the tuple. - */ - ENL1_printf("testing qualification"); - - if (ExecQual(joinqual, econtext, false)) - { - nlstate->nl_MatchedOuter = 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"); - - result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone); - - if (isDone != ExprEndResult) - { - nlstate->jstate.cs_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } - } - - /* - * Tuple fails qual, so free per-tuple memory and try again. - */ - ResetExprContext(econtext); - - ENL1_printf("qualification failed, looping"); - } -} - -/* ---------------------------------------------------------------- - * ExecInitNestLoop - * - * Creates the run-time state information for the nestloop node - * produced by the planner and initailizes inner and outer relations - * (child nodes). - * ---------------------------------------------------------------- - */ -bool -ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent) -{ - NestLoopState *nlstate; - - NL1_printf("ExecInitNestLoop: %s\n", - "initializing node"); - - /* - * assign execution state to node - */ - node->join.plan.state = estate; - - /* - * create new nest loop state - */ - nlstate = makeNode(NestLoopState); - node->nlstate = nlstate; - - /* - * Miscellaneous initialization - * - * create expression context for node - */ - ExecAssignExprContext(estate, &nlstate->jstate); - - /* - * now initialize children - */ - ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node); - ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node); - -#define NESTLOOP_NSLOTS 2 - - /* - * tuple table initialization - */ - ExecInitResultTupleSlot(estate, &nlstate->jstate); - - switch (node->join.jointype) - { - case JOIN_INNER: - break; - case JOIN_LEFT: - nlstate->nl_NullInnerTupleSlot = - ExecInitNullTupleSlot(estate, - ExecGetTupType(innerPlan((Plan *) node))); - break; - default: - elog(ERROR, "ExecInitNestLoop: unsupported join type %d", - (int) node->join.jointype); - } - - /* - * initialize tuple type and projection info - */ - ExecAssignResultTypeFromTL((Plan *) node, &nlstate->jstate); - ExecAssignProjectionInfo((Plan *) node, &nlstate->jstate); - - /* - * finally, wipe the current outer tuple clean. - */ - nlstate->jstate.cs_OuterTupleSlot = NULL; - nlstate->jstate.cs_TupFromTlist = false; - nlstate->nl_NeedNewOuter = true; - nlstate->nl_MatchedOuter = false; - - NL1_printf("ExecInitNestLoop: %s\n", - "node initialized"); - return TRUE; -} - -int -ExecCountSlotsNestLoop(NestLoop *node) -{ - return ExecCountSlotsNode(outerPlan(node)) + - ExecCountSlotsNode(innerPlan(node)) + - NESTLOOP_NSLOTS; -} - -/* ---------------------------------------------------------------- - * ExecEndNestLoop - * - * closes down scans and frees allocated storage - * ---------------------------------------------------------------- - */ -void -ExecEndNestLoop(NestLoop *node) -{ - NestLoopState *nlstate; - - NL1_printf("ExecEndNestLoop: %s\n", - "ending node processing"); - - /* - * get info from the node - */ - nlstate = node->nlstate; - - /* - * Free the projection info - * - * Note: we don't ExecFreeResultType(nlstate) because the rule manager - * depends on the tupType returned by ExecMain(). So for now, this is - * freed at end-transaction time. -cim 6/2/91 - */ - ExecFreeProjectionInfo(&nlstate->jstate); - ExecFreeExprContext(&nlstate->jstate); - - /* - * close down subplans - */ - ExecEndNode(outerPlan((Plan *) node), (Plan *) node); - ExecEndNode(innerPlan((Plan *) node), (Plan *) node); - - /* - * clean out the tuple table - */ - ExecClearTuple(nlstate->jstate.cs_ResultTupleSlot); - - NL1_printf("ExecEndNestLoop: %s\n", - "node processing ended"); -} - -/* ---------------------------------------------------------------- - * ExecReScanNestLoop - * ---------------------------------------------------------------- - */ -void -ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent) -{ - NestLoopState *nlstate = node->nlstate; - Plan *outerPlan = outerPlan((Plan *) node); - - /* - * If outerPlan->chgParam is not null then plan will be automatically - * re-scanned by first ExecProcNode. innerPlan is re-scanned for each - * new outer tuple and MUST NOT be re-scanned from here or you'll get - * troubles from inner index scans when outer Vars are used as - * run-time keys... - */ - if (outerPlan->chgParam == NULL) - ExecReScan(outerPlan, exprCtxt, (Plan *) node); - - /* let outerPlan to free its result tuple ... */ - nlstate->jstate.cs_OuterTupleSlot = NULL; - nlstate->jstate.cs_TupFromTlist = false; - nlstate->nl_NeedNewOuter = true; - nlstate->nl_MatchedOuter = false; -} |