Quelle nodeProjectSet.c
Sprache: C
/*-------------------------------------------------------------------------
*
* nodeProjectSet . c
* support for evaluating targetlists containing set - returning functions
*
* DESCRIPTION
*
* ProjectSet nodes are inserted by the planner to evaluate set - returning
* functions in the targetlist . It ' s guaranteed that all set - returning
* functions are directly at the top level of the targetlist , i . e . they
* can ' t be inside more - complex expressions . If that ' d otherwise be
* the case , the planner adds additional ProjectSet nodes .
*
* Portions Copyright ( c ) 1996 - 2025 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
* IDENTIFICATION
* src / backend / executor / nodeProjectSet . c
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#include "postgres.h"
#include "executor/executor.h"
#include "executor/nodeProjectSet.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
/* ----------------------------------------------------------------
* ExecProjectSet ( node )
*
* Return tuples after evaluating the targetlist ( which contains set
* returning functions ) .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
static TupleTableSlot *
ExecProjectSet(PlanState *pstate)
{
ProjectSetState *node = castNode(ProjectSetState, pstate);
TupleTableSlot *outerTupleSlot;
TupleTableSlot *resultSlot;
PlanState *outerPlan;
ExprContext *econtext;
CHECK_FOR_INTERRUPTS();
econtext = node->ps.ps_ExprContext;
/*
* Reset per - tuple context to free expression - evaluation storage allocated
* for a potentially previously returned tuple . Note that the SRF argument
* context has a different lifetime and is reset below .
*/
ResetExprContext(econtext);
/*
* Check to see if we ' re still projecting out tuples from a previous scan
* tuple ( because there is a function - returning - set in the projection
* expressions ) . If so , try to project another one .
*/
if (node->pending_srf_tuples)
{
resultSlot = ExecProjectSRF(node, true );
if (resultSlot != NULL)
return resultSlot;
}
/*
* Get another input tuple and project SRFs from it .
*/
for (;;)
{
/*
* Reset argument 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 scan tuple , as
* ValuePerCall functions are allowed to reference the arguments for
* each returned tuple . However , if we loop around after finding that
* no rows are produced from a scan tuple , we should reset , to avoid
* leaking memory when many successive scan tuples produce no rows .
*/
MemoryContextReset(node->argcontext);
/*
* Retrieve tuples from the outer plan until there are no more .
*/
outerPlan = outerPlanState(node);
outerTupleSlot = ExecProcNode(outerPlan);
if (TupIsNull(outerTupleSlot))
return NULL;
/*
* Prepare to compute projection expressions , which will expect to
* access the input tuples as varno OUTER .
*/
econtext->ecxt_outertuple = outerTupleSlot;
/* Evaluate the expressions */
resultSlot = ExecProjectSRF(node, false );
/*
* Return the tuple unless the projection produced no rows ( due to an
* empty set ) , in which case we must loop back to see if there are
* more outerPlan tuples .
*/
if (resultSlot)
return resultSlot;
/*
* When we do loop back , we ' d better reset the econtext again , just in
* case the SRF leaked some memory there .
*/
ResetExprContext(econtext);
}
return NULL;
}
/* ----------------------------------------------------------------
* ExecProjectSRF
*
* Project a targetlist containing one or more set - returning functions .
*
* ' continuing ' indicates whether to continue projecting rows for the
* same input tuple ; or whether a new input tuple is being projected .
*
* Returns NULL if no output tuple has been produced .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
static TupleTableSlot *
ExecProjectSRF(ProjectSetState *node, bool continuing)
{
TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot;
ExprContext *econtext = node->ps.ps_ExprContext;
MemoryContext oldcontext;
bool hassrf PG_USED_FOR_ASSERTS_ONLY;
bool hasresult;
int argno;
ExecClearTuple(resultSlot);
/* Call SRFs, as well as plain expressions, in per-tuple context */
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
/*
* Assume no further tuples are produced unless an ExprMultipleResult is
* encountered from a set returning function .
*/
node->pending_srf_tuples = false ;
hassrf = hasresult = false ;
for (argno = 0 ; argno < node->nelems; argno++)
{
Node *elem = node->elems[argno];
ExprDoneCond *isdone = &node->elemdone[argno];
Datum *result = &resultSlot->tts_values[argno];
bool *isnull = &resultSlot->tts_isnull[argno];
if (continuing && *isdone == ExprEndResult)
{
/*
* If we ' re continuing to project output rows from a source tuple ,
* return NULLs once the SRF has been exhausted .
*/
*result = (Datum) 0 ;
*isnull = true ;
hassrf = true ;
}
else if (IsA(elem, SetExprState))
{
/*
* Evaluate SRF - possibly continuing previously started output .
*/
*result = ExecMakeFunctionResultSet((SetExprState *) elem,
econtext, node->argcontext,
isnull, isdone);
if (*isdone != ExprEndResult)
hasresult = true ;
if (*isdone == ExprMultipleResult)
node->pending_srf_tuples = true ;
hassrf = true ;
}
else
{
/* Non-SRF tlist expression, just evaluate normally. */
*result = ExecEvalExpr((ExprState *) elem, econtext, isnull);
*isdone = ExprSingleResult;
}
}
MemoryContextSwitchTo(oldcontext);
/* ProjectSet should not be used if there's no SRFs */
Assert(hassrf);
/*
* If all the SRFs returned ExprEndResult , we consider that as no row
* being produced .
*/
if (hasresult)
{
ExecStoreVirtualTuple(resultSlot);
return resultSlot;
}
return NULL;
}
/* ----------------------------------------------------------------
* ExecInitProjectSet
*
* Creates the run - time state information for the ProjectSet node
* produced by the planner and initializes outer relations
* ( child nodes ) .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
ProjectSetState *
ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
{
ProjectSetState *state;
ListCell *lc;
int off;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)));
/*
* create state structure
*/
state = makeNode(ProjectSetState);
state->ps.plan = (Plan *) node;
state->ps.state = estate;
state->ps.ExecProcNode = ExecProjectSet;
state->pending_srf_tuples = false ;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &state->ps);
/*
* initialize child nodes
*/
outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
/*
* we don ' t use inner plan
*/
Assert(innerPlan(node) == NULL);
/*
* tuple table and result type initialization
*/
ExecInitResultTupleSlotTL(&state->ps, &TTSOpsVirtual);
/* Create workspace for per-tlist-entry expr state & SRF-is-done state */
state->nelems = list_length(node->plan.targetlist);
state->elems = (Node **)
palloc(sizeof (Node *) * state->nelems);
state->elemdone = (ExprDoneCond *)
palloc(sizeof (ExprDoneCond) * state->nelems);
/*
* Build expressions to evaluate targetlist . We can ' t use
* ExecBuildProjectionInfo here , since that doesn ' t deal with SRFs .
* Instead compile each expression separately , using
* ExecInitFunctionResultSet where applicable .
*/
off = 0 ;
foreach(lc, node->plan.targetlist)
{
TargetEntry *te = (TargetEntry *) lfirst(lc);
Expr *expr = te->expr;
if ((IsA(expr, FuncExpr) && ((FuncExpr *) expr)->funcretset) ||
(IsA(expr, OpExpr) && ((OpExpr *) expr)->opretset))
{
state->elems[off] = (Node *)
ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext,
&state->ps);
}
else
{
Assert(!expression_returns_set((Node *) expr));
state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps);
}
off++;
}
/* We don't support any qual on ProjectSet nodes */
Assert(node->plan.qual == NIL);
/*
* Create a memory context that ExecMakeFunctionResultSet can use to
* evaluate function arguments in . We can ' t use the per - tuple context for
* this because it gets reset too often ; but we don ' t want to leak
* evaluation results into the query - lifespan context either . We use one
* context for the arguments of all tSRFs , as they have roughly equivalent
* lifetimes .
*/
state->argcontext = AllocSetContextCreate(CurrentMemoryContext,
"tSRF function arguments" ,
ALLOCSET_DEFAULT_SIZES);
return state;
}
/* ----------------------------------------------------------------
* ExecEndProjectSet
*
* frees up storage allocated through C routines
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
ExecEndProjectSet(ProjectSetState *node)
{
/*
* shut down subplans
*/
ExecEndNode(outerPlanState(node));
}
void
ExecReScanProjectSet(ProjectSetState *node)
{
PlanState *outerPlan = outerPlanState(node);
/* Forget any incompletely-evaluated SRFs */
node->pending_srf_tuples = false ;
/*
* If chgParam of subnode is not null then plan will be re - scanned by
* first ExecProcNode .
*/
if (outerPlan->chgParam == NULL)
ExecReScan(outerPlan);
}
Messung V0.5 in Prozent C=92 H=95 G=93
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland
2026-08-25
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=141584
#Domains=752002