}
/*
- * begin_partition
- * Start buffering rows of the next partition.
+ * prepare_tuplestore
+ * Prepare the tuplestore and all of the required read pointers for the
+ * WindowAggState's frameOptions.
+ *
+ * Note: We use pg_noinline to avoid bloating the calling function with code
+ * which is only called once.
*/
-static void
-begin_partition(WindowAggState *winstate)
+static pg_noinline void
+prepare_tuplestore(WindowAggState *winstate)
{
WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan;
- PlanState *outerPlan = outerPlanState(winstate);
int frameOptions = winstate->frameOptions;
int numfuncs = winstate->numfuncs;
- int i;
-
- winstate->partition_spooled = false;
- winstate->framehead_valid = false;
- winstate->frametail_valid = false;
- winstate->grouptail_valid = false;
- winstate->spooled_rows = 0;
- winstate->currentpos = 0;
- winstate->frameheadpos = 0;
- winstate->frametailpos = 0;
- winstate->currentgroup = 0;
- winstate->frameheadgroup = 0;
- winstate->frametailgroup = 0;
- winstate->groupheadpos = 0;
- winstate->grouptailpos = -1; /* see update_grouptailpos */
- ExecClearTuple(winstate->agg_row_slot);
- if (winstate->framehead_slot)
- ExecClearTuple(winstate->framehead_slot);
- if (winstate->frametail_slot)
- ExecClearTuple(winstate->frametail_slot);
-
- /*
- * If this is the very first partition, we need to fetch the first input
- * row to store in first_part_slot.
- */
- if (TupIsNull(winstate->first_part_slot))
- {
- TupleTableSlot *outerslot = ExecProcNode(outerPlan);
- if (!TupIsNull(outerslot))
- ExecCopySlot(winstate->first_part_slot, outerslot);
- else
- {
- /* outer plan is empty, so we have nothing to do */
- winstate->partition_spooled = true;
- winstate->more_partitions = false;
- return;
- }
- }
+ /* we shouldn't be called if this was done already */
+ Assert(winstate->buffer == NULL);
- /* Create new tuplestore for this partition */
+ /* Create new tuplestore */
winstate->buffer = tuplestore_begin_heap(false, false, work_mem);
/*
agg_winobj->readptr = tuplestore_alloc_read_pointer(winstate->buffer,
readptr_flags);
- agg_winobj->markpos = -1;
- agg_winobj->seekpos = -1;
-
- /* Also reset the row counters for aggregates */
- winstate->aggregatedbase = 0;
- winstate->aggregatedupto = 0;
}
/* create mark and read pointers for each real window function */
- for (i = 0; i < numfuncs; i++)
+ for (int i = 0; i < numfuncs; i++)
{
WindowStatePerFunc perfuncstate = &(winstate->perfunc[i]);
0);
winobj->readptr = tuplestore_alloc_read_pointer(winstate->buffer,
EXEC_FLAG_BACKWARD);
- winobj->markpos = -1;
- winobj->seekpos = -1;
}
}
winstate->grouptail_ptr =
tuplestore_alloc_read_pointer(winstate->buffer, 0);
}
+}
+
+/*
+ * begin_partition
+ * Start buffering rows of the next partition.
+ */
+static void
+begin_partition(WindowAggState *winstate)
+{
+ PlanState *outerPlan = outerPlanState(winstate);
+ int numfuncs = winstate->numfuncs;
+
+ winstate->partition_spooled = false;
+ winstate->framehead_valid = false;
+ winstate->frametail_valid = false;
+ winstate->grouptail_valid = false;
+ winstate->spooled_rows = 0;
+ winstate->currentpos = 0;
+ winstate->frameheadpos = 0;
+ winstate->frametailpos = 0;
+ winstate->currentgroup = 0;
+ winstate->frameheadgroup = 0;
+ winstate->frametailgroup = 0;
+ winstate->groupheadpos = 0;
+ winstate->grouptailpos = -1; /* see update_grouptailpos */
+ ExecClearTuple(winstate->agg_row_slot);
+ if (winstate->framehead_slot)
+ ExecClearTuple(winstate->framehead_slot);
+ if (winstate->frametail_slot)
+ ExecClearTuple(winstate->frametail_slot);
+
+ /*
+ * If this is the very first partition, we need to fetch the first input
+ * row to store in first_part_slot.
+ */
+ if (TupIsNull(winstate->first_part_slot))
+ {
+ TupleTableSlot *outerslot = ExecProcNode(outerPlan);
+
+ if (!TupIsNull(outerslot))
+ ExecCopySlot(winstate->first_part_slot, outerslot);
+ else
+ {
+ /* outer plan is empty, so we have nothing to do */
+ winstate->partition_spooled = true;
+ winstate->more_partitions = false;
+ return;
+ }
+ }
+
+ /* Create new tuplestore if not done already. */
+ if (unlikely(winstate->buffer == NULL))
+ prepare_tuplestore(winstate);
+
+ winstate->next_partition = false;
+
+ if (winstate->numaggs > 0)
+ {
+ WindowObject agg_winobj = winstate->agg_winobj;
+
+ /* reset mark and see positions for aggregate functions */
+ agg_winobj->markpos = -1;
+ agg_winobj->seekpos = -1;
+
+ /* Also reset the row counters for aggregates */
+ winstate->aggregatedbase = 0;
+ winstate->aggregatedupto = 0;
+ }
+
+ /* reset mark and seek positions for each real window function */
+ for (int i = 0; i < numfuncs; i++)
+ {
+ WindowStatePerFunc perfuncstate = &(winstate->perfunc[i]);
+
+ if (!perfuncstate->plain_agg)
+ {
+ WindowObject winobj = perfuncstate->winobj;
+
+ winobj->markpos = -1;
+ winobj->seekpos = -1;
+ }
+ }
/*
* Store the first tuple into the tuplestore (it's always available now;
}
if (winstate->buffer)
- tuplestore_end(winstate->buffer);
- winstate->buffer = NULL;
+ tuplestore_clear(winstate->buffer);
winstate->partition_spooled = false;
+ winstate->next_partition = true;
}
/*
/* We need to loop as the runCondition or qual may filter out tuples */
for (;;)
{
- if (winstate->buffer == NULL)
+ if (winstate->next_partition)
{
/* Initialize for first partition and set current row = 0 */
begin_partition(winstate);
winstate->all_first = true;
winstate->partition_spooled = false;
winstate->more_partitions = false;
+ winstate->next_partition = true;
return winstate;
}
PlanState *outerPlan;
int i;
+ if (node->buffer != NULL)
+ {
+ tuplestore_end(node->buffer);
+
+ /* nullify so that release_partition skips the tuplestore_clear() */
+ node->buffer = NULL;
+ }
+
release_partition(node);
for (i = 0; i < node->numaggs; i++)
bool inRangeAsc; /* use ASC sort order for in_range tests? */
bool inRangeNullsFirst; /* nulls sort first for in_range tests? */
+ /* fields relating to runconditions */
+ bool use_pass_through; /* When false, stop execution when
+ * runcondition is no longer true. Else
+ * just stop evaluating window funcs. */
+ bool top_window; /* true if this is the top-most WindowAgg or
+ * the only WindowAgg in this query level */
+ ExprState *runcondition; /* Condition which must remain true otherwise
+ * execution of the WindowAgg will finish or
+ * go into pass-through mode. NULL when there
+ * is no such condition. */
+
/* these fields are used in GROUPS mode: */
int64 currentgroup; /* peer group # of current row in partition */
int64 frameheadgroup; /* peer group # of frame head row */
MemoryContext curaggcontext; /* current aggregate's working data */
ExprContext *tmpcontext; /* short-term evaluation context */
- ExprState *runcondition; /* Condition which must remain true otherwise
- * execution of the WindowAgg will finish or
- * go into pass-through mode. NULL when there
- * is no such condition. */
-
- bool use_pass_through; /* When false, stop execution when
- * runcondition is no longer true. Else
- * just stop evaluating window funcs. */
- bool top_window; /* true if this is the top-most WindowAgg or
- * the only WindowAgg in this query level */
bool all_first; /* true if the scan is starting */
bool partition_spooled; /* true if all tuples in current partition
* have been spooled into tuplestore */
+ bool next_partition; /* true if begin_partition needs to be called */
bool more_partitions; /* true if there's more partitions after
* this one */
bool framehead_valid; /* true if frameheadpos is known up to