summaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeNestloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeNestloop.c')
-rw-r--r--src/backend/executor/nodeNestloop.c418
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;
-}