PostgreSQL Source Code  git master
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/optimizer.h"
#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/expandeddatum.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 int row_is_in_frame (WindowAggState *winstate, int64 pos, TupleTableSlot *slot)
 
static void update_frameheadpos (WindowAggState *winstate)
 
static void update_frametailpos (WindowAggState *winstate)
 
static void update_grouptailpos (WindowAggState *winstate)
 
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

◆ WindowObjectData

◆ WindowStatePerAggData

◆ WindowStatePerFuncData

Function Documentation

◆ advance_windowaggregate()

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

Definition at line 241 of file nodeWindowAgg.c.

References WindowStatePerAggData::aggcontext, WindowFuncExprState::aggfilter, arg, WindowFuncExprState::args, Assert, CurrentMemoryContext, datumCopy(), DatumGetBool, DatumGetEOHP(), DatumGetPointer, DatumIsReadWriteExpandedObject, DeleteExpandedObject(), ExprContext::ecxt_per_tuple_memory, ereport, errcode(), errmsg(), ERROR, ExecEvalExpr(), FmgrInfo::fn_strict, FUNC_MAX_ARGS, FunctionCallInvoke, i, InitFunctionCallInfoData, WindowStatePerAggData::invtransfn_oid, lfirst, LOCAL_FCINFO, 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().

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

◆ advance_windowaggregate_base()

static bool advance_windowaggregate_base ( WindowAggState winstate,
WindowStatePerFunc  perfuncstate,
WindowStatePerAgg  peraggstate 
)
static

Definition at line 417 of file nodeWindowAgg.c.

References WindowStatePerAggData::aggcontext, WindowFuncExprState::aggfilter, arg, WindowFuncExprState::args, Assert, CurrentMemoryContext, datumCopy(), DatumGetBool, DatumGetEOHP(), DatumGetPointer, DatumIsReadWriteExpandedObject, DeleteExpandedObject(), ExprContext::ecxt_per_tuple_memory, elog, ERROR, ExecEvalExpr(), FmgrInfo::fn_strict, FUNC_MAX_ARGS, FunctionCallInvoke, i, InitFunctionCallInfoData, initialize_windowaggregate(), WindowStatePerAggData::invtransfn, lfirst, LOCAL_FCINFO, 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().

420 {
421  LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
422  WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate;
423  int numArguments = perfuncstate->numArguments;
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->args[i].value = ExecEvalExpr(argstate, econtext,
453  &fcinfo->args[i].isnull);
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->args[i].isnull)
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->args[0].value = peraggstate->transValue;
513  fcinfo->args[0].isnull = 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:2092
ExprState * aggfilter
Definition: execnodes.h:765
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:439
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
WindowFuncExprState * wfuncstate
Definition: nodeWindowAgg.c:80
WindowStatePerFunc perfunc
Definition: execnodes.h:2052
#define FUNC_MAX_ARGS
ExprContext * tmpcontext
Definition: execnodes.h:2093
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:167
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:285
#define DatumGetBool(X)
Definition: postgres.h:393
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
uintptr_t Datum
Definition: postgres.h:367
static void initialize_windowaggregate(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate)
void DeleteExpandedObject(Datum d)
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
MemoryContext aggcontext
#define DatumGetPointer(X)
Definition: postgres.h:549
#define elog(elevel,...)
Definition: elog.h:226
int i
void * arg

◆ are_peers()

static bool are_peers ( WindowAggState winstate,
TupleTableSlot slot1,
TupleTableSlot slot2 
)
static

Definition at line 2904 of file nodeWindowAgg.c.

References ExprContext::ecxt_outertuple, ExecQualAndReset(), WindowAggState::ordEqfunction, WindowAgg::ordNumCols, PlanState::plan, ScanState::ps, WindowAggState::ss, and WindowAggState::tmpcontext.

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

2906 {
2907  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
2908  ExprContext *econtext = winstate->tmpcontext;
2909 
2910  /* If no ORDER BY, all rows are peers with each other */
2911  if (node->ordNumCols == 0)
2912  return true;
2913 
2914  econtext->ecxt_outertuple = slot1;
2915  econtext->ecxt_innertuple = slot2;
2916  return ExecQualAndReset(winstate->ordEqfunction, econtext);
2917 }
int ordNumCols
Definition: plannodes.h:830
ScanState ss
Definition: execnodes.h:2045
ExprContext * tmpcontext
Definition: execnodes.h:2093
PlanState ps
Definition: execnodes.h:1280
ExprState * ordEqfunction
Definition: execnodes.h:2055
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:392
Plan * plan
Definition: execnodes.h:945
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:228

◆ begin_partition()

static void begin_partition ( WindowAggState winstate)
static

Definition at line 1079 of file nodeWindowAgg.c.

References WindowAggState::agg_row_slot, WindowAggState::agg_winobj, WindowAggState::aggregatedbase, WindowAggState::aggregatedupto, WindowAggState::buffer, WindowAggState::current_ptr, WindowAggState::currentgroup, WindowAggState::currentpos, EXEC_FLAG_BACKWARD, ExecClearTuple(), ExecCopySlot(), ExecProcNode(), WindowAggState::first_part_slot, WindowAggState::framehead_ptr, WindowAggState::framehead_slot, WindowAggState::framehead_valid, WindowAggState::frameheadgroup, WindowAggState::frameheadpos, FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_END_OFFSET, FRAMEOPTION_EXCLUDE_GROUP, FRAMEOPTION_EXCLUDE_TIES, FRAMEOPTION_EXCLUSION, FRAMEOPTION_GROUPS, FRAMEOPTION_RANGE, FRAMEOPTION_START_CURRENT_ROW, FRAMEOPTION_START_OFFSET, FRAMEOPTION_START_UNBOUNDED_PRECEDING, WindowAggState::frameOptions, WindowAggState::frametail_ptr, WindowAggState::frametail_slot, WindowAggState::frametail_valid, WindowAggState::frametailgroup, WindowAggState::frametailpos, WindowAggState::groupheadpos, WindowAggState::grouptail_ptr, WindowAggState::grouptail_valid, WindowAggState::grouptailpos, i, WindowObjectData::markpos, WindowObjectData::markptr, WindowAggState::more_partitions, WindowAggState::numaggs, WindowAggState::numfuncs, WindowAgg::ordNumCols, outerPlan, outerPlanState, WindowAggState::partition_spooled, WindowAggState::perfunc, WindowStatePerFuncData::plain_agg, PlanState::plan, ScanState::ps, WindowObjectData::readptr, WindowObjectData::seekpos, WindowAggState::spooled_rows, WindowAggState::ss, TupIsNull, tuplestore_alloc_read_pointer(), tuplestore_begin_heap(), tuplestore_puttupleslot(), tuplestore_set_eflags(), WindowStatePerFuncData::winobj, and work_mem.

Referenced by ExecWindowAgg().

1080 {
1081  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
1082  PlanState *outerPlan = outerPlanState(winstate);
1083  int frameOptions = winstate->frameOptions;
1084  int numfuncs = winstate->numfuncs;
1085  int i;
1086 
1087  winstate->partition_spooled = false;
1088  winstate->framehead_valid = false;
1089  winstate->frametail_valid = false;
1090  winstate->grouptail_valid = false;
1091  winstate->spooled_rows = 0;
1092  winstate->currentpos = 0;
1093  winstate->frameheadpos = 0;
1094  winstate->frametailpos = 0;
1095  winstate->currentgroup = 0;
1096  winstate->frameheadgroup = 0;
1097  winstate->frametailgroup = 0;
1098  winstate->groupheadpos = 0;
1099  winstate->grouptailpos = -1; /* see update_grouptailpos */
1100  ExecClearTuple(winstate->agg_row_slot);
1101  if (winstate->framehead_slot)
1102  ExecClearTuple(winstate->framehead_slot);
1103  if (winstate->frametail_slot)
1104  ExecClearTuple(winstate->frametail_slot);
1105 
1106  /*
1107  * If this is the very first partition, we need to fetch the first input
1108  * row to store in first_part_slot.
1109  */
1110  if (TupIsNull(winstate->first_part_slot))
1111  {
1112  TupleTableSlot *outerslot = ExecProcNode(outerPlan);
1113 
1114  if (!TupIsNull(outerslot))
1115  ExecCopySlot(winstate->first_part_slot, outerslot);
1116  else
1117  {
1118  /* outer plan is empty, so we have nothing to do */
1119  winstate->partition_spooled = true;
1120  winstate->more_partitions = false;
1121  return;
1122  }
1123  }
1124 
1125  /* Create new tuplestore for this partition */
1126  winstate->buffer = tuplestore_begin_heap(false, false, work_mem);
1127 
1128  /*
1129  * Set up read pointers for the tuplestore. The current pointer doesn't
1130  * need BACKWARD capability, but the per-window-function read pointers do,
1131  * and the aggregate pointer does if we might need to restart aggregation.
1132  */
1133  winstate->current_ptr = 0; /* read pointer 0 is pre-allocated */
1134 
1135  /* reset default REWIND capability bit for current ptr */
1136  tuplestore_set_eflags(winstate->buffer, 0);
1137 
1138  /* create read pointers for aggregates, if needed */
1139  if (winstate->numaggs > 0)
1140  {
1141  WindowObject agg_winobj = winstate->agg_winobj;
1142  int readptr_flags = 0;
1143 
1144  /*
1145  * If the frame head is potentially movable, or we have an EXCLUSION
1146  * clause, we might need to restart aggregation ...
1147  */
1148  if (!(frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) ||
1149  (frameOptions & FRAMEOPTION_EXCLUSION))
1150  {
1151  /* ... so create a mark pointer to track the frame head */
1152  agg_winobj->markptr = tuplestore_alloc_read_pointer(winstate->buffer, 0);
1153  /* and the read pointer will need BACKWARD capability */
1154  readptr_flags |= EXEC_FLAG_BACKWARD;
1155  }
1156 
1157  agg_winobj->readptr = tuplestore_alloc_read_pointer(winstate->buffer,
1158  readptr_flags);
1159  agg_winobj->markpos = -1;
1160  agg_winobj->seekpos = -1;
1161 
1162  /* Also reset the row counters for aggregates */
1163  winstate->aggregatedbase = 0;
1164  winstate->aggregatedupto = 0;
1165  }
1166 
1167  /* create mark and read pointers for each real window function */
1168  for (i = 0; i < numfuncs; i++)
1169  {
1170  WindowStatePerFunc perfuncstate = &(winstate->perfunc[i]);
1171 
1172  if (!perfuncstate->plain_agg)
1173  {
1174  WindowObject winobj = perfuncstate->winobj;
1175 
1176  winobj->markptr = tuplestore_alloc_read_pointer(winstate->buffer,
1177  0);
1178  winobj->readptr = tuplestore_alloc_read_pointer(winstate->buffer,
1180  winobj->markpos = -1;
1181  winobj->seekpos = -1;
1182  }
1183  }
1184 
1185  /*
1186  * If we are in RANGE or GROUPS mode, then determining frame boundaries
1187  * requires physical access to the frame endpoint rows, except in certain
1188  * degenerate cases. We create read pointers to point to those rows, to
1189  * simplify access and ensure that the tuplestore doesn't discard the
1190  * endpoint rows prematurely. (Must create pointers in exactly the same
1191  * cases that update_frameheadpos and update_frametailpos need them.)
1192  */
1193  winstate->framehead_ptr = winstate->frametail_ptr = -1; /* if not used */
1194 
1195  if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS))
1196  {
1197  if (((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
1198  node->ordNumCols != 0) ||
1199  (frameOptions & FRAMEOPTION_START_OFFSET))
1200  winstate->framehead_ptr =
1201  tuplestore_alloc_read_pointer(winstate->buffer, 0);
1202  if (((frameOptions & FRAMEOPTION_END_CURRENT_ROW) &&
1203  node->ordNumCols != 0) ||
1204  (frameOptions & FRAMEOPTION_END_OFFSET))
1205  winstate->frametail_ptr =
1206  tuplestore_alloc_read_pointer(winstate->buffer, 0);
1207  }
1208 
1209  /*
1210  * If we have an exclusion clause that requires knowing the boundaries of
1211  * the current row's peer group, we create a read pointer to track the
1212  * tail position of the peer group (i.e., first row of the next peer
1213  * group). The head position does not require its own pointer because we
1214  * maintain that as a side effect of advancing the current row.
1215  */
1216  winstate->grouptail_ptr = -1;
1217 
1218  if ((frameOptions & (FRAMEOPTION_EXCLUDE_GROUP |
1220  node->ordNumCols != 0)
1221  {
1222  winstate->grouptail_ptr =
1223  tuplestore_alloc_read_pointer(winstate->buffer, 0);
1224  }
1225 
1226  /*
1227  * Store the first tuple into the tuplestore (it's always available now;
1228  * we either read it above, or saved it at the end of previous partition)
1229  */
1230  tuplestore_puttupleslot(winstate->buffer, winstate->first_part_slot);
1231  winstate->spooled_rows++;
1232 }
int ordNumCols
Definition: plannodes.h:830
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:476
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition: tuplestore.c:708
#define FRAMEOPTION_EXCLUSION
Definition: parsenodes.h:527
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
ScanState ss
Definition: execnodes.h:2045
void tuplestore_set_eflags(Tuplestorestate *state, int eflags)
Definition: tuplestore.c:359
int64 groupheadpos
Definition: execnodes.h:2087
int64 currentgroup
Definition: execnodes.h:2084
int64 aggregatedupto
Definition: execnodes.h:2068
bool frametail_valid
Definition: execnodes.h:2103
int64 frametailgroup
Definition: execnodes.h:2086
int64 grouptailpos
Definition: execnodes.h:2088
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:509
WindowStatePerFunc perfunc
Definition: execnodes.h:2052
#define FRAMEOPTION_START_OFFSET
Definition: parsenodes.h:523
TupleTableSlot * first_part_slot
Definition: execnodes.h:2108
PlanState ps
Definition: execnodes.h:1280
struct WindowObjectData * agg_winobj
Definition: execnodes.h:2066
int64 frameheadpos
Definition: execnodes.h:2063
#define FRAMEOPTION_EXCLUDE_GROUP
Definition: parsenodes.h:520
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define outerPlanState(node)
Definition: execnodes.h:1039
int64 frameheadgroup
Definition: execnodes.h:2085
int64 aggregatedbase
Definition: execnodes.h:2067
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:514
#define TupIsNull(slot)
Definition: tuptable.h:293
Tuplestorestate * buffer
Definition: execnodes.h:2056
#define FRAMEOPTION_START_CURRENT_ROW
Definition: parsenodes.h:513
#define outerPlan(node)
Definition: plannodes.h:170
int64 spooled_rows
Definition: execnodes.h:2061
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:235
int work_mem
Definition: globals.c:121
TupleTableSlot * agg_row_slot
Definition: execnodes.h:2114
Plan * plan
Definition: execnodes.h:945
TupleTableSlot * frametail_slot
Definition: execnodes.h:2111
bool more_partitions
Definition: execnodes.h:2099
int64 frametailpos
Definition: execnodes.h:2064
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:505
#define FRAMEOPTION_EXCLUDE_TIES
Definition: parsenodes.h:521
bool grouptail_valid
Definition: execnodes.h:2105
TupleTableSlot * framehead_slot
Definition: execnodes.h:2110
#define FRAMEOPTION_END_OFFSET
Definition: parsenodes.h:525
int64 currentpos
Definition: execnodes.h:2062
int tuplestore_alloc_read_pointer(Tuplestorestate *state, int eflags)
Definition: tuplestore.c:383
bool partition_spooled
Definition: execnodes.h:2097
bool framehead_valid
Definition: execnodes.h:2101
int i
#define FRAMEOPTION_GROUPS
Definition: parsenodes.h:507

◆ eval_windowaggregates()

static void eval_windowaggregates ( WindowAggState winstate)
static

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

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

◆ eval_windowfunction()

static void eval_windowfunction ( WindowAggState winstate,
WindowStatePerFunc  perfuncstate,
Datum result,
bool isnull 
)
static

Definition at line 1032 of file nodeWindowAgg.c.

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

Referenced by ExecWindowAgg().

1034 {
1035  LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
1036  MemoryContext oldContext;
1037 
1039 
1040  /*
1041  * We don't pass any normal arguments to a window function, but we do pass
1042  * it the number of arguments, in order to permit window function
1043  * implementations to support varying numbers of arguments. The real info
1044  * goes through the WindowObject, which is passed via fcinfo->context.
1045  */
1046  InitFunctionCallInfoData(*fcinfo, &(perfuncstate->flinfo),
1047  perfuncstate->numArguments,
1048  perfuncstate->winCollation,
1049  (void *) perfuncstate->winobj, NULL);
1050  /* Just in case, make all the regular argument slots be null */
1051  for (int argno = 0; argno < perfuncstate->numArguments; argno++)
1052  fcinfo->args[argno].isnull = true;
1053  /* Window functions don't have a current aggregate context, either */
1054  winstate->curaggcontext = NULL;
1055 
1056  *result = FunctionCallInvoke(fcinfo);
1057  *isnull = fcinfo->isnull;
1058 
1059  /*
1060  * Make sure pass-by-ref data is allocated in the appropriate context. (We
1061  * need this in case the function returns a pointer into some short-lived
1062  * tuple, as is entirely possible.)
1063  */
1064  if (!perfuncstate->resulttypeByVal && !fcinfo->isnull &&
1066  DatumGetPointer(*result)))
1067  *result = datumCopy(*result,
1068  perfuncstate->resulttypeByVal,
1069  perfuncstate->resulttypeLen);
1070 
1071  MemoryContextSwitchTo(oldContext);
1072 }
MemoryContext curaggcontext
Definition: execnodes.h:2092
ScanState ss
Definition: execnodes.h:2045
ExprContext * ps_ExprContext
Definition: execnodes.h:984
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define FUNC_MAX_ARGS
PlanState ps
Definition: execnodes.h:1280
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:167
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:667
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define DatumGetPointer(X)
Definition: postgres.h:549

◆ ExecEndWindowAgg()

void ExecEndWindowAgg ( WindowAggState node)

Definition at line 2533 of file nodeWindowAgg.c.

References WindowAggState::agg_row_slot, WindowStatePerAggData::aggcontext, WindowAggState::aggcontext, ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), WindowAggState::first_part_slot, WindowAggState::framehead_slot, WindowAggState::frametail_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().

2534 {
2536  int i;
2537 
2538  release_partition(node);
2539 
2543  ExecClearTuple(node->temp_slot_1);
2544  ExecClearTuple(node->temp_slot_2);
2545  if (node->framehead_slot)
2547  if (node->frametail_slot)
2549 
2550  /*
2551  * Free both the expr contexts.
2552  */
2553  ExecFreeExprContext(&node->ss.ps);
2554  node->ss.ps.ps_ExprContext = node->tmpcontext;
2555  ExecFreeExprContext(&node->ss.ps);
2556 
2557  for (i = 0; i < node->numaggs; i++)
2558  {
2559  if (node->peragg[i].aggcontext != node->aggcontext)
2561  }
2564 
2565  pfree(node->perfunc);
2566  pfree(node->peragg);
2567 
2568  outerPlan = outerPlanState(node);
2569  ExecEndNode(outerPlan);
2570 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
ScanState ss
Definition: execnodes.h:2045
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:538
ExprContext * ps_ExprContext
Definition: execnodes.h:984
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
static void release_partition(WindowAggState *winstate)
TupleTableSlot * temp_slot_1
Definition: execnodes.h:2115
WindowStatePerFunc perfunc
Definition: execnodes.h:2052
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:616
TupleTableSlot * first_part_slot
Definition: execnodes.h:2108
ExprContext * tmpcontext
Definition: execnodes.h:2093
PlanState ps
Definition: execnodes.h:1280
void pfree(void *pointer)
Definition: mcxt.c:1031
#define outerPlanState(node)
Definition: execnodes.h:1039
TupleTableSlot * temp_slot_2
Definition: execnodes.h:2116
WindowStatePerAgg peragg
Definition: execnodes.h:2053
MemoryContext aggcontext
Definition: execnodes.h:2091
#define outerPlan(node)
Definition: plannodes.h:170
TupleTableSlot * agg_row_slot
Definition: execnodes.h:2114
TupleTableSlot * frametail_slot
Definition: execnodes.h:2111
TupleTableSlot * framehead_slot
Definition: execnodes.h:2110
MemoryContext aggcontext
int i
MemoryContext partcontext
Definition: execnodes.h:2090

◆ ExecInitWindowAgg()

WindowAggState* ExecInitWindowAgg ( WindowAgg node,
EState estate,
int  eflags 
)

Definition at line 2249 of file nodeWindowAgg.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowAggState::agg_row_slot, WindowAggState::agg_winobj, WindowAggState::aggcontext, WindowStatePerFuncData::aggno, 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::endInRangeFunc, WindowAgg::endOffset, equal(), ERROR, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecCreateScanSlotFromOuterPlan(), ExecInitExpr(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitResultTupleSlotTL(), PlanState::ExecProcNode, execTuplesMatchPrepare(), ExecWindowAgg(), WindowAggState::first_part_slot, WindowStatePerFuncData::flinfo, fmgr_info(), fmgr_info_cxt(), fmgr_info_set_expr, WindowAggState::framehead_slot, FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_END_OFFSET, FRAMEOPTION_GROUPS, FRAMEOPTION_RANGE, FRAMEOPTION_START_CURRENT_ROW, FRAMEOPTION_START_OFFSET, WindowAgg::frameOptions, WindowAggState::frameOptions, WindowAggState::frametail_slot, WindowAggState::funcs, get_func_name(), get_typlenbyval(), GetUserId(), i, initialize_peragg(), WindowAgg::inRangeAsc, WindowAgg::inRangeColl, WindowAgg::inRangeNullsFirst, InvokeFunctionExecuteHook, lfirst, list_length(), WindowObjectData::localmem, makeNode, WindowObjectData::markptr, NIL, WindowAggState::numaggs, WindowStatePerFuncData::numArguments, WindowAggState::numfuncs, OBJECT_FUNCTION, OidIsValid, WindowAgg::ordColIdx, WindowAgg::ordCollations, WindowAggState::ordEqfunction, WindowAgg::ordNumCols, WindowAgg::ordOperators, PlanState::outerops, PlanState::outeropsfixed, PlanState::outeropsset, outerPlan, outerPlanState, palloc0(), WindowAgg::partColIdx, WindowAgg::partCollations, WindowAggState::partcontext, WindowAggState::partEqfunction, 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::startInRangeFunc, WindowAgg::startOffset, WindowAggState::startOffset, PlanState::state, WindowAggState::temp_slot_1, WindowAggState::temp_slot_2, WindowAggState::tmpcontext, TupleTableSlot::tts_tupleDescriptor, TTSOpsMinimalTuple, TTSOpsVirtual, WindowStatePerFuncData::wfunc, WindowFuncExprState::wfunc, WindowStatePerAggData::wfuncno, WindowFuncExprState::wfuncno, WindowStatePerFuncData::wfuncstate, WindowStatePerFuncData::winCollation, WindowFunc::winfnoid, WindowStatePerFuncData::winobj, WindowFunc::winref, WindowAgg::winref, and WindowObjectData::winstate.

Referenced by ExecInitNode().

2250 {
2251  WindowAggState *winstate;
2252  Plan *outerPlan;
2253  ExprContext *econtext;
2254  ExprContext *tmpcontext;
2255  WindowStatePerFunc perfunc;
2256  WindowStatePerAgg peragg;
2257  int frameOptions = node->frameOptions;
2258  int numfuncs,
2259  wfuncno,
2260  numaggs,
2261  aggno;
2262  TupleDesc scanDesc;
2263  ListCell *l;
2264 
2265  /* check for unsupported flags */
2266  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2267 
2268  /*
2269  * create state structure
2270  */
2271  winstate = makeNode(WindowAggState);
2272  winstate->ss.ps.plan = (Plan *) node;
2273  winstate->ss.ps.state = estate;
2274  winstate->ss.ps.ExecProcNode = ExecWindowAgg;
2275 
2276  /*
2277  * Create expression contexts. We need two, one for per-input-tuple
2278  * processing and one for per-output-tuple processing. We cheat a little
2279  * by using ExecAssignExprContext() to build both.
2280  */
2281  ExecAssignExprContext(estate, &winstate->ss.ps);
2282  tmpcontext = winstate->ss.ps.ps_ExprContext;
2283  winstate->tmpcontext = tmpcontext;
2284  ExecAssignExprContext(estate, &winstate->ss.ps);
2285 
2286  /* Create long-lived context for storage of partition-local memory etc */
2287  winstate->partcontext =
2289  "WindowAgg Partition",
2291 
2292  /*
2293  * Create mid-lived context for aggregate trans values etc.
2294  *
2295  * Note that moving aggregates each use their own private context, not
2296  * this one.
2297  */
2298  winstate->aggcontext =
2300  "WindowAgg Aggregates",
2302 
2303  /*
2304  * WindowAgg nodes never have quals, since they can only occur at the
2305  * logical top level of a query (ie, after any WHERE or HAVING filters)
2306  */
2307  Assert(node->plan.qual == NIL);
2308  winstate->ss.ps.qual = NULL;
2309 
2310  /*
2311  * initialize child nodes
2312  */
2313  outerPlan = outerPlan(node);
2314  outerPlanState(winstate) = ExecInitNode(outerPlan, estate, eflags);
2315 
2316  /*
2317  * initialize source tuple type (which is also the tuple type that we'll
2318  * store in the tuplestore and use in all our working slots).
2319  */
2321  scanDesc = winstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
2322 
2323  /* the outer tuple isn't the child's tuple, but always a minimal tuple */
2324  winstate->ss.ps.outeropsset = true;
2325  winstate->ss.ps.outerops = &TTSOpsMinimalTuple;
2326  winstate->ss.ps.outeropsfixed = true;
2327 
2328  /*
2329  * tuple table initialization
2330  */
2331  winstate->first_part_slot = ExecInitExtraTupleSlot(estate, scanDesc,
2333  winstate->agg_row_slot = ExecInitExtraTupleSlot(estate, scanDesc,
2335  winstate->temp_slot_1 = ExecInitExtraTupleSlot(estate, scanDesc,
2337  winstate->temp_slot_2 = ExecInitExtraTupleSlot(estate, scanDesc,
2339 
2340  /*
2341  * create frame head and tail slots only if needed (must create slots in
2342  * exactly the same cases that update_frameheadpos and update_frametailpos
2343  * need them)
2344  */
2345  winstate->framehead_slot = winstate->frametail_slot = NULL;
2346 
2347  if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS))
2348  {
2349  if (((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
2350  node->ordNumCols != 0) ||
2351  (frameOptions & FRAMEOPTION_START_OFFSET))
2352  winstate->framehead_slot = ExecInitExtraTupleSlot(estate, scanDesc,
2354  if (((frameOptions & FRAMEOPTION_END_CURRENT_ROW) &&
2355  node->ordNumCols != 0) ||
2356  (frameOptions & FRAMEOPTION_END_OFFSET))
2357  winstate->frametail_slot = ExecInitExtraTupleSlot(estate, scanDesc,
2359  }
2360 
2361  /*
2362  * Initialize result slot, type and projection.
2363  */
2365  ExecAssignProjectionInfo(&winstate->ss.ps, NULL);
2366 
2367  /* Set up data for comparing tuples */
2368  if (node->partNumCols > 0)
2369  winstate->partEqfunction =
2370  execTuplesMatchPrepare(scanDesc,
2371  node->partNumCols,
2372  node->partColIdx,
2373  node->partOperators,
2374  node->partCollations,
2375  &winstate->ss.ps);
2376 
2377  if (node->ordNumCols > 0)
2378  winstate->ordEqfunction =
2379  execTuplesMatchPrepare(scanDesc,
2380  node->ordNumCols,
2381  node->ordColIdx,
2382  node->ordOperators,
2383  node->ordCollations,
2384  &winstate->ss.ps);
2385 
2386  /*
2387  * WindowAgg nodes use aggvalues and aggnulls as well as Agg nodes.
2388  */
2389  numfuncs = winstate->numfuncs;
2390  numaggs = winstate->numaggs;
2391  econtext = winstate->ss.ps.ps_ExprContext;
2392  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numfuncs);
2393  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numfuncs);
2394 
2395  /*
2396  * allocate per-wfunc/per-agg state information.
2397  */
2398  perfunc = (WindowStatePerFunc) palloc0(sizeof(WindowStatePerFuncData) * numfuncs);
2399  peragg = (WindowStatePerAgg) palloc0(sizeof(WindowStatePerAggData) * numaggs);
2400  winstate->perfunc = perfunc;
2401  winstate->peragg = peragg;
2402 
2403  wfuncno = -1;
2404  aggno = -1;
2405  foreach(l, winstate->funcs)
2406  {
2407  WindowFuncExprState *wfuncstate = (WindowFuncExprState *) lfirst(l);
2408  WindowFunc *wfunc = wfuncstate->wfunc;
2409  WindowStatePerFunc perfuncstate;
2410  AclResult aclresult;
2411  int i;
2412 
2413  if (wfunc->winref != node->winref) /* planner screwed up? */
2414  elog(ERROR, "WindowFunc with winref %u assigned to WindowAgg with winref %u",
2415  wfunc->winref, node->winref);
2416 
2417  /* Look for a previous duplicate window function */
2418  for (i = 0; i <= wfuncno; i++)
2419  {
2420  if (equal(wfunc, perfunc[i].wfunc) &&
2421  !contain_volatile_functions((Node *) wfunc))
2422  break;
2423  }
2424  if (i <= wfuncno)
2425  {
2426  /* Found a match to an existing entry, so just mark it */
2427  wfuncstate->wfuncno = i;
2428  continue;
2429  }
2430 
2431  /* Nope, so assign a new PerAgg record */
2432  perfuncstate = &perfunc[++wfuncno];
2433 
2434  /* Mark WindowFunc state node with assigned index in the result array */
2435  wfuncstate->wfuncno = wfuncno;
2436 
2437  /* Check permission to call window function */
2438  aclresult = pg_proc_aclcheck(wfunc->winfnoid, GetUserId(),
2439  ACL_EXECUTE);
2440  if (aclresult != ACLCHECK_OK)
2441  aclcheck_error(aclresult, OBJECT_FUNCTION,
2442  get_func_name(wfunc->winfnoid));
2443  InvokeFunctionExecuteHook(wfunc->winfnoid);
2444 
2445  /* Fill in the perfuncstate data */
2446  perfuncstate->wfuncstate = wfuncstate;
2447  perfuncstate->wfunc = wfunc;
2448  perfuncstate->numArguments = list_length(wfuncstate->args);
2449 
2450  fmgr_info_cxt(wfunc->winfnoid, &perfuncstate->flinfo,
2451  econtext->ecxt_per_query_memory);
2452  fmgr_info_set_expr((Node *) wfunc, &perfuncstate->flinfo);
2453 
2454  perfuncstate->winCollation = wfunc->inputcollid;
2455 
2456  get_typlenbyval(wfunc->wintype,
2457  &perfuncstate->resulttypeLen,
2458  &perfuncstate->resulttypeByVal);
2459 
2460  /*
2461  * If it's really just a plain aggregate function, we'll emulate the
2462  * Agg environment for it.
2463  */
2464  perfuncstate->plain_agg = wfunc->winagg;
2465  if (wfunc->winagg)
2466  {
2467  WindowStatePerAgg peraggstate;
2468 
2469  perfuncstate->aggno = ++aggno;
2470  peraggstate = &winstate->peragg[aggno];
2471  initialize_peragg(winstate, wfunc, peraggstate);
2472  peraggstate->wfuncno = wfuncno;
2473  }
2474  else
2475  {
2477 
2478  winobj->winstate = winstate;
2479  winobj->argstates = wfuncstate->args;
2480  winobj->localmem = NULL;
2481  perfuncstate->winobj = winobj;
2482  }
2483  }
2484 
2485  /* Update numfuncs, numaggs to match number of unique functions found */
2486  winstate->numfuncs = wfuncno + 1;
2487  winstate->numaggs = aggno + 1;
2488 
2489  /* Set up WindowObject for aggregates, if needed */
2490  if (winstate->numaggs > 0)
2491  {
2492  WindowObject agg_winobj = makeNode(WindowObjectData);
2493 
2494  agg_winobj->winstate = winstate;
2495  agg_winobj->argstates = NIL;
2496  agg_winobj->localmem = NULL;
2497  /* make sure markptr = -1 to invalidate. It may not get used */
2498  agg_winobj->markptr = -1;
2499  agg_winobj->readptr = -1;
2500  winstate->agg_winobj = agg_winobj;
2501  }
2502 
2503  /* copy frame options to state node for easy access */
2504  winstate->frameOptions = frameOptions;
2505 
2506  /* initialize frame bound offset expressions */
2507  winstate->startOffset = ExecInitExpr((Expr *) node->startOffset,
2508  (PlanState *) winstate);
2509  winstate->endOffset = ExecInitExpr((Expr *) node->endOffset,
2510  (PlanState *) winstate);
2511 
2512  /* Lookup in_range support functions if needed */
2513  if (OidIsValid(node->startInRangeFunc))
2514  fmgr_info(node->startInRangeFunc, &winstate->startInRangeFunc);
2515  if (OidIsValid(node->endInRangeFunc))
2516  fmgr_info(node->endInRangeFunc, &winstate->endInRangeFunc);
2517  winstate->inRangeColl = node->inRangeColl;
2518  winstate->inRangeAsc = node->inRangeAsc;
2519  winstate->inRangeNullsFirst = node->inRangeNullsFirst;
2520 
2521  winstate->all_first = true;
2522  winstate->partition_spooled = false;
2523  winstate->more_partitions = false;
2524 
2525  return winstate;
2526 }
int ordNumCols
Definition: plannodes.h:830
#define NIL
Definition: pg_list.h:65
List * qual
Definition: plannodes.h:141
ExprState * endOffset
Definition: execnodes.h:2072
#define AllocSetContextCreate
Definition: memutils.h:169
Datum * ecxt_aggvalues
Definition: execnodes.h:243
struct WindowStatePerAggData * WindowStatePerAgg
Definition: execnodes.h:2041
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1796
Oid inRangeColl
Definition: plannodes.h:840
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2998
Oid GetUserId(void)
Definition: miscinit.c:380
ScanState ss
Definition: execnodes.h:2045
ExprContext * ps_ExprContext
Definition: execnodes.h:984
AttrNumber * ordColIdx
Definition: plannodes.h:831
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
Definition: nodes.h:524
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
struct WindowStatePerFuncData * WindowStatePerFunc
Definition: execnodes.h:2040
WindowFuncExprState * wfuncstate
Definition: nodeWindowAgg.c:80
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:724
EState * state
Definition: execnodes.h:947
Index winref
Definition: primnodes.h:365
TupleTableSlot * temp_slot_1
Definition: execnodes.h:2115
#define OidIsValid(objectId)
Definition: c.h:638
WindowStatePerFunc perfunc
Definition: execnodes.h:2052
Oid * ordOperators
Definition: plannodes.h:832
#define FRAMEOPTION_START_OFFSET
Definition: parsenodes.h:523
Oid endInRangeFunc
Definition: plannodes.h:839
TupleTableSlot * first_part_slot
Definition: execnodes.h:2108
Oid * partCollations
Definition: plannodes.h:829
ExprContext * tmpcontext
Definition: execnodes.h:2093
PlanState ps
Definition: execnodes.h:1280
struct WindowObjectData * agg_winobj
Definition: execnodes.h:2066
bool inRangeNullsFirst
Definition: execnodes.h:2081
Node * startOffset
Definition: plannodes.h:835
static WindowStatePerAggData * initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, WindowStatePerAgg peraggstate)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3353
Oid * ordCollations
Definition: plannodes.h:833
ExprState * partEqfunction
Definition: execnodes.h:2054
#define ERROR
Definition: elog.h:43
FmgrInfo endInRangeFunc
Definition: execnodes.h:2078
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1410
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:124
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:191
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define outerPlanState(node)
Definition: execnodes.h:1039
TupleTableSlot * temp_slot_2
Definition: execnodes.h:2116
WindowStatePerAgg peragg
Definition: execnodes.h:2053
ExprState * ordEqfunction
Definition: execnodes.h:2055
ExprState * startOffset
Definition: execnodes.h:2071
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:501
Node * endOffset
Definition: plannodes.h:836
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:514
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
int partNumCols
Definition: plannodes.h:826
bool outeropsset
Definition: execnodes.h:1026
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
MemoryContext aggcontext
Definition: execnodes.h:2091
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:134
#define FRAMEOPTION_START_CURRENT_ROW
Definition: parsenodes.h:513
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:179
#define outerPlan(node)
Definition: plannodes.h:170
bool inRangeAsc
Definition: plannodes.h:841
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
bool * ecxt_aggnulls
Definition: execnodes.h:245
static TupleTableSlot * ExecWindowAgg(PlanState *pstate)
WindowAggState * winstate
Definition: nodeWindowAgg.c:64
void * palloc0(Size size)
Definition: mcxt.c:955
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:951
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
TupleTableSlot * agg_row_slot
Definition: execnodes.h:2114
AttrNumber * partColIdx
Definition: plannodes.h:827
Plan * plan
Definition: execnodes.h:945
TupleTableSlot * frametail_slot
Definition: execnodes.h:2111
bool more_partitions
Definition: execnodes.h:2099
Oid * partOperators
Definition: plannodes.h:828
#define makeNode(_type_)
Definition: nodes.h:572
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:505
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
Index winref
Definition: plannodes.h:825
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
#define EXEC_FLAG_MARK
Definition: executor.h:59
FmgrInfo startInRangeFunc
Definition: execnodes.h:2077
TupleTableSlot * framehead_slot
Definition: execnodes.h:2110
bool inRangeNullsFirst
Definition: plannodes.h:842
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:446
static int list_length(const List *l)
Definition: pg_list.h:169
#define FRAMEOPTION_END_OFFSET
Definition: parsenodes.h:525
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2029
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1764
bool outeropsfixed
Definition: execnodes.h:1022
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:231
ExprState * qual
Definition: execnodes.h:966
Oid startInRangeFunc
Definition: plannodes.h:838
bool partition_spooled
Definition: execnodes.h:2097
#define ACL_EXECUTE
Definition: parsenodes.h:81
#define elog(elevel,...)
Definition: elog.h:226
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4655
int i
Plan plan
Definition: plannodes.h:824
#define FRAMEOPTION_GROUPS
Definition: parsenodes.h:507
MemoryContext partcontext
Definition: execnodes.h:2090
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:121
int frameOptions
Definition: plannodes.h:834
WindowFunc * wfunc
Definition: execnodes.h:763
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:648
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:86
const TupleTableSlotOps * outerops
Definition: execnodes.h:1018

◆ ExecReScanWindowAgg()

void ExecReScanWindowAgg ( WindowAggState node)

Definition at line 2577 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, WindowAggState::framehead_slot, WindowAggState::frametail_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().

2578 {
2580  ExprContext *econtext = node->ss.ps.ps_ExprContext;
2581 
2582  node->all_done = false;
2583  node->all_first = true;
2584 
2585  /* release tuplestore et al */
2586  release_partition(node);
2587 
2588  /* release all temp tuples, but especially first_part_slot */
2592  ExecClearTuple(node->temp_slot_1);
2593  ExecClearTuple(node->temp_slot_2);
2594  if (node->framehead_slot)
2596  if (node->frametail_slot)
2598 
2599  /* Forget current wfunc values */
2600  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numfuncs);
2601  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numfuncs);
2602 
2603  /*
2604  * if chgParam of subnode is not null then plan will be re-scanned by
2605  * first ExecProcNode.
2606  */
2607  if (outerPlan->chgParam == NULL)
2608  ExecReScan(outerPlan);
2609 }
Datum * ecxt_aggvalues
Definition: execnodes.h:243
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
ScanState ss
Definition: execnodes.h:2045
ExprContext * ps_ExprContext
Definition: execnodes.h:984
void ExecReScan(PlanState *node)
Definition: execAmi.c:77
#define MemSet(start, val, len)
Definition: c.h:955
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
static void release_partition(WindowAggState *winstate)
TupleTableSlot * temp_slot_1
Definition: execnodes.h:2115
TupleTableSlot * first_part_slot
Definition: execnodes.h:2108
PlanState ps
Definition: execnodes.h:1280
#define outerPlanState(node)
Definition: execnodes.h:1039
TupleTableSlot * temp_slot_2
Definition: execnodes.h:2116
Bitmapset * chgParam
Definition: execnodes.h:977
#define outerPlan(node)
Definition: plannodes.h:170
bool * ecxt_aggnulls
Definition: execnodes.h:245
uintptr_t Datum
Definition: postgres.h:367
TupleTableSlot * agg_row_slot
Definition: execnodes.h:2114
TupleTableSlot * frametail_slot
Definition: execnodes.h:2111
TupleTableSlot * framehead_slot
Definition: execnodes.h:2110

◆ ExecWindowAgg()

static TupleTableSlot* ExecWindowAgg ( PlanState pstate)
static

Definition at line 2023 of file nodeWindowAgg.c.

References WindowAggState::all_done, WindowAggState::all_first, are_peers(), Assert, begin_partition(), WindowAggState::buffer, castNode, CHECK_FOR_INTERRUPTS, WindowAggState::current_ptr, WindowAggState::currentgroup, 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(), ExecClearTuple(), ExecCopySlot(), ExecEvalExprSwitchContext(), ExecProject(), ExprState::expr, exprType(), WindowAggState::framehead_ptr, WindowAggState::framehead_valid, FRAMEOPTION_END_OFFSET, FRAMEOPTION_EXCLUDE_GROUP, FRAMEOPTION_EXCLUDE_TIES, FRAMEOPTION_GROUPS, FRAMEOPTION_ROWS, FRAMEOPTION_START_OFFSET, WindowAggState::frameOptions, WindowAggState::frametail_ptr, WindowAggState::frametail_valid, get_typlenbyval(), WindowAggState::groupheadpos, WindowAggState::grouptail_ptr, WindowAggState::grouptail_valid, 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, WindowAggState::temp_slot_2, tuplestore_gettupleslot(), tuplestore_select_read_pointer(), tuplestore_trim(), update_frameheadpos(), update_frametailpos(), update_grouptailpos(), value, WindowFuncExprState::wfuncno, WindowStatePerFuncData::wfuncstate, and WindowObjectData::winstate.

Referenced by ExecInitWindowAgg().

2024 {
2025  WindowAggState *winstate = castNode(WindowAggState, pstate);
2026  ExprContext *econtext;
2027  int i;
2028  int numfuncs;
2029 
2031 
2032  if (winstate->all_done)
2033  return NULL;
2034 
2035  /*
2036  * Compute frame offset values, if any, during first call (or after a
2037  * rescan). These are assumed to hold constant throughout the scan; if
2038  * user gives us a volatile expression, we'll only use its initial value.
2039  */
2040  if (winstate->all_first)
2041  {
2042  int frameOptions = winstate->frameOptions;
2043  ExprContext *econtext = winstate->ss.ps.ps_ExprContext;
2044  Datum value;
2045  bool isnull;
2046  int16 len;
2047  bool byval;
2048 
2049  if (frameOptions & FRAMEOPTION_START_OFFSET)
2050  {
2051  Assert(winstate->startOffset != NULL);
2052  value = ExecEvalExprSwitchContext(winstate->startOffset,
2053  econtext,
2054  &isnull);
2055  if (isnull)
2056  ereport(ERROR,
2057  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2058  errmsg("frame starting offset must not be null")));
2059  /* copy value into query-lifespan context */
2060  get_typlenbyval(exprType((Node *) winstate->startOffset->expr),
2061  &len, &byval);
2062  winstate->startOffsetValue = datumCopy(value, byval, len);
2063  if (frameOptions & (FRAMEOPTION_ROWS | FRAMEOPTION_GROUPS))
2064  {
2065  /* value is known to be int8 */
2066  int64 offset = DatumGetInt64(value);
2067 
2068  if (offset < 0)
2069  ereport(ERROR,
2070  (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2071  errmsg("frame starting offset must not be negative")));
2072  }
2073  }
2074  if (frameOptions & FRAMEOPTION_END_OFFSET)
2075  {
2076  Assert(winstate->endOffset != NULL);
2077  value = ExecEvalExprSwitchContext(winstate->endOffset,
2078  econtext,
2079  &isnull);
2080  if (isnull)
2081  ereport(ERROR,
2082  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2083  errmsg("frame ending offset must not be null")));
2084  /* copy value into query-lifespan context */
2085  get_typlenbyval(exprType((Node *) winstate->endOffset->expr),
2086  &len, &byval);
2087  winstate->endOffsetValue = datumCopy(value, byval, len);
2088  if (frameOptions & (FRAMEOPTION_ROWS | FRAMEOPTION_GROUPS))
2089  {
2090  /* value is known to be int8 */
2091  int64 offset = DatumGetInt64(value);
2092 
2093  if (offset < 0)
2094  ereport(ERROR,
2095  (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2096  errmsg("frame ending offset must not be negative")));
2097  }
2098  }
2099  winstate->all_first = false;
2100  }
2101 
2102  if (winstate->buffer == NULL)
2103  {
2104  /* Initialize for first partition and set current row = 0 */
2105  begin_partition(winstate);
2106  /* If there are no input rows, we'll detect that and exit below */
2107  }
2108  else
2109  {
2110  /* Advance current row within partition */
2111  winstate->currentpos++;
2112  /* This might mean that the frame moves, too */
2113  winstate->framehead_valid = false;
2114  winstate->frametail_valid = false;
2115  /* we don't need to invalidate grouptail here; see below */
2116  }
2117 
2118  /*
2119  * Spool all tuples up to and including the current row, if we haven't
2120  * already
2121  */
2122  spool_tuples(winstate, winstate->currentpos);
2123 
2124  /* Move to the next partition if we reached the end of this partition */
2125  if (winstate->partition_spooled &&
2126  winstate->currentpos >= winstate->spooled_rows)
2127  {
2128  release_partition(winstate);
2129 
2130  if (winstate->more_partitions)
2131  {
2132  begin_partition(winstate);
2133  Assert(winstate->spooled_rows > 0);
2134  }
2135  else
2136  {
2137  winstate->all_done = true;
2138  return NULL;
2139  }
2140  }
2141 
2142  /* final output execution is in ps_ExprContext */
2143  econtext = winstate->ss.ps.ps_ExprContext;
2144 
2145  /* Clear the per-output-tuple context for current row */
2146  ResetExprContext(econtext);
2147 
2148  /*
2149  * Read the current row from the tuplestore, and save in ScanTupleSlot.
2150  * (We can't rely on the outerplan's output slot because we may have to
2151  * read beyond the current row. Also, we have to actually copy the row
2152  * out of the tuplestore, since window function evaluation might cause the
2153  * tuplestore to dump its state to disk.)
2154  *
2155  * In GROUPS mode, or when tracking a group-oriented exclusion clause, we
2156  * must also detect entering a new peer group and update associated state
2157  * when that happens. We use temp_slot_2 to temporarily hold the previous
2158  * row for this purpose.
2159  *
2160  * Current row must be in the tuplestore, since we spooled it above.
2161  */
2162  tuplestore_select_read_pointer(winstate->buffer, winstate->current_ptr);
2163  if ((winstate->frameOptions & (FRAMEOPTION_GROUPS |
2166  winstate->currentpos > 0)
2167  {
2168  ExecCopySlot(winstate->temp_slot_2, winstate->ss.ss_ScanTupleSlot);
2169  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
2170  winstate->ss.ss_ScanTupleSlot))
2171  elog(ERROR, "unexpected end of tuplestore");
2172  if (!are_peers(winstate, winstate->temp_slot_2,
2173  winstate->ss.ss_ScanTupleSlot))
2174  {
2175  winstate->currentgroup++;
2176  winstate->groupheadpos = winstate->currentpos;
2177  winstate->grouptail_valid = false;
2178  }
2179  ExecClearTuple(winstate->temp_slot_2);
2180  }
2181  else
2182  {
2183  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
2184  winstate->ss.ss_ScanTupleSlot))
2185  elog(ERROR, "unexpected end of tuplestore");
2186  }
2187 
2188  /*
2189  * Evaluate true window functions
2190  */
2191  numfuncs = winstate->numfuncs;
2192  for (i = 0; i < numfuncs; i++)
2193  {
2194  WindowStatePerFunc perfuncstate = &(winstate->perfunc[i]);
2195 
2196  if (perfuncstate->plain_agg)
2197  continue;
2198  eval_windowfunction(winstate, perfuncstate,
2199  &(econtext->ecxt_aggvalues[perfuncstate->wfuncstate->wfuncno]),
2200  &(econtext->ecxt_aggnulls[perfuncstate->wfuncstate->wfuncno]));
2201  }
2202 
2203  /*
2204  * Evaluate aggregates
2205  */
2206  if (winstate->numaggs > 0)
2207  eval_windowaggregates(winstate);
2208 
2209  /*
2210  * If we have created auxiliary read pointers for the frame or group
2211  * boundaries, force them to be kept up-to-date, because we don't know
2212  * whether the window function(s) will do anything that requires that.
2213  * Failing to advance the pointers would result in being unable to trim
2214  * data from the tuplestore, which is bad. (If we could know in advance
2215  * whether the window functions will use frame boundary info, we could
2216  * skip creating these pointers in the first place ... but unfortunately
2217  * the window function API doesn't require that.)
2218  */
2219  if (winstate->framehead_ptr >= 0)
2220  update_frameheadpos(winstate);
2221  if (winstate->frametail_ptr >= 0)
2222  update_frametailpos(winstate);
2223  if (winstate->grouptail_ptr >= 0)
2224  update_grouptailpos(winstate);
2225 
2226  /*
2227  * Truncate any no-longer-needed rows from the tuplestore.
2228  */
2229  tuplestore_trim(winstate->buffer);
2230 
2231  /*
2232  * Form and return a projection tuple using the windowfunc results and the
2233  * current row. Setting ecxt_outertuple arranges that any Vars will be
2234  * evaluated with respect to that row.
2235  */
2236  econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
2237 
2238  return ExecProject(winstate->ss.ps.ps_ProjInfo);
2239 }
signed short int16
Definition: c.h:345
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:476
ExprState * endOffset
Definition: execnodes.h:2072
Datum * ecxt_aggvalues
Definition: execnodes.h:243
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:300
Datum startOffsetValue
Definition: execnodes.h:2073
static void update_grouptailpos(WindowAggState *winstate)
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:985
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
#define castNode(_type_, nodeptr)
Definition: nodes.h:593
void tuplestore_trim(Tuplestorestate *state)
Definition: tuplestore.c:1360
ScanState ss
Definition: execnodes.h:2045
int64 groupheadpos
Definition: execnodes.h:2087
ExprContext * ps_ExprContext
Definition: execnodes.h:984
static struct @144 value
static void update_frametailpos(WindowAggState *winstate)
int64 currentgroup
Definition: execnodes.h:2084
Definition: nodes.h:524
int errcode(int sqlerrcode)
Definition: elog.c:570
bool frametail_valid
Definition: execnodes.h:2103
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
static void release_partition(WindowAggState *winstate)
WindowFuncExprState * wfuncstate
Definition: nodeWindowAgg.c:80
static void update_frameheadpos(WindowAggState *winstate)
WindowStatePerFunc perfunc
Definition: execnodes.h:2052
#define FRAMEOPTION_START_OFFSET
Definition: parsenodes.h:523
static void spool_tuples(WindowAggState *winstate, int64 pos)
PlanState ps
Definition: execnodes.h:1280
#define FRAMEOPTION_EXCLUDE_GROUP
Definition: parsenodes.h:520
#define ERROR
Definition: elog.h:43
Expr * expr
Definition: execnodes.h:95
#define DatumGetInt64(X)
Definition: postgres.h:607
TupleTableSlot * temp_slot_2
Definition: execnodes.h:2116
Datum endOffsetValue
Definition: execnodes.h:2074
ExprState * startOffset
Definition: execnodes.h:2071
Tuplestorestate * buffer
Definition: execnodes.h:2056
#define ereport(elevel, rest)
Definition: elog.h:141
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
static void eval_windowaggregates(WindowAggState *winstate)
int64 spooled_rows
Definition: execnodes.h:2061
bool * ecxt_aggnulls
Definition: execnodes.h:245
uintptr_t Datum
Definition: postgres.h:367
static void begin_partition(WindowAggState *winstate)
bool more_partitions
Definition: execnodes.h:2099
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:228
#define Assert(condition)
Definition: c.h:732
#define FRAMEOPTION_EXCLUDE_TIES
Definition: parsenodes.h:521
bool grouptail_valid
Definition: execnodes.h:2105
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
#define FRAMEOPTION_END_OFFSET
Definition: parsenodes.h:525
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2029
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:506
int64 currentpos
Definition: execnodes.h:2062
static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
bool partition_spooled
Definition: execnodes.h:2097
int errmsg(const char *fmt,...)
Definition: elog.c:784
bool framehead_valid
Definition: execnodes.h:2101
#define elog(elevel,...)
Definition: elog.h:226
int i
void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
Definition: tuplestore.c:473
#define FRAMEOPTION_GROUPS
Definition: parsenodes.h:507
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:328
static void eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate, Datum *result, bool *isnull)
#define ResetExprContext(econtext)
Definition: executor.h:495

◆ finalize_windowaggregate()

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, CurrentMemoryContext, datumCopy(), DatumGetPointer, ExprContext::ecxt_per_tuple_memory, WindowStatePerAggData::finalfn, WindowStatePerAggData::finalfn_oid, FUNC_MAX_ARGS, FunctionCallInvoke, i, InitFunctionCallInfoData, LOCAL_FCINFO, 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  LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
594  int numFinalArgs = peraggstate->numFinalArgs;
595  bool anynull;
596  int i;
597 
598  InitFunctionCallInfoData(fcinfodata.fcinfo, &(peraggstate->finalfn),
599  numFinalArgs,
600  perfuncstate->winCollation,
601  (void *) winstate, NULL);
602  fcinfo->args[0].value =
604  peraggstate->transValueIsNull,
605  peraggstate->transtypeLen);
606  fcinfo->args[0].isnull = peraggstate->transValueIsNull;
607  anynull = peraggstate->transValueIsNull;
608 
609  /* Fill any remaining argument positions with nulls */
610  for (i = 1; i < numFinalArgs; i++)
611  {
612  fcinfo->args[i].value = (Datum) 0;
613  fcinfo->args[i].isnull = true;
614  anynull = true;
615  }
616 
617  if (fcinfo->flinfo->fn_strict && anynull)
618  {
619  /* don't call a strict function with NULL inputs */
620  *result = (Datum) 0;
621  *isnull = true;
622  }
623  else
624  {
625  winstate->curaggcontext = peraggstate->aggcontext;
626  *result = FunctionCallInvoke(fcinfo);
627  winstate->curaggcontext = NULL;
628  *isnull = fcinfo->isnull;
629  }
630  }
631  else
632  {
633  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
634  *result = peraggstate->transValue;
635  *isnull = peraggstate->transValueIsNull;
636  }
637 
638  /*
639  * If result is pass-by-ref, make sure it is in the right context.
640  */
641  if (!peraggstate->resulttypeByVal && !*isnull &&
643  DatumGetPointer(*result)))
644  *result = datumCopy(*result,
645  peraggstate->resulttypeByVal,
646  peraggstate->resulttypeLen);
647  MemoryContextSwitchTo(oldContext);
648 }
MemoryContext curaggcontext
Definition: execnodes.h:2092
ScanState ss
Definition: execnodes.h:2045
ExprContext * ps_ExprContext
Definition: execnodes.h:984
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define OidIsValid(objectId)
Definition: c.h:638
#define FUNC_MAX_ARGS
PlanState ps
Definition: execnodes.h:1280
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:167
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
uintptr_t Datum
Definition: postgres.h:367
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:667
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
MemoryContext aggcontext
#define DatumGetPointer(X)
Definition: postgres.h:549
int i

◆ GetAggInitVal()

static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 2882 of file nodeWindowAgg.c.

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

Referenced by initialize_peragg().

2883 {
2884  Oid typinput,
2885  typioparam;
2886  char *strInitVal;
2887  Datum initVal;
2888 
2889  getTypeInputInfo(transtype, &typinput, &typioparam);
2890  strInitVal = TextDatumGetCString(textInitVal);
2891  initVal = OidInputFunctionCall(typinput, strInitVal,
2892  typioparam, -1);
2893  pfree(strInitVal);
2894  return initVal;
2895 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:1031
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2641
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1646

◆ initialize_peragg()

static WindowStatePerAggData * initialize_peragg ( WindowAggState winstate,
WindowFunc wfunc,
WindowStatePerAgg  peraggstate 
)
static

Definition at line 2617 of file nodeWindowAgg.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowStatePerAggData::aggcontext, WindowAggState::aggcontext, AGGFNOID, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, 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, InvalidOid, InvokeFunctionExecuteHook, WindowStatePerAggData::invtransfn, WindowStatePerAggData::invtransfn_oid, IsBinaryCoercible(), lfirst, list_length(), WindowStatePerAggData::numFinalArgs, OBJECT_FUNCTION, 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, and WindowFunc::winfnoid.

Referenced by ExecInitWindowAgg().

2619 {
2620  Oid inputTypes[FUNC_MAX_ARGS];
2621  int numArguments;
2622  HeapTuple aggTuple;
2623  Form_pg_aggregate aggform;
2624  Oid aggtranstype;
2625  AttrNumber initvalAttNo;
2626  AclResult aclresult;
2627  bool use_ma_code;
2628  Oid transfn_oid,
2629  invtransfn_oid,
2630  finalfn_oid;
2631  bool finalextra;
2632  char finalmodify;
2633  Expr *transfnexpr,
2634  *invtransfnexpr,
2635  *finalfnexpr;
2636  Datum textInitVal;
2637  int i;
2638  ListCell *lc;
2639 
2640  numArguments = list_length(wfunc->args);
2641 
2642  i = 0;
2643  foreach(lc, wfunc->args)
2644  {
2645  inputTypes[i++] = exprType((Node *) lfirst(lc));
2646  }
2647 
2648  aggTuple = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(wfunc->winfnoid));
2649  if (!HeapTupleIsValid(aggTuple))
2650  elog(ERROR, "cache lookup failed for aggregate %u",
2651  wfunc->winfnoid);
2652  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
2653 
2654  /*
2655  * Figure out whether we want to use the moving-aggregate implementation,
2656  * and collect the right set of fields from the pg_attribute entry.
2657  *
2658  * It's possible that an aggregate would supply a safe moving-aggregate
2659  * implementation and an unsafe normal one, in which case our hand is
2660  * forced. Otherwise, if the frame head can't move, we don't need
2661  * moving-aggregate code. Even if we'd like to use it, don't do so if the
2662  * aggregate's arguments (and FILTER clause if any) contain any calls to
2663  * volatile functions. Otherwise, the difference between restarting and
2664  * not restarting the aggregation would be user-visible.
2665  */
2666  if (!OidIsValid(aggform->aggminvtransfn))
2667  use_ma_code = false; /* sine qua non */
2668  else if (aggform->aggmfinalmodify == AGGMODIFY_READ_ONLY &&
2669  aggform->aggfinalmodify != AGGMODIFY_READ_ONLY)
2670  use_ma_code = true; /* decision forced by safety */
2672  use_ma_code = false; /* non-moving frame head */
2673  else if (contain_volatile_functions((Node *) wfunc))
2674  use_ma_code = false; /* avoid possible behavioral change */
2675  else
2676  use_ma_code = true; /* yes, let's use it */
2677  if (use_ma_code)
2678  {
2679  peraggstate->transfn_oid = transfn_oid = aggform->aggmtransfn;
2680  peraggstate->invtransfn_oid = invtransfn_oid = aggform->aggminvtransfn;
2681  peraggstate->finalfn_oid = finalfn_oid = aggform->aggmfinalfn;
2682  finalextra = aggform->aggmfinalextra;
2683  finalmodify = aggform->aggmfinalmodify;
2684  aggtranstype = aggform->aggmtranstype;
2685  initvalAttNo = Anum_pg_aggregate_aggminitval;
2686  }
2687  else
2688  {
2689  peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
2690  peraggstate->invtransfn_oid = invtransfn_oid = InvalidOid;
2691  peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
2692  finalextra = aggform->aggfinalextra;
2693  finalmodify = aggform->aggfinalmodify;
2694  aggtranstype = aggform->aggtranstype;
2695  initvalAttNo = Anum_pg_aggregate_agginitval;
2696  }
2697 
2698  /*
2699  * ExecInitWindowAgg already checked permission to call aggregate function
2700  * ... but we still need to check the component functions
2701  */
2702 
2703  /* Check that aggregate owner has permission to call component fns */
2704  {
2705  HeapTuple procTuple;
2706  Oid aggOwner;
2707 
2708  procTuple = SearchSysCache1(PROCOID,
2709  ObjectIdGetDatum(wfunc->winfnoid));
2710  if (!HeapTupleIsValid(procTuple))
2711  elog(ERROR, "cache lookup failed for function %u",
2712  wfunc->winfnoid);
2713  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
2714  ReleaseSysCache(procTuple);
2715 
2716  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
2717  ACL_EXECUTE);
2718  if (aclresult != ACLCHECK_OK)
2719  aclcheck_error(aclresult, OBJECT_FUNCTION,
2720  get_func_name(transfn_oid));
2721  InvokeFunctionExecuteHook(transfn_oid);
2722 
2723  if (OidIsValid(invtransfn_oid))
2724  {
2725  aclresult = pg_proc_aclcheck(invtransfn_oid, aggOwner,
2726  ACL_EXECUTE);
2727  if (aclresult != ACLCHECK_OK)
2728  aclcheck_error(aclresult, OBJECT_FUNCTION,
2729  get_func_name(invtransfn_oid));
2730  InvokeFunctionExecuteHook(invtransfn_oid);
2731  }
2732 
2733  if (OidIsValid(finalfn_oid))
2734  {
2735  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
2736  ACL_EXECUTE);
2737  if (aclresult != ACLCHECK_OK)
2738  aclcheck_error(aclresult, OBJECT_FUNCTION,
2739  get_func_name(finalfn_oid));
2740  InvokeFunctionExecuteHook(finalfn_oid);
2741  }
2742  }
2743 
2744  /*
2745  * If the selected finalfn isn't read-only, we can't run this aggregate as
2746  * a window function. This is a user-facing error, so we take a bit more
2747  * care with the error message than elsewhere in this function.
2748  */
2749  if (finalmodify != AGGMODIFY_READ_ONLY)
2750  ereport(ERROR,
2751  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2752  errmsg("aggregate function %s does not support use as a window function",
2753  format_procedure(wfunc->winfnoid))));
2754 
2755  /* Detect how many arguments to pass to the finalfn */
2756  if (finalextra)
2757  peraggstate->numFinalArgs = numArguments + 1;
2758  else
2759  peraggstate->numFinalArgs = 1;
2760 
2761  /* resolve actual type of transition state, if polymorphic */
2762  aggtranstype = resolve_aggregate_transtype(wfunc->winfnoid,
2763  aggtranstype,
2764  inputTypes,
2765  numArguments);
2766 
2767  /* build expression trees using actual argument & result types */
2768  build_aggregate_transfn_expr(inputTypes,
2769  numArguments,
2770  0, /* no ordered-set window functions yet */
2771  false, /* no variadic window functions yet */
2772  aggtranstype,
2773  wfunc->inputcollid,
2774  transfn_oid,
2775  invtransfn_oid,
2776  &transfnexpr,
2777  &invtransfnexpr);
2778 
2779  /* set up infrastructure for calling the transfn(s) and finalfn */
2780  fmgr_info(transfn_oid, &peraggstate->transfn);
2781  fmgr_info_set_expr((Node *) transfnexpr, &peraggstate->transfn);
2782 
2783  if (OidIsValid(invtransfn_oid))
2784  {
2785  fmgr_info(invtransfn_oid, &peraggstate->invtransfn);
2786  fmgr_info_set_expr((Node *) invtransfnexpr, &peraggstate->invtransfn);
2787  }
2788 
2789  if (OidIsValid(finalfn_oid))
2790  {
2791  build_aggregate_finalfn_expr(inputTypes,
2792  peraggstate->numFinalArgs,
2793  aggtranstype,
2794  wfunc->wintype,
2795  wfunc->inputcollid,
2796  finalfn_oid,
2797  &finalfnexpr);
2798  fmgr_info(finalfn_oid, &peraggstate->finalfn);
2799  fmgr_info_set_expr((Node *) finalfnexpr, &peraggstate->finalfn);
2800  }
2801 
2802  /* get info about relevant datatypes */
2803  get_typlenbyval(wfunc->wintype,
2804  &peraggstate->resulttypeLen,
2805  &peraggstate->resulttypeByVal);
2806  get_typlenbyval(aggtranstype,
2807  &peraggstate->transtypeLen,
2808  &peraggstate->transtypeByVal);
2809 
2810  /*
2811  * initval is potentially null, so don't try to access it as a struct
2812  * field. Must do it the hard way with SysCacheGetAttr.
2813  */
2814  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple, initvalAttNo,
2815  &peraggstate->initValueIsNull);
2816 
2817  if (peraggstate->initValueIsNull)
2818  peraggstate->initValue = (Datum) 0;
2819  else
2820  peraggstate->initValue = GetAggInitVal(textInitVal,
2821  aggtranstype);
2822 
2823  /*
2824  * If the transfn is strict and the initval is NULL, make sure input type
2825  * and transtype are the same (or at least binary-compatible), so that
2826  * it's OK to use the first input value as the initial transValue. This
2827  * should have been checked at agg definition time, but we must check
2828  * again in case the transfn's strictness property has been changed.
2829  */
2830  if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
2831  {
2832  if (numArguments < 1 ||
2833  !IsBinaryCoercible(inputTypes[0], aggtranstype))
2834  ereport(ERROR,
2835  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2836  errmsg("aggregate %u needs to have compatible input type and transition type",
2837  wfunc->winfnoid)));
2838  }
2839 
2840  /*
2841  * Insist that forward and inverse transition functions have the same
2842  * strictness setting. Allowing them to differ would require handling
2843  * more special cases in advance_windowaggregate and
2844  * advance_windowaggregate_base, for no discernible benefit. This should
2845  * have been checked at agg definition time, but we must check again in
2846  * case either function's strictness property has been changed.
2847  */
2848  if (OidIsValid(invtransfn_oid) &&
2849  peraggstate->transfn.fn_strict != peraggstate->invtransfn.fn_strict)
2850  ereport(ERROR,
2851  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2852  errmsg("strictness of aggregate's forward and inverse transition functions must match")));
2853 
2854  /*
2855  * Moving aggregates use their own aggcontext.
2856  *
2857  * This is necessary because they might restart at different times, so we
2858  * might never be able to reset the shared context otherwise. We can't
2859  * make it the aggregates' responsibility to clean up after themselves,
2860  * because strict aggregates must be restarted whenever we remove their
2861  * last non-NULL input, which the aggregate won't be aware is happening.
2862  * Also, just pfree()ing the transValue upon restarting wouldn't help,
2863  * since we'd miss any indirectly referenced data. We could, in theory,
2864  * make the memory allocation rules for moving aggregates different than
2865  * they have historically been for plain aggregates, but that seems grotty
2866  * and likely to lead to memory leaks.
2867  */
2868  if (OidIsValid(invtransfn_oid))
2869  peraggstate->aggcontext =
2871  "WindowAgg Per Aggregate",
2873  else
2874  peraggstate->aggcontext = winstate->aggcontext;
2875 
2876  ReleaseSysCache(aggTuple);
2877 
2878  return peraggstate;
2879 }
#define AllocSetContextCreate
Definition: memutils.h:169
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
List * args
Definition: primnodes.h:363
Definition: nodes.h:524
int errcode(int sqlerrcode)
Definition: elog.c:570
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:2037
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:724
unsigned int Oid
Definition: postgres_ext.h:31
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:509
#define OidIsValid(objectId)
Definition: c.h:638
#define FUNC_MAX_ARGS
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3353
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1410
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:124
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:191
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
Oid winfnoid
Definition: primnodes.h:359
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
MemoryContext aggcontext
Definition: execnodes.h:2091
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:179
bool IsBinaryCoercible(Oid srctype, Oid targettype)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1385
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:134
#define InvalidOid
Definition: postgres_ext.h:36
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:323
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:190
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
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:1900
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static int list_length(const List *l)
Definition: pg_list.h:169
MemoryContext aggcontext
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2029
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define ACL_EXECUTE
Definition: parsenodes.h:81
#define elog(elevel,...)
Definition: elog.h:226
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4655
int i
int16 AttrNumber
Definition: attnum.h:21
Oid resolve_aggregate_transtype(Oid aggfuncid, Oid aggtranstype, Oid *inputTypes, int numArguments)
Definition: parse_agg.c:1845

◆ initialize_windowaggregate()

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

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

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

◆ release_partition()

static void release_partition ( WindowAggState winstate)
static

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

1313 {
1314  int i;
1315 
1316  for (i = 0; i < winstate->numfuncs; i++)
1317  {
1318  WindowStatePerFunc perfuncstate = &(winstate->perfunc[i]);
1319 
1320  /* Release any partition-local state of this window function */
1321  if (perfuncstate->winobj)
1322  perfuncstate->winobj->localmem = NULL;
1323  }
1324 
1325  /*
1326  * Release all partition-local memory (in particular, any partition-local
1327  * state that we might have trashed our pointers to in the above loop, and
1328  * any aggregate temp data). We don't rely on retail pfree because some
1329  * aggregates might have allocated data we don't have direct pointers to.
1330  */
1333  for (i = 0; i < winstate->numaggs; i++)
1334  {
1335  if (winstate->peragg[i].aggcontext != winstate->aggcontext)
1337  }
1338 
1339  if (winstate->buffer)
1340  tuplestore_end(winstate->buffer);
1341  winstate->buffer = NULL;
1342  winstate->partition_spooled = false;
1343 }
WindowStatePerFunc perfunc
Definition: execnodes.h:2052
WindowStatePerAgg peragg
Definition: execnodes.h:2053
Tuplestorestate * buffer
Definition: execnodes.h:2056
MemoryContext aggcontext
Definition: execnodes.h:2091
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:67
MemoryContext aggcontext
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
bool partition_spooled
Definition: execnodes.h:2097
int i
MemoryContext partcontext
Definition: execnodes.h:2090

◆ row_is_in_frame()

static int row_is_in_frame ( WindowAggState winstate,
int64  pos,
TupleTableSlot slot 
)
static

Definition at line 1362 of file nodeWindowAgg.c.

References are_peers(), Assert, WindowAggState::currentpos, DatumGetInt64, WindowAggState::endOffsetValue, FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_END_OFFSET, FRAMEOPTION_END_OFFSET_PRECEDING, FRAMEOPTION_EXCLUDE_CURRENT_ROW, FRAMEOPTION_EXCLUDE_GROUP, FRAMEOPTION_EXCLUDE_TIES, FRAMEOPTION_GROUPS, FRAMEOPTION_RANGE, FRAMEOPTION_ROWS, WindowAggState::frameOptions, WindowAggState::frametailpos, WindowAggState::groupheadpos, WindowAgg::ordNumCols, PlanState::plan, ScanState::ps, WindowAggState::ss, ScanState::ss_ScanTupleSlot, update_frameheadpos(), update_frametailpos(), and update_grouptailpos().

Referenced by eval_windowaggregates(), and WinGetFuncArgInFrame().

1363 {
1364  int frameOptions = winstate->frameOptions;
1365 
1366  Assert(pos >= 0); /* else caller error */
1367 
1368  /*
1369  * First, check frame starting conditions. We might as well delegate this
1370  * to update_frameheadpos always; it doesn't add any notable cost.
1371  */
1372  update_frameheadpos(winstate);
1373  if (pos < winstate->frameheadpos)
1374  return 0;
1375 
1376  /*
1377  * Okay so far, now check frame ending conditions. Here, we avoid calling
1378  * update_frametailpos in simple cases, so as not to spool tuples further
1379  * ahead than necessary.
1380  */
1381  if (frameOptions & FRAMEOPTION_END_CURRENT_ROW)
1382  {
1383  if (frameOptions & FRAMEOPTION_ROWS)
1384  {
1385  /* rows after current row are out of frame */
1386  if (pos > winstate->currentpos)
1387  return -1;
1388  }
1389  else if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS))
1390  {
1391  /* following row that is not peer is out of frame */
1392  if (pos > winstate->currentpos &&
1393  !are_peers(winstate, slot, winstate->ss.ss_ScanTupleSlot))
1394  return -1;
1395  }
1396  else
1397  Assert(false);
1398  }
1399  else if (frameOptions & FRAMEOPTION_END_OFFSET)
1400  {
1401  if (frameOptions & FRAMEOPTION_ROWS)
1402  {
1403  int64 offset = DatumGetInt64(winstate->endOffsetValue);
1404 
1405  /* rows after current row + offset are out of frame */
1406  if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
1407  offset = -offset;
1408 
1409  if (pos > winstate->currentpos + offset)
1410  return -1;
1411  }
1412  else if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS))
1413  {
1414  /* hard cases, so delegate to update_frametailpos */
1415  update_frametailpos(winstate);
1416  if (pos >= winstate->frametailpos)
1417  return -1;
1418  }
1419  else
1420  Assert(false);
1421  }
1422 
1423  /* Check exclusion clause */
1424  if (frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
1425  {
1426  if (pos == winstate->currentpos)
1427  return 0;
1428  }
1429  else if ((frameOptions & FRAMEOPTION_EXCLUDE_GROUP) ||
1430  ((frameOptions & FRAMEOPTION_EXCLUDE_TIES) &&
1431  pos != winstate->currentpos))
1432  {
1433  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
1434 
1435  /* If no ORDER BY, all rows are peers with each other */
1436  if (node->ordNumCols == 0)
1437  return 0;
1438  /* Otherwise, check the group boundaries */
1439  if (pos >= winstate->groupheadpos)
1440  {
1441  update_grouptailpos(winstate);
1442  if (pos < winstate->grouptailpos)
1443  return 0;
1444  }
1445  }
1446 
1447  /* If we get here, it's in frame */
1448  return 1;
1449 }
int ordNumCols
Definition: plannodes.h:830
static void update_grouptailpos(WindowAggState *winstate)
ScanState ss
Definition: execnodes.h:2045
int64 groupheadpos
Definition: execnodes.h:2087
static void update_frametailpos(WindowAggState *winstate)
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
static void update_frameheadpos(WindowAggState *winstate)
PlanState ps
Definition: execnodes.h:1280
#define FRAMEOPTION_EXCLUDE_GROUP
Definition: parsenodes.h:520
#define DatumGetInt64(X)
Definition: postgres.h:607
Datum endOffsetValue
Definition: execnodes.h:2074
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:514
#define FRAMEOPTION_EXCLUDE_CURRENT_ROW
Definition: parsenodes.h:519
Plan * plan
Definition: execnodes.h:945
int64 frametailpos
Definition: execnodes.h:2064
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:505
#define Assert(condition)
Definition: c.h:732
#define FRAMEOPTION_EXCLUDE_TIES
Definition: parsenodes.h:521
#define FRAMEOPTION_END_OFFSET
Definition: parsenodes.h:525
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:506
int64 currentpos
Definition: execnodes.h:2062
#define FRAMEOPTION_END_OFFSET_PRECEDING
Definition: parsenodes.h:516
static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
#define FRAMEOPTION_GROUPS
Definition: parsenodes.h:507

◆ spool_tuples()

static void spool_tuples ( WindowAggState winstate,
int64  pos 
)
static

Definition at line 1239 of file nodeWindowAgg.c.

References WindowAggState::buffer, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, ExprContext::ecxt_per_query_memory, ExecCopySlot(), ExecProcNode(), ExecQualAndReset(), WindowAggState::first_part_slot, MemoryContextSwitchTo(), WindowAggState::more_partitions, outerPlan, outerPlanState, WindowAggState::partEqfunction, 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(), update_grouptailpos(), window_gettupleslot(), WinGetFuncArgInPartition(), and WinGetPartitionRowCount().

1240 {
1241  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
1243  TupleTableSlot *outerslot;
1244  MemoryContext oldcontext;
1245 
1246  if (!winstate->buffer)
1247  return; /* just a safety check */
1248  if (winstate->partition_spooled)
1249  return; /* whole partition done already */
1250 
1251  /*
1252  * If the tuplestore has spilled to disk, alternate reading and writing
1253  * becomes quite expensive due to frequent buffer flushes. It's cheaper
1254  * to force the entire partition to get spooled in one go.
1255  *
1256  * XXX this is a horrid kluge --- it'd be better to fix the performance
1257  * problem inside tuplestore. FIXME
1258  */
1259  if (!tuplestore_in_memory(winstate->buffer))
1260  pos = -1;
1261 
1262  outerPlan = outerPlanState(winstate);
1263 
1264  /* Must be in query context to call outerplan */
1266 
1267  while (winstate->spooled_rows <= pos || pos == -1)
1268  {
1269  outerslot = ExecProcNode(outerPlan);
1270  if (TupIsNull(outerslot))
1271  {
1272  /* reached the end of the last partition */
1273  winstate->partition_spooled = true;
1274  winstate->more_partitions = false;
1275  break;
1276  }
1277 
1278  if (node->partNumCols > 0)
1279  {
1280  ExprContext *econtext = winstate->tmpcontext;
1281 
1282  econtext->ecxt_innertuple = winstate->first_part_slot;
1283  econtext->ecxt_outertuple = outerslot;
1284 
1285  /* Check if this tuple still belongs to the current partition */
1286  if (!ExecQualAndReset(winstate->partEqfunction, econtext))
1287  {
1288  /*
1289  * end of partition; copy the tuple for the next cycle.
1290  */
1291  ExecCopySlot(winstate->first_part_slot, outerslot);
1292  winstate->partition_spooled = true;
1293  winstate->more_partitions = true;
1294  break;
1295  }
1296  }
1297 
1298  /* Still in partition, so save it into the tuplestore */
1299  tuplestore_puttupleslot(winstate->buffer, outerslot);
1300  winstate->spooled_rows++;
1301  }
1302 
1303  MemoryContextSwitchTo(oldcontext);
1304 }
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:476
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition: tuplestore.c:708
ScanState ss
Definition: execnodes.h:2045
ExprContext * ps_ExprContext
Definition: execnodes.h:984
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
TupleTableSlot * first_part_slot
Definition: execnodes.h:2108
ExprContext * tmpcontext
Definition: execnodes.h:2093
PlanState ps
Definition: execnodes.h:1280
bool tuplestore_in_memory(Tuplestorestate *state)
Definition: tuplestore.c:1455
ExprState * partEqfunction
Definition: execnodes.h:2054
#define outerPlanState(node)
Definition: execnodes.h:1039
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:226
#define TupIsNull(slot)
Definition: tuptable.h:293
int partNumCols
Definition: plannodes.h:826
Tuplestorestate * buffer
Definition: execnodes.h:2056
#define outerPlan(node)
Definition: plannodes.h:170
int64 spooled_rows
Definition: execnodes.h:2061
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:392
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:235
Plan * plan
Definition: execnodes.h:945
bool more_partitions
Definition: execnodes.h:2099
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:228
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:231
bool partition_spooled
Definition: execnodes.h:2097

◆ update_frameheadpos()

static void update_frameheadpos ( WindowAggState winstate)
static

Definition at line 1462 of file nodeWindowAgg.c.

References are_peers(), Assert, BoolGetDatum, WindowAggState::buffer, WindowAggState::currentgroup, WindowAggState::currentpos, DatumGetBool, DatumGetInt64, ExprContext::ecxt_per_query_memory, elog, ERROR, ExecClearTuple(), ExecCopySlot(), WindowAggState::framehead_ptr, WindowAggState::framehead_slot, WindowAggState::framehead_valid, WindowAggState::frameheadgroup, WindowAggState::frameheadpos, FRAMEOPTION_GROUPS, FRAMEOPTION_RANGE, FRAMEOPTION_ROWS, FRAMEOPTION_START_CURRENT_ROW, FRAMEOPTION_START_OFFSET, FRAMEOPTION_START_OFFSET_PRECEDING, FRAMEOPTION_START_UNBOUNDED_PRECEDING, WindowAggState::frameOptions, FunctionCall5Coll(), WindowAggState::inRangeAsc, WindowAggState::inRangeColl, WindowAggState::inRangeNullsFirst, MemoryContextSwitchTo(), WindowAgg::ordColIdx, WindowAgg::ordNumCols, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, slot_getattr(), spool_tuples(), WindowAggState::spooled_rows, WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowAggState::startInRangeFunc, WindowAggState::startOffsetValue, WindowAggState::temp_slot_2, TupIsNull, tuplestore_gettupleslot(), and tuplestore_select_read_pointer().

Referenced by eval_windowaggregates(), ExecWindowAgg(), row_is_in_frame(), and WinGetFuncArgInFrame().

1463 {
1464  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
1465  int frameOptions = winstate->frameOptions;
1466  MemoryContext oldcontext;
1467 
1468  if (winstate->framehead_valid)
1469  return; /* already known for current row */
1470 
1471  /* We may be called in a short-lived context */
1473 
1474  if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
1475  {
1476  /* In UNBOUNDED PRECEDING mode, frame head is always row 0 */
1477  winstate->frameheadpos = 0;
1478  winstate->framehead_valid = true;
1479  }
1480  else if (frameOptions & FRAMEOPTION_START_CURRENT_ROW)
1481  {
1482  if (frameOptions & FRAMEOPTION_ROWS)
1483  {
1484  /* In ROWS mode, frame head is the same as current */
1485  winstate->frameheadpos = winstate->currentpos;
1486  winstate->framehead_valid = true;
1487  }
1488  else if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS))
1489  {
1490  /* If no ORDER BY, all rows are peers with each other */
1491  if (node->ordNumCols == 0)
1492  {
1493  winstate->frameheadpos = 0;
1494  winstate->framehead_valid = true;
1495  MemoryContextSwitchTo(oldcontext);
1496  return;
1497  }
1498 
1499  /*
1500  * In RANGE or GROUPS START_CURRENT_ROW mode, frame head is the
1501  * first row that is a peer of current row. We keep a copy of the
1502  * last-known frame head row in framehead_slot, and advance as
1503  * necessary. Note that if we reach end of partition, we will
1504  * leave frameheadpos = end+1 and framehead_slot empty.
1505  */
1507  winstate->framehead_ptr);
1508  if (winstate->frameheadpos == 0 &&
1509  TupIsNull(winstate->framehead_slot))
1510  {
1511  /* fetch first row into framehead_slot, if we didn't already */
1512  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1513  winstate->framehead_slot))
1514  elog(ERROR, "unexpected end of tuplestore");
1515  }
1516 
1517  while (!TupIsNull(winstate->framehead_slot))
1518  {
1519  if (are_peers(winstate, winstate->framehead_slot,
1520  winstate->ss.ss_ScanTupleSlot))
1521  break; /* this row is the correct frame head */
1522  /* Note we advance frameheadpos even if the fetch fails */
1523  winstate->frameheadpos++;
1524  spool_tuples(winstate, winstate->frameheadpos);
1525  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1526  winstate->framehead_slot))
1527  break; /* end of partition */
1528  }
1529  winstate->framehead_valid = true;
1530  }
1531  else
1532  Assert(false);
1533  }
1534  else if (frameOptions & FRAMEOPTION_START_OFFSET)
1535  {
1536  if (frameOptions & FRAMEOPTION_ROWS)
1537  {
1538  /* In ROWS mode, bound is physically n before/after current */
1539  int64 offset = DatumGetInt64(winstate->startOffsetValue);
1540 
1541  if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
1542  offset = -offset;
1543 
1544  winstate->frameheadpos = winstate->currentpos + offset;
1545  /* frame head can't go before first row */
1546  if (winstate->frameheadpos < 0)
1547  winstate->frameheadpos = 0;
1548  else if (winstate->frameheadpos > winstate->currentpos + 1)
1549  {
1550  /* make sure frameheadpos is not past end of partition */
1551  spool_tuples(winstate, winstate->frameheadpos - 1);
1552  if (winstate->frameheadpos > winstate->spooled_rows)
1553  winstate->frameheadpos = winstate->spooled_rows;
1554  }
1555  winstate->framehead_valid = true;
1556  }
1557  else if (frameOptions & FRAMEOPTION_RANGE)
1558  {
1559  /*
1560  * In RANGE START_OFFSET mode, frame head is the first row that
1561  * satisfies the in_range constraint relative to the current row.
1562  * We keep a copy of the last-known frame head row in
1563  * framehead_slot, and advance as necessary. Note that if we
1564  * reach end of partition, we will leave frameheadpos = end+1 and
1565  * framehead_slot empty.
1566  */
1567  int sortCol = node->ordColIdx[0];
1568  bool sub,
1569  less;
1570 
1571  /* We must have an ordering column */
1572  Assert(node->ordNumCols == 1);
1573 
1574  /* Precompute flags for in_range checks */
1575  if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
1576  sub = true; /* subtract startOffset from current row */
1577  else
1578  sub = false; /* add it */
1579  less = false; /* normally, we want frame head >= sum */
1580  /* If sort order is descending, flip both flags */
1581  if (!winstate->inRangeAsc)
1582  {
1583  sub = !sub;
1584  less = true;
1585  }
1586 
1588  winstate->framehead_ptr);
1589  if (winstate->frameheadpos == 0 &&
1590  TupIsNull(winstate->framehead_slot))
1591  {
1592  /* fetch first row into framehead_slot, if we didn't already */
1593  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1594  winstate->framehead_slot))
1595  elog(ERROR, "unexpected end of tuplestore");
1596  }
1597 
1598  while (!TupIsNull(winstate->framehead_slot))
1599  {
1600  Datum headval,
1601  currval;
1602  bool headisnull,
1603  currisnull;
1604 
1605  headval = slot_getattr(winstate->framehead_slot, sortCol,
1606  &headisnull);
1607  currval = slot_getattr(winstate->ss.ss_ScanTupleSlot, sortCol,
1608  &currisnull);
1609  if (headisnull || currisnull)
1610  {
1611  /* order of the rows depends only on nulls_first */
1612  if (winstate->inRangeNullsFirst)
1613  {
1614  /* advance head if head is null and curr is not */
1615  if (!headisnull || currisnull)
1616  break;
1617  }
1618  else
1619  {
1620  /* advance head if head is not null and curr is null */
1621  if (headisnull || !currisnull)
1622  break;
1623  }
1624  }
1625  else
1626  {
1628  winstate->inRangeColl,
1629  headval,
1630  currval,
1631  winstate->startOffsetValue,
1632  BoolGetDatum(sub),
1633  BoolGetDatum(less))))
1634  break; /* this row is the correct frame head */
1635  }
1636  /* Note we advance frameheadpos even if the fetch fails */
1637  winstate->frameheadpos++;
1638  spool_tuples(winstate, winstate->frameheadpos);
1639  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1640  winstate->framehead_slot))
1641  break; /* end of partition */
1642  }
1643  winstate->framehead_valid = true;
1644  }
1645  else if (frameOptions & FRAMEOPTION_GROUPS)
1646  {
1647  /*
1648  * In GROUPS START_OFFSET mode, frame head is the first row of the
1649  * first peer group whose number satisfies the offset constraint.
1650  * We keep a copy of the last-known frame head row in
1651  * framehead_slot, and advance as necessary. Note that if we
1652  * reach end of partition, we will leave frameheadpos = end+1 and
1653  * framehead_slot empty.
1654  */
1655  int64 offset = DatumGetInt64(winstate->startOffsetValue);
1656  int64 minheadgroup;
1657 
1658  if (frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
1659  minheadgroup = winstate->currentgroup - offset;
1660  else
1661  minheadgroup = winstate->currentgroup + offset;
1662 
1664  winstate->framehead_ptr);
1665  if (winstate->frameheadpos == 0 &&
1666  TupIsNull(winstate->framehead_slot))
1667  {
1668  /* fetch first row into framehead_slot, if we didn't already */
1669  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1670  winstate->framehead_slot))
1671  elog(ERROR, "unexpected end of tuplestore");
1672  }
1673 
1674  while (!TupIsNull(winstate->framehead_slot))
1675  {
1676  if (winstate->frameheadgroup >= minheadgroup)
1677  break; /* this row is the correct frame head */
1678  ExecCopySlot(winstate->temp_slot_2, winstate->framehead_slot);
1679  /* Note we advance frameheadpos even if the fetch fails */
1680  winstate->frameheadpos++;
1681  spool_tuples(winstate, winstate->frameheadpos);
1682  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1683  winstate->framehead_slot))
1684  break; /* end of partition */
1685  if (!are_peers(winstate, winstate->temp_slot_2,
1686  winstate->framehead_slot))
1687  winstate->frameheadgroup++;
1688  }
1689  ExecClearTuple(winstate->temp_slot_2);
1690  winstate->framehead_valid = true;
1691  }
1692  else
1693  Assert(false);
1694  }
1695  else
1696  Assert(false);
1697 
1698  MemoryContextSwitchTo(oldcontext);
1699 }
int ordNumCols
Definition: plannodes.h:830
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:476
Datum startOffsetValue
Definition: execnodes.h:2073
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
ScanState ss
Definition: execnodes.h:2045
Datum FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5)
Definition: fmgr.c:1224
ExprContext * ps_ExprContext
Definition: execnodes.h:984
AttrNumber * ordColIdx
Definition: plannodes.h:831
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int64 currentgroup
Definition: execnodes.h:2084
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING
Definition: parsenodes.h:509
#define FRAMEOPTION_START_OFFSET
Definition: parsenodes.h:523
static void spool_tuples(WindowAggState *winstate, int64 pos)
PlanState ps
Definition: execnodes.h:1280
bool inRangeNullsFirst
Definition: execnodes.h:2081
int64 frameheadpos
Definition: execnodes.h:2063
#define ERROR
Definition: elog.h:43
#define DatumGetInt64(X)
Definition: postgres.h:607
TupleTableSlot * temp_slot_2
Definition: execnodes.h:2116
int64 frameheadgroup
Definition: execnodes.h:2085
#define FRAMEOPTION_START_OFFSET_PRECEDING
Definition: parsenodes.h:515
#define DatumGetBool(X)
Definition: postgres.h:393
#define TupIsNull(slot)
Definition: tuptable.h:293
Tuplestorestate * buffer
Definition: execnodes.h:2056
#define FRAMEOPTION_START_CURRENT_ROW
Definition: parsenodes.h:513
int64 spooled_rows
Definition: execnodes.h:2061
uintptr_t Datum
Definition: postgres.h:367
#define BoolGetDatum(X)
Definition: postgres.h:402
Plan * plan
Definition: execnodes.h:945
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:382
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:505
#define Assert(condition)
Definition: c.h:732
FmgrInfo startInRangeFunc
Definition: execnodes.h:2077
TupleTableSlot * framehead_slot
Definition: execnodes.h:2110
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:506
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:231
int64 currentpos
Definition: execnodes.h:2062
static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
bool framehead_valid
Definition: execnodes.h:2101
#define elog(elevel,...)
Definition: elog.h:226
void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
Definition: tuplestore.c:473
#define FRAMEOPTION_GROUPS
Definition: parsenodes.h:507

◆ update_frametailpos()

static void update_frametailpos ( WindowAggState winstate)
static

Definition at line 1712 of file nodeWindowAgg.c.

References are_peers(), Assert, BoolGetDatum, WindowAggState::buffer, WindowAggState::currentgroup, WindowAggState::currentpos, DatumGetBool, DatumGetInt64, ExprContext::ecxt_per_query_memory, elog, WindowAggState::endInRangeFunc, WindowAggState::endOffsetValue, ERROR, ExecClearTuple(), ExecCopySlot(), FRAMEOPTION_END_CURRENT_ROW, FRAMEOPTION_END_OFFSET, FRAMEOPTION_END_OFFSET_PRECEDING, FRAMEOPTION_END_UNBOUNDED_FOLLOWING, FRAMEOPTION_GROUPS, FRAMEOPTION_RANGE, FRAMEOPTION_ROWS, WindowAggState::frameOptions, WindowAggState::frametail_ptr, WindowAggState::frametail_slot, WindowAggState::frametail_valid, WindowAggState::frametailgroup, WindowAggState::frametailpos, FunctionCall5Coll(), WindowAggState::inRangeAsc, WindowAggState::inRangeColl, WindowAggState::inRangeNullsFirst, MemoryContextSwitchTo(), WindowAgg::ordColIdx, WindowAgg::ordNumCols, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, slot_getattr(), spool_tuples(), WindowAggState::spooled_rows, WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowAggState::temp_slot_2, TupIsNull, tuplestore_gettupleslot(), and tuplestore_select_read_pointer().

Referenced by ExecWindowAgg(), row_is_in_frame(), and WinGetFuncArgInFrame().

1713 {
1714  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
1715  int frameOptions = winstate->frameOptions;
1716  MemoryContext oldcontext;
1717 
1718  if (winstate->frametail_valid)
1719  return; /* already known for current row */
1720 
1721  /* We may be called in a short-lived context */
1723 
1724  if (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
1725  {
1726  /* In UNBOUNDED FOLLOWING mode, all partition rows are in frame */
1727  spool_tuples(winstate, -1);
1728  winstate->frametailpos = winstate->spooled_rows;
1729  winstate->frametail_valid = true;
1730  }
1731  else if (frameOptions & FRAMEOPTION_END_CURRENT_ROW)
1732  {
1733  if (frameOptions & FRAMEOPTION_ROWS)
1734  {
1735  /* In ROWS mode, exactly the rows up to current are in frame */
1736  winstate->frametailpos = winstate->currentpos + 1;
1737  winstate->frametail_valid = true;
1738  }
1739  else if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS))
1740  {
1741  /* If no ORDER BY, all rows are peers with each other */
1742  if (node->ordNumCols == 0)
1743  {
1744  spool_tuples(winstate, -1);
1745  winstate->frametailpos = winstate->spooled_rows;
1746  winstate->frametail_valid = true;
1747  MemoryContextSwitchTo(oldcontext);
1748  return;
1749  }
1750 
1751  /*
1752  * In RANGE or GROUPS END_CURRENT_ROW mode, frame end is the last
1753  * row that is a peer of current row, frame tail is the row after
1754  * that (if any). We keep a copy of the last-known frame tail row
1755  * in frametail_slot, and advance as necessary. Note that if we
1756  * reach end of partition, we will leave frametailpos = end+1 and
1757  * frametail_slot empty.
1758  */
1760  winstate->frametail_ptr);
1761  if (winstate->frametailpos == 0 &&
1762  TupIsNull(winstate->frametail_slot))
1763  {
1764  /* fetch first row into frametail_slot, if we didn't already */
1765  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1766  winstate->frametail_slot))
1767  elog(ERROR, "unexpected end of tuplestore");
1768  }
1769 
1770  while (!TupIsNull(winstate->frametail_slot))
1771  {
1772  if (winstate->frametailpos > winstate->currentpos &&
1773  !are_peers(winstate, winstate->frametail_slot,
1774  winstate->ss.ss_ScanTupleSlot))
1775  break; /* this row is the frame tail */
1776  /* Note we advance frametailpos even if the fetch fails */
1777  winstate->frametailpos++;
1778  spool_tuples(winstate, winstate->frametailpos);
1779  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1780  winstate->frametail_slot))
1781  break; /* end of partition */
1782  }
1783  winstate->frametail_valid = true;
1784  }
1785  else
1786  Assert(false);
1787  }
1788  else if (frameOptions & FRAMEOPTION_END_OFFSET)
1789  {
1790  if (frameOptions & FRAMEOPTION_ROWS)
1791  {
1792  /* In ROWS mode, bound is physically n before/after current */
1793  int64 offset = DatumGetInt64(winstate->endOffsetValue);
1794 
1795  if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
1796  offset = -offset;
1797 
1798  winstate->frametailpos = winstate->currentpos + offset + 1;
1799  /* smallest allowable value of frametailpos is 0 */
1800  if (winstate->frametailpos < 0)
1801  winstate->frametailpos = 0;
1802  else if (winstate->frametailpos > winstate->currentpos + 1)
1803  {
1804  /* make sure frametailpos is not past end of partition */
1805  spool_tuples(winstate, winstate->frametailpos - 1);
1806  if (winstate->frametailpos > winstate->spooled_rows)
1807  winstate->frametailpos = winstate->spooled_rows;
1808  }
1809  winstate->frametail_valid = true;
1810  }
1811  else if (frameOptions & FRAMEOPTION_RANGE)
1812  {
1813  /*
1814  * In RANGE END_OFFSET mode, frame end is the last row that
1815  * satisfies the in_range constraint relative to the current row,
1816  * frame tail is the row after that (if any). We keep a copy of
1817  * the last-known frame tail row in frametail_slot, and advance as
1818  * necessary. Note that if we reach end of partition, we will
1819  * leave frametailpos = end+1 and frametail_slot empty.
1820  */
1821  int sortCol = node->ordColIdx[0];
1822  bool sub,
1823  less;
1824 
1825  /* We must have an ordering column */
1826  Assert(node->ordNumCols == 1);
1827 
1828  /* Precompute flags for in_range checks */
1829  if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
1830  sub = true; /* subtract endOffset from current row */
1831  else
1832  sub = false; /* add it */
1833  less = true; /* normally, we want frame tail <= sum */
1834  /* If sort order is descending, flip both flags */
1835  if (!winstate->inRangeAsc)
1836  {
1837  sub = !sub;
1838  less = false;
1839  }
1840 
1842  winstate->frametail_ptr);
1843  if (winstate->frametailpos == 0 &&
1844  TupIsNull(winstate->frametail_slot))
1845  {
1846  /* fetch first row into frametail_slot, if we didn't already */
1847  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1848  winstate->frametail_slot))
1849  elog(ERROR, "unexpected end of tuplestore");
1850  }
1851 
1852  while (!TupIsNull(winstate->frametail_slot))
1853  {
1854  Datum tailval,
1855  currval;
1856  bool tailisnull,
1857  currisnull;
1858 
1859  tailval = slot_getattr(winstate->frametail_slot, sortCol,
1860  &tailisnull);
1861  currval = slot_getattr(winstate->ss.ss_ScanTupleSlot, sortCol,
1862  &currisnull);
1863  if (tailisnull || currisnull)
1864  {
1865  /* order of the rows depends only on nulls_first */
1866  if (winstate->inRangeNullsFirst)
1867  {
1868  /* advance tail if tail is null or curr is not */
1869  if (!tailisnull)
1870  break;
1871  }
1872  else
1873  {
1874  /* advance tail if tail is not null or curr is null */
1875  if (!currisnull)
1876  break;
1877  }
1878  }
1879  else
1880  {
1882  winstate->inRangeColl,
1883  tailval,
1884  currval,
1885  winstate->endOffsetValue,
1886  BoolGetDatum(sub),
1887  BoolGetDatum(less))))
1888  break; /* this row is the correct frame tail */
1889  }
1890  /* Note we advance frametailpos even if the fetch fails */
1891  winstate->frametailpos++;
1892  spool_tuples(winstate, winstate->frametailpos);
1893  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1894  winstate->frametail_slot))
1895  break; /* end of partition */
1896  }
1897  winstate->frametail_valid = true;
1898  }
1899  else if (frameOptions & FRAMEOPTION_GROUPS)
1900  {
1901  /*
1902  * In GROUPS END_OFFSET mode, frame end is the last row of the
1903  * last peer group whose number satisfies the offset constraint,
1904  * and frame tail is the row after that (if any). We keep a copy
1905  * of the last-known frame tail row in frametail_slot, and advance
1906  * as necessary. Note that if we reach end of partition, we will
1907  * leave frametailpos = end+1 and frametail_slot empty.
1908  */
1909  int64 offset = DatumGetInt64(winstate->endOffsetValue);
1910  int64 maxtailgroup;
1911 
1912  if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
1913  maxtailgroup = winstate->currentgroup - offset;
1914  else
1915  maxtailgroup = winstate->currentgroup + offset;
1916 
1918  winstate->frametail_ptr);
1919  if (winstate->frametailpos == 0 &&
1920  TupIsNull(winstate->frametail_slot))
1921  {
1922  /* fetch first row into frametail_slot, if we didn't already */
1923  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1924  winstate->frametail_slot))
1925  elog(ERROR, "unexpected end of tuplestore");
1926  }
1927 
1928  while (!TupIsNull(winstate->frametail_slot))
1929  {
1930  if (winstate->frametailgroup > maxtailgroup)
1931  break; /* this row is the correct frame tail */
1932  ExecCopySlot(winstate->temp_slot_2, winstate->frametail_slot);
1933  /* Note we advance frametailpos even if the fetch fails */
1934  winstate->frametailpos++;
1935  spool_tuples(winstate, winstate->frametailpos);
1936  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1937  winstate->frametail_slot))
1938  break; /* end of partition */
1939  if (!are_peers(winstate, winstate->temp_slot_2,
1940  winstate->frametail_slot))
1941  winstate->frametailgroup++;
1942  }
1943  ExecClearTuple(winstate->temp_slot_2);
1944  winstate->frametail_valid = true;
1945  }
1946  else
1947  Assert(false);
1948  }
1949  else
1950  Assert(false);
1951 
1952  MemoryContextSwitchTo(oldcontext);
1953 }
int ordNumCols
Definition: plannodes.h:830
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:476
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
ScanState ss
Definition: execnodes.h:2045
Datum FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5)
Definition: fmgr.c:1224
ExprContext * ps_ExprContext
Definition: execnodes.h:984
AttrNumber * ordColIdx
Definition: plannodes.h:831
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int64 currentgroup
Definition: execnodes.h:2084
bool frametail_valid
Definition: execnodes.h:2103
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
int64 frametailgroup
Definition: execnodes.h:2086
static void spool_tuples(WindowAggState *winstate, int64 pos)
PlanState ps
Definition: execnodes.h:1280
bool inRangeNullsFirst
Definition: execnodes.h:2081
#define ERROR
Definition: elog.h:43
FmgrInfo endInRangeFunc
Definition: execnodes.h:2078
#define DatumGetInt64(X)
Definition: postgres.h:607
TupleTableSlot * temp_slot_2
Definition: execnodes.h:2116
Datum endOffsetValue
Definition: execnodes.h:2074
#define FRAMEOPTION_END_CURRENT_ROW
Definition: parsenodes.h:514
#define DatumGetBool(X)
Definition: postgres.h:393
#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING
Definition: parsenodes.h:512
#define TupIsNull(slot)
Definition: tuptable.h:293
Tuplestorestate * buffer
Definition: execnodes.h:2056
int64 spooled_rows
Definition: execnodes.h:2061
uintptr_t Datum
Definition: postgres.h:367
#define BoolGetDatum(X)
Definition: postgres.h:402
Plan * plan
Definition: execnodes.h:945
TupleTableSlot * frametail_slot
Definition: execnodes.h:2111
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:382
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
int64 frametailpos
Definition: execnodes.h:2064
#define FRAMEOPTION_RANGE
Definition: parsenodes.h:505
#define Assert(condition)
Definition: c.h:732
#define FRAMEOPTION_END_OFFSET
Definition: parsenodes.h:525
#define FRAMEOPTION_ROWS
Definition: parsenodes.h:506
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:231
int64 currentpos
Definition: execnodes.h:2062
#define FRAMEOPTION_END_OFFSET_PRECEDING
Definition: parsenodes.h:516
static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
#define elog(elevel,...)
Definition: elog.h:226
void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
Definition: tuplestore.c:473
#define FRAMEOPTION_GROUPS
Definition: parsenodes.h:507

◆ update_grouptailpos()

static void update_grouptailpos ( WindowAggState winstate)
static

Definition at line 1962 of file nodeWindowAgg.c.

References are_peers(), Assert, WindowAggState::buffer, WindowAggState::currentpos, ExprContext::ecxt_per_query_memory, ExecClearTuple(), WindowAggState::grouptail_ptr, WindowAggState::grouptail_valid, WindowAggState::grouptailpos, MemoryContextSwitchTo(), WindowAgg::ordNumCols, PlanState::plan, ScanState::ps, PlanState::ps_ExprContext, spool_tuples(), WindowAggState::spooled_rows, WindowAggState::ss, ScanState::ss_ScanTupleSlot, WindowAggState::temp_slot_2, tuplestore_gettupleslot(), and tuplestore_select_read_pointer().

Referenced by ExecWindowAgg(), row_is_in_frame(), and WinGetFuncArgInFrame().

1963 {
1964  WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
1965  MemoryContext oldcontext;
1966 
1967  if (winstate->grouptail_valid)
1968  return; /* already known for current row */
1969 
1970  /* We may be called in a short-lived context */
1972 
1973  /* If no ORDER BY, all rows are peers with each other */
1974  if (node->ordNumCols == 0)
1975  {
1976  spool_tuples(winstate, -1);
1977  winstate->grouptailpos = winstate->spooled_rows;
1978  winstate->grouptail_valid = true;
1979  MemoryContextSwitchTo(oldcontext);
1980  return;
1981  }
1982 
1983  /*
1984  * Because grouptail_valid is reset only when current row advances into a
1985  * new peer group, we always reach here knowing that grouptailpos needs to
1986  * be advanced by at least one row. Hence, unlike the otherwise similar
1987  * case for frame tail tracking, we do not need persistent storage of the
1988  * group tail row.
1989  */
1990  Assert(winstate->grouptailpos <= winstate->currentpos);
1992  winstate->grouptail_ptr);
1993  for (;;)
1994  {
1995  /* Note we advance grouptailpos even if the fetch fails */
1996  winstate->grouptailpos++;
1997  spool_tuples(winstate, winstate->grouptailpos);
1998  if (!tuplestore_gettupleslot(winstate->buffer, true, true,
1999  winstate->temp_slot_2))
2000  break; /* end of partition */
2001  if (winstate->grouptailpos > winstate->currentpos &&
2002  !are_peers(winstate, winstate->temp_slot_2,
2003  winstate->ss.ss_ScanTupleSlot))
2004  break; /* this row is the group tail */
2005  }
2006  ExecClearTuple(winstate->temp_slot_2);
2007  winstate->grouptail_valid = true;
2008 
2009  MemoryContextSwitchTo(oldcontext);
2010 }
int ordNumCols
Definition: plannodes.h:830
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
ScanState ss
Definition: execnodes.h:2045
ExprContext * ps_ExprContext
Definition: execnodes.h:984
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
int64 grouptailpos
Definition: execnodes.h:2088
static void spool_tuples(WindowAggState *winstate, int64 pos)
PlanState ps
Definition: execnodes.h:1280
TupleTableSlot * temp_slot_2
Definition: execnodes.h:2116
Tuplestorestate * buffer
Definition: execnodes.h:2056
int64 spooled_rows
Definition: execnodes.h:2061
Plan * plan
Definition: execnodes.h:945
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
#define Assert(condition)
Definition: c.h:732
bool grouptail_valid
Definition: execnodes.h:2105
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:231
int64 currentpos
Definition: execnodes.h:2062
static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
Definition: tuplestore.c:473

◆ window_gettupleslot()

static bool window_gettupleslot ( WindowObject  winobj,
int64  pos,
TupleTableSlot slot 
)
static

Definition at line 2927 of file nodeWindowAgg.c.

References Assert, WindowAggState::buffer, CHECK_FOR_INTERRUPTS, ExprContext::ecxt_per_query_memory, elog, ERROR, WindowObjectData::markpos, 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(), WinGetFuncArgInFrame(), WinGetFuncArgInPartition(), and WinRowsArePeers().

2928 {
2929  WindowAggState *winstate = winobj->winstate;
2930  MemoryContext oldcontext;
2931 
2932  /* often called repeatedly in a row */
2934 
2935  /* Don't allow passing -1 to spool_tuples here */
2936  if (pos < 0)
2937  return false;
2938 
2939  /* If necessary, fetch the tuple into the spool */
2940  spool_tuples(winstate, pos);
2941 
2942  if (pos >= winstate->spooled_rows)
2943  return false;
2944 
2945  if (pos < winobj->markpos)
2946  elog(ERROR, "cannot fetch row before WindowObject's mark position");
2947 
2949 
2950  tuplestore_select_read_pointer(winstate->buffer, winobj->readptr);
2951 
2952  /*
2953  * Advance or rewind until we are within one tuple of the one we want.
2954  */
2955  if (winobj->seekpos < pos - 1)
2956  {
2957  if (!tuplestore_skiptuples(winstate->buffer,
2958  pos - 1 - winobj->seekpos,
2959  true))
2960  elog(ERROR, "unexpected end of tuplestore");
2961  winobj->seekpos = pos - 1;
2962  }
2963  else if (winobj->seekpos > pos + 1)
2964  {
2965  if (!tuplestore_skiptuples(winstate->buffer,
2966  winobj->seekpos - (pos + 1),
2967  false))
2968  elog(ERROR, "unexpected end of tuplestore");
2969  winobj->seekpos = pos + 1;
2970  }
2971  else if (winobj->seekpos == pos)
2972  {
2973  /*
2974  * There's no API to refetch the tuple at the current position. We
2975  * have to move one tuple forward, and then one backward. (We don't
2976  * do it the other way because we might try to fetch the row before
2977  * our mark, which isn't allowed.) XXX this case could stand to be
2978  * optimized.
2979  */
2980  tuplestore_advance(winstate->buffer, true);
2981  winobj->seekpos++;
2982  }
2983 
2984  /*
2985  * Now we should be on the tuple immediately before or after the one we
2986  * want, so just fetch forwards or backwards as appropriate.
2987  */
2988  if (winobj->seekpos > pos)
2989  {
2990  if (!tuplestore_gettupleslot(winstate->buffer, false, true, slot))
2991  elog(ERROR, "unexpected end of tuplestore");
2992  winobj->seekpos--;
2993  }
2994  else
2995  {
2996  if (!tuplestore_gettupleslot(winstate->buffer, true, true, slot))
2997  elog(ERROR, "unexpected end of tuplestore");
2998  winobj->seekpos++;
2999  }
3000 
3001  Assert(winobj->seekpos == pos);
3002 
3003  MemoryContextSwitchTo(oldcontext);
3004 
3005  return true;
3006 }
bool tuplestore_advance(Tuplestorestate *state, bool forward)
Definition: tuplestore.c:1110
ScanState ss
Definition: execnodes.h:2045
ExprContext * ps_ExprContext
Definition: execnodes.h:984
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void spool_tuples(WindowAggState *winstate, int64 pos)
PlanState ps
Definition: execnodes.h:1280
#define ERROR
Definition: elog.h:43
Tuplestorestate * buffer
Definition: execnodes.h:2056
int64 spooled_rows
Definition: execnodes.h:2061
WindowAggState * winstate
Definition: nodeWindowAgg.c:64
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
#define Assert(condition)
Definition: c.h:732
bool tuplestore_skiptuples(Tuplestorestate *state, int64 ntuples, bool forward)
Definition: tuplestore.c:1135
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:231
#define elog(elevel,...)
Definition: elog.h:226
void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
Definition: tuplestore.c:473
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99

◆ WinGetCurrentPosition()

int64 WinGetCurrentPosition ( WindowObject  winobj)

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

3043 {
3044  Assert(WindowObjectIsValid(winobj));
3045  return winobj->winstate->currentpos;
3046 }
WindowAggState * winstate
Definition: nodeWindowAgg.c:64
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:732
int64 currentpos
Definition: execnodes.h:2062

◆ WinGetFuncArgCurrent()

Datum WinGetFuncArgCurrent ( WindowObject  winobj,
int  argno,
bool isnull 
)

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

3451 {
3452  WindowAggState *winstate;
3453  ExprContext *econtext;
3454 
3455  Assert(WindowObjectIsValid(winobj));
3456  winstate = winobj->winstate;
3457 
3458  econtext = winstate->ss.ps.ps_ExprContext;
3459 
3460  econtext->ecxt_outertuple = winstate->ss.ss_ScanTupleSlot;
3461  return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
3462  econtext, isnull);
3463 }
ScanState ss
Definition: execnodes.h:2045
ExprContext * ps_ExprContext
Definition: execnodes.h:984
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
PlanState ps
Definition: execnodes.h:1280
static void * list_nth(const List *list, int n)
Definition: pg_list.h:277
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:285
WindowAggState * winstate
Definition: nodeWindowAgg.c:64
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:228
#define Assert(condition)
Definition: c.h:732

◆ WinGetFuncArgInFrame()

Datum WinGetFuncArgInFrame ( WindowObject  winobj,
int  argno,
int  relpos,
int  seektype,
bool  set_mark,
bool isnull,
bool isout 
)

Definition at line 3255 of file nodeWindowAgg.c.

References WindowObjectData::argstates, Assert, WindowAggState::currentpos, ExprContext::ecxt_outertuple, elog, ERROR, ExecEvalExpr(), WindowAggState::frameheadpos, FRAMEOPTION_EXCLUDE_CURRENT_ROW, FRAMEOPTION_EXCLUDE_GROUP, FRAMEOPTION_EXCLUDE_TIES, FRAMEOPTION_EXCLUSION, WindowAggState::frameOptions, WindowAggState::frametailpos, WindowAggState::groupheadpos, WindowAggState::grouptailpos, list_nth(), Max, Min, ScanState::ps, PlanState::ps_ExprContext, row_is_in_frame(), WindowAggState::ss, WindowAggState::temp_slot_1, update_frameheadpos(), update_frametailpos(), update_grouptailpos(), 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().

3258 {
3259  WindowAggState *winstate;
3260  ExprContext *econtext;
3261  TupleTableSlot *slot;
3262  int64 abs_pos;
3263  int64 mark_pos;
3264 
3265  Assert(WindowObjectIsValid(winobj));
3266  winstate = winobj->winstate;
3267  econtext = winstate->ss.ps.ps_ExprContext;
3268  slot = winstate->temp_slot_1;
3269 
3270  switch (seektype)
3271  {
3272  case WINDOW_SEEK_CURRENT:
3273  elog(ERROR, "WINDOW_SEEK_CURRENT is not supported for WinGetFuncArgInFrame");
3274  abs_pos = mark_pos = 0; /* keep compiler quiet */
3275  break;
3276  case WINDOW_SEEK_HEAD:
3277  /* rejecting relpos < 0 is easy and simplifies code below */
3278  if (relpos < 0)
3279  goto out_of_frame;
3280  update_frameheadpos(winstate);
3281  abs_pos = winstate->frameheadpos + relpos;
3282  mark_pos = abs_pos;
3283 
3284  /*
3285  * Account for exclusion option if one is active, but advance only
3286  * abs_pos not mark_pos. This prevents changes of the current
3287  * row's peer group from resulting in trying to fetch a row before
3288  * some previous mark position.
3289  *
3290  * Note that in some corner cases such as current row being
3291  * outside frame, these calculations are theoretically too simple,
3292  * but it doesn't matter because we'll end up deciding the row is
3293  * out of frame. We do not attempt to avoid fetching rows past
3294  * end of frame; that would happen in some cases anyway.
3295  */
3296  switch (winstate->frameOptions & FRAMEOPTION_EXCLUSION)
3297  {
3298  case 0:
3299  /* no adjustment needed */
3300  break;
3302  if (abs_pos >= winstate->currentpos &&
3303  winstate->currentpos >= winstate->frameheadpos)
3304  abs_pos++;
3305  break;
3307  update_grouptailpos(winstate);
3308  if (abs_pos >= winstate->groupheadpos &&
3309  winstate->grouptailpos > winstate->frameheadpos)
3310  {
3311  int64 overlapstart = Max(winstate->groupheadpos,
3312  winstate->frameheadpos);
3313 
3314  abs_pos += winstate->grouptailpos - overlapstart;
3315  }
3316  break;
3318  update_grouptailpos(winstate);
3319  if (abs_pos >= winstate->groupheadpos &&
3320  winstate->grouptailpos > winstate->frameheadpos)
3321  {
3322  int64 overlapstart = Max(winstate->groupheadpos,
3323  winstate->frameheadpos);
3324 
3325  if (abs_pos == overlapstart)
3326  abs_pos = winstate->currentpos;
3327  else
3328  abs_pos += winstate->grouptailpos - overlapstart - 1;
3329  }
3330  break;
3331  default:
3332  elog(ERROR, "unrecognized frame option state: 0x%x",
3333  winstate->frameOptions);
3334  break;
3335  }
3336  break;
3337  case WINDOW_SEEK_TAIL:
3338  /* rejecting relpos > 0 is easy and simplifies code below */
3339  if (relpos > 0)
3340  goto out_of_frame;
3341  update_frametailpos(winstate);
3342  abs_pos = winstate->frametailpos - 1 + relpos;
3343 
3344  /*
3345  * Account for exclusion option if one is active. If there is no
3346  * exclusion, we can safely set the mark at the accessed row. But
3347  * if there is, we can only mark the frame start, because we can't
3348  * be sure how far back in the frame the exclusion might cause us
3349  * to fetch in future. Furthermore, we have to actually check
3350  * against frameheadpos here, since it's unsafe to try to fetch a
3351  * row before frame start if the mark might be there already.
3352  */
3353  switch (winstate->frameOptions & FRAMEOPTION_EXCLUSION)
3354  {
3355  case 0:
3356  /* no adjustment needed */
3357  mark_pos = abs_pos;
3358  break;
3360  if (abs_pos <= winstate->currentpos &&
3361  winstate->currentpos < winstate->frametailpos)
3362  abs_pos--;
3363  update_frameheadpos(winstate);
3364  if (abs_pos < winstate->frameheadpos)
3365  goto out_of_frame;
3366  mark_pos = winstate->frameheadpos;
3367  break;
3369  update_grouptailpos(winstate);
3370  if (abs_pos < winstate->grouptailpos &&
3371  winstate->groupheadpos < winstate->frametailpos)
3372  {
3373  int64 overlapend = Min(winstate->grouptailpos,
3374  winstate->frametailpos);
3375 
3376  abs_pos -= overlapend - winstate->groupheadpos;
3377  }
3378  update_frameheadpos(winstate);
3379  if (abs_pos < winstate->frameheadpos)
3380  goto out_of_frame;
3381  mark_pos = winstate->frameheadpos;
3382  break;
3384  update_grouptailpos(winstate);
3385  if (abs_pos < winstate->grouptailpos &&
3386  winstate->groupheadpos < winstate->frametailpos)
3387  {
3388  int64 overlapend = Min(winstate->grouptailpos,
3389  winstate->frametailpos);
3390 
3391  if (abs_pos == overlapend - 1)
3392  abs_pos = winstate->currentpos;
3393  else
3394  abs_pos -= overlapend - 1 - winstate->groupheadpos;
3395  }
3396  update_frameheadpos(winstate);
3397  if (abs_pos < winstate->frameheadpos)
3398  goto out_of_frame;
3399  mark_pos = winstate->frameheadpos;
3400  break;
3401  default:
3402  elog(ERROR, "unrecognized frame option state: 0x%x",
3403  winstate->frameOptions);
3404  mark_pos = 0; /* keep compiler quiet */
3405  break;
3406  }
3407  break;
3408  default:
3409  elog(ERROR, "unrecognized window seek type: %d", seektype);
3410  abs_pos = mark_pos = 0; /* keep compiler quiet */
3411  break;
3412  }
3413 
3414  if (!window_gettupleslot(winobj, abs_pos, slot))
3415  goto out_of_frame;
3416 
3417  /* The code above does not detect all out-of-frame cases, so check */
3418  if (row_is_in_frame(winstate, abs_pos, slot) <= 0)
3419  goto out_of_frame;
3420 
3421  if (isout)
3422  *isout = false;
3423  if (set_mark)
3424  WinSetMarkPosition(winobj, mark_pos);
3425  econtext->ecxt_outertuple = slot;
3426  return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
3427  econtext, isnull);
3428 
3429 out_of_frame:
3430  if (isout)
3431  *isout = true;
3432  *isnull = true;
3433  return (Datum) 0;
3434 }
#define FRAMEOPTION_EXCLUSION
Definition: parsenodes.h:527
static void update_grouptailpos(WindowAggState *winstate)
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:2045
int64 groupheadpos
Definition: execnodes.h:2087
ExprContext * ps_ExprContext
Definition: execnodes.h:984
#define Min(x, y)
Definition: c.h:904
static void update_frametailpos(WindowAggState *winstate)
int64 grouptailpos
Definition: execnodes.h:2088
static void update_frameheadpos(WindowAggState *winstate)
TupleTableSlot * temp_slot_1
Definition: execnodes.h:2115
#define WINDOW_SEEK_TAIL
Definition: windowapi.h:34
PlanState ps
Definition: execnodes.h:1280
int64 frameheadpos
Definition: execnodes.h:2063
#define FRAMEOPTION_EXCLUDE_GROUP
Definition: parsenodes.h:520
#define ERROR
Definition: elog.h:43
static void * list_nth(const List *list, int n)
Definition: pg_list.h:277
static int row_is_in_frame(WindowAggState *winstate, int64 pos, TupleTableSlot *slot)
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:285
#define WINDOW_SEEK_HEAD
Definition: windowapi.h:33
WindowAggState * winstate
Definition: nodeWindowAgg.c:64
uintptr_t Datum
Definition: postgres.h:367
#define FRAMEOPTION_EXCLUDE_CURRENT_ROW
Definition: parsenodes.h:519
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Max(x, y)
Definition: c.h:898
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:228
#define WINDOW_SEEK_CURRENT
Definition: windowapi.h:32
int64 frametailpos
Definition: execnodes.h:2064
#define Assert(condition)
Definition: c.h:732
#define FRAMEOPTION_EXCLUDE_TIES
Definition: parsenodes.h:521
int64 currentpos
Definition: execnodes.h:2062
#define elog(elevel,...)
Definition: elog.h:226
void WinSetMarkPosition(WindowObject winobj, int64 markpos)

◆ WinGetFuncArgInPartition()

Datum WinGetFuncArgInPartition ( WindowObject  winobj,
int  argno,
int  relpos,
int  seektype,
bool  set_mark,
bool isnull,
bool isout 
)

Definition at line 3167 of file nodeWindowAgg.c.

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

Referenced by leadlag_common().

3170 {
3171  WindowAggState *winstate;
3172  ExprContext *econtext;
3173  TupleTableSlot *slot;
3174  bool gottuple;
3175  int64 abs_pos;
3176 
3177  Assert(WindowObjectIsValid(winobj));
3178  winstate = winobj->winstate;
3179  econtext = winstate->ss.ps.ps_ExprContext;
3180  slot = winstate->temp_slot_1;
3181 
3182  switch (seektype)
3183  {
3184  case WINDOW_SEEK_CURRENT:
3185  abs_pos = winstate->currentpos + relpos;
3186  break;
3187  case WINDOW_SEEK_HEAD:
3188  abs_pos = relpos;
3189  break;
3190  case WINDOW_SEEK_TAIL:
3191  spool_tuples(winstate, -1);
3192  abs_pos = winstate->spooled_rows - 1 + relpos;
3193  break;
3194  default:
3195  elog(ERROR, "unrecognized window seek type: %d", seektype);
3196  abs_pos = 0; /* keep compiler quiet */
3197  break;
3198  }
3199 
3200  gottuple = window_gettupleslot(winobj, abs_pos, slot);
3201 
3202  if (!gottuple)
3203  {
3204  if (isout)
3205  *isout = true;
3206  *isnull = true;
3207  return (Datum) 0;
3208  }
3209  else
3210  {
3211  if (isout)
3212  *isout = false;
3213  if (set_mark)
3214  WinSetMarkPosition(winobj, abs_pos);
3215  econtext->ecxt_outertuple = slot;
3216  return ExecEvalExpr((ExprState *) list_nth(winobj->argstates, argno),
3217  econtext, isnull);
3218  }
3219 }
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
ScanState ss
Definition: execnodes.h:2045
ExprContext * ps_ExprContext
Definition: execnodes.h:984
TupleTableSlot * temp_slot_1
Definition: execnodes.h:2115
static void spool_tuples(WindowAggState *winstate, int64 pos)
#define WINDOW_SEEK_TAIL
Definition: windowapi.h:34
PlanState ps
Definition: execnodes.h:1280
#define ERROR
Definition: elog.h:43
static void * list_nth(const List *list, int n)
Definition: pg_list.h:277
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:285
int64 spooled_rows
Definition: execnodes.h:2061
#define WINDOW_SEEK_HEAD
Definition: windowapi.h:33
WindowAggState * winstate
Definition: nodeWindowAgg.c:64
uintptr_t Datum
Definition: postgres.h:367
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:228
#define WINDOW_SEEK_CURRENT
Definition: windowapi.h:32
#define Assert(condition)
Definition: c.h:732
int64 currentpos
Definition: execnodes.h:2062
#define elog(elevel,...)
Definition: elog.h:226
void WinSetMarkPosition(WindowObject winobj, int64 markpos)

◆ WinGetPartitionLocalMemory()

void* WinGetPartitionLocalMemory ( WindowObject  winobj,
Size  sz 
)

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

3028 {
3029  Assert(WindowObjectIsValid(winobj));
3030  if (winobj->localmem == NULL)
3031  winobj->localmem =
3033  return winobj->localmem;
3034 }
WindowAggState * winstate
Definition: nodeWindowAgg.c:64
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:814
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:732
MemoryContext partcontext
Definition: execnodes.h:2090

◆ WinGetPartitionRowCount()

int64 WinGetPartitionRowCount ( WindowObject  winobj)

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

3058 {
3059  Assert(WindowObjectIsValid(winobj));
3060  spool_tuples(winobj->winstate, -1);
3061  return winobj->winstate->spooled_rows;
3062 }
static void spool_tuples(WindowAggState *winstate, int64 pos)
int64 spooled_rows
Definition: execnodes.h:2061
WindowAggState * winstate
Definition: nodeWindowAgg.c:64
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:732

◆ WinRowsArePeers()

bool WinRowsArePeers ( WindowObject  winobj,
int64  pos1,
int64  pos2 
)

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

3111 {
3112  WindowAggState *winstate;
3113  WindowAgg *node;
3114  TupleTableSlot *slot1;
3115  TupleTableSlot *slot2;
3116  bool res;
3117 
3118  Assert(WindowObjectIsValid(winobj));
3119  winstate = winobj->winstate;
3120  node = (WindowAgg *) winstate->ss.ps.plan;
3121 
3122  /* If no ORDER BY, all rows are peers; don't bother to fetch them */
3123  if (node->ordNumCols == 0)
3124  return true;
3125 
3126  /*
3127  * Note: OK to use temp_slot_2 here because we aren't calling any
3128  * frame-related functions (those tend to clobber temp_slot_2).
3129  */
3130  slot1 = winstate->temp_slot_1;
3131  slot2 = winstate->temp_slot_2;
3132 
3133  if (!window_gettupleslot(winobj, pos1, slot1))
3134  elog(ERROR, "specified position is out of window: " INT64_FORMAT,
3135  pos1);
3136  if (!window_gettupleslot(winobj, pos2, slot2))
3137  elog(ERROR, "specified position is out of window: " INT64_FORMAT,
3138  pos2);
3139 
3140  res = are_peers(winstate, slot1, slot2);
3141 
3142  ExecClearTuple(slot1);
3143  ExecClearTuple(slot2);
3144 
3145  return res;
3146 }
int ordNumCols
Definition: plannodes.h:830
static bool window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
ScanState ss
Definition: execnodes.h:2045
TupleTableSlot * temp_slot_1
Definition: execnodes.h:2115
PlanState ps
Definition: execnodes.h:1280
#define ERROR
Definition: elog.h:43
TupleTableSlot * temp_slot_2
Definition: execnodes.h:2116
WindowAggState * winstate
Definition: nodeWindowAgg.c:64
Plan * plan
Definition: execnodes.h:945
#define WindowObjectIsValid(winobj)
Definition: windowapi.h:41
#define Assert(condition)
Definition: c.h:732
#define INT64_FORMAT
Definition: c.h:400
static bool are_peers(WindowAggState *winstate, TupleTableSlot *slot1, TupleTableSlot *slot2)
#define elog(elevel,...)
Definition: elog.h:226

◆ WinSetMarkPosition()

void WinSetMarkPosition ( WindowObject  winobj,
int64  markpos 
)

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

3076 {
3077  WindowAggState *winstate;
3078 
3079  Assert(WindowObjectIsValid(winobj));
3080  winstate = winobj->winstate;
3081 
3082  if (markpos < winobj->markpos)
3083  elog(ERROR, "cannot move WindowObject's mark position backward");
3084  tuplestore_select_read_pointer(winstate->buffer, winobj->markptr);
3085  if (