nodeNestloop.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:10k
- /*-------------------------------------------------------------------------
- *
- * nodeNestloop.c
- * routines to support nest-loop joins
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /usr/local/cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.11 1999/02/13 23:15:25 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/executor.h"
- #include "executor/execdebug.h"
- #include "executor/nodeNestloop.h"
- #include "executor/nodeIndexscan.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 form the outer relation is retrieved
- * and the inner relation is scanned from the beginning again to join
- * with the outer tuple.
- *
- * Nil is returned if all the remaining outer tuples are tried and
- * all fail to join with the inner tuples.
- *
- * Nil is also returned if there is no tuple from inner realtion.
- *
- * Conditions:
- * -- outerTuple contains current tuple from outer relation and
- * the right son(inner realtion) 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, Plan *parent)
- {
- NestLoopState *nlstate;
- Plan *innerPlan;
- Plan *outerPlan;
- bool needNewOuterTuple;
- TupleTableSlot *outerTupleSlot;
- TupleTableSlot *innerTupleSlot;
- List *qual;
- bool qualResult;
- ExprContext *econtext;
- /* ----------------
- * get information from the node
- * ----------------
- */
- ENL1_printf("getting info from node");
- nlstate = node->nlstate;
- qual = node->join.qual;
- outerPlan = outerPlan(&node->join);
- innerPlan = innerPlan(&node->join);
- /* ----------------
- * initialize expression context
- * ----------------
- */
- econtext = nlstate->jstate.cs_ExprContext;
- /* ----------------
- * get the current outer tuple
- * ----------------
- */
- outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
- econtext->ecxt_outertuple = outerTupleSlot;
- /* ----------------
- * Ok, everything is setup for the join so now loop until
- * we return a qualifying join tuple..
- * ----------------
- */
- if (nlstate->jstate.cs_TupFromTlist)
- {
- TupleTableSlot *result;
- bool isDone;
- result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
- if (!isDone)
- return result;
- }
- ENL1_printf("entering main loop");
- for (;;)
- {
- /* ----------------
- * The essential idea now is to get the next inner tuple
- * and join it with the current outer tuple.
- * ----------------
- */
- needNewOuterTuple = false;
- if (!TupIsNull(outerTupleSlot))
- ENL1_printf("have outer tuple, deal with it");
- else
- {
- ENL1_printf("outer tuple is nil, need new outer tuple");
- needNewOuterTuple = true;
- }
- /* ----------------
- * if we have an outerTuple, try to get the next inner tuple.
- * ----------------
- */
- if (!needNewOuterTuple)
- {
- 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");
- needNewOuterTuple = true;
- }
- }
- /* ----------------
- * loop until we have a new outer tuple and a new
- * inner tuple.
- * ----------------
- */
- while (needNewOuterTuple)
- {
- /* ----------------
- * now try to get the next outer tuple
- * ----------------
- */
- ENL1_printf("getting new outer tuple");
- outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
- econtext->ecxt_outertuple = outerTupleSlot;
- /* ----------------
- * 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;
- /* ----------------
- * now rescan the inner plan and get a new inner tuple
- * ----------------
- */
- 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, parent);
- ENL1_printf("getting new inner tuple");
- innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
- econtext->ecxt_innertuple = innerTupleSlot;
- if (TupIsNull(innerTupleSlot))
- ENL1_printf("couldn't get inner tuple - need new outer tuple");
- else
- {
- ENL1_printf("got inner and outer tuples");
- needNewOuterTuple = false;
- }
- } /* while (needNewOuterTuple) */
- /* ----------------
- * 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 satisify the node's qualification.
- * ----------------
- */
- ENL1_printf("testing qualification");
- qualResult = ExecQual((List *) qual, econtext);
- if (qualResult)
- {
- /* ----------------
- * qualification was satisified so we project and
- * return the slot containing the result tuple
- * using ExecProject().
- * ----------------
- */
- ProjectionInfo *projInfo;
- TupleTableSlot *result;
- bool isDone;
- ENL1_printf("qualification succeeded, projecting tuple");
- projInfo = nlstate->jstate.cs_ProjInfo;
- result = ExecProject(projInfo, &isDone);
- nlstate->jstate.cs_TupFromTlist = !isDone;
- return result;
- }
- /* ----------------
- * qualification failed so we have to try again..
- * ----------------
- */
- 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: %sn",
- "initializing node");
- /* ----------------
- * assign execution state to node
- * ----------------
- */
- node->join.state = estate;
- /* ----------------
- * create new nest loop state
- * ----------------
- */
- nlstate = makeNode(NestLoopState);
- nlstate->nl_PortalFlag = false;
- node->nlstate = nlstate;
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- * + create expression context for node
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &nlstate->jstate, parent);
- ExecAssignExprContext(estate, &nlstate->jstate);
- #define NESTLOOP_NSLOTS 1
- /* ----------------
- * tuple table initialization
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &nlstate->jstate);
- /* ----------------
- * now initialize children
- * ----------------
- */
- ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
- ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
- /* ----------------
- * 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;
- NL1_printf("ExecInitNestLoop: %sn",
- "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: %sn",
- "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);
- /* ----------------
- * 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: %sn",
- "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 typle ... */
- nlstate->jstate.cs_OuterTupleSlot = NULL;
- nlstate->jstate.cs_TupFromTlist = false;
- return;
- }