Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/test/modules/test_slru/sql/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 2 kB image not shown  

Quelle  nodeNestloop.c   Sprache: unbekannt

 
/*-------------------------------------------------------------------------
 *
 * nodeNestloop.c
 *   routines to support nest-loop joins
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *   src/backend/executor/nodeNestloop.c
 *
 *-------------------------------------------------------------------------
 */

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

static TupleTableSlot *
ExecNestLoop(PlanState *pstate)
{
 NestLoopState *node = castNode(NestLoopState, pstate);
 NestLoop   *nl;
 PlanState  *innerPlan;
 PlanState  *outerPlan;
 TupleTableSlot *outerTupleSlot;
 TupleTableSlot *innerTupleSlot;
 ExprState  *joinqual;
 ExprState  *otherqual;
 ExprContext *econtext;
 ListCell   *lc;

 CHECK_FOR_INTERRUPTS();

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

 /*
  * Reset per-tuple memory context to free any expression evaluation
  * storage allocated in the previous tuple cycle.
 */

 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 == NULL || ExecQual(otherqual, econtext))
    {
     /*
      * qualification was satisfied so we project and return
      * the slot containing the result tuple using
      * ExecProject().
 */

     ENL1_printf("qualification succeeded, projecting tuple");

     return ExecProject(node->js.ps.ps_ProjInfo);
    }
    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))
  {
   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 */
   }

   /*
    * If we only need to join to the first matching inner tuple, then
    * consider returning this one, but after that continue with next
    * outer tuple.
 */

   if (node->js.single_match)
    node->nl_NeedNewOuter = true;

   if (otherqual == NULL || ExecQual(otherqual, econtext))
   {
    /*
     * qualification was satisfied so we project and return the
     * slot containing the result tuple using ExecProject().
 */

    ENL1_printf("qualification succeeded, projecting tuple");

    return ExecProject(node->js.ps.ps_ProjInfo);
   }
   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");
 }
}

/* ----------------------------------------------------------------
 *  ExecInitNestLoop
 * ----------------------------------------------------------------
 */

NestLoopState *
ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
{
 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;
 nlstate->js.ps.ExecProcNode = ExecNestLoop;

 /*
  * Miscellaneous initialization
  *
  * create expression context for node
 */

 ExecAssignExprContext(estate, &nlstate->js.ps);

 /*
  * 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);

 /*
  * Initialize result slot, type and projection.
 */

 ExecInitResultTupleSlotTL(&nlstate->js.ps, &TTSOpsVirtual);
 ExecAssignProjectionInfo(&nlstate->js.ps, NULL);

 /*
  * initialize child expressions
 */

 nlstate->js.ps.qual =
  ExecInitQual(node->join.plan.qual, (PlanState *) nlstate);
 nlstate->js.jointype = node->join.jointype;
 nlstate->js.joinqual =
  ExecInitQual(node->join.joinqual, (PlanState *) nlstate);

 /*
  * detect whether we need only consider the first matching inner tuple
 */

 nlstate->js.single_match = (node->join.inner_unique ||
        node->join.jointype == JOIN_SEMI);

 /* set up null tuples for outer joins, if needed */
 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)),
           &TTSOpsVirtual);
   break;
  default:
   elog(ERROR, "unrecognized join type: %d",
     (int) node->join.jointype);
 }

 /*
  * finally, wipe the current outer tuple clean.
 */

 nlstate->nl_NeedNewOuter = true;
 nlstate->nl_MatchedOuter = false;

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

 return nlstate;
}

/* ----------------------------------------------------------------
 *  ExecEndNestLoop
 *
 *  closes down scans and frees allocated storage
 * ----------------------------------------------------------------
 */

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

 /*
  * close down subplans
 */

 ExecEndNode(outerPlanState(node));
 ExecEndNode(innerPlanState(node));

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

/* ----------------------------------------------------------------
 *  ExecReScanNestLoop
 * ----------------------------------------------------------------
 */

void
ExecReScanNestLoop(NestLoopState *node)
{
 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->nl_NeedNewOuter = true;
 node->nl_MatchedOuter = false;
}

Messung V0.5 in Prozent
C=92 H=96 G=93

[zur Elbe Produktseite wechseln0.15QuellennavigatorsAnalyse erneut starten2026-08-08]