#include "nodes/execnodes.h"

Go to the source code of this file.
Functions | |
| WindowAggState * | ExecInitWindowAgg (WindowAgg *node, EState *estate, int eflags) |
| TupleTableSlot * | ExecWindowAgg (WindowAggState *node) |
| void | ExecEndWindowAgg (WindowAggState *node) |
| void | ExecReScanWindowAgg (WindowAggState *node) |
| void ExecEndWindowAgg | ( | WindowAggState * | node | ) |
Definition at line 1644 of file nodeWindowAgg.c.
References WindowAggState::agg_row_slot, WindowAggState::aggcontext, ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), WindowAggState::first_part_slot, MemoryContextDelete(), outerPlanState, WindowAggState::partcontext, WindowAggState::peragg, WindowAggState::perfunc, pfree(), ScanState::ps, PlanState::ps_ExprContext, release_partition(), WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowAggState::temp_slot_1, WindowAggState::temp_slot_2, and WindowAggState::tmpcontext.
Referenced by ExecEndNode().
{
PlanState *outerPlan;
release_partition(node);
pfree(node->perfunc);
pfree(node->peragg);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
ExecClearTuple(node->first_part_slot);
ExecClearTuple(node->agg_row_slot);
ExecClearTuple(node->temp_slot_1);
ExecClearTuple(node->temp_slot_2);
/*
* Free both the expr contexts.
*/
ExecFreeExprContext(&node->ss.ps);
node->ss.ps.ps_ExprContext = node->tmpcontext;
ExecFreeExprContext(&node->ss.ps);
MemoryContextDelete(node->partcontext);
MemoryContextDelete(node->aggcontext);
outerPlan = outerPlanState(node);
ExecEndNode(outerPlan);
}
| WindowAggState* ExecInitWindowAgg | ( | WindowAgg * | node, | |
| EState * | estate, | |||
| int | eflags | |||
| ) |
Definition at line 1398 of file nodeWindowAgg.c.
References ACL_EXECUTE, ACL_KIND_PROC, aclcheck_error(), ACLCHECK_OK, WindowAggState::agg_row_slot, WindowAggState::agg_winobj, WindowAggState::aggcontext, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), WindowFuncExprState::args, WindowObjectData::argstates, Assert, contain_volatile_functions(), CurrentMemoryContext, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExprContext::ecxt_per_query_memory, elog, WindowAgg::endOffset, equal(), ERROR, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecAssignResultTypeFromTL(), ExecAssignScanTypeFromOuterPlan(), ExecInitExpr(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitResultTupleSlot(), ExecInitScanTupleSlot(), ExecSetSlotDescriptor(), execTuplesMatchPrepare(), ExprState::expr, WindowAggState::first_part_slot, fmgr_info_cxt(), fmgr_info_set_expr, WindowAgg::frameOptions, WindowAggState::frameOptions, WindowAggState::funcs, get_func_name(), get_typlenbyval(), GetUserId(), i, initialize_peragg(), InvokeFunctionExecuteHook, lfirst, list_length(), WindowObjectData::localmem, makeNode, WindowObjectData::markptr, NIL, NULL, WindowAggState::numaggs, WindowAggState::numfuncs, WindowAggState::ordEqfunctions, WindowAgg::ordNumCols, WindowAgg::ordOperators, outerPlan, outerPlanState, palloc0(), WindowAggState::partcontext, WindowAggState::partEqfunctions, WindowAgg::partNumCols, WindowAgg::partOperators, WindowAggState::peragg, WindowAggState::perfunc, pg_proc_aclcheck(), WindowAgg::plan, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, PlanState::ps_TupFromTlist, PlanState::qual, Plan::qual, WindowObjectData::readptr, WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowAgg::startOffset, WindowAggState::startOffset, PlanState::state, Plan::targetlist, PlanState::targetlist, WindowAggState::temp_slot_1, WindowAggState::temp_slot_2, WindowAggState::tmpcontext, TupleTableSlot::tts_tupleDescriptor, WindowStatePerAggData::wfuncno, WindowFuncExprState::wfuncno, WindowFunc::winfnoid, WindowAgg::winref, WindowFunc::winref, WindowObjectData::winstate, and WindowFuncExprState::xprstate.
Referenced by ExecInitNode().
{
WindowAggState *winstate;
Plan *outerPlan;
ExprContext *econtext;
ExprContext *tmpcontext;
WindowStatePerFunc perfunc;
WindowStatePerAgg peragg;
int numfuncs,
wfuncno,
numaggs,
aggno;
ListCell *l;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
/*
* create state structure
*/
winstate = makeNode(WindowAggState);
winstate->ss.ps.plan = (Plan *) node;
winstate->ss.ps.state = estate;
/*
* Create expression contexts. We need two, one for per-input-tuple
* processing and one for per-output-tuple processing. We cheat a little
* by using ExecAssignExprContext() to build both.
*/
ExecAssignExprContext(estate, &winstate->ss.ps);
tmpcontext = winstate->ss.ps.ps_ExprContext;
winstate->tmpcontext = tmpcontext;
ExecAssignExprContext(estate, &winstate->ss.ps);
/* Create long-lived context for storage of partition-local memory etc */
winstate->partcontext =
AllocSetContextCreate(CurrentMemoryContext,
"WindowAgg_Partition",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* Create mid-lived context for aggregate trans values etc */
winstate->aggcontext =
AllocSetContextCreate(CurrentMemoryContext,
"WindowAgg_Aggregates",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/*
* tuple table initialization
*/
ExecInitScanTupleSlot(estate, &winstate->ss);
ExecInitResultTupleSlot(estate, &winstate->ss.ps);
winstate->first_part_slot = ExecInitExtraTupleSlot(estate);
winstate->agg_row_slot = ExecInitExtraTupleSlot(estate);
winstate->temp_slot_1 = ExecInitExtraTupleSlot(estate);
winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate);
winstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->plan.targetlist,
(PlanState *) winstate);
/*
* WindowAgg nodes never have quals, since they can only occur at the
* logical top level of a query (ie, after any WHERE or HAVING filters)
*/
Assert(node->plan.qual == NIL);
winstate->ss.ps.qual = NIL;
/*
* initialize child nodes
*/
outerPlan = outerPlan(node);
outerPlanState(winstate) = ExecInitNode(outerPlan, estate, eflags);
/*
* initialize source tuple type (which is also the tuple type that we'll
* store in the tuplestore and use in all our working slots).
*/
ExecAssignScanTypeFromOuterPlan(&winstate->ss);
ExecSetSlotDescriptor(winstate->first_part_slot,
winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor);
ExecSetSlotDescriptor(winstate->agg_row_slot,
winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor);
ExecSetSlotDescriptor(winstate->temp_slot_1,
winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor);
ExecSetSlotDescriptor(winstate->temp_slot_2,
winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor);
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&winstate->ss.ps);
ExecAssignProjectionInfo(&winstate->ss.ps, NULL);
winstate->ss.ps.ps_TupFromTlist = false;
/* Set up data for comparing tuples */
if (node->partNumCols > 0)
winstate->partEqfunctions = execTuplesMatchPrepare(node->partNumCols,
node->partOperators);
if (node->ordNumCols > 0)
winstate->ordEqfunctions = execTuplesMatchPrepare(node->ordNumCols,
node->ordOperators);
/*
* WindowAgg nodes use aggvalues and aggnulls as well as Agg nodes.
*/
numfuncs = winstate->numfuncs;
numaggs = winstate->numaggs;
econtext = winstate->ss.ps.ps_ExprContext;
econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numfuncs);
econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numfuncs);
/*
* allocate per-wfunc/per-agg state information.
*/
perfunc = (WindowStatePerFunc) palloc0(sizeof(WindowStatePerFuncData) * numfuncs);
peragg = (WindowStatePerAgg) palloc0(sizeof(WindowStatePerAggData) * numaggs);
winstate->perfunc = perfunc;
winstate->peragg = peragg;
wfuncno = -1;
aggno = -1;
foreach(l, winstate->funcs)
{
WindowFuncExprState *wfuncstate = (WindowFuncExprState *) lfirst(l);
WindowFunc *wfunc = (WindowFunc *) wfuncstate->xprstate.expr;
WindowStatePerFunc perfuncstate;
AclResult aclresult;
int i;
if (wfunc->winref != node->winref) /* planner screwed up? */
elog(ERROR, "WindowFunc with winref %u assigned to WindowAgg with winref %u",
wfunc->winref, node->winref);
/* Look for a previous duplicate window function */
for (i = 0; i <= wfuncno; i++)
{
if (equal(wfunc, perfunc[i].wfunc) &&
!contain_volatile_functions((Node *) wfunc))
break;
}
if (i <= wfuncno)
{
/* Found a match to an existing entry, so just mark it */
wfuncstate->wfuncno = i;
continue;
}
/* Nope, so assign a new PerAgg record */
perfuncstate = &perfunc[++wfuncno];
/* Mark WindowFunc state node with assigned index in the result array */
wfuncstate->wfuncno = wfuncno;
/* Check permission to call window function */
aclresult = pg_proc_aclcheck(wfunc->winfnoid, GetUserId(),
ACL_EXECUTE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_PROC,
get_func_name(wfunc->winfnoid));
InvokeFunctionExecuteHook(wfunc->winfnoid);
/* Fill in the perfuncstate data */
perfuncstate->wfuncstate = wfuncstate;
perfuncstate->wfunc = wfunc;
perfuncstate->numArguments = list_length(wfuncstate->args);
fmgr_info_cxt(wfunc->winfnoid, &perfuncstate->flinfo,
econtext->ecxt_per_query_memory);
fmgr_info_set_expr((Node *) wfunc, &perfuncstate->flinfo);
perfuncstate->winCollation = wfunc->inputcollid;
get_typlenbyval(wfunc->wintype,
&perfuncstate->resulttypeLen,
&perfuncstate->resulttypeByVal);
/*
* If it's really just a plain aggregate function, we'll emulate the
* Agg environment for it.
*/
perfuncstate->plain_agg = wfunc->winagg;
if (wfunc->winagg)
{
WindowStatePerAgg peraggstate;
perfuncstate->aggno = ++aggno;
peraggstate = &winstate->peragg[aggno];
initialize_peragg(winstate, wfunc, peraggstate);
peraggstate->wfuncno = wfuncno;
}
else
{
WindowObject winobj = makeNode(WindowObjectData);
winobj->winstate = winstate;
winobj->argstates = wfuncstate->args;
winobj->localmem = NULL;
perfuncstate->winobj = winobj;
}
}
/* Update numfuncs, numaggs to match number of unique functions found */
winstate->numfuncs = wfuncno + 1;
winstate->numaggs = aggno + 1;
/* Set up WindowObject for aggregates, if needed */
if (winstate->numaggs > 0)
{
WindowObject agg_winobj = makeNode(WindowObjectData);
agg_winobj->winstate = winstate;
agg_winobj->argstates = NIL;
agg_winobj->localmem = NULL;
/* make sure markptr = -1 to invalidate. It may not get used */
agg_winobj->markptr = -1;
agg_winobj->readptr = -1;
winstate->agg_winobj = agg_winobj;
}
/* copy frame options to state node for easy access */
winstate->frameOptions = node->frameOptions;
/* initialize frame bound offset expressions */
winstate->startOffset = ExecInitExpr((Expr *) node->startOffset,
(PlanState *) winstate);
winstate->endOffset = ExecInitExpr((Expr *) node->endOffset,
(PlanState *) winstate);
winstate->all_first = true;
winstate->partition_spooled = false;
winstate->more_partitions = false;
return winstate;
}
| void ExecReScanWindowAgg | ( | WindowAggState * | node | ) |
Definition at line 1678 of file nodeWindowAgg.c.
References WindowAggState::agg_row_slot, WindowAggState::all_done, WindowAggState::all_first, PlanState::chgParam, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecClearTuple(), ExecReScan(), WindowAggState::first_part_slot, PlanState::lefttree, MemSet, NULL, WindowAggState::numfuncs, ScanState::ps, PlanState::ps_ExprContext, PlanState::ps_TupFromTlist, release_partition(), WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowAggState::temp_slot_1, and WindowAggState::temp_slot_2.
Referenced by ExecReScan().
{
ExprContext *econtext = node->ss.ps.ps_ExprContext;
node->all_done = false;
node->ss.ps.ps_TupFromTlist = false;
node->all_first = true;
/* release tuplestore et al */
release_partition(node);
/* release all temp tuples, but especially first_part_slot */
ExecClearTuple(node->ss.ss_ScanTupleSlot);
ExecClearTuple(node->first_part_slot);
ExecClearTuple(node->agg_row_slot);
ExecClearTuple(node->temp_slot_1);
ExecClearTuple(node->temp_slot_2);
/* Forget current wfunc values */
MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numfuncs);
MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numfuncs);
/*
* if chgParam of subnode is not null then plan will be re-scanned by
* first ExecProcNode.
*/
if (node->ss.ps.lefttree->chgParam == NULL)
ExecReScan(node->ss.ps.lefttree);
}
| TupleTableSlot* ExecWindowAgg | ( | WindowAggState * | node | ) |
Definition at line 1190 of file nodeWindowAgg.c.
References WindowAggState::all_done, WindowAggState::all_first, Assert, begin_partition(), WindowAggState::buffer, WindowAggState::current_ptr, WindowAggState::currentpos, datumCopy(), DatumGetInt64, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExprContext::ecxt_outertuple, elog, WindowAggState::endOffset, WindowAggState::endOffsetValue, ereport, errcode(), errmsg(), ERROR, eval_windowaggregates(), eval_windowfunction(), ExecEvalExprSwitchContext(), ExecProject(), ExprState::expr, ExprEndResult, ExprMultipleResult, exprType(), WindowAggState::framehead_valid, FRAMEOPTION_END_VALUE, FRAMEOPTION_ROWS, FRAMEOPTION_START_VALUE, WindowAggState::frameOptions, WindowAggState::frametail_valid, get_typlenbyval(), i, WindowAggState::more_partitions, NULL, WindowAggState::numaggs, WindowAggState::numfuncs, WindowAggState::partition_spooled, WindowAggState::perfunc, WindowStatePerFuncData::plain_agg, ScanState::ps, PlanState::ps_ExprContext, PlanState::ps_ProjInfo, PlanState::ps_TupFromTlist, release_partition(), ResetExprContext, spool_tuples(), WindowAggState::spooled_rows, WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowAggState::startOffset, WindowAggState::startOffsetValue, tuplestore_gettupleslot(), tuplestore_select_read_pointer(), tuplestore_trim(), value, WindowFuncExprState::wfuncno, and WindowStatePerFuncData::wfuncstate.
Referenced by ExecProcNode().
{
TupleTableSlot *result;
ExprDoneCond isDone;
ExprContext *econtext;
int i;
int numfuncs;
if (winstate->all_done)
return NULL;
/*
* Check to see if we're still projecting out tuples from a previous
* output tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
*/
if (winstate->ss.ps.ps_TupFromTlist)
{
TupleTableSlot *result;
ExprDoneCond isDone;
result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return result;
/* Done with that source tuple... */
winstate->ss.ps.ps_TupFromTlist = false;
}
/*
* Compute frame offset values, if any, during first call.
*/
if (winstate->all_first)
{
int frameOptions = winstate->frameOptions;
ExprContext *econtext = winstate->ss.ps.ps_ExprContext;
Datum value;
bool isnull;
int16 len;
bool byval;
if (frameOptions & FRAMEOPTION_START_VALUE)
{
Assert(winstate->startOffset != NULL);
value = ExecEvalExprSwitchContext(winstate->startOffset,
econtext,
&isnull,
NULL);
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("frame starting offset must not be null")));
/* copy value into query-lifespan context */
get_typlenbyval(exprType((Node *) winstate->startOffset->expr),
&len, &byval);
winstate->startOffsetValue = datumCopy(value, byval, len);
if (frameOptions & FRAMEOPTION_ROWS)
{
/* value is known to be int8 */
int64 offset = DatumGetInt64(value);
if (offset < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("frame starting offset must not be negative")));
}
}
if (frameOptions & FRAMEOPTION_END_VALUE)
{
Assert(winstate->endOffset != NULL);
value = ExecEvalExprSwitchContext(winstate->endOffset,
econtext,
&isnull,
NULL);
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("frame ending offset must not be null")));
/* copy value into query-lifespan context */
get_typlenbyval(exprType((Node *) winstate->endOffset->expr),
&len, &byval);
winstate->endOffsetValue = datumCopy(value, byval, len);
if (frameOptions & FRAMEOPTION_ROWS)
{
/* value is known to be int8 */
int64 offset = DatumGetInt64(value);
if (offset < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("frame ending offset must not be negative")));
}
}
winstate->all_first = false;
}
restart:
if (winstate->buffer == NULL)
{
/* Initialize for first partition and set current row = 0 */
begin_partition(winstate);
/* If there are no input rows, we'll detect that and exit below */
}
else
{
/* Advance current row within partition */
winstate->currentpos++;
/* This might mean that the frame moves, too */
winstate->framehead_valid = false;
winstate->frametail_valid = false;
}
/*
* Spool all tuples up to and including the current row, if we haven't
* already
*/
spool_tuples(winstate, winstate->currentpos);
/* Move to the next partition if we reached the end of this partition */
if (winstate->partition_spooled &&
winstate->currentpos >= winstate->spooled_rows)
{
release_partition(winstate);
if (winstate->more_partitions)
{
begin_partition(winstate);
Assert(winstate->spooled_rows > 0);
}
else
{
winstate->all_done = true;
return NULL;
}
}
/* final output execution is in ps_ExprContext */
econtext = winstate->ss.ps.ps_ExprContext;
/* Clear the per-output-tuple context for current row */
ResetExprContext(econtext);
/*
* Read the current row from the tuplestore, and save in ScanTupleSlot.
* (We can't rely on the outerplan's output slot because we may have to
* read beyond the current row. Also, we have to actually copy the row
* out of the tuplestore, since window function evaluation might cause the
* tuplestore to dump its state to disk.)
*
* Current row must be in the tuplestore, since we spooled it above.
*/
tuplestore_select_read_pointer(winstate->buffer, winstate->current_ptr);
if (!tuplestore_gettupleslot(winstate->buffer, true, true,
winstate->ss.ss_ScanTupleSlot))
elog(ERROR, "unexpected end of tuplestore");
/*
* Evaluate true window functions
*/
numfuncs = winstate->numfuncs;
for (i = 0; i < numfuncs; i++)
{
WindowStatePerFunc perfuncstate = &(winstate->perfunc[i]);
if (perfuncstate->plain_agg)
continue;
eval_windowfunction(winstate, perfuncstate,
&(econtext->ecxt_aggvalues[perfuncstate->wfuncstate->wfuncno]),
&(econtext->ecxt_aggnulls[perfuncstate->wfuncstate->wfuncno]));
}
/*
* Evaluate aggregates
*/
if (winstate->numaggs > 0)
eval_windowaggregates(winstate);
/*
* Truncate any no-longer-needed rows from the tuplestore.
*/
tuplestore_trim(winstate->buffer);
/*
* Form and return a projection tuple using the windowfunc results and the
* current row. Setting ecxt_outertuple arranges that any Vars will be
* evaluated with respect to that row.
*/
econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
result = ExecProject(winstate->ss.ps.ps_ProjInfo, &isDone);
if (isDone == ExprEndResult)
{
/* SRF in tlist returned no rows, so advance to next input tuple */
goto restart;
}
winstate->ss.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
1.7.1