Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

nodeNestloop.h File Reference

#include "nodes/execnodes.h"
Include dependency graph for nodeNestloop.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

NestLoopStateExecInitNestLoop (NestLoop *node, EState *estate, int eflags)
TupleTableSlotExecNestLoop (NestLoopState *node)
void ExecEndNestLoop (NestLoopState *node)
void ExecReScanNestLoop (NestLoopState *node)

Function Documentation

void ExecEndNestLoop ( NestLoopState node  ) 

Definition at line 397 of file nodeNestloop.c.

References ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), innerPlanState, NestLoopState::js, NL1_printf, outerPlanState, JoinState::ps, and PlanState::ps_ResultTupleSlot.

Referenced by ExecEndNode().

{
    NL1_printf("ExecEndNestLoop: %s\n",
               "ending node processing");

    /*
     * Free the exprcontext
     */
    ExecFreeExprContext(&node->js.ps);

    /*
     * clean out the tuple table
     */
    ExecClearTuple(node->js.ps.ps_ResultTupleSlot);

    /*
     * close down subplans
     */
    ExecEndNode(outerPlanState(node));
    ExecEndNode(innerPlanState(node));

    NL1_printf("ExecEndNestLoop: %s\n",
               "node processing ended");
}

NestLoopState* ExecInitNestLoop ( NestLoop node,
EState estate,
int  eflags 
)

Definition at line 296 of file nodeNestloop.c.

References Assert, elog, ERROR, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecAssignResultTypeFromTL(), ExecGetResultType(), ExecInitExpr(), ExecInitNode(), ExecInitNullTupleSlot(), ExecInitResultTupleSlot(), innerPlan, innerPlanState, NestLoop::join, JOIN_ANTI, JOIN_INNER, JOIN_LEFT, JOIN_SEMI, Join::joinqual, JoinState::joinqual, Join::jointype, JoinState::jointype, NestLoopState::js, makeNode, NestLoop::nestParams, NIL, NL1_printf, NestLoopState::nl_MatchedOuter, NestLoopState::nl_NeedNewOuter, NestLoopState::nl_NullInnerTupleSlot, NULL, outerPlan, outerPlanState, Join::plan, PlanState::plan, JoinState::ps, PlanState::ps_TupFromTlist, Plan::qual, PlanState::qual, PlanState::state, Plan::targetlist, and PlanState::targetlist.

Referenced by ExecInitNode().

{
    NestLoopState *nlstate;

    /* check for unsupported flags */
    Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));

    NL1_printf("ExecInitNestLoop: %s\n",
               "initializing node");

    /*
     * create state structure
     */
    nlstate = makeNode(NestLoopState);
    nlstate->js.ps.plan = (Plan *) node;
    nlstate->js.ps.state = estate;

    /*
     * Miscellaneous initialization
     *
     * create expression context for node
     */
    ExecAssignExprContext(estate, &nlstate->js.ps);

    /*
     * initialize child expressions
     */
    nlstate->js.ps.targetlist = (List *)
        ExecInitExpr((Expr *) node->join.plan.targetlist,
                     (PlanState *) nlstate);
    nlstate->js.ps.qual = (List *)
        ExecInitExpr((Expr *) node->join.plan.qual,
                     (PlanState *) nlstate);
    nlstate->js.jointype = node->join.jointype;
    nlstate->js.joinqual = (List *)
        ExecInitExpr((Expr *) node->join.joinqual,
                     (PlanState *) nlstate);

    /*
     * initialize child nodes
     *
     * If we have no parameters to pass into the inner rel from the outer,
     * tell the inner child that cheap rescans would be good.  If we do have
     * such parameters, then there is no point in REWIND support at all in the
     * inner child, because it will always be rescanned with fresh parameter
     * values.
     */
    outerPlanState(nlstate) = ExecInitNode(outerPlan(node), estate, eflags);
    if (node->nestParams == NIL)
        eflags |= EXEC_FLAG_REWIND;
    else
        eflags &= ~EXEC_FLAG_REWIND;
    innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, eflags);

    /*
     * tuple table initialization
     */
    ExecInitResultTupleSlot(estate, &nlstate->js.ps);

    switch (node->join.jointype)
    {
        case JOIN_INNER:
        case JOIN_SEMI:
            break;
        case JOIN_LEFT:
        case JOIN_ANTI:
            nlstate->nl_NullInnerTupleSlot =
                ExecInitNullTupleSlot(estate,
                                 ExecGetResultType(innerPlanState(nlstate)));
            break;
        default:
            elog(ERROR, "unrecognized join type: %d",
                 (int) node->join.jointype);
    }

    /*
     * initialize tuple type and projection info
     */
    ExecAssignResultTypeFromTL(&nlstate->js.ps);
    ExecAssignProjectionInfo(&nlstate->js.ps, NULL);

    /*
     * finally, wipe the current outer tuple clean.
     */
    nlstate->js.ps.ps_TupFromTlist = false;
    nlstate->nl_NeedNewOuter = true;
    nlstate->nl_MatchedOuter = false;

    NL1_printf("ExecInitNestLoop: %s\n",
               "node initialized");

    return nlstate;
}

TupleTableSlot* ExecNestLoop ( NestLoopState node  ) 

Definition at line 60 of file nodeNestloop.c.

References Assert, bms_add_member(), PlanState::chgParam, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, ExprContext::ecxt_param_exec_vals, ENL1_printf, ExecProcNode(), ExecProject(), ExecQual(), ExecReScan(), ExprEndResult, ExprMultipleResult, innerPlanState, InstrCountFiltered1, InstrCountFiltered2, IsA, ParamExecData::isnull, JOIN_ANTI, JOIN_LEFT, JOIN_SEMI, JoinState::joinqual, JoinState::jointype, NestLoopState::js, lfirst, NestLoop::nestParams, NIL, NestLoopState::nl_MatchedOuter, NestLoopState::nl_NeedNewOuter, NestLoopState::nl_NullInnerTupleSlot, OUTER_VAR, outerPlanState, NestLoopParam::paramno, NestLoopParam::paramval, PlanState::plan, JoinState::ps, PlanState::ps_ExprContext, PlanState::ps_ProjInfo, PlanState::ps_TupFromTlist, PlanState::qual, ResetExprContext, slot_getattr(), TupIsNull, ParamExecData::value, Var::varattno, and Var::varno.

Referenced by ExecProcNode().

{
    NestLoop   *nl;
    PlanState  *innerPlan;
    PlanState  *outerPlan;
    TupleTableSlot *outerTupleSlot;
    TupleTableSlot *innerTupleSlot;
    List       *joinqual;
    List       *otherqual;
    ExprContext *econtext;
    ListCell   *lc;

    /*
     * get information from the node
     */
    ENL1_printf("getting info from node");

    nl = (NestLoop *) node->js.ps.plan;
    joinqual = node->js.joinqual;
    otherqual = node->js.ps.qual;
    outerPlan = outerPlanState(node);
    innerPlan = innerPlanState(node);
    econtext = node->js.ps.ps_ExprContext;

    /*
     * 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 (node->js.ps.ps_TupFromTlist)
    {
        TupleTableSlot *result;
        ExprDoneCond isDone;

        result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
        if (isDone == ExprMultipleResult)
            return result;
        /* Done with that source tuple... */
        node->js.ps.ps_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 (node->nl_NeedNewOuter)
        {
            ENL1_printf("getting new outer tuple");
            outerTupleSlot = ExecProcNode(outerPlan);

            /*
             * 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");
            econtext->ecxt_outertuple = outerTupleSlot;
            node->nl_NeedNewOuter = false;
            node->nl_MatchedOuter = false;

            /*
             * fetch the values of any outer Vars that must be passed to the
             * inner scan, and store them in the appropriate PARAM_EXEC slots.
             */
            foreach(lc, nl->nestParams)
            {
                NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
                int         paramno = nlp->paramno;
                ParamExecData *prm;

                prm = &(econtext->ecxt_param_exec_vals[paramno]);
                /* Param value should be an OUTER_VAR var */
                Assert(IsA(nlp->paramval, Var));
                Assert(nlp->paramval->varno == OUTER_VAR);
                Assert(nlp->paramval->varattno > 0);
                prm->value = slot_getattr(outerTupleSlot,
                                          nlp->paramval->varattno,
                                          &(prm->isnull));
                /* Flag parameter value as changed */
                innerPlan->chgParam = bms_add_member(innerPlan->chgParam,
                                                     paramno);
            }

            /*
             * now rescan the inner plan
             */
            ENL1_printf("rescanning inner plan");
            ExecReScan(innerPlan);
        }

        /*
         * we have an outerTuple, try to get the next inner tuple.
         */
        ENL1_printf("getting new inner tuple");

        innerTupleSlot = ExecProcNode(innerPlan);
        econtext->ecxt_innertuple = innerTupleSlot;

        if (TupIsNull(innerTupleSlot))
        {
            ENL1_printf("no inner tuple, need new outer tuple");

            node->nl_NeedNewOuter = true;

            if (!node->nl_MatchedOuter &&
                (node->js.jointype == JOIN_LEFT ||
                 node->js.jointype == JOIN_ANTI))
            {
                /*
                 * 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 = node->nl_NullInnerTupleSlot;

                ENL1_printf("testing qualification for outer-join tuple");

                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(node->js.ps.ps_ProjInfo, &isDone);

                    if (isDone != ExprEndResult)
                    {
                        node->js.ps.ps_TupFromTlist =
                            (isDone == ExprMultipleResult);
                        return result;
                    }
                }
                else
                    InstrCountFiltered2(node, 1);
            }

            /*
             * 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))
        {
            node->nl_MatchedOuter = true;

            /* In an antijoin, we never return a matched tuple */
            if (node->js.jointype == JOIN_ANTI)
            {
                node->nl_NeedNewOuter = true;
                continue;       /* return to top of loop */
            }

            /*
             * In a semijoin, we'll consider returning the first match, but
             * after that we're done with this outer tuple.
             */
            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");

                result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);

                if (isDone != ExprEndResult)
                {
                    node->js.ps.ps_TupFromTlist =
                        (isDone == ExprMultipleResult);
                    return result;
                }
            }
            else
                InstrCountFiltered2(node, 1);
        }
        else
            InstrCountFiltered1(node, 1);

        /*
         * Tuple fails qual, so free per-tuple memory and try again.
         */
        ResetExprContext(econtext);

        ENL1_printf("qualification failed, looping");
    }
}

void ExecReScanNestLoop ( NestLoopState node  ) 

Definition at line 427 of file nodeNestloop.c.

References PlanState::chgParam, ExecReScan(), NestLoopState::js, NestLoopState::nl_MatchedOuter, NestLoopState::nl_NeedNewOuter, NULL, outerPlan, outerPlanState, JoinState::ps, and PlanState::ps_TupFromTlist.

Referenced by ExecReScan().

{
    PlanState  *outerPlan = outerPlanState(node);

    /*
     * If outerPlan->chgParam is not null then plan will be automatically
     * re-scanned by first ExecProcNode.
     */
    if (outerPlan->chgParam == NULL)
        ExecReScan(outerPlan);

    /*
     * 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...
     */

    node->js.ps.ps_TupFromTlist = false;
    node->nl_NeedNewOuter = true;
    node->nl_MatchedOuter = false;
}