PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeWindowAgg.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "executor/executor.h"
#include "executor/nodeWindowAgg.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "windowapi.h"
Include dependency graph for nodeWindowAgg.c:

Go to the source code of this file.

Data Structures

struct  WindowObjectData
 
struct  WindowStatePerFuncData
 
struct  WindowStatePerAggData
 

Typedefs

typedef struct WindowObjectData WindowObjectData
 
typedef struct
WindowStatePerFuncData 
WindowStatePerFuncData
 
typedef struct
WindowStatePerAggData 
WindowStatePerAggData
 

Functions

static void initialize_windowaggregate (WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate)
 
static void advance_windowaggregate (WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate)
 
static bool advance_windowaggregate_base (WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate)
 
static void finalize_windowaggregate (WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate, Datum *result, bool *isnull)
 
static void eval_windowaggregates (WindowAggState *winstate)
 
static void eval_windowfunction (WindowAggState *winstate, WindowStatePerFunc perfuncstate, Datum *result, bool *isnull)
 
static void begin_partition (WindowAggState *winstate)
 
static void spool_tuples (WindowAggState *winstate, int64 pos)
 
static void release_partition (WindowAggState *winstate)
 
static bool row_is_in_frame (WindowAggState *winstate, int64 pos, TupleTableSlot *slot)
 
static void update_frameheadpos (WindowObject winobj, TupleTableSlot *slot)
 
static void update_frametailpos (WindowObject winobj, TupleTableSlot *slot)
 
static WindowStatePerAggDatainitialize_peragg (WindowAggState *winstate, WindowFunc *wfunc, WindowStatePerAgg peraggstate)
 
static Datum GetAggInitVal (Datum textInitVal, Oid transtype)
 
static bool are_peers (WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
 
static bool window_gettupleslot (WindowObject winobj, int64 pos, TupleTableSlot *slot)
 
TupleTableSlotExecWindowAgg (WindowAggState *winstate)
 
WindowAggStateExecInitWindowAgg (WindowAgg *node, EState *estate, int eflags)
 
void ExecEndWindowAgg (WindowAggState *node)
 
void ExecReScanWindowAgg (WindowAggState *node)
 
void * WinGetPartitionLocalMemory (WindowObject winobj, Size sz)
 
int64 WinGetCurrentPosition (WindowObject winobj)
 
int64 WinGetPartitionRowCount (WindowObject winobj)
 
void WinSetMarkPosition (WindowObject winobj, int64 markpos)
 
bool WinRowsArePeers (WindowObject winobj, int64 pos1, int64 pos2)
 
Datum WinGetFuncArgInPartition (WindowObject winobj, int argno, int relpos, int seektype, bool set_mark, bool *isnull, bool *isout)
 
Datum WinGetFuncArgInFrame (WindowObject winobj, int argno, int relpos, int seektype, bool set_mark, bool *isnull, bool *isout)
 
Datum WinGetFuncArgCurrent (WindowObject winobj, int argno, bool *isnull)
 

Typedef Documentation

Function Documentation

static void advance_windowaggregate ( WindowAggState winstate,
WindowStatePerFunc  perfuncstate,
WindowStatePerAgg  peraggstate 
)
static

Definition at line 238 of file nodeWindowAgg.c.

References WindowStatePerAggData::aggcontext, WindowFuncExprState::aggfilter, arg, FunctionCallInfoData::arg, FunctionCallInfoData::argnull, WindowFuncExprState::args, Assert, WindowAggState::curaggcontext, CurrentMemoryContext, datumCopy(), DatumGetBool, DatumGetEOHP(), DatumGetPointer, DatumIsReadWriteExpandedObject, DeleteExpandedObject(), ExprContext::ecxt_per_tuple_memory, ereport, errcode(), errmsg(), ERROR, ExecEvalExpr(), FmgrInfo::fn_strict, FunctionCallInvoke, i, InitFunctionCallInfoData, WindowStatePerAggData::invtransfn_oid, FunctionCallInfoData::isnull, lfirst, MemoryContextGetParent(), MemoryContextSwitchTo(), NULL, WindowStatePerFuncData::numArguments, OidIsValid, pfree(), WindowAggState::tmpcontext, WindowStatePerAggData::transfn, WindowStatePerAggData::transtypeByVal, WindowStatePerAggData::transtypeLen, WindowStatePerAggData::transValue, WindowStatePerAggData::transValueCount, WindowStatePerAggData::transValueIsNull, WindowStatePerFuncData::wfuncstate, and WindowStatePerFuncData::winCollation.

Referenced by eval_windowaggregates().

241 {
242  WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
243  int numArguments = perfuncstate->numArguments;
244  FunctionCallInfoData fcinfodata;
245  FunctionCallInfo fcinfo = &fcinfodata;
246  Datum newVal;
247  ListCell *arg;
248  int i;
249  MemoryContext oldContext;
250  ExprContext *econtext = winstate->tmpcontext;
251  ExprState *filter = wfuncstate->aggfilter;
252 
253  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
254 
255  /* Skip anything FILTERed out */
256  if (filter)
257  {
258  bool isnull;
259  Datum res = ExecEvalExpr(filter, econtext, &isnull);
260 
261  if (isnull || !DatumGetBool(res))
262  {
263  MemoryContextSwitchTo(oldContext);
264  return;
265  }
266  }
267 
268  /* We start from 1, since the 0th arg will be the transition value */
269  i = 1;
270  foreach(arg, wfuncstate->args)
271  {
272  ExprState *argstate = (ExprState *) lfirst(arg);
273 
274  fcinfo->arg[i] = ExecEvalExpr(argstate, econtext,
275  &fcinfo->argnull[i]);
276  i++;
277  }
278 
279  if (peraggstate->transfn.fn_strict)
280  {
281  /*
282  * For a strict transfn, nothing happens when there's a NULL input; we
283  * just keep the prior transValue. Note transValueCount doesn't
284  * change either.
285  */
286  for (i = 1; i <= numArguments; i++)
287  {
288  if (fcinfo->argnull[i])
289  {
290  MemoryContextSwitchTo(oldContext);
291  return;
292  }
293  }
294 
295  /*
296  * For strict transition functions with initial value NULL we use the
297  * first non-NULL input as the initial state. (We already checked
298  * that the agg's input type is binary-compatible with its transtype,
299  * so straight copy here is OK.)
300  *
301  * We must copy the datum into aggcontext if it is pass-by-ref. We do
302  * not need to pfree the old transValue, since it's NULL.
303  */
304  if (peraggstate->transValueCount == 0 && peraggstate->transValueIsNull)
305  {
306  MemoryContextSwitchTo(peraggstate->aggcontext);
307  peraggstate->transValue = datumCopy(fcinfo->arg[1],
308  peraggstate->transtypeByVal,
309  peraggstate->transtypeLen);
310  peraggstate->transValueIsNull = false;
311  peraggstate->transValueCount = 1;
312  MemoryContextSwitchTo(oldContext);
313  return;
314  }
315 
316  if (peraggstate->transValueIsNull)
317  {
318  /*
319  * Don't call a strict function with NULL inputs. Note it is
320  * possible to get here despite the above tests, if the transfn is
321  * strict *and* returned a NULL on a prior cycle. If that happens
322  * we will propagate the NULL all the way to the end. That can
323  * only happen if there's no inverse transition function, though,
324  * since we disallow transitions back to NULL when there is one.
325  */
326  MemoryContextSwitchTo(oldContext);
327  Assert(!OidIsValid(peraggstate->invtransfn_oid));
328  return;
329  }
330  }
331 
332  /*
333  * OK to call the transition function. Set winstate->curaggcontext while
334  * calling it, for possible use by AggCheckCallContext.
335  */
336  InitFunctionCallInfoData(*fcinfo, &(peraggstate->transfn),
337  numArguments + 1,
338  perfuncstate->winCollation,
339  (void *) winstate, NULL);
340  fcinfo->arg[0] = peraggstate->transValue;
341  fcinfo->argnull[0] = peraggstate->transValueIsNull;
342  winstate->curaggcontext = peraggstate->aggcontext;
343  newVal = FunctionCallInvoke(fcinfo);
344  winstate->curaggcontext = NULL;
345 
346  /*
347  * Moving-aggregate transition functions must not return null, see
348  * advance_windowaggregate_base().
349  */
350  if (fcinfo->isnull && OidIsValid(peraggstate->invtransfn_oid))
351  ereport(ERROR,
352  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
353  errmsg("moving-aggregate transition function must not return null")));
354 
355  /*
356  * We must track the number of rows included in transValue, since to
357  * remove the last input, advance_windowaggregate_base() mustn't call the
358  * inverse transition function, but simply reset transValue back to its
359  * initial value.
360  */
361  peraggstate->transValueCount++;
362 
363  /*
364  * If pass-by-ref datatype, must copy the new value into aggcontext and
365  * free the prior transValue. But if transfn returned a pointer to its
366  * first input, we don't need to do anything. Also, if transfn returned a
367  * pointer to a R/W expanded object that is already a child of the
368  * aggcontext, assume we can adopt that value without copying it.
369  */
370  if (!peraggstate->transtypeByVal &&
371  DatumGetPointer(newVal) != DatumGetPointer(peraggstate->transValue))
372  {
373  if (!fcinfo->isnull)
374  {
375  MemoryContextSwitchTo(peraggstate->aggcontext);
377  false,
378  peraggstate->transtypeLen) &&
380  /* do nothing */ ;
381  else
382  newVal = datumCopy(newVal,
383  peraggstate->transtypeByVal,
384  peraggstate->transtypeLen);
385  }
386  if (!peraggstate->transValueIsNull)
387  {
389  false,
390  peraggstate->transtypeLen))
391  DeleteExpandedObject(peraggstate->transValue);
392  else
393  pfree(DatumGetPointer(peraggstate->transValue));
394  }
395  }
396 
397  MemoryContextSwitchTo(oldContext);
398  peraggstate->transValue = newVal;
399  peraggstate->transValueIsNull = fcinfo->isnull;
400 }
MemoryContext curaggcontext
Definition: execnodes.h:1815
ExprState * aggfilter
Definition: execnodes.h:637
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:403
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
WindowFuncExprState * wfuncstate
Definition: nodeWindowAgg.c:78
#define OidIsValid(objectId)
Definition: c.h:538
ExprContext * tmpcontext
Definition: execnodes.h:1816
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:137
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:265
#define DatumGetBool(X)
Definition: postgres.h:399
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define ereport(elevel, rest)
Definition: elog.h:122
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
uintptr_t Datum
Definition: postgres.h:372
void DeleteExpandedObject(Datum d)
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:120
MemoryContext aggcontext
#define DatumGetPointer(X)
Definition: postgres.h:555
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
void * arg
static bool advance_windowaggregate_base ( WindowAggState winstate,
WindowStatePerFunc  perfuncstate,
WindowStatePerAgg  peraggstate 
)
static

Definition at line 415 of file nodeWindowAgg.c.

References WindowStatePerAggData::aggcontext, WindowFuncExprState::aggfilter, arg, FunctionCallInfoData::arg, FunctionCallInfoData::argnull, WindowFuncExprState::args, Assert, WindowAggState::curaggcontext, CurrentMemoryContext, datumCopy(), DatumGetBool, DatumGetEOHP(), DatumGetPointer, DatumIsReadWriteExpandedObject, DeleteExpandedObject(), ExprContext::ecxt_per_tuple_memory, elog, ERROR, ExecEvalExpr(), FmgrInfo::fn_strict, FunctionCallInvoke, i, InitFunctionCallInfoData, initialize_windowaggregate(), WindowStatePerAggData::invtransfn, FunctionCallInfoData::isnull, lfirst, MemoryContextGetParent(), MemoryContextSwitchTo(), NULL, WindowStatePerFuncData::numArguments, WindowAggState::perfunc, pfree(), WindowAggState::tmpcontext, WindowStatePerAggData::transtypeByVal, WindowStatePerAggData::transtypeLen, WindowStatePerAggData::transValue, WindowStatePerAggData::transValueCount, WindowStatePerAggData::transValueIsNull, WindowStatePerAggData::wfuncno, WindowStatePerFuncData::wfuncstate, and WindowStatePerFuncData::winCollation.

Referenced by eval_windowaggregates().

418 {
419  WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
420  int numArguments = perfuncstate->numArguments;
421  FunctionCallInfoData fcinfodata;
422  FunctionCallInfo fcinfo = &fcinfodata;
423  Datum newVal;
424  ListCell *arg;
425  int i;
426  MemoryContext oldContext;
427  ExprContext *econtext = winstate->tmpcontext;
428  ExprState *filter = wfuncstate->aggfilter;
429 
430  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
431 
432  /* Skip anything FILTERed out */
433  if (filter)
434  {
435  bool isnull;
436  Datum res = ExecEvalExpr(filter, econtext, &isnull);
437 
438  if (isnull || !DatumGetBool(res))
439  {
440  MemoryContextSwitchTo(oldContext);
441  return true;
442  }
443  }
444 
445  /* We start from 1, since the 0th arg will be the transition value */
446  i = 1;
447  foreach(arg, wfuncstate->args)
448  {
449  ExprState *argstate = (ExprState *) lfirst(arg);
450 
451  fcinfo->arg[i] = ExecEvalExpr(argstate, econtext,
452  &fcinfo->argnull[i]);
453  i++;
454  }
455 
456  if (peraggstate->invtransfn.fn_strict)
457  {
458  /*
459  * For a strict (inv)transfn, nothing happens when there's a NULL
460  * input; we just keep the prior transValue. Note transValueCount
461  * doesn't change either.
462  */
463  for (i = 1; i <= numArguments; i++)
464  {
465  if (fcinfo->argnull[i])
466  {
467  MemoryContextSwitchTo(oldContext);
468  return true;
469  }
470  }
471  }
472 
473  /* There should still be an added but not yet removed value */
474  Assert(peraggstate->transValueCount > 0);
475 
476  /*
477  * In moving-aggregate mode, the state must never be NULL, except possibly
478  * before any rows have been aggregated (which is surely not the case at
479  * this point). This restriction allows us to interpret a NULL result
480  * from the inverse function as meaning "sorry, can't do an inverse
481  * transition in this case". We already checked this in
482  * advance_windowaggregate, but just for safety, check again.
483  */
484  if (peraggstate->transValueIsNull)
485  elog(ERROR, "aggregate transition value is NULL before inverse transition");
486 
487  /*
488  * We mustn't use the inverse transition function to remove the last
489  * input. Doing so would yield a non-NULL state, whereas we should be in
490  * the initial state afterwards which may very well be NULL. So instead,
491  * we simply re-initialize the aggregate in this case.
492  */
493  if (peraggstate->transValueCount == 1)
494  {
495  MemoryContextSwitchTo(oldContext);
497  &winstate->perfunc[peraggstate->wfuncno],
498  peraggstate);
499  return true;
500  }
501 
502  /*
503  * OK to call the inverse transition function. Set
504  * winstate->curaggcontext while calling it, for possible use by
505  * AggCheckCallContext.
506  */
507  InitFunctionCallInfoData(*fcinfo, &(peraggstate->invtransfn),
508  numArguments + 1,
509  perfuncstate->winCollation,
510  (void *) winstate, NULL);
511  fcinfo->arg[0] = peraggstate->transValue;
512  fcinfo->argnull[0] = peraggstate->transValueIsNull;
513  winstate->curaggcontext = peraggstate->aggcontext;
514  newVal = FunctionCallInvoke(fcinfo);
515  winstate->curaggcontext = NULL;
516 
517  /*
518  * If the function returns NULL, report failure, forcing a restart.
519  */
520  if (fcinfo->isnull)
521  {
522  MemoryContextSwitchTo(oldContext);
523  return false;
524  }
525 
526  /* Update number of rows included in transValue */
527  peraggstate->transValueCount--;
528 
529  /*
530  * If pass-by-ref datatype, must copy the new value into aggcontext and
531  * free the prior transValue. But if invtransfn returned a pointer to its
532  * first input, we don't need to do anything. Also, if invtransfn
533  * returned a pointer to a R/W expanded object that is already a child of
534  * the aggcontext, assume we can adopt that value without copying it.
535  *
536  * Note: the checks for null values here will never fire, but it seems
537  * best to have this stanza look just like advance_windowaggregate.
538  */
539  if (!peraggstate->transtypeByVal &&
540  DatumGetPointer(newVal) != DatumGetPointer(peraggstate->transValue))
541  {
542  if (!fcinfo->isnull)
543  {
544  MemoryContextSwitchTo(peraggstate->aggcontext);
546  false,
547  peraggstate->transtypeLen) &&
549  /* do nothing */ ;
550  else
551  newVal = datumCopy(newVal,
552  peraggstate->transtypeByVal,
553  peraggstate->transtypeLen);
554  }
555  if (!peraggstate->transValueIsNull)
556  {
558  false,
559  peraggstate->transtypeLen))
560  DeleteExpandedObject(peraggstate->transValue);
561  else
562  pfree(DatumGetPointer(peraggstate->transValue));
563  }
564  }
565 
566  MemoryContextSwitchTo(oldContext);
567  peraggstate->transValue = newVal;
568  peraggstate->transValueIsNull = fcinfo->isnull;
569 
570  return true;
571 }
MemoryContext curaggcontext
Definition: execnodes.h:1815
ExprState * aggfilter
Definition: execnodes.h:637
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:403
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
WindowFuncExprState * wfuncstate
Definition: nodeWindowAgg.c:78
WindowStatePerFunc perfunc
Definition: execnodes.h:1791
ExprContext * tmpcontext
Definition: execnodes.h:1816
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:137
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:265
#define DatumGetBool(X)
Definition: postgres.h:399
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
uintptr_t Datum
Definition: postgres.h:372
static void initialize_windowaggregate(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate)
void DeleteExpandedObject(Datum d)
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:120
MemoryContext aggcontext
#define DatumGetPointer(X)
Definition: postgres.h:555
int i
void * arg
#define elog
Definition: elog.h:219
static bool are_peers ( WindowAggState winstate,
TupleTableSlot slot1,
TupleTableSlot slot2 
)
static

Definition at line 2346 of file nodeWindowAgg.c.

References ExprContext::ecxt_per_tuple_memory, execTuplesMatch(), WindowAgg::ordColIdx, WindowAggState::ordEqfunctions, WindowAgg::ordNumCols, PlanState::plan, ScanState::ps, WindowAggState::ss, and WindowAggState::tmpcontext.

Referenced by row_is_in_frame(), update_frameheadpos(), update_frametailpos(), and WinRowsArePeers().

2348 {
2349  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
2350 
2351  /* If no ORDER BY, all rows are peers with each other */
2352  if (node->ordNumCols == 0)
2353  return true;
2354 
2355  return execTuplesMatch(slot1, slot2,
2356  node->ordNumCols, node->ordColIdx,
2357  winstate->ordEqfunctions,
2358  winstate->tmpcontext->ecxt_per_tuple_memory);
2359 }
int ordNumCols
Definition: plannodes.h:797
ScanState ss
Definition: execnodes.h:1784
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
AttrNumber * ordColIdx
Definition: plannodes.h:798
bool execTuplesMatch(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext)
Definition: execGrouping.c:69
ExprContext * tmpcontext
Definition: execnodes.h:1816
PlanState ps
Definition: execnodes.h:1047
Plan * plan
Definition: execnodes.h:803
FmgrInfo * ordEqfunctions
Definition: execnodes.h:1794
static void begin_partition ( WindowAggState winstate)
static

Definition at line 1061 of file nodeWindowAgg.c.

References WindowAggState::agg_row_slot, WindowAggState::agg_winobj, WindowAggState::aggregatedbase, WindowAggState::aggregatedupto, WindowAggState::buffer, WindowAggState::current_ptr, WindowAggState::currentpos, EXEC_FLAG_BACKWARD, ExecClearTuple(), ExecCopySlot(), ExecProcNode(), WindowAggState::first_part_slot, WindowAggState::framehead_valid, WindowAggState::frameheadpos, FRAMEOPTION_START_UNBOUNDED_PRECEDING, WindowAggState::frameOptions, WindowAggState::frametail_valid, WindowAggState::frametailpos, i, WindowObjectData::markpos, WindowObjectData::markptr, WindowAggState::more_partitions, WindowAggState::numaggs, WindowAggState::numfuncs, outerPlan, outerPlanState, WindowAggState::partition_spooled, WindowAggState::perfunc, WindowStatePerFuncData::plain_agg, WindowObjectData::readptr, WindowObjectData::seekpos, WindowAggState::spooled_rows, TupIsNull, tuplestore_alloc_read_pointer(), tuplestore_begin_heap(), tuplestore_puttupleslot(), tuplestore_set_eflags(), WindowStatePerFuncData::winobj, and work_mem.

Referenced by ExecWindowAgg().

1062 {
1063  PlanState *outerPlan = outerPlanState(winstate);
1064  int numfuncs = winstate->numfuncs;
1065  int i;
1066 
1067  winstate->partition_spooled = false;
1068  winstate->framehead_valid = false;
1069  winstate->frametail_valid = false;
1070  winstate->spooled_rows = 0;
1071  winstate->currentpos = 0;
1072  winstate->frameheadpos = 0;
1073  winstate->frametailpos = -1;
1074  ExecClearTuple(winstate->agg_row_slot);
1075 
1076  /*
1077  * If this is the very first partition, we need to fetch the first input
1078  * row to store in first_part_slot.
1079  */
1080  if (TupIsNull(winstate->first_part_slot))
1081  {
1082  TupleTableSlot *outerslot = ExecProcNode(outerPlan);
1083 
1084  if (!TupIsNull(outerslot))
1085  ExecCopySlot(winstate->first_part_slot, outerslot);
1086  else
1087  {
1088  /* outer plan is empty, so we have nothing to do */
1089  winstate->partition_spooled = true;
1090  winstate->more_partitions = false;
1091  return;
1092  }
1093  }
1094 
1095  /* Create new tuplestore for this partition */
1096  winstate->buffer = tuplestore_begin_heap(false, false, work_mem);
1097 
1098  /*
1099  * Set up read pointers for the tuplestore. The current pointer doesn't
1100  * need BACKWARD capability, but the per-window-function read pointers do,
1101  * and the aggregate pointer does if frame start is movable.
1102  */
1103  winstate->current_ptr = 0; /* read pointer 0 is pre-allocated */
1104 
1105  /* reset default REWIND capability bit for current ptr */
1106  tuplestore_set_eflags(winstate->buffer, 0);
1107 
1108  /* create read pointers for aggregates, if needed */
1109  if (winstate->numaggs > 0)
1110  {
1111  WindowObject agg_winobj = winstate->agg_winobj;
1112  int readptr_flags = 0;
1113 
1114  /* If the frame head is potentially movable ... */
1116  {
1117  /* ... create a mark pointer to track the frame head */
1118  agg_winobj->markptr = tuplestore_alloc_read_pointer(winstate->buffer, 0);
1119  /* and the read pointer will need BACKWARD capability */
1120  readptr_flags |= EXEC_FLAG_BACKWARD;
1121  }
1122 
1123  agg_winobj->readptr = tuplestore_alloc_read_pointer(winstate->buffer,
1124  readptr_flags);
1125  agg_winobj->markpos = -1;
1126  agg_winobj->seekpos = -1;
1127 
1128  /* Also reset the row counters for aggregates */
1129  winstate->aggregatedbase = 0;
1130  winstate->aggregatedupto = 0;
1131  }
1132 
1133  /* create mark and read pointers for each real window function */
1134  for (i = 0; i < numfuncs; i++)
1135  {
1136  WindowStatePerFunc perfuncstate = &(winstate->perfunc[i]);
1137 
1138  if (!perfuncstate->plain_agg)
1139  {
1140  WindowObject winobj = perfuncstate->winobj;
1141 
1142  winobj->markptr = tuplestore_alloc_read_pointer(winstate->buffer,
1143  0);
1144  winobj->readptr = tuplestore_alloc_read_pointer(winstate->buffer,
1146  winobj->markpos = -1;
1147  winobj->seekpos = -1;
1148  }
1149  }
1150 
1151  /*
1152  * Store the first tuple into the tuplestore (it's always available now;
1153  * we either read it above, or saved it at the end of previous partition)
1154  */
1155  tuplestore_puttupleslot(winstate->buffer, winstate->first_part_slot);
1156  winstate->spooled_rows++;
1157 }
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition: tuplestore.c:708
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:398
void tuplestore_set_eflags(Tuplestorestate *state, int eflags)
Definition: tuplestore.c:359
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
int64 aggregatedupto
Definition: execnodes.h:1805
bool frametail_valid
Definition: execnodes.h:1827
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:509
WindowStatePerFunc perfunc
Definition: execnodes.h:1791
TupleTableSlot * first_part_slot
Definition: execnodes.h:1830
struct WindowObjectData * agg_winobj
Definition: execnodes.h:1802
int64 frameheadpos
Definition: execnodes.h:1799
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define outerPlanState(node)
Definition: execnodes.h:845
int64 aggregatedbase
Definition: execnodes.h:1804
#define TupIsNull(slot)
Definition: tuptable.h:138
Tuplestorestate * buffer
Definition: execnodes.h:1795
#define outerPlan(node)
Definition: plannodes.h:164
int64 spooled_rows
Definition: execnodes.h:1797
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:112
TupleTableSlot * agg_row_slot
Definition: execnodes.h:1834
bool more_partitions
Definition: execnodes.h:1823
TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: execTuples.c:795
int64 frametailpos
Definition: execnodes.h:1800
int64 currentpos
Definition: execnodes.h:1798
int tuplestore_alloc_read_pointer(Tuplestorestate *state, int eflags)
Definition: tuplestore.c:383
bool partition_spooled
Definition: execnodes.h:1820
bool framehead_valid
Definition: execnodes.h:1825
int i
static void eval_windowaggregates ( WindowAggState winstate)
static

Definition at line 660 of file nodeWindowAgg.c.

References advance_windowaggregate(), advance_windowaggregate_base(), WindowAggState::agg_row_slot, WindowAggState::agg_winobj, WindowStatePerAggData::aggcontext, WindowAggState::aggcontext, WindowAggState::aggregatedbase, WindowAggState::aggregatedupto, Assert, WindowAggState::currentpos, datumCopy(), DatumGetPointer, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExprContext::ecxt_outertuple, elog, ERROR, ExecClearTuple(), finalize_windowaggregate(), WindowAggState::frameheadpos, FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_END_UNBOUNDED_FOLLOWING, WindowAggState::frameOptions, i, initialize_windowaggregate(), WindowStatePerAggData::invtransfn_oid, WindowObjectData::markptr, MemoryContextResetAndDeleteChildren, MemoryContextSwitchTo(), WindowAggState::numaggs, OidIsValid, WindowAggState::peragg, WindowAggState::perfunc, pfree(), ScanState::ps, PlanState::ps_ExprContext, ResetExprContext, WindowStatePerAggData::restart, result, WindowStatePerAggData::resulttypeByVal, WindowStatePerAggData::resulttypeLen, WindowStatePerAggData::resultValue, WindowStatePerAggData::resultValueIsNull, row_is_in_frame(), WindowAggState::ss, WindowAggState::temp_slot_1, WindowAggState::tmpcontext, TupIsNull, update_frameheadpos(), WindowStatePerAggData::wfuncno, window_gettupleslot(), and WinSetMarkPosition().

Referenced by ExecWindowAgg().

661 {
662  WindowStatePerAgg peraggstate;
663  int wfuncno,
664  numaggs,
665  numaggs_restart,
666  i;
667  int64 aggregatedupto_nonrestarted;
668  MemoryContext oldContext;
669  ExprContext *econtext;
670  WindowObject agg_winobj;
671  TupleTableSlot *agg_row_slot;
672  TupleTableSlot *temp_slot;
673 
674  numaggs = winstate->numaggs;
675  if (numaggs == 0)
676  return; /* nothing to do */
677 
678  /* final output execution is in ps_ExprContext */
679  econtext = winstate->ss.ps.ps_ExprContext;
680  agg_winobj = winstate->agg_winobj;
681  agg_row_slot = winstate->agg_row_slot;
682  temp_slot = winstate->temp_slot_1;
683 
684  /*
685  * Currently, we support only a subset of the SQL-standard window framing
686  * rules.
687  *
688  * If the frame start is UNBOUNDED_PRECEDING, the window frame consists of
689  * a contiguous group of rows extending forward from the start of the
690  * partition, and rows only enter the frame, never exit it, as the current
691  * row advances forward. This makes it possible to use an incremental
692  * strategy for evaluating aggregates: we run the transition function for
693  * each row added to the frame, and run the final function whenever we
694  * need the current aggregate value. This is considerably more efficient
695  * than the naive approach of re-running the entire aggregate calculation
696  * for each current row. It does assume that the final function doesn't
697  * damage the running transition value, but we have the same assumption in
698  * nodeAgg.c too (when it rescans an existing hash table).
699  *
700  * If the frame start does sometimes move, we can still optimize as above
701  * whenever successive rows share the same frame head, but if the frame
702  * head moves beyond the previous head we try to remove those rows using
703  * the aggregate's inverse transition function. This function restores
704  * the aggregate's current state to what it would be if the removed row
705  * had never been aggregated in the first place. Inverse transition
706  * functions may optionally return NULL, indicating that the function was
707  * unable to remove the tuple from aggregation. If this happens, or if
708  * the aggregate doesn't have an inverse transition function at all, we
709  * must perform the aggregation all over again for all tuples within the
710  * new frame boundaries.
711  *
712  * In many common cases, multiple rows share the same frame and hence the
713  * same aggregate value. (In particular, if there's no ORDER BY in a RANGE
714  * window, then all rows are peers and so they all have window frame equal
715  * to the whole partition.) We optimize such cases by calculating the
716  * aggregate value once when we reach the first row of a peer group, and
717  * then returning the saved value for all subsequent rows.
718  *
719  * 'aggregatedupto' keeps track of the first row that has not yet been
720  * accumulated into the aggregate transition values. Whenever we start a
721  * new peer group, we accumulate forward to the end of the peer group.
722  */
723 
724  /*
725  * First, update the frame head position.
726  *
727  * The frame head should never move backwards, and the code below wouldn't
728  * cope if it did, so for safety we complain if it does.
729  */
730  update_frameheadpos(agg_winobj, temp_slot);
731  if (winstate->frameheadpos < winstate->aggregatedbase)
732  elog(ERROR, "window frame head moved backward");
733 
734  /*
735  * If the frame didn't change compared to the previous row, we can re-use
736  * the result values that were previously saved at the bottom of this
737  * function. Since we don't know the current frame's end yet, this is not
738  * possible to check for fully. But if the frame end mode is UNBOUNDED
739  * FOLLOWING or CURRENT ROW, and the current row lies within the previous
740  * row's frame, then the two frames' ends must coincide. Note that on the
741  * first row aggregatedbase == aggregatedupto, meaning this test must
742  * fail, so we don't need to check the "there was no previous row" case
743  * explicitly here.
744  */
745  if (winstate->aggregatedbase == winstate->frameheadpos &&
748  winstate->aggregatedbase <= winstate->currentpos &&
749  winstate->aggregatedupto > winstate->currentpos)
750  {
751  for (i = 0; i < numaggs; i++)
752  {
753  peraggstate = &winstate->peragg[i];
754  wfuncno = peraggstate->wfuncno;
755  econtext->ecxt_aggvalues[wfuncno] = peraggstate->resultValue;
756  econtext->ecxt_aggnulls[wfuncno] = peraggstate->resultValueIsNull;
757  }
758  return;
759  }
760 
761  /*----------
762  * Initialize restart flags.
763  *
764  * We restart the aggregation:
765  * - if we're processing the first row in the partition, or
766  * - if the frame's head moved and we cannot use an inverse
767  * transition function, or
768  * - if the new frame doesn't overlap the old one
769  *
770  * Note that we don't strictly need to restart in the last case, but if
771  * we're going to remove all rows from the aggregation anyway, a restart
772  * surely is faster.
773  *----------
774  */
775  numaggs_restart = 0;
776  for (i = 0; i < numaggs; i++)
777  {
778  peraggstate = &winstate->peragg[i];
779  if (winstate->currentpos == 0 ||
780  (winstate->aggregatedbase != winstate->frameheadpos &&
781  !OidIsValid(peraggstate->invtransfn_oid)) ||
782  winstate->aggregatedupto <= winstate->frameheadpos)
783  {
784  peraggstate->restart = true;
785  numaggs_restart++;
786  }
787  else
788  peraggstate->restart = false;
789  }
790 
791  /*
792  * If we have any possibly-moving aggregates, attempt to advance
793  * aggregatedbase to match the frame's head by removing input rows that
794  * fell off the top of the frame from the aggregations. This can fail,
795  * i.e. advance_windowaggregate_base() can return false, in which case
796  * we'll restart that aggregate below.
797  */
798  while (numaggs_restart < numaggs &&
799  winstate->aggregatedbase < winstate->frameheadpos)
800  {
801  /*
802  * Fetch the next tuple of those being removed. This should never fail
803  * as we should have been here before.
804  */
805  if (!window_gettupleslot(agg_winobj, winstate->aggregatedbase,
806  temp_slot))
807  elog(ERROR, "could not re-fetch previously fetched frame row");
808 
809  /* Set tuple context for evaluation of aggregate arguments */
810  winstate->tmpcontext->ecxt_outertuple = temp_slot;
811 
812  /*
813  * Perform the inverse transition for each aggregate function in the
814  * window, unless it has already been marked as needing a restart.
815  */
816  for (i = 0; i < numaggs; i++)
817  {
818  bool ok;
819 
820  peraggstate = &winstate->peragg[i];
821  if (peraggstate->restart)
822  continue;
823 
824  wfuncno = peraggstate->wfuncno;
825  ok = advance_windowaggregate_base(winstate,
826  &winstate->perfunc[wfuncno],
827  peraggstate);
828  if (!ok)
829  {
830  /* Inverse transition function has failed, must restart */
831  peraggstate->restart = true;
832  numaggs_restart++;
833  }
834  }
835 
836  /* Reset per-input-tuple context after each tuple */
837  ResetExprContext(winstate->tmpcontext);
838 
839  /* And advance the aggregated-row state */
840  winstate->aggregatedbase++;
841  ExecClearTuple(temp_slot);
842  }
843 
844  /*
845  * If we successfully advanced the base rows of all the aggregates,
846  * aggregatedbase now equals frameheadpos; but if we failed for any, we
847  * must forcibly update aggregatedbase.
848  */
849  winstate->aggregatedbase = winstate->frameheadpos;
850 
851  /*
852  * If we created a mark pointer for aggregates, keep it pushed up to frame
853  * head, so that tuplestore can discard unnecessary rows.
854  */
855  if (agg_winobj->markptr >= 0)
856  WinSetMarkPosition(agg_winobj, winstate->frameheadpos);
857 
858  /*
859  * Now restart the aggregates that require it.
860  *
861  * We assume that aggregates using the shared context always restart if
862  * *any* aggregate restarts, and we may thus clean up the shared
863  * aggcontext if that is the case. Private aggcontexts are reset by
864  * initialize_windowaggregate() if their owning aggregate restarts. If we
865  * aren't restarting an aggregate, we need to free any previously saved
866  * result for it, else we'll leak memory.
867  */
868  if (numaggs_restart > 0)
870  for (i = 0; i < numaggs; i++)
871  {
872  peraggstate = &winstate->peragg[i];
873 
874  /* Aggregates using the shared ctx must restart if *any* agg does */
875  Assert(peraggstate->aggcontext != winstate->aggcontext ||
876  numaggs_restart == 0 ||
877  peraggstate->restart);
878 
879  if (peraggstate->restart)
880  {
881  wfuncno = peraggstate->wfuncno;
883  &winstate->perfunc[wfuncno],
884  peraggstate);
885  }
886  else if (!peraggstate->resultValueIsNull)
887  {
888  if (!peraggstate->resulttypeByVal)
889  pfree(DatumGetPointer(peraggstate->resultValue));
890  peraggstate->resultValue = (Datum) 0;
891  peraggstate->resultValueIsNull = true;
892  }
893  }
894 
895  /*
896  * Non-restarted aggregates now contain the rows between aggregatedbase
897  * (i.e., frameheadpos) and aggregatedupto, while restarted aggregates
898  * contain no rows. If there are any restarted aggregates, we must thus
899  * begin aggregating anew at frameheadpos, otherwise we may simply
900  * continue at aggregatedupto. We must remember the old value of
901  * aggregatedupto to know how long to skip advancing non-restarted
902  * aggregates. If we modify aggregatedupto, we must also clear
903  * agg_row_slot, per the loop invariant below.
904  */
905  aggregatedupto_nonrestarted = winstate->aggregatedupto;
906  if (numaggs_restart > 0 &&
907  winstate->aggregatedupto != winstate->frameheadpos)
908  {
909  winstate->aggregatedupto = winstate->frameheadpos;
910  ExecClearTuple(agg_row_slot);
911  }
912 
913  /*
914  * Advance until we reach a row not in frame (or end of partition).
915  *
916  * Note the loop invariant: agg_row_slot is either empty or holds the row
917  * at position aggregatedupto. We advance aggregatedupto after processing
918  * a row.
919  */
920  for (;;)
921  {
922  /* Fetch next row if we didn't already */
923  if (TupIsNull(agg_row_slot))
924  {
925  if (!window_gettupleslot(agg_winobj, winstate->aggregatedupto,
926  agg_row_slot))
927  break; /* must be end of partition */
928  }
929 
930  /* Exit loop (for now) if not in frame */
931  if (!row_is_in_frame(winstate, winstate->aggregatedupto, agg_row_slot))
932  break;
933 
934  /* Set tuple context for evaluation of aggregate arguments */
935  winstate->tmpcontext->ecxt_outertuple = agg_row_slot;
936 
937  /* Accumulate row into the aggregates */
938  for (i = 0; i < numaggs; i++)
939  {
940  peraggstate = &winstate->peragg[i];
941 
942  /* Non-restarted aggs skip until aggregatedupto_nonrestarted */
943  if (!peraggstate->restart &&
944  winstate->aggregatedupto < aggregatedupto_nonrestarted)
945  continue;
946 
947  wfuncno = peraggstate->wfuncno;
948  advance_windowaggregate(winstate,
949  &winstate->perfunc[wfuncno],
950  peraggstate);
951  }
952 
953  /* Reset per-input-tuple context after each tuple */
954  ResetExprContext(winstate->tmpcontext);
955 
956  /* And advance the aggregated-row state */
957  winstate->aggregatedupto++;
958  ExecClearTuple(agg_row_slot);
959  }
960 
961  /* The frame's end is not supposed to move backwards, ever */
962  Assert(aggregatedupto_nonrestarted <= winstate->aggregatedupto);
963 
964  /*
965  * finalize aggregates and fill result/isnull fields.
966  */
967  for (i = 0; i < numaggs; i++)
968  {
969  Datum *result;
970  bool *isnull;
971 
972  peraggstate = &winstate->peragg[i];
973  wfuncno = peraggstate->wfuncno;
974  result = &econtext->ecxt_aggvalues[wfuncno];
975  isnull = &econtext->ecxt_aggnulls[wfuncno];
976  finalize_windowaggregate(winstate,
977  &winstate->perfunc[wfuncno],
978  peraggstate,
979  result, isnull);
980 
981  /*
982  * save the result in case next row shares the same frame.
983  *
984  * XXX in some framing modes, eg ROWS/END_CURRENT_ROW, we can know in
985  * advance that the next row can't possibly share the same frame. Is
986  * it worth detecting that and skipping this code?
987  */
988  if (!peraggstate->resulttypeByVal && !*isnull)
989  {
990  oldContext = MemoryContextSwitchTo(peraggstate->aggcontext);
991  peraggstate->resultValue =
992  datumCopy(*result,
993  peraggstate->resulttypeByVal,
994  peraggstate->resulttypeLen);
995  MemoryContextSwitchTo(oldContext);
996  }
997  else
998  {
999  peraggstate->resultValue = *result;
1000  }
1001  peraggstate->resultValueIsNull = *isnull;
1002  }
1003 }
Datum * ecxt_aggvalues
Definition: execnodes.h:213
static void finalize_windowaggregate(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate, Datum *result, bool *isnull)
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int64 aggregatedupto
Definition: execnodes.h:1805
return result
Definition: formatting.c:1618
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1835
#define OidIsValid(objectId)
Definition: c.h:538
WindowStatePerFunc perfunc
Definition: execnodes.h:1791
static bool advance_windowaggregate_base(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate)
ExprContext * tmpcontext
Definition: execnodes.h:1816
PlanState ps
Definition: execnodes.h:1047
struct WindowObjectData * agg_winobj
Definition: execnodes.h:1802
int64 frameheadpos
Definition: execnodes.h:1799
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
static bool row_is_in_frame(WindowAggState *winstate, int64 pos, TupleTableSlot *slot)
WindowStatePerAgg peragg
Definition: execnodes.h:1792
int64 aggregatedbase
Definition: execnodes.h:1804
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:514
#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING
Definition: parsenodes.h:512
#define TupIsNull(slot)
Definition: tuptable.h:138
static void update_frameheadpos(WindowObject winobj, TupleTableSlot *slot)
MemoryContext aggcontext
Definition: execnodes.h:1814
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:67
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
TupleTableSlot * agg_row_slot
Definition: execnodes.h:1834
static void initialize_windowaggregate(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate)
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define Assert(condition)
Definition: c.h:675
static void advance_windowaggregate(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate)
MemoryContext aggcontext
int64 currentpos
Definition: execnodes.h:1798
#define DatumGetPointer(X)
Definition: postgres.h:555
int i
void WinSetMarkPosition(WindowObject winobj, int64 markpos)
#define elog
Definition: elog.h:219
#define ResetExprContext(econtext)
Definition: executor.h:449
static void eval_windowfunction ( WindowAggState winstate,
WindowStatePerFunc  perfuncstate,
Datum result,
bool isnull 
)
static

Definition at line 1015 of file nodeWindowAgg.c.

References FunctionCallInfoData::argnull, WindowAggState::curaggcontext, CurrentMemoryContext, datumCopy(), DatumGetPointer, ExprContext::ecxt_per_tuple_memory, WindowStatePerFuncData::flinfo, FunctionCallInvoke, InitFunctionCallInfoData, FunctionCallInfoData::isnull, MemoryContextContains(), MemoryContextSwitchTo(), NULL, WindowStatePerFuncData::numArguments, ScanState::ps, PlanState::ps_ExprContext, WindowStatePerFuncData::resulttypeByVal, WindowStatePerFuncData::resulttypeLen, WindowAggState::ss, WindowStatePerFuncData::winCollation, and WindowStatePerFuncData::winobj.

Referenced by ExecWindowAgg().

1017 {
1018  FunctionCallInfoData fcinfo;
1019  MemoryContext oldContext;
1020 
1022 
1023  /*
1024  * We don't pass any normal arguments to a window function, but we do pass
1025  * it the number of arguments, in order to permit window function
1026  * implementations to support varying numbers of arguments. The real info
1027  * goes through the WindowObject, which is passed via fcinfo->context.
1028  */
1029  InitFunctionCallInfoData(fcinfo, &(perfuncstate->flinfo),
1030  perfuncstate->numArguments,
1031  perfuncstate->winCollation,
1032  (void *) perfuncstate->winobj, NULL);
1033  /* Just in case, make all the regular argument slots be null */
1034  memset(fcinfo.argnull, true, perfuncstate->numArguments);
1035  /* Window functions don't have a current aggregate context, either */
1036  winstate->curaggcontext = NULL;
1037 
1038  *result = FunctionCallInvoke(&fcinfo);
1039  *isnull = fcinfo.isnull;
1040 
1041  /*
1042  * Make sure pass-by-ref data is allocated in the appropriate context. (We
1043  * need this in case the function returns a pointer into some short-lived
1044  * tuple, as is entirely possible.)
1045  */
1046  if (!perfuncstate->resulttypeByVal && !fcinfo.isnull &&
1049  *result = datumCopy(*result,
1050  perfuncstate->resulttypeByVal,
1051  perfuncstate->resulttypeLen);
1052 
1053  MemoryContextSwitchTo(oldContext);
1054 }
MemoryContext curaggcontext
Definition: execnodes.h:1815
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
return result
Definition: formatting.c:1618
PlanState ps
Definition: execnodes.h:1047
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:137
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
#define NULL
Definition: c.h:229
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:567
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:120
#define DatumGetPointer(X)
Definition: postgres.h:555
void ExecEndWindowAgg ( WindowAggState node)

Definition at line 2009 of file nodeWindowAgg.c.

References WindowAggState::agg_row_slot, WindowStatePerAggData::aggcontext, WindowAggState::aggcontext, ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), WindowAggState::first_part_slot, i, MemoryContextDelete(), WindowAggState::numaggs, outerPlan, 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().

2010 {
2012  int i;
2013 
2014  release_partition(node);
2015 
2019  ExecClearTuple(node->temp_slot_1);
2020  ExecClearTuple(node->temp_slot_2);
2021 
2022  /*
2023  * Free both the expr contexts.
2024  */
2025  ExecFreeExprContext(&node->ss.ps);
2026  node->ss.ps.ps_ExprContext = node->tmpcontext;
2027  ExecFreeExprContext(&node->ss.ps);
2028 
2029  for (i = 0; i < node->numaggs; i++)
2030  {
2031  if (node->peragg[i].aggcontext != node->aggcontext)
2033  }
2036 
2037  pfree(node->perfunc);
2038  pfree(node->peragg);
2039 
2040  outerPlan = outerPlanState(node);
2041  ExecEndNode(outerPlan);
2042 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
ScanState ss
Definition: execnodes.h:1784
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:654
ExprContext * ps_ExprContext
Definition: execnodes.h:833
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
static void release_partition(WindowAggState *winstate)
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1835
WindowStatePerFunc perfunc
Definition: execnodes.h:1791
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:516
TupleTableSlot * first_part_slot
Definition: execnodes.h:1830
ExprContext * tmpcontext
Definition: execnodes.h:1816
PlanState ps
Definition: execnodes.h:1047
void pfree(void *pointer)
Definition: mcxt.c:950
#define outerPlanState(node)
Definition: execnodes.h:845
TupleTableSlot * temp_slot_2
Definition: execnodes.h:1836
WindowStatePerAgg peragg
Definition: execnodes.h:1792
MemoryContext aggcontext
Definition: execnodes.h:1814
#define outerPlan(node)
Definition: plannodes.h:164
TupleTableSlot * agg_row_slot
Definition: execnodes.h:1834
MemoryContext aggcontext
int i
MemoryContext partcontext
Definition: execnodes.h:1813
WindowAggState* ExecInitWindowAgg ( WindowAgg node,
EState estate,
int  eflags 
)

Definition at line 1768 of file nodeWindowAgg.c.

References ACL_EXECUTE, ACL_KIND_PROC, aclcheck_error(), ACLCHECK_OK, WindowAggState::agg_row_slot, WindowAggState::agg_winobj, WindowAggState::aggcontext, WindowStatePerFuncData::aggno, WindowAggState::all_first, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), WindowFuncExprState::args, WindowObjectData::argstates, Assert, contain_volatile_functions(), CurrentMemoryContext, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExprContext::ecxt_per_query_memory, elog, WindowAgg::endOffset, WindowAggState::endOffset, equal(), ERROR, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecAssignResultTypeFromTL(), ExecAssignScanTypeFromOuterPlan(), ExecInitExpr(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitResultTupleSlot(), ExecInitScanTupleSlot(), ExecSetSlotDescriptor(), execTuplesMatchPrepare(), WindowAggState::first_part_slot, WindowStatePerFuncData::flinfo, fmgr_info_cxt(), fmgr_info_set_expr, WindowAgg::frameOptions, WindowAggState::frameOptions, WindowAggState::funcs, get_func_name(), get_typlenbyval(), GetUserId(), i, initialize_peragg(), WindowFunc::inputcollid, InvokeFunctionExecuteHook, lfirst, list_length(), WindowObjectData::localmem, makeNode, WindowObjectData::markptr, WindowAggState::more_partitions, NIL, NULL, WindowAggState::numaggs, WindowStatePerFuncData::numArguments, WindowAggState::numfuncs, WindowAggState::ordEqfunctions, WindowAgg::ordNumCols, WindowAgg::ordOperators, outerPlan, outerPlanState, palloc0(), WindowAggState::partcontext, WindowAggState::partEqfunctions, WindowAggState::partition_spooled, WindowAgg::partNumCols, WindowAgg::partOperators, WindowAggState::peragg, WindowAggState::perfunc, pg_proc_aclcheck(), WindowStatePerFuncData::plain_agg, WindowAgg::plan, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, Plan::qual, PlanState::qual, WindowObjectData::readptr, WindowStatePerFuncData::resulttypeByVal, WindowStatePerFuncData::resulttypeLen, WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowAgg::startOffset, WindowAggState::startOffset, PlanState::state, WindowAggState::temp_slot_1, WindowAggState::temp_slot_2, WindowAggState::tmpcontext, TupleTableSlot::tts_tupleDescriptor, WindowStatePerFuncData::wfunc, WindowFuncExprState::wfunc, WindowStatePerAggData::wfuncno, WindowFuncExprState::wfuncno, WindowStatePerFuncData::wfuncstate, WindowFunc::winagg, WindowStatePerFuncData::winCollation, WindowFunc::winfnoid, WindowStatePerFuncData::winobj, WindowFunc::winref, WindowAgg::winref, WindowObjectData::winstate, and WindowFunc::wintype.

Referenced by ExecInitNode().

1769 {
1770  WindowAggState *winstate;
1771  Plan *outerPlan;
1772  ExprContext *econtext;
1773  ExprContext *tmpcontext;
1774  WindowStatePerFunc perfunc;
1775  WindowStatePerAgg peragg;
1776  int numfuncs,
1777  wfuncno,
1778  numaggs,
1779  aggno;
1780  ListCell *l;
1781 
1782  /* check for unsupported flags */
1783  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
1784 
1785  /*
1786  * create state structure
1787  */
1788  winstate = makeNode(WindowAggState);
1789  winstate->ss.ps.plan = (Plan *) node;
1790  winstate->ss.ps.state = estate;
1791 
1792  /*
1793  * Create expression contexts. We need two, one for per-input-tuple
1794  * processing and one for per-output-tuple processing. We cheat a little
1795  * by using ExecAssignExprContext() to build both.
1796  */
1797  ExecAssignExprContext(estate, &winstate->ss.ps);
1798  tmpcontext = winstate->ss.ps.ps_ExprContext;
1799  winstate->tmpcontext = tmpcontext;
1800  ExecAssignExprContext(estate, &winstate->ss.ps);
1801 
1802  /* Create long-lived context for storage of partition-local memory etc */
1803  winstate->partcontext =
1805  "WindowAgg Partition",
1807 
1808  /*
1809  * Create mid-lived context for aggregate trans values etc.
1810  *
1811  * Note that moving aggregates each use their own private context, not
1812  * this one.
1813  */
1814  winstate->aggcontext =
1816  "WindowAgg Aggregates",
1818 
1819  /*
1820  * tuple table initialization
1821  */
1822  ExecInitScanTupleSlot(estate, &winstate->ss);
1823  ExecInitResultTupleSlot(estate, &winstate->ss.ps);
1824  winstate->first_part_slot = ExecInitExtraTupleSlot(estate);
1825  winstate->agg_row_slot = ExecInitExtraTupleSlot(estate);
1826  winstate->temp_slot_1 = ExecInitExtraTupleSlot(estate);
1827  winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate);
1828 
1829  /*
1830  * WindowAgg nodes never have quals, since they can only occur at the
1831  * logical top level of a query (ie, after any WHERE or HAVING filters)
1832  */
1833  Assert(node->plan.qual == NIL);
1834  winstate->ss.ps.qual = NULL;
1835 
1836  /*
1837  * initialize child nodes
1838  */
1839  outerPlan = outerPlan(node);
1840  outerPlanState(winstate) = ExecInitNode(outerPlan, estate, eflags);
1841 
1842  /*
1843  * initialize source tuple type (which is also the tuple type that we'll
1844  * store in the tuplestore and use in all our working slots).
1845  */
1846  ExecAssignScanTypeFromOuterPlan(&winstate->ss);
1847 
1856 
1857  /*
1858  * Initialize result tuple type and projection info.
1859  */
1860  ExecAssignResultTypeFromTL(&winstate->ss.ps);
1861  ExecAssignProjectionInfo(&winstate->ss.ps, NULL);
1862 
1863  /* Set up data for comparing tuples */
1864  if (node->partNumCols > 0)
1866  node->partOperators);
1867  if (node->ordNumCols > 0)
1869  node->ordOperators);
1870 
1871  /*
1872  * WindowAgg nodes use aggvalues and aggnulls as well as Agg nodes.
1873  */
1874  numfuncs = winstate->numfuncs;
1875  numaggs = winstate->numaggs;
1876  econtext = winstate->ss.ps.ps_ExprContext;
1877  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numfuncs);
1878  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numfuncs);
1879 
1880  /*
1881  * allocate per-wfunc/per-agg state information.
1882  */
1883  perfunc = (WindowStatePerFunc) palloc0(sizeof(WindowStatePerFuncData) * numfuncs);
1884  peragg = (WindowStatePerAgg) palloc0(sizeof(WindowStatePerAggData) * numaggs);
1885  winstate->perfunc = perfunc;
1886  winstate->peragg = peragg;
1887 
1888  wfuncno = -1;
1889  aggno = -1;
1890  foreach(l, winstate->funcs)
1891  {
1892  WindowFuncExprState *wfuncstate = (WindowFuncExprState *) lfirst(l);
1893  WindowFunc *wfunc = wfuncstate->wfunc;
1894  WindowStatePerFunc perfuncstate;
1895  AclResult aclresult;
1896  int i;
1897 
1898  if (wfunc->winref != node->winref) /* planner screwed up? */
1899  elog(ERROR, "WindowFunc with winref %u assigned to WindowAgg with winref %u",
1900  wfunc->winref, node->winref);
1901 
1902  /* Look for a previous duplicate window function */
1903  for (i = 0; i <= wfuncno; i++)
1904  {
1905  if (equal(wfunc, perfunc[i].wfunc) &&
1906  !contain_volatile_functions((Node *) wfunc))
1907  break;
1908  }
1909  if (i <= wfuncno)
1910  {
1911  /* Found a match to an existing entry, so just mark it */
1912  wfuncstate->wfuncno = i;
1913  continue;
1914  }
1915 
1916  /* Nope, so assign a new PerAgg record */
1917  perfuncstate = &perfunc[++wfuncno];
1918 
1919  /* Mark WindowFunc state node with assigned index in the result array */
1920  wfuncstate->wfuncno = wfuncno;
1921 
1922  /* Check permission to call window function */
1923  aclresult = pg_proc_aclcheck(wfunc->winfnoid, GetUserId(),
1924  ACL_EXECUTE);
1925  if (aclresult != ACLCHECK_OK)
1926  aclcheck_error(aclresult, ACL_KIND_PROC,
1927  get_func_name(wfunc->winfnoid));
1928  InvokeFunctionExecuteHook(wfunc->winfnoid);
1929 
1930  /* Fill in the perfuncstate data */
1931  perfuncstate->wfuncstate = wfuncstate;
1932  perfuncstate->wfunc = wfunc;
1933  perfuncstate->numArguments = list_length(wfuncstate->args);
1934 
1935  fmgr_info_cxt(wfunc->winfnoid, &perfuncstate->flinfo,
1936  econtext->ecxt_per_query_memory);
1937  fmgr_info_set_expr((Node *) wfunc, &perfuncstate->flinfo);
1938 
1939  perfuncstate->winCollation = wfunc->inputcollid;
1940 
1941  get_typlenbyval(wfunc->wintype,
1942  &perfuncstate->resulttypeLen,
1943  &perfuncstate->resulttypeByVal);
1944 
1945  /*
1946  * If it's really just a plain aggregate function, we'll emulate the
1947  * Agg environment for it.
1948  */
1949  perfuncstate->plain_agg = wfunc->winagg;
1950  if (wfunc->winagg)
1951  {
1952  WindowStatePerAgg peraggstate;
1953 
1954  perfuncstate->aggno = ++aggno;
1955  peraggstate = &winstate->peragg[aggno];
1956  initialize_peragg(winstate, wfunc, peraggstate);
1957  peraggstate->wfuncno = wfuncno;
1958  }
1959  else
1960  {
1962 
1963  winobj->winstate = winstate;
1964  winobj->argstates = wfuncstate->args;
1965  winobj->localmem = NULL;
1966  perfuncstate->winobj = winobj;
1967  }
1968  }
1969 
1970  /* Update numfuncs, numaggs to match number of unique functions found */
1971  winstate->numfuncs = wfuncno + 1;
1972  winstate->numaggs = aggno + 1;
1973 
1974  /* Set up WindowObject for aggregates, if needed */
1975  if (winstate->numaggs > 0)
1976  {
1977  WindowObject agg_winobj = makeNode(WindowObjectData);
1978 
1979  agg_winobj->winstate = winstate;
1980  agg_winobj->argstates = NIL;
1981  agg_winobj->localmem = NULL;
1982  /* make sure markptr = -1 to invalidate. It may not get used */
1983  agg_winobj->markptr = -1;
1984  agg_winobj->readptr = -1;
1985  winstate->agg_winobj = agg_winobj;
1986  }
1987 
1988  /* copy frame options to state node for easy access */
1989  winstate->frameOptions = node->frameOptions;
1990 
1991  /* initialize frame bound offset expressions */
1992  winstate->startOffset = ExecInitExpr((Expr *) node->startOffset,
1993  (PlanState *) winstate);
1994  winstate->endOffset = ExecInitExpr((Expr *) node->endOffset,
1995  (PlanState *) winstate);
1996 
1997  winstate->all_first = true;
1998  winstate->partition_spooled = false;
1999  winstate->more_partitions = false;
2000 
2001  return winstate;
2002 }
int ordNumCols
Definition: plannodes.h:797
#define NIL
Definition: pg_list.h:69
List * qual
Definition: plannodes.h:135
ExprState * endOffset
Definition: execnodes.h:1809
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate)
Definition: execTuples.c:852
Datum * ecxt_aggvalues
Definition: execnodes.h:213
struct WindowStatePerAggData * WindowStatePerAgg
Definition: execnodes.h:1780
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
Definition: execTuples.c:842
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2961
Oid GetUserId(void)
Definition: miscinit.c:283
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
Definition: nodes.h:509
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
struct WindowStatePerFuncData * WindowStatePerFunc
Definition: execnodes.h:1779
FmgrInfo * partEqfunctions
Definition: execnodes.h:1793
WindowFuncExprState * wfuncstate
Definition: nodeWindowAgg.c:78
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:951
EState * state
Definition: execnodes.h:805
Index winref
Definition: primnodes.h:361
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1835
WindowStatePerFunc perfunc
Definition: execnodes.h:1791
Oid * ordOperators
Definition: plannodes.h:799
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:440
TupleTableSlot * first_part_slot
Definition: execnodes.h:1830
ExprContext * tmpcontext
Definition: execnodes.h:1816
PlanState ps
Definition: execnodes.h:1047
struct WindowObjectData * agg_winobj
Definition: execnodes.h:1802
Node * startOffset
Definition: plannodes.h:801
static WindowStatePerAggData * initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, WindowStatePerAgg peraggstate)
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1412
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define outerPlanState(node)
Definition: execnodes.h:845
TupleTableSlot * temp_slot_2
Definition: execnodes.h:1836
WindowStatePerAgg peragg
Definition: execnodes.h:1792
ExprState * startOffset
Definition: execnodes.h:1808
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:487
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
Node * endOffset
Definition: plannodes.h:802
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:104
int partNumCols
Definition: plannodes.h:794
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
MemoryContext aggcontext
Definition: execnodes.h:1814
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:179
#define outerPlan(node)
Definition: plannodes.h:164
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
bool * ecxt_aggnulls
Definition: execnodes.h:214
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
AclResult
Definition: acl.h:170
uintptr_t Datum
Definition: postgres.h:372
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
TupleTableSlot * agg_row_slot
Definition: execnodes.h:1834
Plan * plan
Definition: execnodes.h:803
bool more_partitions
Definition: execnodes.h:1823
FmgrInfo * ordEqfunctions
Definition: execnodes.h:1794
Oid * partOperators
Definition: plannodes.h:796
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
Index winref
Definition: plannodes.h:793
#define EXEC_FLAG_MARK
Definition: executor.h:61
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:418
static int list_length(const List *l)
Definition: pg_list.h:89
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2001
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:202
ExprState * qual
Definition: execnodes.h:817
bool partition_spooled
Definition: execnodes.h:1820
void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
Definition: execUtils.c:552
#define ACL_EXECUTE
Definition: parsenodes.h:79
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4446
int i
Plan plan
Definition: plannodes.h:792
MemoryContext partcontext
Definition: execnodes.h:1813
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:113
#define elog
Definition: elog.h:219
int frameOptions
Definition: plannodes.h:800
WindowFunc * wfunc
Definition: execnodes.h:635
FmgrInfo * execTuplesMatchPrepare(int numCols, Oid *eqOperators)
Definition: execGrouping.c:204
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:140
void ExecReScanWindowAgg ( WindowAggState node)

Definition at line 2049 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, MemSet, NULL, WindowAggState::numfuncs, outerPlan, outerPlanState, ScanState::ps, PlanState::ps_ExprContext, release_partition(), WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowAggState::temp_slot_1, and WindowAggState::temp_slot_2.

Referenced by ExecReScan().

2050 {
2052  ExprContext *econtext = node->ss.ps.ps_ExprContext;
2053 
2054  node->all_done = false;
2055  node->all_first = true;
2056 
2057  /* release tuplestore et al */
2058  release_partition(node);
2059 
2060  /* release all temp tuples, but especially first_part_slot */
2064  ExecClearTuple(node->temp_slot_1);
2065  ExecClearTuple(node->temp_slot_2);
2066 
2067  /* Forget current wfunc values */
2068  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numfuncs);
2069  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numfuncs);
2070 
2071  /*
2072  * if chgParam of subnode is not null then plan will be re-scanned by
2073  * first ExecProcNode.
2074  */
2075  if (outerPlan->chgParam == NULL)
2076  ExecReScan(outerPlan);
2077 }
Datum * ecxt_aggvalues
Definition: execnodes.h:213
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
void ExecReScan(PlanState *node)
Definition: execAmi.c:75
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define MemSet(start, val, len)
Definition: c.h:857
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
static void release_partition(WindowAggState *winstate)
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1835
TupleTableSlot * first_part_slot
Definition: execnodes.h:1830
PlanState ps
Definition: execnodes.h:1047
#define outerPlanState(node)
Definition: execnodes.h:845
TupleTableSlot * temp_slot_2
Definition: execnodes.h:1836
Bitmapset * chgParam
Definition: execnodes.h:827
#define outerPlan(node)
Definition: plannodes.h:164
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
TupleTableSlot * agg_row_slot
Definition: execnodes.h:1834
#define NULL
Definition: c.h:229
TupleTableSlot* ExecWindowAgg ( WindowAggState winstate)

Definition at line 1591 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, 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, 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().

1592 {
1593  ExprContext *econtext;
1594  int i;
1595  int numfuncs;
1596 
1597  if (winstate->all_done)
1598  return NULL;
1599 
1600  /*
1601  * Compute frame offset values, if any, during first call.
1602  */
1603  if (winstate->all_first)
1604  {
1605  int frameOptions = winstate->frameOptions;
1606  ExprContext *econtext = winstate->ss.ps.ps_ExprContext;
1607  Datum value;
1608  bool isnull;
1609  int16 len;
1610  bool byval;
1611 
1612  if (frameOptions & FRAMEOPTION_START_VALUE)
1613  {
1614  Assert(winstate->startOffset != NULL);
1615  value = ExecEvalExprSwitchContext(winstate->startOffset,
1616  econtext,
1617  &isnull);
1618  if (isnull)
1619  ereport(ERROR,
1620  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1621  errmsg("frame starting offset must not be null")));
1622  /* copy value into query-lifespan context */
1623  get_typlenbyval(exprType((Node *) winstate->startOffset->expr),
1624  &len, &byval);
1625  winstate->startOffsetValue = datumCopy(value, byval, len);
1626  if (frameOptions & FRAMEOPTION_ROWS)
1627  {
1628  /* value is known to be int8 */
1629  int64 offset = DatumGetInt64(value);
1630 
1631  if (offset < 0)
1632  ereport(ERROR,
1633  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1634  errmsg("frame starting offset must not be negative")));
1635  }
1636  }
1637  if (frameOptions & FRAMEOPTION_END_VALUE)
1638  {
1639  Assert(winstate->endOffset != NULL);
1640  value = ExecEvalExprSwitchContext(winstate->endOffset,
1641  econtext,
1642  &isnull);
1643  if (isnull)
1644  ereport(ERROR,
1645  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1646  errmsg("frame ending offset must not be null")));
1647  /* copy value into query-lifespan context */
1648  get_typlenbyval(exprType((Node *) winstate->endOffset->expr),
1649  &len, &byval);
1650  winstate->endOffsetValue = datumCopy(value, byval, len);
1651  if (frameOptions & FRAMEOPTION_ROWS)
1652  {
1653  /* value is known to be int8 */
1654  int64 offset = DatumGetInt64(value);
1655 
1656  if (offset < 0)
1657  ereport(ERROR,
1658  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1659  errmsg("frame ending offset must not be negative")));
1660  }
1661  }
1662  winstate->all_first = false;
1663  }
1664 
1665  if (winstate->buffer == NULL)
1666  {
1667  /* Initialize for first partition and set current row = 0 */
1668  begin_partition(winstate);
1669  /* If there are no input rows, we'll detect that and exit below */
1670  }
1671  else
1672  {
1673  /* Advance current row within partition */
1674  winstate->currentpos++;
1675  /* This might mean that the frame moves, too */
1676  winstate->framehead_valid = false;
1677  winstate->frametail_valid = false;
1678  }
1679 
1680  /*
1681  * Spool all tuples up to and including the current row, if we haven't
1682  * already
1683  */
1684  spool_tuples(winstate, winstate->currentpos);
1685 
1686  /* Move to the next partition if we reached the end of this partition */
1687  if (winstate->partition_spooled &&
1688  winstate->currentpos >= winstate->spooled_rows)
1689  {
1690  release_partition(winstate);
1691 
1692  if (winstate->more_partitions)
1693  {
1694  begin_partition(winstate);
1695  Assert(winstate->spooled_rows > 0);
1696  }
1697  else
1698  {
1699  winstate->all_done = true;
1700  return NULL;
1701  }
1702  }
1703 
1704  /* final output execution is in ps_ExprContext */
1705  econtext = winstate->ss.ps.ps_ExprContext;
1706 
1707  /* Clear the per-output-tuple context for current row */
1708  ResetExprContext(econtext);
1709 
1710  /*
1711  * Read the current row from the tuplestore, and save in ScanTupleSlot.
1712  * (We can't rely on the outerplan's output slot because we may have to
1713  * read beyond the current row. Also, we have to actually copy the row
1714  * out of the tuplestore, since window function evaluation might cause the
1715  * tuplestore to dump its state to disk.)
1716  *
1717  * Current row must be in the tuplestore, since we spooled it above.
1718  */
1719  tuplestore_select_read_pointer(winstate->buffer, winstate->current_ptr);
1720  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1721  winstate->ss.ss_ScanTupleSlot))
1722  elog(ERROR, "unexpected end of tuplestore");
1723 
1724  /*
1725  * Evaluate true window functions
1726  */
1727  numfuncs = winstate->numfuncs;
1728  for (i = 0; i < numfuncs; i++)
1729  {
1730  WindowStatePerFunc perfuncstate = &(winstate->perfunc[i]);
1731 
1732  if (perfuncstate->plain_agg)
1733  continue;
1734  eval_windowfunction(winstate, perfuncstate,
1735  &(econtext->ecxt_aggvalues[perfuncstate->wfuncstate->wfuncno]),
1736  &(econtext->ecxt_aggnulls[perfuncstate->wfuncstate->wfuncno]));
1737  }
1738 
1739  /*
1740  * Evaluate aggregates
1741  */
1742  if (winstate->numaggs > 0)
1743  eval_windowaggregates(winstate);
1744 
1745  /*
1746  * Truncate any no-longer-needed rows from the tuplestore.
1747  */
1748  tuplestore_trim(winstate->buffer);
1749 
1750  /*
1751  * Form and return a projection tuple using the windowfunc results and the
1752  * current row. Setting ecxt_outertuple arranges that any Vars will be
1753  * evaluated with respect to that row.
1754  */
1755  econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
1756 
1757  return ExecProject(winstate->ss.ps.ps_ProjInfo);
1758 }
signed short int16
Definition: c.h:255
ExprState * endOffset
Definition: execnodes.h:1809
Datum * ecxt_aggvalues
Definition: execnodes.h:213
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:280
Datum startOffsetValue
Definition: execnodes.h:1810
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:834
void tuplestore_trim(Tuplestorestate *state)
Definition: tuplestore.c:1360
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
#define FRAMEOPTION_START_VALUE
Definition: parsenodes.h:520
Definition: nodes.h:509
int errcode(int sqlerrcode)
Definition: elog.c:575
bool frametail_valid
Definition: execnodes.h:1827
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
static void release_partition(WindowAggState *winstate)
WindowFuncExprState * wfuncstate
Definition: nodeWindowAgg.c:78
WindowStatePerFunc perfunc
Definition: execnodes.h:1791
static void spool_tuples(WindowAggState *winstate, int64 pos)
PlanState ps
Definition: execnodes.h:1047
#define ERROR
Definition: elog.h:43
Expr * expr
Definition: execnodes.h:83
#define DatumGetInt64(X)
Definition: postgres.h:613
Datum endOffsetValue
Definition: execnodes.h:1811
ExprState * startOffset
Definition: execnodes.h:1808
Tuplestorestate * buffer
Definition: execnodes.h:1795
#define ereport(elevel, rest)
Definition: elog.h:122
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
static void eval_windowaggregates(WindowAggState *winstate)
int64 spooled_rows
Definition: execnodes.h:1797
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
static void begin_partition(WindowAggState *winstate)
bool more_partitions
Definition: execnodes.h:1823
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2001
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:507
int64 currentpos
Definition: execnodes.h:1798
bool partition_spooled
Definition: execnodes.h:1820
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool framehead_valid
Definition: execnodes.h:1825
int i
void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
Definition: tuplestore.c:473
#define elog
Definition: elog.h:219
static struct @121 value
#define FRAMEOPTION_END_VALUE
Definition: parsenodes.h:522
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:308
static void eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate, Datum *result, bool *isnull)
#define ResetExprContext(econtext)
Definition: executor.h:449
static void finalize_windowaggregate ( WindowAggState winstate,
WindowStatePerFunc  perfuncstate,
WindowStatePerAgg  peraggstate,
Datum result,
bool isnull 
)
static

Definition at line 578 of file nodeWindowAgg.c.

References WindowStatePerAggData::aggcontext, FunctionCallInfoData::arg, FunctionCallInfoData::argnull, WindowAggState::curaggcontext, CurrentMemoryContext, datumCopy(), DatumGetPointer, ExprContext::ecxt_per_tuple_memory, WindowStatePerAggData::finalfn, WindowStatePerAggData::finalfn_oid, FunctionCallInfoData::flinfo, FmgrInfo::fn_strict, FunctionCallInvoke, i, InitFunctionCallInfoData, FunctionCallInfoData::isnull, MakeExpandedObjectReadOnly, MemoryContextContains(), MemoryContextSwitchTo(), NULL, WindowStatePerAggData::numFinalArgs, OidIsValid, ScanState::ps, PlanState::ps_ExprContext, WindowStatePerAggData::resulttypeByVal, WindowStatePerAggData::resulttypeLen, WindowAggState::ss, WindowStatePerAggData::transtypeLen, WindowStatePerAggData::transValue, WindowStatePerAggData::transValueIsNull, and WindowStatePerFuncData::winCollation.

Referenced by eval_windowaggregates().

582 {
583  MemoryContext oldContext;
584 
586 
587  /*
588  * Apply the agg's finalfn if one is provided, else return transValue.
589  */
590  if (OidIsValid(peraggstate->finalfn_oid))
591  {
592  int numFinalArgs = peraggstate->numFinalArgs;
593  FunctionCallInfoData fcinfo;
594  bool anynull;
595  int i;
596 
597  InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn),
598  numFinalArgs,
599  perfuncstate->winCollation,
600  (void *) winstate, NULL);
601  fcinfo.arg[0] = MakeExpandedObjectReadOnly(peraggstate->transValue,
602  peraggstate->transValueIsNull,
603  peraggstate->transtypeLen);
604  fcinfo.argnull[0] = peraggstate->transValueIsNull;
605  anynull = peraggstate->transValueIsNull;
606 
607  /* Fill any remaining argument positions with nulls */
608  for (i = 1; i < numFinalArgs; i++)
609  {
610  fcinfo.arg[i] = (Datum) 0;
611  fcinfo.argnull[i] = true;
612  anynull = true;
613  }
614 
615  if (fcinfo.flinfo->fn_strict && anynull)
616  {
617  /* don't call a strict function with NULL inputs */
618  *result = (Datum) 0;
619  *isnull = true;
620  }
621  else
622  {
623  winstate->curaggcontext = peraggstate->aggcontext;
624  *result = FunctionCallInvoke(&fcinfo);
625  winstate->curaggcontext = NULL;
626  *isnull = fcinfo.isnull;
627  }
628  }
629  else
630  {
631  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
632  *result = peraggstate->transValue;
633  *isnull = peraggstate->transValueIsNull;
634  }
635 
636  /*
637  * If result is pass-by-ref, make sure it is in the right context.
638  */
639  if (!peraggstate->resulttypeByVal && !*isnull &&
642  *result = datumCopy(*result,
643  peraggstate->resulttypeByVal,
644  peraggstate->resulttypeLen);
645  MemoryContextSwitchTo(oldContext);
646 }
MemoryContext curaggcontext
Definition: execnodes.h:1815
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
return result
Definition: formatting.c:1618
#define OidIsValid(objectId)
Definition: c.h:538
PlanState ps
Definition: execnodes.h:1047
FmgrInfo * flinfo
Definition: fmgr.h:79
bool fn_strict
Definition: fmgr.h:61
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:137
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
uintptr_t Datum
Definition: postgres.h:372
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define NULL
Definition: c.h:229
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:567
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:120
MemoryContext aggcontext
#define DatumGetPointer(X)
Definition: postgres.h:555
int i
static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 2324 of file nodeWindowAgg.c.

References getTypeInputInfo(), OidInputFunctionCall(), pfree(), and TextDatumGetCString.

Referenced by initialize_peragg().

2325 {
2326  Oid typinput,
2327  typioparam;
2328  char *strInitVal;
2329  Datum initVal;
2330 
2331  getTypeInputInfo(transtype, &typinput, &typioparam);
2332  strInitVal = TextDatumGetCString(textInitVal);
2333  initVal = OidInputFunctionCall(typinput, strInitVal,
2334  typioparam, -1);
2335  pfree(strInitVal);
2336  return initVal;
2337 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:950
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2599
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:372
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1738
static WindowStatePerAggData * initialize_peragg ( WindowAggState winstate,
WindowFunc wfunc,
WindowStatePerAgg  peraggstate 
)
static

Definition at line 2085 of file nodeWindowAgg.c.

References ACL_EXECUTE, ACL_KIND_PROC, aclcheck_error(), ACLCHECK_OK, WindowStatePerAggData::aggcontext, WindowAggState::aggcontext, AGGFNOID, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), Anum_pg_aggregate_agginitval, Anum_pg_aggregate_aggminitval, WindowFunc::args, build_aggregate_finalfn_expr(), build_aggregate_transfn_expr(), contain_volatile_functions(), CurrentMemoryContext, elog, ereport, errcode(), errmsg(), ERROR, exprType(), WindowStatePerAggData::finalfn, WindowStatePerAggData::finalfn_oid, fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_strict, FRAMEOPTION_START_UNBOUNDED_PRECEDING, WindowAggState::frameOptions, FUNC_MAX_ARGS, get_func_name(), get_typlenbyval(), GetAggInitVal(), GETSTRUCT, HeapTupleIsValid, i, WindowStatePerAggData::initValue, WindowStatePerAggData::initValueIsNull, WindowFunc::inputcollid, InvalidOid, InvokeFunctionExecuteHook, WindowStatePerAggData::invtransfn, WindowStatePerAggData::invtransfn_oid, IsBinaryCoercible(), lfirst, list_length(), WindowStatePerAggData::numFinalArgs, ObjectIdGetDatum, OidIsValid, pg_proc_aclcheck(), PROCOID, ReleaseSysCache(), resolve_aggregate_transtype(), WindowStatePerAggData::resulttypeByVal, WindowStatePerAggData::resulttypeLen, SearchSysCache1, SysCacheGetAttr(), WindowStatePerAggData::transfn, WindowStatePerAggData::transfn_oid, WindowStatePerAggData::transtypeByVal, WindowStatePerAggData::transtypeLen, WindowFunc::winfnoid, and WindowFunc::wintype.

Referenced by ExecInitWindowAgg().

2087 {
2088  Oid inputTypes[FUNC_MAX_ARGS];
2089  int numArguments;
2090  HeapTuple aggTuple;
2091  Form_pg_aggregate aggform;
2092  Oid aggtranstype;
2093  AttrNumber initvalAttNo;
2094  AclResult aclresult;
2095  Oid transfn_oid,
2096  invtransfn_oid,
2097  finalfn_oid;
2098  bool finalextra;
2099  Expr *transfnexpr,
2100  *invtransfnexpr,
2101  *finalfnexpr;
2102  Datum textInitVal;
2103  int i;
2104  ListCell *lc;
2105 
2106  numArguments = list_length(wfunc->args);
2107 
2108  i = 0;
2109  foreach(lc, wfunc->args)
2110  {
2111  inputTypes[i++] = exprType((Node *) lfirst(lc));
2112  }
2113 
2114  aggTuple = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(wfunc->winfnoid));
2115  if (!HeapTupleIsValid(aggTuple))
2116  elog(ERROR, "cache lookup failed for aggregate %u",
2117  wfunc->winfnoid);
2118  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
2119 
2120  /*
2121  * Figure out whether we want to use the moving-aggregate implementation,
2122  * and collect the right set of fields from the pg_attribute entry.
2123  *
2124  * If the frame head can't move, we don't need moving-aggregate code. Even
2125  * if we'd like to use it, don't do so if the aggregate's arguments (and
2126  * FILTER clause if any) contain any calls to volatile functions.
2127  * Otherwise, the difference between restarting and not restarting the
2128  * aggregation would be user-visible.
2129  */
2130  if (OidIsValid(aggform->aggminvtransfn) &&
2132  !contain_volatile_functions((Node *) wfunc))
2133  {
2134  peraggstate->transfn_oid = transfn_oid = aggform->aggmtransfn;
2135  peraggstate->invtransfn_oid = invtransfn_oid = aggform->aggminvtransfn;
2136  peraggstate->finalfn_oid = finalfn_oid = aggform->aggmfinalfn;
2137  finalextra = aggform->aggmfinalextra;
2138  aggtranstype = aggform->aggmtranstype;
2139  initvalAttNo = Anum_pg_aggregate_aggminitval;
2140  }
2141  else
2142  {
2143  peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
2144  peraggstate->invtransfn_oid = invtransfn_oid = InvalidOid;
2145  peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
2146  finalextra = aggform->aggfinalextra;
2147  aggtranstype = aggform->aggtranstype;
2148  initvalAttNo = Anum_pg_aggregate_agginitval;
2149  }
2150 
2151  /*
2152  * ExecInitWindowAgg already checked permission to call aggregate function
2153  * ... but we still need to check the component functions
2154  */
2155 
2156  /* Check that aggregate owner has permission to call component fns */
2157  {
2158  HeapTuple procTuple;
2159  Oid aggOwner;
2160 
2161  procTuple = SearchSysCache1(PROCOID,
2162  ObjectIdGetDatum(wfunc->winfnoid));
2163  if (!HeapTupleIsValid(procTuple))
2164  elog(ERROR, "cache lookup failed for function %u",
2165  wfunc->winfnoid);
2166  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
2167  ReleaseSysCache(procTuple);
2168 
2169  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
2170  ACL_EXECUTE);
2171  if (aclresult != ACLCHECK_OK)
2172  aclcheck_error(aclresult, ACL_KIND_PROC,
2173  get_func_name(transfn_oid));
2174  InvokeFunctionExecuteHook(transfn_oid);
2175 
2176  if (OidIsValid(invtransfn_oid))
2177  {
2178  aclresult = pg_proc_aclcheck(invtransfn_oid, aggOwner,
2179  ACL_EXECUTE);
2180  if (aclresult != ACLCHECK_OK)
2181  aclcheck_error(aclresult, ACL_KIND_PROC,
2182  get_func_name(invtransfn_oid));
2183  InvokeFunctionExecuteHook(invtransfn_oid);
2184  }
2185 
2186  if (OidIsValid(finalfn_oid))
2187  {
2188  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
2189  ACL_EXECUTE);
2190  if (aclresult != ACLCHECK_OK)
2191  aclcheck_error(aclresult, ACL_KIND_PROC,
2192  get_func_name(finalfn_oid));
2193  InvokeFunctionExecuteHook(finalfn_oid);
2194  }
2195  }
2196 
2197  /* Detect how many arguments to pass to the finalfn */
2198  if (finalextra)
2199  peraggstate->numFinalArgs = numArguments + 1;
2200  else
2201  peraggstate->numFinalArgs = 1;
2202 
2203  /* resolve actual type of transition state, if polymorphic */
2204  aggtranstype = resolve_aggregate_transtype(wfunc->winfnoid,
2205  aggtranstype,
2206  inputTypes,
2207  numArguments);
2208 
2209  /* build expression trees using actual argument & result types */
2210  build_aggregate_transfn_expr(inputTypes,
2211  numArguments,
2212  0, /* no ordered-set window functions yet */
2213  false, /* no variadic window functions yet */
2214  aggtranstype,
2215  wfunc->inputcollid,
2216  transfn_oid,
2217  invtransfn_oid,
2218  &transfnexpr,
2219  &invtransfnexpr);
2220 
2221  /* set up infrastructure for calling the transfn(s) and finalfn */
2222  fmgr_info(transfn_oid, &peraggstate->transfn);
2223  fmgr_info_set_expr((Node *) transfnexpr, &peraggstate->transfn);
2224 
2225  if (OidIsValid(invtransfn_oid))
2226  {
2227  fmgr_info(invtransfn_oid, &peraggstate->invtransfn);
2228  fmgr_info_set_expr((Node *) invtransfnexpr, &peraggstate->invtransfn);
2229  }
2230 
2231  if (OidIsValid(finalfn_oid))
2232  {
2233  build_aggregate_finalfn_expr(inputTypes,
2234  peraggstate->numFinalArgs,
2235  aggtranstype,
2236  wfunc->wintype,
2237  wfunc->inputcollid,
2238  finalfn_oid,
2239  &finalfnexpr);
2240  fmgr_info(finalfn_oid, &peraggstate->finalfn);
2241  fmgr_info_set_expr((Node *) finalfnexpr, &peraggstate->finalfn);
2242  }
2243 
2244  /* get info about relevant datatypes */
2245  get_typlenbyval(wfunc->wintype,
2246  &peraggstate->resulttypeLen,
2247  &peraggstate->resulttypeByVal);
2248  get_typlenbyval(aggtranstype,
2249  &peraggstate->transtypeLen,
2250  &peraggstate->transtypeByVal);
2251 
2252  /*
2253  * initval is potentially null, so don't try to access it as a struct
2254  * field. Must do it the hard way with SysCacheGetAttr.
2255  */
2256  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple, initvalAttNo,
2257  &peraggstate->initValueIsNull);
2258 
2259  if (peraggstate->initValueIsNull)
2260  peraggstate->initValue = (Datum) 0;
2261  else
2262  peraggstate->initValue = GetAggInitVal(textInitVal,
2263  aggtranstype);
2264 
2265  /*
2266  * If the transfn is strict and the initval is NULL, make sure input type
2267  * and transtype are the same (or at least binary-compatible), so that
2268  * it's OK to use the first input value as the initial transValue. This
2269  * should have been checked at agg definition time, but we must check
2270  * again in case the transfn's strictness property has been changed.
2271  */
2272  if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
2273  {
2274  if (numArguments < 1 ||
2275  !IsBinaryCoercible(inputTypes[0], aggtranstype))
2276  ereport(ERROR,
2277  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2278  errmsg("aggregate %u needs to have compatible input type and transition type",
2279  wfunc->winfnoid)));
2280  }
2281 
2282  /*
2283  * Insist that forward and inverse transition functions have the same
2284  * strictness setting. Allowing them to differ would require handling
2285  * more special cases in advance_windowaggregate and
2286  * advance_windowaggregate_base, for no discernible benefit. This should
2287  * have been checked at agg definition time, but we must check again in
2288  * case either function's strictness property has been changed.
2289  */
2290  if (OidIsValid(invtransfn_oid) &&
2291  peraggstate->transfn.fn_strict != peraggstate->invtransfn.fn_strict)
2292  ereport(ERROR,
2293  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2294  errmsg("strictness of aggregate's forward and inverse transition functions must match")));
2295 
2296  /*
2297  * Moving aggregates use their own aggcontext.
2298  *
2299  * This is necessary because they might restart at different times, so we
2300  * might never be able to reset the shared context otherwise. We can't
2301  * make it the aggregates' responsibility to clean up after themselves,
2302  * because strict aggregates must be restarted whenever we remove their
2303  * last non-NULL input, which the aggregate won't be aware is happening.
2304  * Also, just pfree()ing the transValue upon restarting wouldn't help,
2305  * since we'd miss any indirectly referenced data. We could, in theory,
2306  * make the memory allocation rules for moving aggregates different than
2307  * they have historically been for plain aggregates, but that seems grotty
2308  * and likely to lead to memory leaks.
2309  */
2310  if (OidIsValid(invtransfn_oid))
2311  peraggstate->aggcontext =
2313  "WindowAgg Per Aggregate",
2315  else
2316  peraggstate->aggcontext = winstate->aggcontext;
2317 
2318  ReleaseSysCache(aggTuple);
2319 
2320  return peraggstate;
2321 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define Anum_pg_aggregate_agginitval
Definition: pg_aggregate.h:113
List * args
Definition: primnodes.h:359
Definition: nodes.h:509
int errcode(int sqlerrcode)
Definition: elog.c:575
void build_aggregate_finalfn_expr(Oid *agg_input_types, int num_finalfn_inputs, Oid agg_state_type, Oid agg_result_type, Oid agg_input_collation, Oid finalfn_oid, Expr **finalfnexpr)
Definition: parse_agg.c:2004
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:951
unsigned int Oid
Definition: postgres_ext.h:31
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:509
#define OidIsValid(objectId)
Definition: c.h:538
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
#define FUNC_MAX_ARGS
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1412
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:104
Oid winfnoid
Definition: primnodes.h:355
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
MemoryContext aggcontext
Definition: execnodes.h:1814
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:179
bool IsBinaryCoercible(Oid srctype, Oid targettype)
#define Anum_pg_aggregate_aggminitval
Definition: pg_aggregate.h:114
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
AclResult
Definition: acl.h:170
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1278
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define lfirst(lc)
Definition: pg_list.h:106
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:87
void build_aggregate_transfn_expr(Oid *agg_input_types, int agg_num_inputs, int agg_num_direct_inputs, bool agg_variadic, Oid agg_state_type, Oid agg_input_collation, Oid transfn_oid, Oid invtransfn_oid, Expr **transfnexpr, Expr **invtransfnexpr)
Definition: parse_agg.c:1867
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static int list_length(const List *l)
Definition: pg_list.h:89
MemoryContext aggcontext
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2001
Oid inputcollid
Definition: primnodes.h:358
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Oid wintype
Definition: primnodes.h:356
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:79
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4446
int i
#define elog
Definition: elog.h:219
int16 AttrNumber
Definition: attnum.h:21
Oid resolve_aggregate_transtype(Oid aggfuncid, Oid aggtranstype, Oid *inputTypes, int numArguments)
Definition: parse_agg.c:1812
static void initialize_windowaggregate ( WindowAggState winstate,
WindowStatePerFunc  perfuncstate,
WindowStatePerAgg  peraggstate 
)
static

Definition at line 203 of file nodeWindowAgg.c.

References WindowStatePerAggData::aggcontext, WindowAggState::aggcontext, datumCopy(), WindowStatePerAggData::initValue, WindowStatePerAggData::initValueIsNull, MemoryContextResetAndDeleteChildren, MemoryContextSwitchTo(), WindowStatePerAggData::resultValue, WindowStatePerAggData::resultValueIsNull, WindowStatePerAggData::transtypeByVal, WindowStatePerAggData::transtypeLen, WindowStatePerAggData::transValue, WindowStatePerAggData::transValueCount, and WindowStatePerAggData::transValueIsNull.

Referenced by advance_windowaggregate_base(), and eval_windowaggregates().

206 {
207  MemoryContext oldContext;
208 
209  /*
210  * If we're using a private aggcontext, we may reset it here. But if the
211  * context is shared, we don't know which other aggregates may still need
212  * it, so we must leave it to the caller to reset at an appropriate time.
213  */
214  if (peraggstate->aggcontext != winstate->aggcontext)
216 
217  if (peraggstate->initValueIsNull)
218  peraggstate->transValue = peraggstate->initValue;
219  else
220  {
221  oldContext = MemoryContextSwitchTo(peraggstate->aggcontext);
222  peraggstate->transValue = datumCopy(peraggstate->initValue,
223  peraggstate->transtypeByVal,
224  peraggstate->transtypeLen);
225  MemoryContextSwitchTo(oldContext);
226  }
227  peraggstate->transValueIsNull = peraggstate->initValueIsNull;
228  peraggstate->transValueCount = 0;
229  peraggstate->resultValue = (Datum) 0;
230  peraggstate->resultValueIsNull = true;
231 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext aggcontext
Definition: execnodes.h:1814
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:67
uintptr_t Datum
Definition: postgres.h:372
MemoryContext aggcontext
static void release_partition ( WindowAggState winstate)
static

Definition at line 1236 of file nodeWindowAgg.c.

References WindowStatePerAggData::aggcontext, WindowAggState::aggcontext, WindowAggState::buffer, i, WindowObjectData::localmem, MemoryContextResetAndDeleteChildren, NULL, WindowAggState::numaggs, WindowAggState::numfuncs, WindowAggState::partcontext, WindowAggState::partition_spooled, WindowAggState::peragg, WindowAggState::perfunc, tuplestore_end(), and WindowStatePerFuncData::winobj.

Referenced by ExecEndWindowAgg(), ExecReScanWindowAgg(), and ExecWindowAgg().

1237 {
1238  int i;
1239 
1240  for (i = 0; i < winstate->numfuncs; i++)
1241  {
1242  WindowStatePerFunc perfuncstate = &(winstate->perfunc[i]);
1243 
1244  /* Release any partition-local state of this window function */
1245  if (perfuncstate->winobj)
1246  perfuncstate->winobj->localmem = NULL;
1247  }
1248 
1249  /*
1250  * Release all partition-local memory (in particular, any partition-local
1251  * state that we might have trashed our pointers to in the above loop, and
1252  * any aggregate temp data). We don't rely on retail pfree because some
1253  * aggregates might have allocated data we don't have direct pointers to.
1254  */
1257  for (i = 0; i < winstate->numaggs; i++)
1258  {
1259  if (winstate->peragg[i].aggcontext != winstate->aggcontext)
1261  }
1262 
1263  if (winstate->buffer)
1264  tuplestore_end(winstate->buffer);
1265  winstate->buffer = NULL;
1266  winstate->partition_spooled = false;
1267 }
WindowStatePerFunc perfunc
Definition: execnodes.h:1791
WindowStatePerAgg peragg
Definition: execnodes.h:1792
Tuplestorestate * buffer
Definition: execnodes.h:1795
MemoryContext aggcontext
Definition: execnodes.h:1814
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:67
#define NULL
Definition: c.h:229
MemoryContext aggcontext
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
bool partition_spooled
Definition: execnodes.h:1820
int i
MemoryContext partcontext
Definition: execnodes.h:1813
static bool row_is_in_frame ( WindowAggState winstate,
int64  pos,
TupleTableSlot slot 
)
static

Definition at line 1279 of file nodeWindowAgg.c.

References are_peers(), Assert, WindowAggState::currentpos, DatumGetInt64, elog, WindowAggState::endOffsetValue, ERROR, FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_END_VALUE, FRAMEOPTION_END_VALUE_PRECEDING, FRAMEOPTION_RANGE, FRAMEOPTION_ROWS, FRAMEOPTION_START_CURRENT_ROW, FRAMEOPTION_START_VALUE, FRAMEOPTION_START_VALUE_PRECEDING, WindowAggState::frameOptions, WindowAggState::ss, ScanState::ss_ScanTupleSlot, and WindowAggState::startOffsetValue.

Referenced by eval_windowaggregates(), and WinGetFuncArgInFrame().

1280 {
1281  int frameOptions = winstate->frameOptions;
1282 
1283  Assert(pos >= 0); /* else caller error */
1284 
1285  /* First, check frame starting conditions */
1286  if (frameOptions & FRAMEOPTION_START_CURRENT_ROW)
1287  {
1288  if (frameOptions & FRAMEOPTION_ROWS)
1289  {
1290  /* rows before current row are out of frame */
1291  if (pos < winstate->currentpos)
1292  return false;
1293  }
1294  else if (frameOptions & FRAMEOPTION_RANGE)
1295  {
1296  /* preceding row that is not peer is out of frame */
1297  if (pos < winstate->currentpos &&
1298  !are_peers(winstate, slot, winstate->ss.ss_ScanTupleSlot))
1299  return false;
1300  }
1301  else
1302  Assert(false);
1303  }
1304  else if (frameOptions & FRAMEOPTION_START_VALUE)
1305  {
1306  if (frameOptions & FRAMEOPTION_ROWS)
1307  {
1308  int64 offset = DatumGetInt64(winstate->startOffsetValue);
1309 
1310  /* rows before current row + offset are out of frame */
1311  if (frameOptions & FRAMEOPTION_START_VALUE_PRECEDING)
1312  offset = -offset;
1313 
1314  if (pos < winstate->currentpos + offset)
1315  return false;
1316  }
1317  else if (frameOptions & FRAMEOPTION_RANGE)
1318  {
1319  /* parser should have rejected this */
1320  elog(ERROR, "window frame with value offset is not implemented");
1321  }
1322  else
1323  Assert(false);
1324  }
1325 
1326  /* Okay so far, now check frame ending conditions */
1327  if (frameOptions & FRAMEOPTION_END_CURRENT_ROW)
1328  {
1329  if (frameOptions & FRAMEOPTION_ROWS)
1330  {
1331  /* rows after current row are out of frame */
1332  if (pos > winstate->currentpos)
1333  return false;
1334  }
1335  else if (frameOptions & FRAMEOPTION_RANGE)
1336  {
1337  /* following row that is not peer is out of frame */
1338  if (pos > winstate->currentpos &&
1339  !are_peers(winstate, slot, winstate->ss.ss_ScanTupleSlot))
1340  return false;
1341  }
1342  else
1343  Assert(false);
1344  }
1345  else if (frameOptions & FRAMEOPTION_END_VALUE)
1346  {
1347  if (frameOptions & FRAMEOPTION_ROWS)
1348  {
1349  int64 offset = DatumGetInt64(winstate->endOffsetValue);
1350 
1351  /* rows after current row + offset are out of frame */
1352  if (frameOptions & FRAMEOPTION_END_VALUE_PRECEDING)
1353  offset = -offset;
1354 
1355  if (pos > winstate->currentpos + offset)
1356  return false;
1357  }
1358  else if (frameOptions & FRAMEOPTION_RANGE)
1359  {
1360  /* parser should have rejected this */
1361  elog(ERROR, "window frame with value offset is not implemented");
1362  }
1363  else
1364  Assert(false);
1365  }
1366 
1367  /* If we get here, it's in frame */
1368  return true;
1369 }
Datum startOffsetValue
Definition: execnodes.h:1810
ScanState ss
Definition: execnodes.h:1784
#define FRAMEOPTION_START_VALUE
Definition: parsenodes.h:520
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
#define ERROR
Definition: elog.h:43
#define DatumGetInt64(X)
Definition: postgres.h:613
Datum endOffsetValue
Definition: execnodes.h:1811
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:514
#define FRAMEOPTION_START_VALUE_PRECEDING
Definition: parsenodes.h:515
#define FRAMEOPTION_START_CURRENT_ROW
Definition: parsenodes.h:513
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:506
#define Assert(condition)
Definition: c.h:675
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:507
#define FRAMEOPTION_END_VALUE_PRECEDING
Definition: parsenodes.h:516
int64 currentpos
Definition: execnodes.h:1798
static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
#define elog
Definition: elog.h:219
#define FRAMEOPTION_END_VALUE
Definition: parsenodes.h:522
static void spool_tuples ( WindowAggState winstate,
int64  pos 
)
static

Definition at line 1164 of file nodeWindowAgg.c.

References WindowAggState::buffer, ExprContext::ecxt_per_query_memory, ExprContext::ecxt_per_tuple_memory, ExecCopySlot(), ExecProcNode(), execTuplesMatch(), WindowAggState::first_part_slot, MemoryContextSwitchTo(), WindowAggState::more_partitions, outerPlan, outerPlanState, WindowAgg::partColIdx, WindowAggState::partEqfunctions, WindowAggState::partition_spooled, WindowAgg::partNumCols, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, WindowAggState::spooled_rows, WindowAggState::ss, WindowAggState::tmpcontext, TupIsNull, tuplestore_in_memory(), and tuplestore_puttupleslot().

Referenced by ExecWindowAgg(), update_frameheadpos(), update_frametailpos(), window_gettupleslot(), WinGetFuncArgInPartition(), and WinGetPartitionRowCount().

1165 {
1166  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
1168  TupleTableSlot *outerslot;
1169  MemoryContext oldcontext;
1170 
1171  if (!winstate->buffer)
1172  return; /* just a safety check */
1173  if (winstate->partition_spooled)
1174  return; /* whole partition done already */
1175 
1176  /*
1177  * If the tuplestore has spilled to disk, alternate reading and writing
1178  * becomes quite expensive due to frequent buffer flushes. It's cheaper
1179  * to force the entire partition to get spooled in one go.
1180  *
1181  * XXX this is a horrid kluge --- it'd be better to fix the performance
1182  * problem inside tuplestore. FIXME
1183  */
1184  if (!tuplestore_in_memory(winstate->buffer))
1185  pos = -1;
1186 
1187  outerPlan = outerPlanState(winstate);
1188 
1189  /* Must be in query context to call outerplan */
1191 
1192  while (winstate->spooled_rows <= pos || pos == -1)
1193  {
1194  outerslot = ExecProcNode(outerPlan);
1195  if (TupIsNull(outerslot))
1196  {
1197  /* reached the end of the last partition */
1198  winstate->partition_spooled = true;
1199  winstate->more_partitions = false;
1200  break;
1201  }
1202 
1203  if (node->partNumCols > 0)
1204  {
1205  /* Check if this tuple still belongs to the current partition */
1206  if (!execTuplesMatch(winstate->first_part_slot,
1207  outerslot,
1208  node->partNumCols, node->partColIdx,
1209  winstate->partEqfunctions,
1210  winstate->tmpcontext->ecxt_per_tuple_memory))
1211  {
1212  /*
1213  * end of partition; copy the tuple for the next cycle.
1214  */
1215  ExecCopySlot(winstate->first_part_slot, outerslot);
1216  winstate->partition_spooled = true;
1217  winstate->more_partitions = true;
1218  break;
1219  }
1220  }
1221 
1222  /* Still in partition, so save it into the tuplestore */
1223  tuplestore_puttupleslot(winstate->buffer, outerslot);
1224  winstate->spooled_rows++;
1225  }
1226 
1227  MemoryContextSwitchTo(oldcontext);
1228 }
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition: tuplestore.c:708
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:398
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool execTuplesMatch(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext)
Definition: execGrouping.c:69
FmgrInfo * partEqfunctions
Definition: execnodes.h:1793
TupleTableSlot * first_part_slot
Definition: execnodes.h:1830
ExprContext * tmpcontext
Definition: execnodes.h:1816
PlanState ps
Definition: execnodes.h:1047
bool tuplestore_in_memory(Tuplestorestate *state)
Definition: tuplestore.c:1455
#define outerPlanState(node)
Definition: execnodes.h:845
#define TupIsNull(slot)
Definition: tuptable.h:138
int partNumCols
Definition: plannodes.h:794
Tuplestorestate * buffer
Definition: execnodes.h:1795
#define outerPlan(node)
Definition: plannodes.h:164
int64 spooled_rows
Definition: execnodes.h:1797
AttrNumber * partColIdx
Definition: plannodes.h:795
Plan * plan
Definition: execnodes.h:803
bool more_partitions
Definition: execnodes.h:1823
TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: execTuples.c:795
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:202
bool partition_spooled
Definition: execnodes.h:1820
static void update_frameheadpos ( WindowObject  winobj,
TupleTableSlot slot 
)
static

Definition at line 1381 of file nodeWindowAgg.c.

References are_peers(), Assert, WindowAggState::currentpos, DatumGetInt64, elog, ERROR, WindowAggState::framehead_valid, WindowAggState::frameheadpos, FRAMEOPTION_RANGE, FRAMEOPTION_ROWS, FRAMEOPTION_START_CURRENT_ROW, FRAMEOPTION_START_UNBOUNDED_PRECEDING, FRAMEOPTION_START_VALUE, FRAMEOPTION_START_VALUE_PRECEDING, WindowAggState::frameOptions, WindowAgg::ordNumCols, PlanState::plan, ScanState::ps, spool_tuples(), WindowAggState::spooled_rows, WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowAggState::startOffsetValue, window_gettupleslot(), and WindowObjectData::winstate.

Referenced by eval_windowaggregates(), WinGetFuncArgInFrame(), and WinGetFuncArgInPartition().

1382 {
1383  WindowAggState *winstate = winobj->winstate;
1384  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
1385  int frameOptions = winstate->frameOptions;
1386 
1387  if (winstate->framehead_valid)
1388  return; /* already known for current row */
1389 
1390  if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
1391  {
1392  /* In UNBOUNDED PRECEDING mode, frame head is always row 0 */
1393  winstate->frameheadpos = 0;
1394  winstate->framehead_valid = true;
1395  }
1396  else if (frameOptions & FRAMEOPTION_START_CURRENT_ROW)
1397  {
1398  if (frameOptions & FRAMEOPTION_ROWS)
1399  {
1400  /* In ROWS mode, frame head is the same as current */
1401  winstate->frameheadpos = winstate->currentpos;
1402  winstate->framehead_valid = true;
1403  }
1404  else if (frameOptions & FRAMEOPTION_RANGE)
1405  {
1406  int64 fhprev;
1407 
1408  /* If no ORDER BY, all rows are peers with each other */
1409  if (node->ordNumCols == 0)
1410  {
1411  winstate->frameheadpos = 0;
1412  winstate->framehead_valid = true;
1413  return;
1414  }
1415 
1416  /*
1417  * In RANGE START_CURRENT mode, frame head is the first row that
1418  * is a peer of current row. We search backwards from current,
1419  * which could be a bit inefficient if peer sets are large. Might
1420  * be better to have a separate read pointer that moves forward
1421  * tracking the frame head.
1422  */
1423  fhprev = winstate->currentpos - 1;
1424  for (;;)
1425  {
1426  /* assume the frame head can't go backwards */
1427  if (fhprev < winstate->frameheadpos)
1428  break;
1429  if (!window_gettupleslot(winobj, fhprev, slot))
1430  break; /* start of partition */
1431  if (!are_peers(winstate, slot, winstate->ss.ss_ScanTupleSlot))
1432  break; /* not peer of current row */
1433  fhprev--;
1434  }
1435  winstate->frameheadpos = fhprev + 1;
1436  winstate->framehead_valid = true;
1437  }
1438  else
1439  Assert(false);
1440  }
1441  else if (frameOptions & FRAMEOPTION_START_VALUE)
1442  {
1443  if (frameOptions & FRAMEOPTION_ROWS)
1444  {
1445  /* In ROWS mode, bound is physically n before/after current */
1446  int64 offset = DatumGetInt64(winstate->startOffsetValue);
1447 
1448  if (frameOptions & FRAMEOPTION_START_VALUE_PRECEDING)
1449  offset = -offset;
1450 
1451  winstate->frameheadpos = winstate->currentpos + offset;
1452  /* frame head can't go before first row */
1453  if (winstate->frameheadpos < 0)
1454  winstate->frameheadpos = 0;
1455  else if (winstate->frameheadpos > winstate->currentpos)
1456  {
1457  /* make sure frameheadpos is not past end of partition */
1458  spool_tuples(winstate, winstate->frameheadpos - 1);
1459  if (winstate->frameheadpos > winstate->spooled_rows)
1460  winstate->frameheadpos = winstate->spooled_rows;
1461  }
1462  winstate->framehead_valid = true;
1463  }
1464  else if (frameOptions & FRAMEOPTION_RANGE)
1465  {
1466  /* parser should have rejected this */
1467  elog(ERROR, "window frame with value offset is not implemented");
1468  }
1469  else
1470  Assert(false);
1471  }
1472  else
1473  Assert(false);
1474 }
int ordNumCols
Definition: plannodes.h:797
Datum startOffsetValue
Definition: execnodes.h:1810
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:1784
#define FRAMEOPTION_START_VALUE
Definition: parsenodes.h:520
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:509
static void spool_tuples(WindowAggState *winstate, int64 pos)
PlanState ps
Definition: execnodes.h:1047
int64 frameheadpos
Definition: execnodes.h:1799
#define ERROR
Definition: elog.h:43
#define DatumGetInt64(X)
Definition: postgres.h:613
#define FRAMEOPTION_START_VALUE_PRECEDING
Definition: parsenodes.h:515
#define FRAMEOPTION_START_CURRENT_ROW
Definition: parsenodes.h:513
int64 spooled_rows
Definition: execnodes.h:1797
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
Plan * plan
Definition: execnodes.h:803
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:506
#define Assert(condition)
Definition: c.h:675
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:507
int64 currentpos
Definition: execnodes.h:1798
static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
bool framehead_valid
Definition: execnodes.h:1825
#define elog
Definition: elog.h:219
static void update_frametailpos ( WindowObject  winobj,
TupleTableSlot slot 
)
static

Definition at line 1486 of file nodeWindowAgg.c.

References are_peers(), Assert, WindowAggState::currentpos, DatumGetInt64, elog, WindowAggState::endOffsetValue, ERROR, FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_END_UNBOUNDED_FOLLOWING, FRAMEOPTION_END_VALUE, FRAMEOPTION_END_VALUE_PRECEDING, FRAMEOPTION_RANGE, FRAMEOPTION_ROWS, WindowAggState::frameOptions, WindowAggState::frametail_valid, WindowAggState::frametailpos, Max, WindowAgg::ordNumCols, PlanState::plan, ScanState::ps, spool_tuples(), WindowAggState::spooled_rows, WindowAggState::ss, ScanState::ss_ScanTupleSlot, window_gettupleslot(), and WindowObjectData::winstate.

Referenced by WinGetFuncArgInFrame().

1487 {
1488  WindowAggState *winstate = winobj->winstate;
1489  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
1490  int frameOptions = winstate->frameOptions;
1491 
1492  if (winstate->frametail_valid)
1493  return; /* already known for current row */
1494 
1495  if (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
1496  {
1497  /* In UNBOUNDED FOLLOWING mode, all partition rows are in frame */
1498  spool_tuples(winstate, -1);
1499  winstate->frametailpos = winstate->spooled_rows - 1;
1500  winstate->frametail_valid = true;
1501  }
1502  else if (frameOptions & FRAMEOPTION_END_CURRENT_ROW)
1503  {
1504  if (frameOptions & FRAMEOPTION_ROWS)
1505  {
1506  /* In ROWS mode, exactly the rows up to current are in frame */
1507  winstate->frametailpos = winstate->currentpos;
1508  winstate->frametail_valid = true;
1509  }
1510  else if (frameOptions & FRAMEOPTION_RANGE)
1511  {
1512  int64 ftnext;
1513 
1514  /* If no ORDER BY, all rows are peers with each other */
1515  if (node->ordNumCols == 0)
1516  {
1517  spool_tuples(winstate, -1);
1518  winstate->frametailpos = winstate->spooled_rows - 1;
1519  winstate->frametail_valid = true;
1520  return;
1521  }
1522 
1523  /*
1524  * Else we have to search for the first non-peer of the current
1525  * row. We assume the current value of frametailpos is a lower
1526  * bound on the possible frame tail location, ie, frame tail never
1527  * goes backward, and that currentpos is also a lower bound, ie,
1528  * frame end always >= current row.
1529  */
1530  ftnext = Max(winstate->frametailpos, winstate->currentpos) + 1;
1531  for (;;)
1532  {
1533  if (!window_gettupleslot(winobj, ftnext, slot))
1534  break; /* end of partition */
1535  if (!are_peers(winstate, slot, winstate->ss.ss_ScanTupleSlot))
1536  break; /* not peer of current row */
1537  ftnext++;
1538  }
1539  winstate->frametailpos = ftnext - 1;
1540  winstate->frametail_valid = true;
1541  }
1542  else
1543  Assert(false);
1544  }
1545  else if (frameOptions & FRAMEOPTION_END_VALUE)
1546  {
1547  if (frameOptions & FRAMEOPTION_ROWS)
1548  {
1549  /* In ROWS mode, bound is physically n before/after current */
1550  int64 offset = DatumGetInt64(winstate->endOffsetValue);
1551 
1552  if (frameOptions & FRAMEOPTION_END_VALUE_PRECEDING)
1553  offset = -offset;
1554 
1555  winstate->frametailpos = winstate->currentpos + offset;
1556  /* smallest allowable value of frametailpos is -1 */
1557  if (winstate->frametailpos < 0)
1558  winstate->frametailpos = -1;
1559  else if (winstate->frametailpos > winstate->currentpos)
1560  {
1561  /* make sure frametailpos is not past last row of partition */
1562  spool_tuples(winstate, winstate->frametailpos);
1563  if (winstate->frametailpos >= winstate->spooled_rows)
1564  winstate->frametailpos = winstate->spooled_rows - 1;
1565  }
1566  winstate->frametail_valid = true;
1567  }
1568  else if (frameOptions & FRAMEOPTION_RANGE)
1569  {
1570  /* parser should have rejected this */
1571  elog(ERROR, "window frame with value offset is not implemented");
1572  }
1573  else
1574  Assert(false);
1575  }
1576  else
1577  Assert(false);
1578 }
int ordNumCols
Definition: plannodes.h:797
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:1784
bool frametail_valid
Definition: execnodes.h:1827
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
static void spool_tuples(WindowAggState *winstate, int64 pos)
PlanState ps
Definition: execnodes.h:1047
#define ERROR
Definition: elog.h:43
#define DatumGetInt64(X)
Definition: postgres.h:613
Datum endOffsetValue
Definition: execnodes.h:1811
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:514
#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING
Definition: parsenodes.h:512
int64 spooled_rows
Definition: execnodes.h:1797
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
Plan * plan
Definition: execnodes.h:803
#define Max(x, y)
Definition: c.h:800
int64 frametailpos
Definition: execnodes.h:1800
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:506
#define Assert(condition)
Definition: c.h:675
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:507
#define FRAMEOPTION_END_VALUE_PRECEDING
Definition: parsenodes.h:516
int64 currentpos
Definition: execnodes.h:1798
static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
#define elog
Definition: elog.h:219
#define FRAMEOPTION_END_VALUE
Definition: parsenodes.h:522
static bool window_gettupleslot ( WindowObject  winobj,
int64  pos,
TupleTableSlot slot 
)
static

Definition at line 2369 of file nodeWindowAgg.c.

References Assert, WindowAggState::buffer, ExprContext::ecxt_per_query_memory, elog, ERROR, MemoryContextSwitchTo(), ScanState::ps, PlanState::ps_ExprContext, WindowObjectData::readptr, WindowObjectData::seekpos, spool_tuples(), WindowAggState::spooled_rows, WindowAggState::ss, tuplestore_advance(), tuplestore_gettupleslot(), tuplestore_select_read_pointer(), tuplestore_skiptuples(), and WindowObjectData::winstate.

Referenced by eval_windowaggregates(), update_frameheadpos(), update_frametailpos(), WinGetFuncArgInFrame(), WinGetFuncArgInPartition(), and WinRowsArePeers().

2370 {
2371  WindowAggState *winstate = winobj->winstate;
2372  MemoryContext oldcontext;
2373 
2374  /* Don't allow passing -1 to spool_tuples here */
2375  if (pos < 0)
2376  return false;
2377 
2378  /* If necessary, fetch the tuple into the spool */
2379  spool_tuples(winstate, pos);
2380 
2381  if (pos >= winstate->spooled_rows)
2382  return false;
2383 
2384  if (pos < winobj->markpos)
2385  elog(ERROR, "cannot fetch row before WindowObject's mark position");
2386 
2388 
2389  tuplestore_select_read_pointer(winstate->buffer, winobj->readptr);
2390 
2391  /*
2392  * Advance or rewind until we are within one tuple of the one we want.
2393  */
2394  if (winobj->seekpos < pos - 1)
2395  {
2396  if (!tuplestore_skiptuples(winstate->buffer,
2397  pos - 1 - winobj->seekpos,
2398  true))
2399  elog(ERROR, "unexpected end of tuplestore");
2400  winobj->seekpos = pos - 1;
2401  }
2402  else if (winobj->seekpos > pos + 1)
2403  {
2404  if (!tuplestore_skiptuples(winstate->buffer,
2405  winobj->seekpos - (pos + 1),
2406  false))
2407  elog(ERROR, "unexpected end of tuplestore");
2408  winobj->seekpos = pos + 1;
2409  }
2410  else if (winobj->seekpos == pos)
2411  {
2412  /*
2413  * There's no API to refetch the tuple at the current position. We
2414  * have to move one tuple forward, and then one backward. (We don't
2415  * do it the other way because we might try to fetch the row before
2416  * our mark, which isn't allowed.) XXX this case could stand to be
2417  * optimized.
2418  */
2419  tuplestore_advance(winstate->buffer, true);
2420  winobj->seekpos++;
2421  }
2422 
2423  /*
2424  * Now we should be on the tuple immediately before or after the one we
2425  * want, so just fetch forwards or backwards as appropriate.
2426  */
2427  if (winobj->seekpos > pos)
2428  {
2429  if (!tuplestore_gettupleslot(winstate->buffer, false, true, slot))
2430  elog(ERROR, "unexpected end of tuplestore");
2431  winobj->seekpos--;
2432  }
2433  else
2434  {
2435  if (!tuplestore_gettupleslot(winstate->buffer, true, true, slot))
2436  elog(ERROR, "unexpected end of tuplestore");
2437  winobj->seekpos++;
2438  }
2439 
2440  Assert(winobj->seekpos == pos);
2441 
2442  MemoryContextSwitchTo(oldcontext);
2443 
2444  return true;
2445 }
bool tuplestore_advance(Tuplestorestate *state, bool forward)
Definition: tuplestore.c:1110
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void spool_tuples(WindowAggState *winstate, int64 pos)
PlanState ps
Definition: execnodes.h:1047
#define ERROR
Definition: elog.h:43
Tuplestorestate * buffer
Definition: execnodes.h:1795
int64 spooled_rows
Definition: execnodes.h:1797
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
#define Assert(condition)
Definition: c.h:675
bool tuplestore_skiptuples(Tuplestorestate *state, int64 ntuples, bool forward)
Definition: tuplestore.c:1135
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:202
void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
Definition: tuplestore.c:473
#define elog
Definition: elog.h:219
int64 WinGetCurrentPosition ( WindowObject  winobj)

Definition at line 2481 of file nodeWindowAgg.c.

References Assert, WindowAggState::currentpos, WindowObjectIsValid, and WindowObjectData::winstate.

Referenced by rank_up(), window_cume_dist(), window_percent_rank(), window_rank(), and window_row_number().

2482 {
2483  Assert(WindowObjectIsValid(winobj));
2484  return winobj->winstate->currentpos;
2485 }
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:675
int64 currentpos
Definition: execnodes.h:1798
Datum WinGetFuncArgCurrent ( WindowObject  winobj,
int  argno,
bool isnull 
)

Definition at line 2792 of file nodeWindowAgg.c.

References WindowObjectData::argstates, Assert, ExprContext::ecxt_outertuple, ExecEvalExpr(), list_nth(), ScanState::ps, PlanState::ps_ExprContext, WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowObjectIsValid, and WindowObjectData::winstate.

Referenced by leadlag_common(), window_nth_value(), and window_ntile().

2793 {
2794  WindowAggState *winstate;
2795  ExprContext *econtext;
2796 
2797  Assert(WindowObjectIsValid(winobj));
2798  winstate = winobj->winstate;
2799 
2800  econtext = winstate->ss.ps.ps_ExprContext;
2801 
2802  econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
2803  return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
2804  econtext, isnull);
2805 }
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
PlanState ps
Definition: execnodes.h:1047
void * list_nth(const List *list, int n)
Definition: list.c:410
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:265
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define Assert(condition)
Definition: c.h:675
Datum WinGetFuncArgInFrame ( WindowObject  winobj,
int  argno,
int  relpos,
int  seektype,
bool  set_mark,
bool isnull,
bool isout 
)

Definition at line 2698 of file nodeWindowAgg.c.

References WindowObjectData::argstates, Assert, WindowAggState::currentpos, ExprContext::ecxt_outertuple, elog, ERROR, ExecEvalExpr(), WindowAggState::frameheadpos, FRAMEOPTION_RANGE, FRAMEOPTION_START_UNBOUNDED_PRECEDING, WindowAggState::frameOptions, WindowAggState::frametailpos, list_nth(), ScanState::ps, PlanState::ps_ExprContext, row_is_in_frame(), WindowAggState::ss, WindowAggState::temp_slot_1, WindowAggState::temp_slot_2, update_frameheadpos(), update_frametailpos(), window_gettupleslot(), WINDOW_SEEK_CURRENT, WINDOW_SEEK_HEAD, WINDOW_SEEK_TAIL, WindowObjectIsValid, WinSetMarkPosition(), and WindowObjectData::winstate.

Referenced by window_first_value(), window_last_value(), and window_nth_value().

2701 {
2702  WindowAggState *winstate;
2703  ExprContext *econtext;
2704  TupleTableSlot *slot;
2705  bool gottuple;
2706  int64 abs_pos;
2707 
2708  Assert(WindowObjectIsValid(winobj));
2709  winstate = winobj->winstate;
2710  econtext = winstate->ss.ps.ps_ExprContext;
2711  slot = winstate->temp_slot_1;
2712 
2713  switch (seektype)
2714  {
2715  case WINDOW_SEEK_CURRENT:
2716  abs_pos = winstate->currentpos + relpos;
2717  break;
2718  case WINDOW_SEEK_HEAD:
2719  update_frameheadpos(winobj, slot);
2720  abs_pos = winstate->frameheadpos + relpos;
2721  break;
2722  case WINDOW_SEEK_TAIL:
2723  update_frametailpos(winobj, slot);
2724  abs_pos = winstate->frametailpos + relpos;
2725  break;
2726  default:
2727  elog(ERROR, "unrecognized window seek type: %d", seektype);
2728  abs_pos = 0; /* keep compiler quiet */
2729  break;
2730  }
2731 
2732  gottuple = window_gettupleslot(winobj, abs_pos, slot);
2733  if (gottuple)
2734  gottuple = row_is_in_frame(winstate, abs_pos, slot);
2735 
2736  if (!gottuple)
2737  {
2738  if (isout)
2739  *isout = true;
2740  *isnull = true;
2741  return (Datum) 0;
2742  }
2743  else
2744  {
2745  if (isout)
2746  *isout = false;
2747  if (set_mark)
2748  {
2749  int frameOptions = winstate->frameOptions;
2750  int64 mark_pos = abs_pos;
2751 
2752  /*
2753  * In RANGE mode with a moving frame head, we must not let the
2754  * mark advance past frameheadpos, since that row has to be
2755  * fetchable during future update_frameheadpos calls.
2756  *
2757  * XXX it is very ugly to pollute window functions' marks with
2758  * this consideration; it could for instance mask a logic bug that
2759  * lets a window function fetch rows before what it had claimed
2760  * was its mark. Perhaps use a separate mark for frame head
2761  * probes?
2762  */
2763  if ((frameOptions & FRAMEOPTION_RANGE) &&
2764  !(frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING))
2765  {
2766  update_frameheadpos(winobj, winstate->temp_slot_2);
2767  if (mark_pos > winstate->frameheadpos)
2768  mark_pos = winstate->frameheadpos;
2769  }
2770  WinSetMarkPosition(winobj, mark_pos);
2771  }
2772  econtext->ecxt_outertuple = slot;
2773  return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
2774  econtext, isnull);
2775  }
2776 }
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:509
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1835
#define WINDOW_SEEK_TAIL
Definition: windowapi.h:34
PlanState ps
Definition: execnodes.h:1047
int64 frameheadpos
Definition: execnodes.h:1799
#define ERROR
Definition: elog.h:43
static bool row_is_in_frame(WindowAggState *winstate, int64 pos, TupleTableSlot *slot)
TupleTableSlot * temp_slot_2
Definition: execnodes.h:1836
void * list_nth(const List *list, int n)
Definition: list.c:410
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:265
static void update_frameheadpos(WindowObject winobj, TupleTableSlot *slot)
#define WINDOW_SEEK_HEAD
Definition: windowapi.h:33
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
uintptr_t Datum
Definition: postgres.h:372
static void update_frametailpos(WindowObject winobj, TupleTableSlot *slot)
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define WINDOW_SEEK_CURRENT
Definition: windowapi.h:32
int64 frametailpos
Definition: execnodes.h:1800
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:506
#define Assert(condition)
Definition: c.h:675
int64 currentpos
Definition: execnodes.h:1798
void WinSetMarkPosition(WindowObject winobj, int64 markpos)
#define elog
Definition: elog.h:219
Datum WinGetFuncArgInPartition ( WindowObject  winobj,
int  argno,
int  relpos,
int  seektype,
bool  set_mark,
bool isnull,
bool isout 
)

Definition at line 2602 of file nodeWindowAgg.c.

References WindowObjectData::argstates, Assert, WindowAggState::currentpos, ExprContext::ecxt_outertuple, elog, ERROR, ExecEvalExpr(), WindowAggState::frameheadpos, FRAMEOPTION_RANGE, FRAMEOPTION_START_UNBOUNDED_PRECEDING, WindowAggState::frameOptions, list_nth(), ScanState::ps, PlanState::ps_ExprContext, spool_tuples(), WindowAggState::spooled_rows, WindowAggState::ss, WindowAggState::temp_slot_1, WindowAggState::temp_slot_2, update_frameheadpos(), window_gettupleslot(), WINDOW_SEEK_CURRENT, WINDOW_SEEK_HEAD, WINDOW_SEEK_TAIL, WindowObjectIsValid, WinSetMarkPosition(), and WindowObjectData::winstate.

Referenced by leadlag_common().

2605 {
2606  WindowAggState *winstate;
2607  ExprContext *econtext;
2608  TupleTableSlot *slot;
2609  bool gottuple;
2610  int64 abs_pos;
2611 
2612  Assert(WindowObjectIsValid(winobj));
2613  winstate = winobj->winstate;
2614  econtext = winstate->ss.ps.ps_ExprContext;
2615  slot = winstate->temp_slot_1;
2616 
2617  switch (seektype)
2618  {
2619  case WINDOW_SEEK_CURRENT:
2620  abs_pos = winstate->currentpos + relpos;
2621  break;
2622  case WINDOW_SEEK_HEAD:
2623  abs_pos = relpos;
2624  break;
2625  case WINDOW_SEEK_TAIL:
2626  spool_tuples(winstate, -1);
2627  abs_pos = winstate->spooled_rows - 1 + relpos;
2628  break;
2629  default:
2630  elog(ERROR, "unrecognized window seek type: %d", seektype);
2631  abs_pos = 0; /* keep compiler quiet */
2632  break;
2633  }
2634 
2635  gottuple = window_gettupleslot(winobj, abs_pos, slot);
2636 
2637  if (!gottuple)
2638  {
2639  if (isout)
2640  *isout = true;
2641  *isnull = true;
2642  return (Datum) 0;
2643  }
2644  else
2645  {
2646  if (isout)
2647  *isout = false;
2648  if (set_mark)
2649  {
2650  int frameOptions = winstate->frameOptions;
2651  int64 mark_pos = abs_pos;
2652 
2653  /*
2654  * In RANGE mode with a moving frame head, we must not let the
2655  * mark advance past frameheadpos, since that row has to be
2656  * fetchable during future update_frameheadpos calls.
2657  *
2658  * XXX it is very ugly to pollute window functions' marks with
2659  * this consideration; it could for instance mask a logic bug that
2660  * lets a window function fetch rows before what it had claimed
2661  * was its mark. Perhaps use a separate mark for frame head
2662  * probes?
2663  */
2664  if ((frameOptions & FRAMEOPTION_RANGE) &&
2665  !(frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING))
2666  {
2667  update_frameheadpos(winobj, winstate->temp_slot_2);
2668  if (mark_pos > winstate->frameheadpos)
2669  mark_pos = winstate->frameheadpos;
2670  }
2671  WinSetMarkPosition(winobj, mark_pos);
2672  }
2673  econtext->ecxt_outertuple = slot;
2674  return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
2675  econtext, isnull);
2676  }
2677 }
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:1784
ExprContext * ps_ExprContext
Definition: execnodes.h:833
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:509
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1835
static void spool_tuples(WindowAggState *winstate, int64 pos)
#define WINDOW_SEEK_TAIL
Definition: windowapi.h:34
PlanState ps
Definition: execnodes.h:1047
int64 frameheadpos
Definition: execnodes.h:1799
#define ERROR
Definition: elog.h:43
TupleTableSlot * temp_slot_2
Definition: execnodes.h:1836
void * list_nth(const List *list, int n)
Definition: list.c:410
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:265
static void update_frameheadpos(WindowObject winobj, TupleTableSlot *slot)
int64 spooled_rows
Definition: execnodes.h:1797
#define WINDOW_SEEK_HEAD
Definition: windowapi.h:33
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
uintptr_t Datum
Definition: postgres.h:372
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define WINDOW_SEEK_CURRENT
Definition: windowapi.h:32
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:506
#define Assert(condition)
Definition: c.h:675
int64 currentpos
Definition: execnodes.h:1798
void WinSetMarkPosition(WindowObject winobj, int64 markpos)
#define elog
Definition: elog.h:219
void* WinGetPartitionLocalMemory ( WindowObject  winobj,
Size  sz 
)

Definition at line 2466 of file nodeWindowAgg.c.

References Assert, WindowObjectData::localmem, MemoryContextAllocZero(), NULL, WindowAggState::partcontext, WindowObjectIsValid, and WindowObjectData::winstate.

Referenced by rank_up(), window_cume_dist(), window_dense_rank(), window_ntile(), window_percent_rank(), and window_rank().

2467 {
2468  Assert(WindowObjectIsValid(winobj));
2469  if (winobj->localmem == NULL)
2470  winobj->localmem =
2472  return winobj->localmem;
2473 }
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:742
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
MemoryContext partcontext
Definition: execnodes.h:1813
int64 WinGetPartitionRowCount ( WindowObject  winobj)

Definition at line 2496 of file nodeWindowAgg.c.

References Assert, spool_tuples(), WindowAggState::spooled_rows, WindowObjectIsValid, and WindowObjectData::winstate.

Referenced by window_cume_dist(), window_ntile(), and window_percent_rank().

2497 {
2498  Assert(WindowObjectIsValid(winobj));
2499  spool_tuples(winobj->winstate, -1);
2500  return winobj->winstate->spooled_rows;
2501 }
static void spool_tuples(WindowAggState *winstate, int64 pos)
int64 spooled_rows
Definition: execnodes.h:1797
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:675
bool WinRowsArePeers ( WindowObject  winobj,
int64  pos1,
int64  pos2 
)

Definition at line 2549 of file nodeWindowAgg.c.

References are_peers(), Assert, elog, ERROR, ExecClearTuple(), INT64_FORMAT, WindowAgg::ordNumCols, PlanState::plan, ScanState::ps, WindowAggState::ss, WindowAggState::temp_slot_1, WindowAggState::temp_slot_2, window_gettupleslot(), WindowObjectIsValid, and WindowObjectData::winstate.

Referenced by rank_up(), and window_cume_dist().

2550 {
2551  WindowAggState *winstate;
2552  WindowAgg *node;
2553  TupleTableSlot *slot1;
2554  TupleTableSlot *slot2;
2555  bool res;
2556 
2557  Assert(WindowObjectIsValid(winobj));
2558  winstate = winobj->winstate;
2559  node = (WindowAgg *) winstate->ss.ps.plan;
2560 
2561  /* If no ORDER BY, all rows are peers; don't bother to fetch them */
2562  if (node->ordNumCols == 0)
2563  return true;
2564 
2565  slot1 = winstate->temp_slot_1;
2566  slot2 = winstate->temp_slot_2;
2567 
2568  if (!window_gettupleslot(winobj, pos1, slot1))
2569  elog(ERROR, "specified position is out of window: " INT64_FORMAT,
2570  pos1);
2571  if (!window_gettupleslot(winobj, pos2, slot2))
2572  elog(ERROR, "specified position is out of window: " INT64_FORMAT,
2573  pos2);
2574 
2575  res = are_peers(winstate, slot1, slot2);
2576 
2577  ExecClearTuple(slot1);
2578  ExecClearTuple(slot2);
2579 
2580  return res;
2581 }
int ordNumCols
Definition: plannodes.h:797
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:1784
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1835
PlanState ps
Definition: execnodes.h:1047
#define ERROR
Definition: elog.h:43
TupleTableSlot * temp_slot_2
Definition: execnodes.h:1836
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
Plan * plan
Definition: execnodes.h:803
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:675
#define INT64_FORMAT
Definition: c.h:315
static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
#define elog
Definition: elog.h:219
void WinSetMarkPosition ( WindowObject  winobj,
int64  markpos 
)

Definition at line 2514 of file nodeWindowAgg.c.

References Assert, WindowAggState::buffer, elog, ERROR, WindowObjectData::markpos, WindowObjectData::markptr, WindowObjectData::readptr, WindowObjectData::seekpos, tuplestore_select_read_pointer(), tuplestore_skiptuples(), WindowObjectIsValid, and WindowObjectData::winstate.

Referenced by eval_windowaggregates(), rank_up(), window_row_number(), WinGetFuncArgInFrame(), and WinGetFuncArgInPartition().

2515 {
2516  WindowAggState *winstate;
2517 
2518  Assert(WindowObjectIsValid(winobj));
2519  winstate = winobj->winstate;
2520 
2521  if (markpos < winobj->markpos)
2522  elog(ERROR, "cannot move WindowObject's mark position backward");
2523  tuplestore_select_read_pointer(winstate->buffer, winobj->markptr);
2524  if (markpos > winobj->markpos)
2525  {
2526  tuplestore_skiptuples(winstate->buffer,
2527  markpos - winobj->markpos,
2528  true);
2529  winobj->markpos = markpos;
2530  }
2531  tuplestore_select_read_pointer(winstate->buffer, winobj->readptr);
2532  if (markpos > winobj->seekpos)
2533  {
2534  tuplestore_skiptuples(winstate->buffer,
2535  markpos - winobj->seekpos,
2536  true);
2537  winobj->seekpos = markpos;
2538  }
2539 }
#define ERROR
Definition: elog.h:43
Tuplestorestate * buffer
Definition: execnodes.h:1795
WindowAggState * winstate
Definition: nodeWindowAgg.c:62
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:675
bool tuplestore_skiptuples(Tuplestorestate *state, int64 ntuples, bool forward)
Definition: tuplestore.c:1135
void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
Definition: tuplestore.c:473
#define elog
Definition: elog.h:219