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/regproc.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)
 
static TupleTableSlotExecWindowAgg (PlanState *pstate)
 
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 239 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(), 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().

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

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

2379 {
2380  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
2381 
2382  /* If no ORDER BY, all rows are peers with each other */
2383  if (node->ordNumCols == 0)
2384  return true;
2385 
2386  return execTuplesMatch(slot1, slot2,
2387  node->ordNumCols, node->ordColIdx,
2388  winstate->ordEqfunctions,
2389  winstate->tmpcontext->ecxt_per_tuple_memory);
2390 }
int ordNumCols
Definition: plannodes.h:806
ScanState ss
Definition: execnodes.h:1847
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
AttrNumber * ordColIdx
Definition: plannodes.h:807
bool execTuplesMatch(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext)
Definition: execGrouping.c:69
ExprContext * tmpcontext
Definition: execnodes.h:1878
PlanState ps
Definition: execnodes.h:1101
Plan * plan
Definition: execnodes.h:847
FmgrInfo * ordEqfunctions
Definition: execnodes.h:1857
static void begin_partition ( WindowAggState winstate)
static

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

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

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

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

Definition at line 1016 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(), WindowStatePerFuncData::numArguments, ScanState::ps, PlanState::ps_ExprContext, WindowStatePerFuncData::resulttypeByVal, WindowStatePerFuncData::resulttypeLen, WindowAggState::ss, WindowStatePerFuncData::winCollation, and WindowStatePerFuncData::winobj.

Referenced by ExecWindowAgg().

1018 {
1019  FunctionCallInfoData fcinfo;
1020  MemoryContext oldContext;
1021 
1023 
1024  /*
1025  * We don't pass any normal arguments to a window function, but we do pass
1026  * it the number of arguments, in order to permit window function
1027  * implementations to support varying numbers of arguments. The real info
1028  * goes through the WindowObject, which is passed via fcinfo->context.
1029  */
1030  InitFunctionCallInfoData(fcinfo, &(perfuncstate->flinfo),
1031  perfuncstate->numArguments,
1032  perfuncstate->winCollation,
1033  (void *) perfuncstate->winobj, NULL);
1034  /* Just in case, make all the regular argument slots be null */
1035  memset(fcinfo.argnull, true, perfuncstate->numArguments);
1036  /* Window functions don't have a current aggregate context, either */
1037  winstate->curaggcontext = NULL;
1038 
1039  *result = FunctionCallInvoke(&fcinfo);
1040  *isnull = fcinfo.isnull;
1041 
1042  /*
1043  * Make sure pass-by-ref data is allocated in the appropriate context. (We
1044  * need this in case the function returns a pointer into some short-lived
1045  * tuple, as is entirely possible.)
1046  */
1047  if (!perfuncstate->resulttypeByVal && !fcinfo.isnull &&
1049  DatumGetPointer(*result)))
1050  *result = datumCopy(*result,
1051  perfuncstate->resulttypeByVal,
1052  perfuncstate->resulttypeLen);
1053 
1054  MemoryContextSwitchTo(oldContext);
1055 }
MemoryContext curaggcontext
Definition: execnodes.h:1877
ScanState ss
Definition: execnodes.h:1847
ExprContext * ps_ExprContext
Definition: execnodes.h:881
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
PlanState ps
Definition: execnodes.h:1101
#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
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:566
#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 2014 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().

2015 {
2017  int i;
2018 
2019  release_partition(node);
2020 
2024  ExecClearTuple(node->temp_slot_1);
2025  ExecClearTuple(node->temp_slot_2);
2026 
2027  /*
2028  * Free both the expr contexts.
2029  */
2030  ExecFreeExprContext(&node->ss.ps);
2031  node->ss.ps.ps_ExprContext = node->tmpcontext;
2032  ExecFreeExprContext(&node->ss.ps);
2033 
2034  for (i = 0; i < node->numaggs; i++)
2035  {
2036  if (node->peragg[i].aggcontext != node->aggcontext)
2038  }
2041 
2042  pfree(node->perfunc);
2043  pfree(node->peragg);
2044 
2045  outerPlan = outerPlanState(node);
2046  ExecEndNode(outerPlan);
2047 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
ScanState ss
Definition: execnodes.h:1847
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:523
ExprContext * ps_ExprContext
Definition: execnodes.h:881
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1104
static void release_partition(WindowAggState *winstate)
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1896
WindowStatePerFunc perfunc
Definition: execnodes.h:1854
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:521
TupleTableSlot * first_part_slot
Definition: execnodes.h:1891
ExprContext * tmpcontext
Definition: execnodes.h:1878
PlanState ps
Definition: execnodes.h:1101
void pfree(void *pointer)
Definition: mcxt.c:949
#define outerPlanState(node)
Definition: execnodes.h:893
TupleTableSlot * temp_slot_2
Definition: execnodes.h:1897
WindowStatePerAgg peragg
Definition: execnodes.h:1855
MemoryContext aggcontext
Definition: execnodes.h:1876
#define outerPlan(node)
Definition: plannodes.h:174
TupleTableSlot * agg_row_slot
Definition: execnodes.h:1895
MemoryContext aggcontext
int i
MemoryContext partcontext
Definition: execnodes.h:1875
WindowAggState* ExecInitWindowAgg ( WindowAgg node,
EState estate,
int  eflags 
)

Definition at line 1772 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(), PlanState::ExecProcNode, ExecSetSlotDescriptor(), execTuplesMatchPrepare(), ExecWindowAgg(), 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, 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().

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

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

2055 {
2057  ExprContext *econtext = node->ss.ps.ps_ExprContext;
2058 
2059  node->all_done = false;
2060  node->all_first = true;
2061 
2062  /* release tuplestore et al */
2063  release_partition(node);
2064 
2065  /* release all temp tuples, but especially first_part_slot */
2069  ExecClearTuple(node->temp_slot_1);
2070  ExecClearTuple(node->temp_slot_2);
2071 
2072  /* Forget current wfunc values */
2073  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numfuncs);
2074  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numfuncs);
2075 
2076  /*
2077  * if chgParam of subnode is not null then plan will be re-scanned by
2078  * first ExecProcNode.
2079  */
2080  if (outerPlan->chgParam == NULL)
2081  ExecReScan(outerPlan);
2082 }
Datum * ecxt_aggvalues
Definition: execnodes.h:213
ScanState ss
Definition: execnodes.h:1847
ExprContext * ps_ExprContext
Definition: execnodes.h:881
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define MemSet(start, val, len)
Definition: c.h:863
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1104
static void release_partition(WindowAggState *winstate)
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1896
TupleTableSlot * first_part_slot
Definition: execnodes.h:1891
PlanState ps
Definition: execnodes.h:1101
#define outerPlanState(node)
Definition: execnodes.h:893
TupleTableSlot * temp_slot_2
Definition: execnodes.h:1897
Bitmapset * chgParam
Definition: execnodes.h:875
#define outerPlan(node)
Definition: plannodes.h:174
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
TupleTableSlot * agg_row_slot
Definition: execnodes.h:1895
static TupleTableSlot* ExecWindowAgg ( PlanState pstate)
static

Definition at line 1592 of file nodeWindowAgg.c.

References WindowAggState::all_done, WindowAggState::all_first, Assert, begin_partition(), WindowAggState::buffer, castNode, CHECK_FOR_INTERRUPTS, 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, 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 ExecInitWindowAgg().

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

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

583 {
584  MemoryContext oldContext;
585 
587 
588  /*
589  * Apply the agg's finalfn if one is provided, else return transValue.
590  */
591  if (OidIsValid(peraggstate->finalfn_oid))
592  {
593  int numFinalArgs = peraggstate->numFinalArgs;
594  FunctionCallInfoData fcinfo;
595  bool anynull;
596  int i;
597 
598  InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn),
599  numFinalArgs,
600  perfuncstate->winCollation,
601  (void *) winstate, NULL);
602  fcinfo.arg[0] = MakeExpandedObjectReadOnly(peraggstate->transValue,
603  peraggstate->transValueIsNull,
604  peraggstate->transtypeLen);
605  fcinfo.argnull[0] = peraggstate->transValueIsNull;
606  anynull = peraggstate->transValueIsNull;
607 
608  /* Fill any remaining argument positions with nulls */
609  for (i = 1; i < numFinalArgs; i++)
610  {
611  fcinfo.arg[i] = (Datum) 0;
612  fcinfo.argnull[i] = true;
613  anynull = true;
614  }
615 
616  if (fcinfo.flinfo->fn_strict && anynull)
617  {
618  /* don't call a strict function with NULL inputs */
619  *result = (Datum) 0;
620  *isnull = true;
621  }
622  else
623  {
624  winstate->curaggcontext = peraggstate->aggcontext;
625  *result = FunctionCallInvoke(&fcinfo);
626  winstate->curaggcontext = NULL;
627  *isnull = fcinfo.isnull;
628  }
629  }
630  else
631  {
632  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
633  *result = peraggstate->transValue;
634  *isnull = peraggstate->transValueIsNull;
635  }
636 
637  /*
638  * If result is pass-by-ref, make sure it is in the right context.
639  */
640  if (!peraggstate->resulttypeByVal && !*isnull &&
642  DatumGetPointer(*result)))
643  *result = datumCopy(*result,
644  peraggstate->resulttypeByVal,
645  peraggstate->resulttypeLen);
646  MemoryContextSwitchTo(oldContext);
647 }
MemoryContext curaggcontext
Definition: execnodes.h:1877
ScanState ss
Definition: execnodes.h:1847
ExprContext * ps_ExprContext
Definition: execnodes.h:881
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define OidIsValid(objectId)
Definition: c.h:532
PlanState ps
Definition: execnodes.h:1101
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
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:566
#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 2355 of file nodeWindowAgg.c.

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

Referenced by initialize_peragg().

2356 {
2357  Oid typinput,
2358  typioparam;
2359  char *strInitVal;
2360  Datum initVal;
2361 
2362  getTypeInputInfo(transtype, &typinput, &typioparam);
2363  strInitVal = TextDatumGetCString(textInitVal);
2364  initVal = OidInputFunctionCall(typinput, strInitVal,
2365  typioparam, -1);
2366  pfree(strInitVal);
2367  return initVal;
2368 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:949
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:1733
static WindowStatePerAggData * initialize_peragg ( WindowAggState winstate,
WindowFunc wfunc,
WindowStatePerAgg  peraggstate 
)
static

Definition at line 2090 of file nodeWindowAgg.c.

References ACL_EXECUTE, ACL_KIND_PROC, aclcheck_error(), ACLCHECK_OK, WindowStatePerAggData::aggcontext, WindowAggState::aggcontext, AGGFNOID, AGGMODIFY_READ_ONLY, 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, format_procedure(), 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().

2092 {
2093  Oid inputTypes[FUNC_MAX_ARGS];
2094  int numArguments;
2095  HeapTuple aggTuple;
2096  Form_pg_aggregate aggform;
2097  Oid aggtranstype;
2098  AttrNumber initvalAttNo;
2099  AclResult aclresult;
2100  bool use_ma_code;
2101  Oid transfn_oid,
2102  invtransfn_oid,
2103  finalfn_oid;
2104  bool finalextra;
2105  char finalmodify;
2106  Expr *transfnexpr,
2107  *invtransfnexpr,
2108  *finalfnexpr;
2109  Datum textInitVal;
2110  int i;
2111  ListCell *lc;
2112 
2113  numArguments = list_length(wfunc->args);
2114 
2115  i = 0;
2116  foreach(lc, wfunc->args)
2117  {
2118  inputTypes[i++] = exprType((Node *) lfirst(lc));
2119  }
2120 
2121  aggTuple = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(wfunc->winfnoid));
2122  if (!HeapTupleIsValid(aggTuple))
2123  elog(ERROR, "cache lookup failed for aggregate %u",
2124  wfunc->winfnoid);
2125  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
2126 
2127  /*
2128  * Figure out whether we want to use the moving-aggregate implementation,
2129  * and collect the right set of fields from the pg_attribute entry.
2130  *
2131  * It's possible that an aggregate would supply a safe moving-aggregate
2132  * implementation and an unsafe normal one, in which case our hand is
2133  * forced. Otherwise, if the frame head can't move, we don't need
2134  * moving-aggregate code. Even if we'd like to use it, don't do so if the
2135  * aggregate's arguments (and FILTER clause if any) contain any calls to
2136  * volatile functions. Otherwise, the difference between restarting and
2137  * not restarting the aggregation would be user-visible.
2138  */
2139  if (!OidIsValid(aggform->aggminvtransfn))
2140  use_ma_code = false; /* sine qua non */
2141  else if (aggform->aggmfinalmodify == AGGMODIFY_READ_ONLY &&
2142  aggform->aggfinalmodify != AGGMODIFY_READ_ONLY)
2143  use_ma_code = true; /* decision forced by safety */
2145  use_ma_code = false; /* non-moving frame head */
2146  else if (contain_volatile_functions((Node *) wfunc))
2147  use_ma_code = false; /* avoid possible behavioral change */
2148  else
2149  use_ma_code = true; /* yes, let's use it */
2150  if (use_ma_code)
2151  {
2152  peraggstate->transfn_oid = transfn_oid = aggform->aggmtransfn;
2153  peraggstate->invtransfn_oid = invtransfn_oid = aggform->aggminvtransfn;
2154  peraggstate->finalfn_oid = finalfn_oid = aggform->aggmfinalfn;
2155  finalextra = aggform->aggmfinalextra;
2156  finalmodify = aggform->aggmfinalmodify;
2157  aggtranstype = aggform->aggmtranstype;
2158  initvalAttNo = Anum_pg_aggregate_aggminitval;
2159  }
2160  else
2161  {
2162  peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
2163  peraggstate->invtransfn_oid = invtransfn_oid = InvalidOid;
2164  peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
2165  finalextra = aggform->aggfinalextra;
2166  finalmodify = aggform->aggfinalmodify;
2167  aggtranstype = aggform->aggtranstype;
2168  initvalAttNo = Anum_pg_aggregate_agginitval;
2169  }
2170 
2171  /*
2172  * ExecInitWindowAgg already checked permission to call aggregate function
2173  * ... but we still need to check the component functions
2174  */
2175 
2176  /* Check that aggregate owner has permission to call component fns */
2177  {
2178  HeapTuple procTuple;
2179  Oid aggOwner;
2180 
2181  procTuple = SearchSysCache1(PROCOID,
2182  ObjectIdGetDatum(wfunc->winfnoid));
2183  if (!HeapTupleIsValid(procTuple))
2184  elog(ERROR, "cache lookup failed for function %u",
2185  wfunc->winfnoid);
2186  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
2187  ReleaseSysCache(procTuple);
2188 
2189  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
2190  ACL_EXECUTE);
2191  if (aclresult != ACLCHECK_OK)
2192  aclcheck_error(aclresult, ACL_KIND_PROC,
2193  get_func_name(transfn_oid));
2194  InvokeFunctionExecuteHook(transfn_oid);
2195 
2196  if (OidIsValid(invtransfn_oid))
2197  {
2198  aclresult = pg_proc_aclcheck(invtransfn_oid, aggOwner,
2199  ACL_EXECUTE);
2200  if (aclresult != ACLCHECK_OK)
2201  aclcheck_error(aclresult, ACL_KIND_PROC,
2202  get_func_name(invtransfn_oid));
2203  InvokeFunctionExecuteHook(invtransfn_oid);
2204  }
2205 
2206  if (OidIsValid(finalfn_oid))
2207  {
2208  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
2209  ACL_EXECUTE);
2210  if (aclresult != ACLCHECK_OK)
2211  aclcheck_error(aclresult, ACL_KIND_PROC,
2212  get_func_name(finalfn_oid));
2213  InvokeFunctionExecuteHook(finalfn_oid);
2214  }
2215  }
2216 
2217  /*
2218  * If the selected finalfn isn't read-only, we can't run this aggregate as
2219  * a window function. This is a user-facing error, so we take a bit more
2220  * care with the error message than elsewhere in this function.
2221  */
2222  if (finalmodify != AGGMODIFY_READ_ONLY)
2223  ereport(ERROR,
2224  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2225  errmsg("aggregate function %s does not support use as a window function",
2226  format_procedure(wfunc->winfnoid))));
2227 
2228  /* Detect how many arguments to pass to the finalfn */
2229  if (finalextra)
2230  peraggstate->numFinalArgs = numArguments + 1;
2231  else
2232  peraggstate->numFinalArgs = 1;
2233 
2234  /* resolve actual type of transition state, if polymorphic */
2235  aggtranstype = resolve_aggregate_transtype(wfunc->winfnoid,
2236  aggtranstype,
2237  inputTypes,
2238  numArguments);
2239 
2240  /* build expression trees using actual argument & result types */
2241  build_aggregate_transfn_expr(inputTypes,
2242  numArguments,
2243  0, /* no ordered-set window functions yet */
2244  false, /* no variadic window functions yet */
2245  aggtranstype,
2246  wfunc->inputcollid,
2247  transfn_oid,
2248  invtransfn_oid,
2249  &transfnexpr,
2250  &invtransfnexpr);
2251 
2252  /* set up infrastructure for calling the transfn(s) and finalfn */
2253  fmgr_info(transfn_oid, &peraggstate->transfn);
2254  fmgr_info_set_expr((Node *) transfnexpr, &peraggstate->transfn);
2255 
2256  if (OidIsValid(invtransfn_oid))
2257  {
2258  fmgr_info(invtransfn_oid, &peraggstate->invtransfn);
2259  fmgr_info_set_expr((Node *) invtransfnexpr, &peraggstate->invtransfn);
2260  }
2261 
2262  if (OidIsValid(finalfn_oid))
2263  {
2264  build_aggregate_finalfn_expr(inputTypes,
2265  peraggstate->numFinalArgs,
2266  aggtranstype,
2267  wfunc->wintype,
2268  wfunc->inputcollid,
2269  finalfn_oid,
2270  &finalfnexpr);
2271  fmgr_info(finalfn_oid, &peraggstate->finalfn);
2272  fmgr_info_set_expr((Node *) finalfnexpr, &peraggstate->finalfn);
2273  }
2274 
2275  /* get info about relevant datatypes */
2276  get_typlenbyval(wfunc->wintype,
2277  &peraggstate->resulttypeLen,
2278  &peraggstate->resulttypeByVal);
2279  get_typlenbyval(aggtranstype,
2280  &peraggstate->transtypeLen,
2281  &peraggstate->transtypeByVal);
2282 
2283  /*
2284  * initval is potentially null, so don't try to access it as a struct
2285  * field. Must do it the hard way with SysCacheGetAttr.
2286  */
2287  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple, initvalAttNo,
2288  &peraggstate->initValueIsNull);
2289 
2290  if (peraggstate->initValueIsNull)
2291  peraggstate->initValue = (Datum) 0;
2292  else
2293  peraggstate->initValue = GetAggInitVal(textInitVal,
2294  aggtranstype);
2295 
2296  /*
2297  * If the transfn is strict and the initval is NULL, make sure input type
2298  * and transtype are the same (or at least binary-compatible), so that
2299  * it's OK to use the first input value as the initial transValue. This
2300  * should have been checked at agg definition time, but we must check
2301  * again in case the transfn's strictness property has been changed.
2302  */
2303  if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
2304  {
2305  if (numArguments < 1 ||
2306  !IsBinaryCoercible(inputTypes[0], aggtranstype))
2307  ereport(ERROR,
2308  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2309  errmsg("aggregate %u needs to have compatible input type and transition type",
2310  wfunc->winfnoid)));
2311  }
2312 
2313  /*
2314  * Insist that forward and inverse transition functions have the same
2315  * strictness setting. Allowing them to differ would require handling
2316  * more special cases in advance_windowaggregate and
2317  * advance_windowaggregate_base, for no discernible benefit. This should
2318  * have been checked at agg definition time, but we must check again in
2319  * case either function's strictness property has been changed.
2320  */
2321  if (OidIsValid(invtransfn_oid) &&
2322  peraggstate->transfn.fn_strict != peraggstate->invtransfn.fn_strict)
2323  ereport(ERROR,
2324  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2325  errmsg("strictness of aggregate's forward and inverse transition functions must match")));
2326 
2327  /*
2328  * Moving aggregates use their own aggcontext.
2329  *
2330  * This is necessary because they might restart at different times, so we
2331  * might never be able to reset the shared context otherwise. We can't
2332  * make it the aggregates' responsibility to clean up after themselves,
2333  * because strict aggregates must be restarted whenever we remove their
2334  * last non-NULL input, which the aggregate won't be aware is happening.
2335  * Also, just pfree()ing the transValue upon restarting wouldn't help,
2336  * since we'd miss any indirectly referenced data. We could, in theory,
2337  * make the memory allocation rules for moving aggregates different than
2338  * they have historically been for plain aggregates, but that seems grotty
2339  * and likely to lead to memory leaks.
2340  */
2341  if (OidIsValid(invtransfn_oid))
2342  peraggstate->aggcontext =
2344  "WindowAgg Per Aggregate",
2346  else
2347  peraggstate->aggcontext = winstate->aggcontext;
2348 
2349  ReleaseSysCache(aggTuple);
2350 
2351  return peraggstate;
2352 }
#define AGGMODIFY_READ_ONLY
Definition: pg_aggregate.h:143
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define Anum_pg_aggregate_agginitval
Definition: pg_aggregate.h:117
List * args
Definition: primnodes.h:359
Definition: nodes.h:510
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:2019
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:957
unsigned int Oid
Definition: postgres_ext.h:31
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:508
#define OidIsValid(objectId)
Definition: c.h:532
#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:122
#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:1876
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:179
bool IsBinaryCoercible(Oid srctype, Oid targettype)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define Anum_pg_aggregate_aggminitval
Definition: pg_aggregate.h:118
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
#define InvalidOid
Definition: postgres_ext.h:36
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:323
#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:89
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:1882
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:1827
static void initialize_windowaggregate ( WindowAggState winstate,
WindowStatePerFunc  perfuncstate,
WindowStatePerAgg  peraggstate 
)
static

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

207 {
208  MemoryContext oldContext;
209 
210  /*
211  * If we're using a private aggcontext, we may reset it here. But if the
212  * context is shared, we don't know which other aggregates may still need
213  * it, so we must leave it to the caller to reset at an appropriate time.
214  */
215  if (peraggstate->aggcontext != winstate->aggcontext)
217 
218  if (peraggstate->initValueIsNull)
219  peraggstate->transValue = peraggstate->initValue;
220  else
221  {
222  oldContext = MemoryContextSwitchTo(peraggstate->aggcontext);
223  peraggstate->transValue = datumCopy(peraggstate->initValue,
224  peraggstate->transtypeByVal,
225  peraggstate->transtypeLen);
226  MemoryContextSwitchTo(oldContext);
227  }
228  peraggstate->transValueIsNull = peraggstate->initValueIsNull;
229  peraggstate->transValueCount = 0;
230  peraggstate->resultValue = (Datum) 0;
231  peraggstate->resultValueIsNull = true;
232 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext aggcontext
Definition: execnodes.h:1876
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 1237 of file nodeWindowAgg.c.

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

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

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

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

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

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

1166 {
1167  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
1169  TupleTableSlot *outerslot;
1170  MemoryContext oldcontext;
1171 
1172  if (!winstate->buffer)
1173  return; /* just a safety check */
1174  if (winstate->partition_spooled)
1175  return; /* whole partition done already */
1176 
1177  /*
1178  * If the tuplestore has spilled to disk, alternate reading and writing
1179  * becomes quite expensive due to frequent buffer flushes. It's cheaper
1180  * to force the entire partition to get spooled in one go.
1181  *
1182  * XXX this is a horrid kluge --- it'd be better to fix the performance
1183  * problem inside tuplestore. FIXME
1184  */
1185  if (!tuplestore_in_memory(winstate->buffer))
1186  pos = -1;
1187 
1188  outerPlan = outerPlanState(winstate);
1189 
1190  /* Must be in query context to call outerplan */
1192 
1193  while (winstate->spooled_rows <= pos || pos == -1)
1194  {
1195  outerslot = ExecProcNode(outerPlan);
1196  if (TupIsNull(outerslot))
1197  {
1198  /* reached the end of the last partition */
1199  winstate->partition_spooled = true;
1200  winstate->more_partitions = false;
1201  break;
1202  }
1203 
1204  if (node->partNumCols > 0)
1205  {
1206  /* Check if this tuple still belongs to the current partition */
1207  if (!execTuplesMatch(winstate->first_part_slot,
1208  outerslot,
1209  node->partNumCols, node->partColIdx,
1210  winstate->partEqfunctions,
1211  winstate->tmpcontext->ecxt_per_tuple_memory))
1212  {
1213  /*
1214  * end of partition; copy the tuple for the next cycle.
1215  */
1216  ExecCopySlot(winstate->first_part_slot, outerslot);
1217  winstate->partition_spooled = true;
1218  winstate->more_partitions = true;
1219  break;
1220  }
1221  }
1222 
1223  /* Still in partition, so save it into the tuplestore */
1224  tuplestore_puttupleslot(winstate->buffer, outerslot);
1225  winstate->spooled_rows++;
1226  }
1227 
1228  MemoryContextSwitchTo(oldcontext);
1229 }
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition: tuplestore.c:708
ScanState ss
Definition: execnodes.h:1847
ExprContext * ps_ExprContext
Definition: execnodes.h:881
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:1856
TupleTableSlot * first_part_slot
Definition: execnodes.h:1891
ExprContext * tmpcontext
Definition: execnodes.h:1878
PlanState ps
Definition: execnodes.h:1101
bool tuplestore_in_memory(Tuplestorestate *state)
Definition: tuplestore.c:1455
#define outerPlanState(node)
Definition: execnodes.h:893
#define TupIsNull(slot)
Definition: tuptable.h:138
int partNumCols
Definition: plannodes.h:803
Tuplestorestate * buffer
Definition: execnodes.h:1858
#define outerPlan(node)
Definition: plannodes.h:174
int64 spooled_rows
Definition: execnodes.h:1860
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:246
AttrNumber * partColIdx
Definition: plannodes.h:804
Plan * plan
Definition: execnodes.h:847
bool more_partitions
Definition: execnodes.h:1884
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:1882
static void update_frameheadpos ( WindowObject  winobj,
TupleTableSlot slot 
)
static

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

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

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

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

Definition at line 2400 of file nodeWindowAgg.c.

References Assert, WindowAggState::buffer, CHECK_FOR_INTERRUPTS, 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().

2401 {
2402  WindowAggState *winstate = winobj->winstate;
2403  MemoryContext oldcontext;
2404 
2405  /* often called repeatedly in a row */
2407 
2408  /* Don't allow passing -1 to spool_tuples here */
2409  if (pos < 0)
2410  return false;
2411 
2412  /* If necessary, fetch the tuple into the spool */
2413  spool_tuples(winstate, pos);
2414 
2415  if (pos >= winstate->spooled_rows)
2416  return false;
2417 
2418  if (pos < winobj->markpos)
2419  elog(ERROR, "cannot fetch row before WindowObject's mark position");
2420 
2422 
2423  tuplestore_select_read_pointer(winstate->buffer, winobj->readptr);
2424 
2425  /*
2426  * Advance or rewind until we are within one tuple of the one we want.
2427  */
2428  if (winobj->seekpos < pos - 1)
2429  {
2430  if (!tuplestore_skiptuples(winstate->buffer,
2431  pos - 1 - winobj->seekpos,
2432  true))
2433  elog(ERROR, "unexpected end of tuplestore");
2434  winobj->seekpos = pos - 1;
2435  }
2436  else if (winobj->seekpos > pos + 1)
2437  {
2438  if (!tuplestore_skiptuples(winstate->buffer,
2439  winobj->seekpos - (pos + 1),
2440  false))
2441  elog(ERROR, "unexpected end of tuplestore");
2442  winobj->seekpos = pos + 1;
2443  }
2444  else if (winobj->seekpos == pos)
2445  {
2446  /*
2447  * There's no API to refetch the tuple at the current position. We
2448  * have to move one tuple forward, and then one backward. (We don't
2449  * do it the other way because we might try to fetch the row before
2450  * our mark, which isn't allowed.) XXX this case could stand to be
2451  * optimized.
2452  */
2453  tuplestore_advance(winstate->buffer, true);
2454  winobj->seekpos++;
2455  }
2456 
2457  /*
2458  * Now we should be on the tuple immediately before or after the one we
2459  * want, so just fetch forwards or backwards as appropriate.
2460  */
2461  if (winobj->seekpos > pos)
2462  {
2463  if (!tuplestore_gettupleslot(winstate->buffer, false, true, slot))
2464  elog(ERROR, "unexpected end of tuplestore");
2465  winobj->seekpos--;
2466  }
2467  else
2468  {
2469  if (!tuplestore_gettupleslot(winstate->buffer, true, true, slot))
2470  elog(ERROR, "unexpected end of tuplestore");
2471  winobj->seekpos++;
2472  }
2473 
2474  Assert(winobj->seekpos == pos);
2475 
2476  MemoryContextSwitchTo(oldcontext);
2477 
2478  return true;
2479 }
bool tuplestore_advance(Tuplestorestate *state, bool forward)
Definition: tuplestore.c:1110
ScanState ss
Definition: execnodes.h:1847
ExprContext * ps_ExprContext
Definition: execnodes.h:881
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void spool_tuples(WindowAggState *winstate, int64 pos)
PlanState ps
Definition: execnodes.h:1101
#define ERROR
Definition: elog.h:43
Tuplestorestate * buffer
Definition: execnodes.h:1858
int64 spooled_rows
Definition: execnodes.h:1860
WindowAggState * winstate
Definition: nodeWindowAgg.c:63
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
#define Assert(condition)
Definition: c.h:681
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 CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define elog
Definition: elog.h:219
int64 WinGetCurrentPosition ( WindowObject  winobj)

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

2516 {
2517  Assert(WindowObjectIsValid(winobj));
2518  return winobj->winstate->currentpos;
2519 }
WindowAggState * winstate
Definition: nodeWindowAgg.c:63
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:681
int64 currentpos
Definition: execnodes.h:1861
Datum WinGetFuncArgCurrent ( WindowObject  winobj,
int  argno,
bool isnull 
)

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

2827 {
2828  WindowAggState *winstate;
2829  ExprContext *econtext;
2830 
2831  Assert(WindowObjectIsValid(winobj));
2832  winstate = winobj->winstate;
2833 
2834  econtext = winstate->ss.ps.ps_ExprContext;
2835 
2836  econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
2837  return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
2838  econtext, isnull);
2839 }
ScanState ss
Definition: execnodes.h:1847
ExprContext * ps_ExprContext
Definition: execnodes.h:881
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1104
PlanState ps
Definition: execnodes.h:1101
void * list_nth(const List *list, int n)
Definition: list.c:410
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:286
WindowAggState * winstate
Definition: nodeWindowAgg.c:63
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define Assert(condition)
Definition: c.h:681
Datum WinGetFuncArgInFrame ( WindowObject  winobj,
int  argno,
int  relpos,
int  seektype,
bool  set_mark,
bool isnull,
bool isout 
)

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

2735 {
2736  WindowAggState *winstate;
2737  ExprContext *econtext;
2738  TupleTableSlot *slot;
2739  bool gottuple;
2740  int64 abs_pos;
2741 
2742  Assert(WindowObjectIsValid(winobj));
2743  winstate = winobj->winstate;
2744  econtext = winstate->ss.ps.ps_ExprContext;
2745  slot = winstate->temp_slot_1;
2746 
2747  switch (seektype)
2748  {
2749  case WINDOW_SEEK_CURRENT:
2750  abs_pos = winstate->currentpos + relpos;
2751  break;
2752  case WINDOW_SEEK_HEAD:
2753  update_frameheadpos(winobj, slot);
2754  abs_pos = winstate->frameheadpos + relpos;
2755  break;
2756  case WINDOW_SEEK_TAIL:
2757  update_frametailpos(winobj, slot);
2758  abs_pos = winstate->frametailpos + relpos;
2759  break;
2760  default:
2761  elog(ERROR, "unrecognized window seek type: %d", seektype);
2762  abs_pos = 0; /* keep compiler quiet */
2763  break;
2764  }
2765 
2766  gottuple = window_gettupleslot(winobj, abs_pos, slot);
2767  if (gottuple)
2768  gottuple = row_is_in_frame(winstate, abs_pos, slot);
2769 
2770  if (!gottuple)
2771  {
2772  if (isout)
2773  *isout = true;
2774  *isnull = true;
2775  return (Datum) 0;
2776  }
2777  else
2778  {
2779  if (isout)
2780  *isout = false;
2781  if (set_mark)
2782  {
2783  int frameOptions = winstate->frameOptions;
2784  int64 mark_pos = abs_pos;
2785 
2786  /*
2787  * In RANGE mode with a moving frame head, we must not let the
2788  * mark advance past frameheadpos, since that row has to be
2789  * fetchable during future update_frameheadpos calls.
2790  *
2791  * XXX it is very ugly to pollute window functions' marks with
2792  * this consideration; it could for instance mask a logic bug that
2793  * lets a window function fetch rows before what it had claimed
2794  * was its mark. Perhaps use a separate mark for frame head
2795  * probes?
2796  */
2797  if ((frameOptions & FRAMEOPTION_RANGE) &&
2798  !(frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING))
2799  {
2800  update_frameheadpos(winobj, winstate->temp_slot_2);
2801  if (mark_pos > winstate->frameheadpos)
2802  mark_pos = winstate->frameheadpos;
2803  }
2804  WinSetMarkPosition(winobj, mark_pos);
2805  }
2806  econtext->ecxt_outertuple = slot;
2807  return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
2808  econtext, isnull);
2809  }
2810 }
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:1847
ExprContext * ps_ExprContext
Definition: execnodes.h:881
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:508
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1896
#define WINDOW_SEEK_TAIL
Definition: windowapi.h:34
PlanState ps
Definition: execnodes.h:1101
int64 frameheadpos
Definition: execnodes.h:1862
#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:1897
void * list_nth(const List *list, int n)
Definition: list.c:410
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:286
static void update_frameheadpos(WindowObject winobj, TupleTableSlot *slot)
#define WINDOW_SEEK_HEAD
Definition: windowapi.h:33
WindowAggState * winstate
Definition: nodeWindowAgg.c:63
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:1863
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:505
#define Assert(condition)
Definition: c.h:681
int64 currentpos
Definition: execnodes.h:1861
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 2636 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().

2639 {
2640  WindowAggState *winstate;
2641  ExprContext *econtext;
2642  TupleTableSlot *slot;
2643  bool gottuple;
2644  int64 abs_pos;
2645 
2646  Assert(WindowObjectIsValid(winobj));
2647  winstate = winobj->winstate;
2648  econtext = winstate->ss.ps.ps_ExprContext;
2649  slot = winstate->temp_slot_1;
2650 
2651  switch (seektype)
2652  {
2653  case WINDOW_SEEK_CURRENT:
2654  abs_pos = winstate->currentpos + relpos;
2655  break;
2656  case WINDOW_SEEK_HEAD:
2657  abs_pos = relpos;
2658  break;
2659  case WINDOW_SEEK_TAIL:
2660  spool_tuples(winstate, -1);
2661  abs_pos = winstate->spooled_rows - 1 + relpos;
2662  break;
2663  default:
2664  elog(ERROR, "unrecognized window seek type: %d", seektype);
2665  abs_pos = 0; /* keep compiler quiet */
2666  break;
2667  }
2668 
2669  gottuple = window_gettupleslot(winobj, abs_pos, slot);
2670 
2671  if (!gottuple)
2672  {
2673  if (isout)
2674  *isout = true;
2675  *isnull = true;
2676  return (Datum) 0;
2677  }
2678  else
2679  {
2680  if (isout)
2681  *isout = false;
2682  if (set_mark)
2683  {
2684  int frameOptions = winstate->frameOptions;
2685  int64 mark_pos = abs_pos;
2686 
2687  /*
2688  * In RANGE mode with a moving frame head, we must not let the
2689  * mark advance past frameheadpos, since that row has to be
2690  * fetchable during future update_frameheadpos calls.
2691  *
2692  * XXX it is very ugly to pollute window functions' marks with
2693  * this consideration; it could for instance mask a logic bug that
2694  * lets a window function fetch rows before what it had claimed
2695  * was its mark. Perhaps use a separate mark for frame head
2696  * probes?
2697  */
2698  if ((frameOptions & FRAMEOPTION_RANGE) &&
2699  !(frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING))
2700  {
2701  update_frameheadpos(winobj, winstate->temp_slot_2);
2702  if (mark_pos > winstate->frameheadpos)
2703  mark_pos = winstate->frameheadpos;
2704  }
2705  WinSetMarkPosition(winobj, mark_pos);
2706  }
2707  econtext->ecxt_outertuple = slot;
2708  return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
2709  econtext, isnull);
2710  }
2711 }
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:1847
ExprContext * ps_ExprContext
Definition: execnodes.h:881
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:508
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1896
static void spool_tuples(WindowAggState *winstate, int64 pos)
#define WINDOW_SEEK_TAIL
Definition: windowapi.h:34
PlanState ps
Definition: execnodes.h:1101
int64 frameheadpos
Definition: execnodes.h:1862
#define ERROR
Definition: elog.h:43
TupleTableSlot * temp_slot_2
Definition: execnodes.h:1897
void * list_nth(const List *list, int n)
Definition: list.c:410
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:286
static void update_frameheadpos(WindowObject winobj, TupleTableSlot *slot)
int64 spooled_rows
Definition: execnodes.h:1860
#define WINDOW_SEEK_HEAD
Definition: windowapi.h:33
WindowAggState * winstate
Definition: nodeWindowAgg.c:63
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:505
#define Assert(condition)
Definition: c.h:681
int64 currentpos
Definition: execnodes.h:1861
void WinSetMarkPosition(WindowObject winobj, int64 markpos)
#define elog
Definition: elog.h:219
void* WinGetPartitionLocalMemory ( WindowObject  winobj,
Size  sz 
)

Definition at line 2500 of file nodeWindowAgg.c.

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

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

2501 {
2502  Assert(WindowObjectIsValid(winobj));
2503  if (winobj->localmem == NULL)
2504  winobj->localmem =
2506  return winobj->localmem;
2507 }
WindowAggState * winstate
Definition: nodeWindowAgg.c:63
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:741
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:681
MemoryContext partcontext
Definition: execnodes.h:1875
int64 WinGetPartitionRowCount ( WindowObject  winobj)

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

2531 {
2532  Assert(WindowObjectIsValid(winobj));
2533  spool_tuples(winobj->winstate, -1);
2534  return winobj->winstate->spooled_rows;
2535 }
static void spool_tuples(WindowAggState *winstate, int64 pos)
int64 spooled_rows
Definition: execnodes.h:1860
WindowAggState * winstate
Definition: nodeWindowAgg.c:63
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:681
bool WinRowsArePeers ( WindowObject  winobj,
int64  pos1,
int64  pos2 
)

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

2584 {
2585  WindowAggState *winstate;
2586  WindowAgg *node;
2587  TupleTableSlot *slot1;
2588  TupleTableSlot *slot2;
2589  bool res;
2590 
2591  Assert(WindowObjectIsValid(winobj));
2592  winstate = winobj->winstate;
2593  node = (WindowAgg *) winstate->ss.ps.plan;
2594 
2595  /* If no ORDER BY, all rows are peers; don't bother to fetch them */
2596  if (node->ordNumCols == 0)
2597  return true;
2598 
2599  slot1 = winstate->temp_slot_1;
2600  slot2 = winstate->temp_slot_2;
2601 
2602  if (!window_gettupleslot(winobj, pos1, slot1))
2603  elog(ERROR, "specified position is out of window: " INT64_FORMAT,
2604  pos1);
2605  if (!window_gettupleslot(winobj, pos2, slot2))
2606  elog(ERROR, "specified position is out of window: " INT64_FORMAT,
2607  pos2);
2608 
2609  res = are_peers(winstate, slot1, slot2);
2610 
2611  ExecClearTuple(slot1);
2612  ExecClearTuple(slot2);
2613 
2614  return res;
2615 }
int ordNumCols
Definition: plannodes.h:806
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:1847
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * temp_slot_1
Definition: execnodes.h:1896
PlanState ps
Definition: execnodes.h:1101
#define ERROR
Definition: elog.h:43
TupleTableSlot * temp_slot_2
Definition: execnodes.h:1897
WindowAggState * winstate
Definition: nodeWindowAgg.c:63
Plan * plan
Definition: execnodes.h:847
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:681
#define INT64_FORMAT
Definition: c.h:300
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 2548 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().

2549 {
2550  WindowAggState *winstate;
2551 
2552  Assert(WindowObjectIsValid(winobj));
2553  winstate = winobj->winstate;
2554 
2555  if (markpos < winobj->markpos)
2556  elog(ERROR, "cannot move WindowObject's mark position backward");
2557  tuplestore_select_read_pointer(winstate->buffer, winobj->markptr);
2558  if (markpos > winobj->markpos)
2559  {
2560  tuplestore_skiptuples(winstate->buffer,
2561  markpos - winobj->markpos,
2562  true);
2563  winobj->markpos = markpos;
2564  }
2565  tuplestore_select_read_pointer(winstate->buffer, winobj->readptr);
2566  if (markpos > winobj->seekpos)
2567  {
2568  tuplestore_skiptuples(winstate->buffer,
2569  markpos - winobj->seekpos,
2570  true);
2571  winobj->seekpos = markpos;
2572  }
2573 }
#define ERROR
Definition: elog.h:43
Tuplestorestate * buffer
Definition: execnodes.h:1858
WindowAggState * winstate
Definition: nodeWindowAgg.c:63
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:681
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