PostgreSQL Source Code git master
Loading...
Searching...
No Matches
nodeAgg.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/parallel.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "common/hashfn.h"
#include "executor/execExpr.h"
#include "executor/executor.h"
#include "executor/instrument.h"
#include "executor/nodeAgg.h"
#include "lib/hyperloglog.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
#include "port/pg_bitutils.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/expandeddatum.h"
#include "utils/injection_point.h"
#include "utils/logtape.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/memutils_memorychunk.h"
#include "utils/syscache.h"
#include "utils/tuplesort.h"
Include dependency graph for nodeAgg.c:

Go to the source code of this file.

Data Structures

struct  HashAggSpill
 
struct  HashAggBatch
 
struct  FindColsContext
 

Macros

#define HASHAGG_PARTITION_FACTOR   1.50
 
#define HASHAGG_MIN_PARTITIONS   4
 
#define HASHAGG_MAX_PARTITIONS   1024
 
#define HASHAGG_READ_BUFFER_SIZE   BLCKSZ
 
#define HASHAGG_WRITE_BUFFER_SIZE   BLCKSZ
 
#define HASHAGG_HLL_BIT_WIDTH   5
 
#define CHUNKHDRSZ   sizeof(MemoryChunk)
 

Typedefs

typedef struct HashAggSpill HashAggSpill
 
typedef struct HashAggBatch HashAggBatch
 
typedef struct FindColsContext FindColsContext
 

Functions

static void select_current_set (AggState *aggstate, int setno, bool is_hash)
 
static void initialize_phase (AggState *aggstate, int newphase)
 
static TupleTableSlotfetch_input_tuple (AggState *aggstate)
 
static void initialize_aggregates (AggState *aggstate, AggStatePerGroup *pergroups, int numReset)
 
static void advance_transition_function (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void advance_aggregates (AggState *aggstate)
 
static void process_ordered_aggregate_single (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void process_ordered_aggregate_multi (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void finalize_aggregate (AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
 
static void finalize_partialaggregate (AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
 
static void prepare_hash_slot (AggStatePerHash perhash, TupleTableSlot *inputslot, TupleTableSlot *hashslot)
 
static void prepare_projection_slot (AggState *aggstate, TupleTableSlot *slot, int currentSet)
 
static void finalize_aggregates (AggState *aggstate, AggStatePerAgg peraggs, AggStatePerGroup pergroup)
 
static TupleTableSlotproject_aggregates (AggState *aggstate)
 
static void find_cols (AggState *aggstate, Bitmapset **aggregated, Bitmapset **unaggregated)
 
static bool find_cols_walker (Node *node, FindColsContext *context)
 
static void build_hash_tables (AggState *aggstate)
 
static void build_hash_table (AggState *aggstate, int setno, double nbuckets)
 
static void hashagg_recompile_expressions (AggState *aggstate, bool minslot, bool nullcheck)
 
static void hash_create_memory (AggState *aggstate)
 
static double hash_choose_num_buckets (double hashentrysize, double ngroups, Size memory)
 
static int hash_choose_num_partitions (double input_groups, double hashentrysize, int used_bits, int *log2_npartitions)
 
static void initialize_hash_entry (AggState *aggstate, TupleHashTable hashtable, TupleHashEntry entry)
 
static void lookup_hash_entries (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_direct (AggState *aggstate)
 
static void agg_fill_hash_table (AggState *aggstate)
 
static bool agg_refill_hash_table (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_hash_table (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_hash_table_in_memory (AggState *aggstate)
 
static void hash_agg_check_limits (AggState *aggstate)
 
static void hash_agg_enter_spill_mode (AggState *aggstate)
 
static void hash_agg_update_metrics (AggState *aggstate, bool from_tape, int npartitions)
 
static void hashagg_finish_initial_spills (AggState *aggstate)
 
static void hashagg_reset_spill_state (AggState *aggstate)
 
static HashAggBatchhashagg_batch_new (LogicalTape *input_tape, int setno, int64 input_tuples, double input_card, int used_bits)
 
static MinimalTuple hashagg_batch_read (HashAggBatch *batch, uint32 *hashp)
 
static void hashagg_spill_init (HashAggSpill *spill, LogicalTapeSet *tapeset, int used_bits, double input_groups, double hashentrysize)
 
static Size hashagg_spill_tuple (AggState *aggstate, HashAggSpill *spill, TupleTableSlot *inputslot, uint32 hash)
 
static void hashagg_spill_finish (AggState *aggstate, HashAggSpill *spill, int setno)
 
static Datum GetAggInitVal (Datum textInitVal, Oid transtype)
 
static void build_pertrans_for_aggref (AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid transfn_oid, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
 
static void initialize_aggregate (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void find_hash_columns (AggState *aggstate)
 
Size hash_agg_entry_size (int numTrans, Size tupleWidth, Size transitionSpace)
 
void hash_agg_set_limits (double hashentrysize, double input_groups, int used_bits, Size *mem_limit, uint64 *ngroups_limit, int *num_partitions)
 
static TupleTableSlotExecAgg (PlanState *pstate)
 
AggStateExecInitAgg (Agg *node, EState *estate, int eflags)
 
void ExecEndAgg (AggState *node)
 
void ExecReScanAgg (AggState *node)
 
int AggCheckCallContext (FunctionCallInfo fcinfo, MemoryContext *aggcontext)
 
AggrefAggGetAggref (FunctionCallInfo fcinfo)
 
MemoryContext AggGetTempMemoryContext (FunctionCallInfo fcinfo)
 
bool AggStateIsShared (FunctionCallInfo fcinfo)
 
void AggRegisterCallback (FunctionCallInfo fcinfo, ExprContextCallbackFunction func, Datum arg)
 
void ExecAggEstimate (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeDSM (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeWorker (AggState *node, ParallelWorkerContext *pwcxt)
 
void ExecAggRetrieveInstrumentation (AggState *node)
 

Macro Definition Documentation

◆ CHUNKHDRSZ

#define CHUNKHDRSZ   sizeof(MemoryChunk)

Definition at line 322 of file nodeAgg.c.

◆ HASHAGG_HLL_BIT_WIDTH

#define HASHAGG_HLL_BIT_WIDTH   5

Definition at line 317 of file nodeAgg.c.

◆ HASHAGG_MAX_PARTITIONS

#define HASHAGG_MAX_PARTITIONS   1024

Definition at line 300 of file nodeAgg.c.

◆ HASHAGG_MIN_PARTITIONS

#define HASHAGG_MIN_PARTITIONS   4

Definition at line 299 of file nodeAgg.c.

◆ HASHAGG_PARTITION_FACTOR

#define HASHAGG_PARTITION_FACTOR   1.50

Definition at line 298 of file nodeAgg.c.

◆ HASHAGG_READ_BUFFER_SIZE

#define HASHAGG_READ_BUFFER_SIZE   BLCKSZ

Definition at line 308 of file nodeAgg.c.

◆ HASHAGG_WRITE_BUFFER_SIZE

#define HASHAGG_WRITE_BUFFER_SIZE   BLCKSZ

Definition at line 309 of file nodeAgg.c.

Typedef Documentation

◆ FindColsContext

◆ HashAggBatch

◆ HashAggSpill

Function Documentation

◆ advance_aggregates()

static void advance_aggregates ( AggState aggstate)
static

Definition at line 819 of file nodeAgg.c.

820{
822 aggstate->tmpcontext);
823}
static void ExecEvalExprNoReturnSwitchContext(ExprState *state, ExprContext *econtext)
Definition executor.h:461
static int fb(int x)

References ExecEvalExprNoReturnSwitchContext(), and fb().

Referenced by agg_fill_hash_table(), agg_refill_hash_table(), and agg_retrieve_direct().

◆ advance_transition_function()

static void advance_transition_function ( AggState aggstate,
AggStatePerTrans  pertrans,
AggStatePerGroup  pergroupstate 
)
static

Definition at line 709 of file nodeAgg.c.

712{
713 FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
715 Datum newVal;
716
717 if (pertrans->transfn.fn_strict)
718 {
719 /*
720 * For a strict transfn, nothing happens when there's a NULL input; we
721 * just keep the prior transValue.
722 */
723 int numTransInputs = pertrans->numTransInputs;
724 int i;
725
726 for (i = 1; i <= numTransInputs; i++)
727 {
728 if (fcinfo->args[i].isnull)
729 return;
730 }
731 if (pergroupstate->noTransValue)
732 {
733 /*
734 * transValue has not been initialized. This is the first non-NULL
735 * input value. We use it as the initial value for transValue. (We
736 * already checked that the agg's input type is binary-compatible
737 * with its transtype, so straight copy here is OK.)
738 *
739 * We must copy the datum into aggcontext if it is pass-by-ref. We
740 * do not need to pfree the old transValue, since it's NULL.
741 */
742 oldContext = MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
743 pergroupstate->transValue = datumCopy(fcinfo->args[1].value,
744 pertrans->transtypeByVal,
745 pertrans->transtypeLen);
746 pergroupstate->transValueIsNull = false;
747 pergroupstate->noTransValue = false;
749 return;
750 }
751 if (pergroupstate->transValueIsNull)
752 {
753 /*
754 * Don't call a strict function with NULL inputs. Note it is
755 * possible to get here despite the above tests, if the transfn is
756 * strict *and* returned a NULL on a prior cycle. If that happens
757 * we will propagate the NULL all the way to the end.
758 */
759 return;
760 }
761 }
762
763 /* We run the transition functions in per-input-tuple memory context */
764 oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
765
766 /* set up aggstate->curpertrans for AggGetAggref() */
767 aggstate->curpertrans = pertrans;
768
769 /*
770 * OK to call the transition function
771 */
772 fcinfo->args[0].value = pergroupstate->transValue;
773 fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
774 fcinfo->isnull = false; /* just in case transfn doesn't set it */
775
776 newVal = FunctionCallInvoke(fcinfo);
777
778 aggstate->curpertrans = NULL;
779
780 /*
781 * If pass-by-ref datatype, must copy the new value into aggcontext and
782 * free the prior transValue. But if transfn returned a pointer to its
783 * first input, we don't need to do anything.
784 *
785 * It's safe to compare newVal with pergroup->transValue without regard
786 * for either being NULL, because ExecAggCopyTransValue takes care to set
787 * transValue to 0 when NULL. Otherwise we could end up accidentally not
788 * reparenting, when the transValue has the same numerical value as
789 * newValue, despite being NULL. This is a somewhat hot path, making it
790 * undesirable to instead solve this with another branch for the common
791 * case of the transition function returning its (modified) input
792 * argument.
793 */
794 if (!pertrans->transtypeByVal &&
795 DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
796 newVal = ExecAggCopyTransValue(aggstate, pertrans,
797 newVal, fcinfo->isnull,
798 pergroupstate->transValue,
799 pergroupstate->transValueIsNull);
800
801 pergroupstate->transValue = newVal;
802 pergroupstate->transValueIsNull = fcinfo->isnull;
803
805}
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132
Datum ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans, Datum newValue, bool newValueIsNull, Datum oldValue, bool oldValueIsNull)
#define FunctionCallInvoke(fcinfo)
Definition fmgr.h:172
int i
Definition isn.c:77
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
FunctionCallInfo transfn_fcinfo
Definition nodeAgg.h:170
bool fn_strict
Definition fmgr.h:61
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition fmgr.h:95
Datum value
Definition postgres.h:87

References FunctionCallInfoBaseData::args, datumCopy(), DatumGetPointer(), ExecAggCopyTransValue(), fb(), FmgrInfo::fn_strict, FunctionCallInvoke, i, FunctionCallInfoBaseData::isnull, NullableDatum::isnull, MemoryContextSwitchTo(), AggStatePerTransData::numTransInputs, AggStatePerTransData::transfn, AggStatePerTransData::transfn_fcinfo, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, and NullableDatum::value.

Referenced by process_ordered_aggregate_multi(), and process_ordered_aggregate_single().

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

Definition at line 2629 of file nodeAgg.c.

2630{
2632 ExprContext *tmpcontext = aggstate->tmpcontext;
2633
2634 /*
2635 * Process each outer-plan tuple, and then fetch the next one, until we
2636 * exhaust the outer plan.
2637 */
2638 for (;;)
2639 {
2641 if (TupIsNull(outerslot))
2642 break;
2643
2644 /* set up for lookup_hash_entries and advance_aggregates */
2645 tmpcontext->ecxt_outertuple = outerslot;
2646
2647 /* Find or build hashtable entries */
2649
2650 /* Advance the aggregates (or combine functions) */
2652
2653 /*
2654 * Reset per-input-tuple context after each tuple, but note that the
2655 * hash lookups do this too
2656 */
2657 ResetExprContext(aggstate->tmpcontext);
2658 }
2659
2660 /* finalize spills, if any */
2662
2663 aggstate->table_filled = true;
2664 /* Initialize to walk the first hash table */
2665 select_current_set(aggstate, 0, true);
2666 ResetTupleHashIterator(aggstate->perhash[0].hashtable,
2667 &aggstate->perhash[0].hashiter);
2668}
#define ResetTupleHashIterator(htable, iter)
Definition execnodes.h:910
#define ResetExprContext(econtext)
Definition executor.h:654
static void hashagg_finish_initial_spills(AggState *aggstate)
Definition nodeAgg.c:3167
static TupleTableSlot * fetch_input_tuple(AggState *aggstate)
Definition nodeAgg.c:550
static void lookup_hash_entries(AggState *aggstate)
Definition nodeAgg.c:2184
static void advance_aggregates(AggState *aggstate)
Definition nodeAgg.c:819
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition nodeAgg.c:458
TupleTableSlot * ecxt_outertuple
Definition execnodes.h:288
#define TupIsNull(slot)
Definition tuptable.h:325

References advance_aggregates(), ExprContext::ecxt_outertuple, fb(), fetch_input_tuple(), hashagg_finish_initial_spills(), lookup_hash_entries(), ResetExprContext, ResetTupleHashIterator, select_current_set(), and TupIsNull.

Referenced by ExecAgg().

◆ agg_refill_hash_table()

static bool agg_refill_hash_table ( AggState aggstate)
static

Definition at line 2683 of file nodeAgg.c.

2684{
2686 AggStatePerHash perhash;
2688 LogicalTapeSet *tapeset = aggstate->hash_tapeset;
2689 bool spill_initialized = false;
2690
2691 if (aggstate->hash_batches == NIL)
2692 return false;
2693
2694 /* hash_batches is a stack, with the top item at the end of the list */
2695 batch = llast(aggstate->hash_batches);
2696 aggstate->hash_batches = list_delete_last(aggstate->hash_batches);
2697
2698 hash_agg_set_limits(aggstate->hashentrysize, batch->input_card,
2699 batch->used_bits, &aggstate->hash_mem_limit,
2700 &aggstate->hash_ngroups_limit, NULL);
2701
2702 /*
2703 * Each batch only processes one grouping set; set the rest to NULL so
2704 * that advance_aggregates() knows to ignore them. We don't touch
2705 * pergroups for sorted grouping sets here, because they will be needed if
2706 * we rescan later. The expressions for sorted grouping sets will not be
2707 * evaluated after we recompile anyway.
2708 */
2709 MemSet(aggstate->hash_pergroup, 0,
2710 sizeof(AggStatePerGroup) * aggstate->num_hashes);
2711
2712 /* free memory and reset hash tables */
2713 ReScanExprContext(aggstate->hashcontext);
2714 for (int setno = 0; setno < aggstate->num_hashes; setno++)
2715 ResetTupleHashTable(aggstate->perhash[setno].hashtable);
2716
2717 aggstate->hash_ngroups_current = 0;
2718
2719 /*
2720 * In AGG_MIXED mode, hash aggregation happens in phase 1 and the output
2721 * happens in phase 0. So, we switch to phase 1 when processing a batch,
2722 * and back to phase 0 after the batch is done.
2723 */
2724 Assert(aggstate->current_phase == 0);
2725 if (aggstate->phase->aggstrategy == AGG_MIXED)
2726 {
2727 aggstate->current_phase = 1;
2728 aggstate->phase = &aggstate->phases[aggstate->current_phase];
2729 }
2730
2731 select_current_set(aggstate, batch->setno, true);
2732
2733 perhash = &aggstate->perhash[aggstate->current_set];
2734
2735 /*
2736 * Spilled tuples are always read back as MinimalTuples, which may be
2737 * different from the outer plan, so recompile the aggregate expressions.
2738 *
2739 * We still need the NULL check, because we are only processing one
2740 * grouping set at a time and the rest will be NULL.
2741 */
2743
2744 INJECTION_POINT("hash-aggregate-process-batch", NULL);
2745 for (;;)
2746 {
2747 TupleTableSlot *spillslot = aggstate->hash_spill_rslot;
2748 TupleTableSlot *hashslot = perhash->hashslot;
2749 TupleHashTable hashtable = perhash->hashtable;
2750 TupleHashEntry entry;
2751 MinimalTuple tuple;
2752 uint32 hash;
2753 bool isnew = false;
2754 bool *p_isnew = aggstate->hash_spill_mode ? NULL : &isnew;
2755
2757
2758 tuple = hashagg_batch_read(batch, &hash);
2759 if (tuple == NULL)
2760 break;
2761
2762 ExecStoreMinimalTuple(tuple, spillslot, true);
2763 aggstate->tmpcontext->ecxt_outertuple = spillslot;
2764
2765 prepare_hash_slot(perhash,
2766 aggstate->tmpcontext->ecxt_outertuple,
2767 hashslot);
2768 entry = LookupTupleHashEntryHash(hashtable, hashslot,
2769 p_isnew, hash);
2770
2771 if (entry != NULL)
2772 {
2773 if (isnew)
2774 initialize_hash_entry(aggstate, hashtable, entry);
2775 aggstate->hash_pergroup[batch->setno] = TupleHashEntryGetAdditional(hashtable, entry);
2777 }
2778 else
2779 {
2780 if (!spill_initialized)
2781 {
2782 /*
2783 * Avoid initializing the spill until we actually need it so
2784 * that we don't assign tapes that will never be used.
2785 */
2786 spill_initialized = true;
2787 hashagg_spill_init(&spill, tapeset, batch->used_bits,
2788 batch->input_card, aggstate->hashentrysize);
2789 }
2790 /* no memory for a new group, spill */
2792
2793 aggstate->hash_pergroup[batch->setno] = NULL;
2794 }
2795
2796 /*
2797 * Reset per-input-tuple context after each tuple, but note that the
2798 * hash lookups do this too
2799 */
2800 ResetExprContext(aggstate->tmpcontext);
2801 }
2802
2803 LogicalTapeClose(batch->input_tape);
2804
2805 /* change back to phase 0 */
2806 aggstate->current_phase = 0;
2807 aggstate->phase = &aggstate->phases[aggstate->current_phase];
2808
2810 {
2812 hash_agg_update_metrics(aggstate, true, spill.npartitions);
2813 }
2814 else
2816
2817 aggstate->hash_spill_mode = false;
2818
2819 /* prepare to walk the first hash table */
2820 select_current_set(aggstate, batch->setno, true);
2821 ResetTupleHashIterator(aggstate->perhash[batch->setno].hashtable,
2822 &aggstate->perhash[batch->setno].hashiter);
2823
2824 pfree(batch);
2825
2826 return true;
2827}
#define Assert(condition)
Definition c.h:945
uint32_t uint32
Definition c.h:618
#define MemSet(start, val, len)
Definition c.h:1109
TupleHashEntry LookupTupleHashEntryHash(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 hash)
void ResetTupleHashTable(TupleHashTable hashtable)
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
void ReScanExprContext(ExprContext *econtext)
Definition execUtils.c:448
static void * TupleHashEntryGetAdditional(TupleHashTable hashtable, TupleHashEntry entry)
Definition executor.h:193
#define INJECTION_POINT(name, arg)
List * list_delete_last(List *list)
Definition list.c:957
void LogicalTapeClose(LogicalTape *lt)
Definition logtape.c:733
void pfree(void *pointer)
Definition mcxt.c:1616
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
static void initialize_hash_entry(AggState *aggstate, TupleHashTable hashtable, TupleHashEntry entry)
Definition nodeAgg.c:2140
static void hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
Definition nodeAgg.c:3201
static MinimalTuple hashagg_batch_read(HashAggBatch *batch, uint32 *hashp)
Definition nodeAgg.c:3118
static void hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
Definition nodeAgg.c:1946
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition nodeAgg.c:1751
static void prepare_hash_slot(AggStatePerHash perhash, TupleTableSlot *inputslot, TupleTableSlot *hashslot)
Definition nodeAgg.c:1204
static Size hashagg_spill_tuple(AggState *aggstate, HashAggSpill *spill, TupleTableSlot *inputslot, uint32 hash)
Definition nodeAgg.c:3029
static void hashagg_spill_init(HashAggSpill *spill, LogicalTapeSet *tapeset, int used_bits, double input_groups, double hashentrysize)
Definition nodeAgg.c:2986
void hash_agg_set_limits(double hashentrysize, double input_groups, int used_bits, Size *mem_limit, uint64 *ngroups_limit, int *num_partitions)
Definition nodeAgg.c:1808
@ AGG_MIXED
Definition nodes.h:367
#define llast(l)
Definition pg_list.h:198
#define NIL
Definition pg_list.h:68
static unsigned hash(unsigned *uv, int n)
Definition rege_dfa.c:715
TupleHashTable hashtable
Definition nodeAgg.h:311
TupleTableSlot * hashslot
Definition nodeAgg.h:313

References advance_aggregates(), AGG_MIXED, Assert, CHECK_FOR_INTERRUPTS, ExecStoreMinimalTuple(), fb(), hash(), hash_agg_set_limits(), hash_agg_update_metrics(), hashagg_batch_read(), hashagg_recompile_expressions(), hashagg_spill_finish(), hashagg_spill_init(), hashagg_spill_tuple(), AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, initialize_hash_entry(), INJECTION_POINT, list_delete_last(), llast, LogicalTapeClose(), LookupTupleHashEntryHash(), MemSet, NIL, pfree(), prepare_hash_slot(), ReScanExprContext(), ResetExprContext, ResetTupleHashIterator, ResetTupleHashTable(), select_current_set(), and TupleHashEntryGetAdditional().

Referenced by agg_retrieve_hash_table().

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

Definition at line 2283 of file nodeAgg.c.

2284{
2285 Agg *node = aggstate->phase->aggnode;
2286 ExprContext *econtext;
2287 ExprContext *tmpcontext;
2288 AggStatePerAgg peragg;
2289 AggStatePerGroup *pergroups;
2292 TupleTableSlot *result;
2293 bool hasGroupingSets = aggstate->phase->numsets > 0;
2294 int numGroupingSets = Max(aggstate->phase->numsets, 1);
2295 int currentSet;
2296 int nextSetSize;
2297 int numReset;
2298 int i;
2299
2300 /*
2301 * get state info from node
2302 *
2303 * econtext is the per-output-tuple expression context
2304 *
2305 * tmpcontext is the per-input-tuple expression context
2306 */
2307 econtext = aggstate->ss.ps.ps_ExprContext;
2308 tmpcontext = aggstate->tmpcontext;
2309
2310 peragg = aggstate->peragg;
2311 pergroups = aggstate->pergroups;
2312 firstSlot = aggstate->ss.ss_ScanTupleSlot;
2313
2314 /*
2315 * We loop retrieving groups until we find one matching
2316 * aggstate->ss.ps.qual
2317 *
2318 * For grouping sets, we have the invariant that aggstate->projected_set
2319 * is either -1 (initial call) or the index (starting from 0) in
2320 * gset_lengths for the group we just completed (either by projecting a
2321 * row or by discarding it in the qual).
2322 */
2323 while (!aggstate->agg_done)
2324 {
2325 /*
2326 * Clear the per-output-tuple context for each group, as well as
2327 * aggcontext (which contains any pass-by-ref transvalues of the old
2328 * group). Some aggregate functions store working state in child
2329 * contexts; those now get reset automatically without us needing to
2330 * do anything special.
2331 *
2332 * We use ReScanExprContext not just ResetExprContext because we want
2333 * any registered shutdown callbacks to be called. That allows
2334 * aggregate functions to ensure they've cleaned up any non-memory
2335 * resources.
2336 */
2337 ReScanExprContext(econtext);
2338
2339 /*
2340 * Determine how many grouping sets need to be reset at this boundary.
2341 */
2342 if (aggstate->projected_set >= 0 &&
2343 aggstate->projected_set < numGroupingSets)
2344 numReset = aggstate->projected_set + 1;
2345 else
2347
2348 /*
2349 * numReset can change on a phase boundary, but that's OK; we want to
2350 * reset the contexts used in _this_ phase, and later, after possibly
2351 * changing phase, initialize the right number of aggregates for the
2352 * _new_ phase.
2353 */
2354
2355 for (i = 0; i < numReset; i++)
2356 {
2357 ReScanExprContext(aggstate->aggcontexts[i]);
2358 }
2359
2360 /*
2361 * Check if input is complete and there are no more groups to project
2362 * in this phase; move to next phase or mark as done.
2363 */
2364 if (aggstate->input_done == true &&
2365 aggstate->projected_set >= (numGroupingSets - 1))
2366 {
2367 if (aggstate->current_phase < aggstate->numphases - 1)
2368 {
2369 initialize_phase(aggstate, aggstate->current_phase + 1);
2370 aggstate->input_done = false;
2371 aggstate->projected_set = -1;
2372 numGroupingSets = Max(aggstate->phase->numsets, 1);
2373 node = aggstate->phase->aggnode;
2375 }
2376 else if (aggstate->aggstrategy == AGG_MIXED)
2377 {
2378 /*
2379 * Mixed mode; we've output all the grouped stuff and have
2380 * full hashtables, so switch to outputting those.
2381 */
2383 aggstate->table_filled = true;
2384 ResetTupleHashIterator(aggstate->perhash[0].hashtable,
2385 &aggstate->perhash[0].hashiter);
2386 select_current_set(aggstate, 0, true);
2388 }
2389 else
2390 {
2391 aggstate->agg_done = true;
2392 break;
2393 }
2394 }
2395
2396 /*
2397 * Get the number of columns in the next grouping set after the last
2398 * projected one (if any). This is the number of columns to compare to
2399 * see if we reached the boundary of that set too.
2400 */
2401 if (aggstate->projected_set >= 0 &&
2402 aggstate->projected_set < (numGroupingSets - 1))
2403 nextSetSize = aggstate->phase->gset_lengths[aggstate->projected_set + 1];
2404 else
2405 nextSetSize = 0;
2406
2407 /*----------
2408 * If a subgroup for the current grouping set is present, project it.
2409 *
2410 * We have a new group if:
2411 * - we're out of input but haven't projected all grouping sets
2412 * (checked above)
2413 * OR
2414 * - we already projected a row that wasn't from the last grouping
2415 * set
2416 * AND
2417 * - the next grouping set has at least one grouping column (since
2418 * empty grouping sets project only once input is exhausted)
2419 * AND
2420 * - the previous and pending rows differ on the grouping columns
2421 * of the next grouping set
2422 *----------
2423 */
2424 tmpcontext->ecxt_innertuple = econtext->ecxt_outertuple;
2425 if (aggstate->input_done ||
2426 (node->aggstrategy != AGG_PLAIN &&
2427 aggstate->projected_set != -1 &&
2428 aggstate->projected_set < (numGroupingSets - 1) &&
2429 nextSetSize > 0 &&
2430 !ExecQualAndReset(aggstate->phase->eqfunctions[nextSetSize - 1],
2431 tmpcontext)))
2432 {
2433 aggstate->projected_set += 1;
2434
2435 Assert(aggstate->projected_set < numGroupingSets);
2436 Assert(nextSetSize > 0 || aggstate->input_done);
2437 }
2438 else
2439 {
2440 /*
2441 * We no longer care what group we just projected, the next
2442 * projection will always be the first (or only) grouping set
2443 * (unless the input proves to be empty).
2444 */
2445 aggstate->projected_set = 0;
2446
2447 /*
2448 * If we don't already have the first tuple of the new group,
2449 * fetch it from the outer plan.
2450 */
2451 if (aggstate->grp_firstTuple == NULL)
2452 {
2454 if (!TupIsNull(outerslot))
2455 {
2456 /*
2457 * Make a copy of the first input tuple; we will use this
2458 * for comparisons (in group mode) and for projection.
2459 */
2460 aggstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
2461 }
2462 else
2463 {
2464 /* outer plan produced no tuples at all */
2465 if (hasGroupingSets)
2466 {
2467 /*
2468 * If there was no input at all, we need to project
2469 * rows only if there are grouping sets of size 0.
2470 * Note that this implies that there can't be any
2471 * references to ungrouped Vars, which would otherwise
2472 * cause issues with the empty output slot.
2473 *
2474 * XXX: This is no longer true, we currently deal with
2475 * this in finalize_aggregates().
2476 */
2477 aggstate->input_done = true;
2478
2479 while (aggstate->phase->gset_lengths[aggstate->projected_set] > 0)
2480 {
2481 aggstate->projected_set += 1;
2482 if (aggstate->projected_set >= numGroupingSets)
2483 {
2484 /*
2485 * We can't set agg_done here because we might
2486 * have more phases to do, even though the
2487 * input is empty. So we need to restart the
2488 * whole outer loop.
2489 */
2490 break;
2491 }
2492 }
2493
2494 if (aggstate->projected_set >= numGroupingSets)
2495 continue;
2496 }
2497 else
2498 {
2499 aggstate->agg_done = true;
2500 /* If we are grouping, we should produce no tuples too */
2501 if (node->aggstrategy != AGG_PLAIN)
2502 return NULL;
2503 }
2504 }
2505 }
2506
2507 /*
2508 * Initialize working state for a new input tuple group.
2509 */
2511
2512 if (aggstate->grp_firstTuple != NULL)
2513 {
2514 /*
2515 * Store the copied first input tuple in the tuple table slot
2516 * reserved for it. The tuple will be deleted when it is
2517 * cleared from the slot.
2518 */
2519 ExecForceStoreHeapTuple(aggstate->grp_firstTuple,
2520 firstSlot, true);
2521 aggstate->grp_firstTuple = NULL; /* don't keep two pointers */
2522
2523 /* set up for first advance_aggregates call */
2524 tmpcontext->ecxt_outertuple = firstSlot;
2525
2526 /*
2527 * Process each outer-plan tuple, and then fetch the next one,
2528 * until we exhaust the outer plan or cross a group boundary.
2529 */
2530 for (;;)
2531 {
2532 /*
2533 * During phase 1 only of a mixed agg, we need to update
2534 * hashtables as well in advance_aggregates.
2535 */
2536 if (aggstate->aggstrategy == AGG_MIXED &&
2537 aggstate->current_phase == 1)
2538 {
2540 }
2541
2542 /* Advance the aggregates (or combine functions) */
2544
2545 /* Reset per-input-tuple context after each tuple */
2546 ResetExprContext(tmpcontext);
2547
2549 if (TupIsNull(outerslot))
2550 {
2551 /* no more outer-plan tuples available */
2552
2553 /* if we built hash tables, finalize any spills */
2554 if (aggstate->aggstrategy == AGG_MIXED &&
2555 aggstate->current_phase == 1)
2557
2558 if (hasGroupingSets)
2559 {
2560 aggstate->input_done = true;
2561 break;
2562 }
2563 else
2564 {
2565 aggstate->agg_done = true;
2566 break;
2567 }
2568 }
2569 /* set up for next advance_aggregates call */
2570 tmpcontext->ecxt_outertuple = outerslot;
2571
2572 /*
2573 * If we are grouping, check whether we've crossed a group
2574 * boundary.
2575 */
2576 if (node->aggstrategy != AGG_PLAIN && node->numCols > 0)
2577 {
2578 tmpcontext->ecxt_innertuple = firstSlot;
2579 if (!ExecQual(aggstate->phase->eqfunctions[node->numCols - 1],
2580 tmpcontext))
2581 {
2582 aggstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
2583 break;
2584 }
2585 }
2586 }
2587 }
2588
2589 /*
2590 * Use the representative input tuple for any references to
2591 * non-aggregated input columns in aggregate direct args, the node
2592 * qual, and the tlist. (If we are not grouping, and there are no
2593 * input rows at all, we will come here with an empty firstSlot
2594 * ... but if not grouping, there can't be any references to
2595 * non-aggregated input columns, so no problem.)
2596 */
2597 econtext->ecxt_outertuple = firstSlot;
2598 }
2599
2600 Assert(aggstate->projected_set >= 0);
2601
2602 currentSet = aggstate->projected_set;
2603
2605
2607
2609 peragg,
2610 pergroups[currentSet]);
2611
2612 /*
2613 * If there's no row to project right now, we must continue rather
2614 * than returning a null since there might be more groups.
2615 */
2616 result = project_aggregates(aggstate);
2617 if (result)
2618 return result;
2619 }
2620
2621 /* No more groups */
2622 return NULL;
2623}
#define Max(x, y)
Definition c.h:1087
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition executor.h:522
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition executor.h:549
static TupleTableSlot * project_aggregates(AggState *aggstate)
Definition nodeAgg.c:1371
static void finalize_aggregates(AggState *aggstate, AggStatePerAgg peraggs, AggStatePerGroup pergroup)
Definition nodeAgg.c:1294
static void initialize_phase(AggState *aggstate, int newphase)
Definition nodeAgg.c:480
static void initialize_aggregates(AggState *aggstate, AggStatePerGroup *pergroups, int numReset)
Definition nodeAgg.c:668
static void prepare_projection_slot(AggState *aggstate, TupleTableSlot *slot, int currentSet)
Definition nodeAgg.c:1249
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition nodeAgg.c:2837
@ AGG_PLAIN
Definition nodes.h:364
int numCols
Definition plannodes.h:1216
AggStrategy aggstrategy
Definition plannodes.h:1210
TupleTableSlot * ecxt_innertuple
Definition execnodes.h:286
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition tuptable.h:503

References advance_aggregates(), AGG_MIXED, AGG_PLAIN, agg_retrieve_hash_table(), Agg::aggstrategy, Assert, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, ExecCopySlotHeapTuple(), ExecForceStoreHeapTuple(), ExecQual(), ExecQualAndReset(), fb(), fetch_input_tuple(), finalize_aggregates(), hashagg_finish_initial_spills(), i, initialize_aggregates(), initialize_phase(), lookup_hash_entries(), Max, Agg::numCols, prepare_projection_slot(), project_aggregates(), ReScanExprContext(), ResetExprContext, ResetTupleHashIterator, select_current_set(), and TupIsNull.

Referenced by ExecAgg().

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

Definition at line 2837 of file nodeAgg.c.

2838{
2839 TupleTableSlot *result = NULL;
2840
2841 while (result == NULL)
2842 {
2844 if (result == NULL)
2845 {
2847 {
2848 aggstate->agg_done = true;
2849 break;
2850 }
2851 }
2852 }
2853
2854 return result;
2855}
static bool agg_refill_hash_table(AggState *aggstate)
Definition nodeAgg.c:2683
static TupleTableSlot * agg_retrieve_hash_table_in_memory(AggState *aggstate)
Definition nodeAgg.c:2862

References agg_refill_hash_table(), agg_retrieve_hash_table_in_memory(), and fb().

Referenced by agg_retrieve_direct(), and ExecAgg().

◆ agg_retrieve_hash_table_in_memory()

static TupleTableSlot * agg_retrieve_hash_table_in_memory ( AggState aggstate)
static

Definition at line 2862 of file nodeAgg.c.

2863{
2864 ExprContext *econtext;
2865 AggStatePerAgg peragg;
2867 TupleHashEntry entry;
2869 TupleTableSlot *result;
2870 AggStatePerHash perhash;
2871
2872 /*
2873 * get state info from node.
2874 *
2875 * econtext is the per-output-tuple expression context.
2876 */
2877 econtext = aggstate->ss.ps.ps_ExprContext;
2878 peragg = aggstate->peragg;
2879 firstSlot = aggstate->ss.ss_ScanTupleSlot;
2880
2881 /*
2882 * Note that perhash (and therefore anything accessed through it) can
2883 * change inside the loop, as we change between grouping sets.
2884 */
2885 perhash = &aggstate->perhash[aggstate->current_set];
2886
2887 /*
2888 * We loop retrieving groups until we find one satisfying
2889 * aggstate->ss.ps.qual
2890 */
2891 for (;;)
2892 {
2893 TupleTableSlot *hashslot = perhash->hashslot;
2894 TupleHashTable hashtable = perhash->hashtable;
2895 int i;
2896
2898
2899 /*
2900 * Find the next entry in the hash table
2901 */
2902 entry = ScanTupleHashTable(hashtable, &perhash->hashiter);
2903 if (entry == NULL)
2904 {
2905 int nextset = aggstate->current_set + 1;
2906
2907 if (nextset < aggstate->num_hashes)
2908 {
2909 /*
2910 * Switch to next grouping set, reinitialize, and restart the
2911 * loop.
2912 */
2914
2915 perhash = &aggstate->perhash[aggstate->current_set];
2916
2917 ResetTupleHashIterator(perhash->hashtable, &perhash->hashiter);
2918
2919 continue;
2920 }
2921 else
2922 {
2923 return NULL;
2924 }
2925 }
2926
2927 /*
2928 * Clear the per-output-tuple context for each group
2929 *
2930 * We intentionally don't use ReScanExprContext here; if any aggs have
2931 * registered shutdown callbacks, they mustn't be called yet, since we
2932 * might not be done with that agg.
2933 */
2934 ResetExprContext(econtext);
2935
2936 /*
2937 * Transform representative tuple back into one with the right
2938 * columns.
2939 */
2940 ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashslot, false);
2941 slot_getallattrs(hashslot);
2942
2944 memset(firstSlot->tts_isnull, true,
2945 firstSlot->tts_tupleDescriptor->natts * sizeof(bool));
2946
2947 for (i = 0; i < perhash->numhashGrpCols; i++)
2948 {
2949 int varNumber = perhash->hashGrpColIdxInput[i] - 1;
2950
2951 firstSlot->tts_values[varNumber] = hashslot->tts_values[i];
2952 firstSlot->tts_isnull[varNumber] = hashslot->tts_isnull[i];
2953 }
2955
2957
2958 /*
2959 * Use the representative input tuple for any references to
2960 * non-aggregated input columns in the qual and tlist.
2961 */
2962 econtext->ecxt_outertuple = firstSlot;
2963
2965 econtext->ecxt_outertuple,
2966 aggstate->current_set);
2967
2969
2970 result = project_aggregates(aggstate);
2971 if (result)
2972 return result;
2973 }
2974
2975 /* No more groups */
2976 return NULL;
2977}
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
#define ScanTupleHashTable(htable, iter)
Definition execnodes.h:912
struct AggStatePerGroupData * AggStatePerGroup
Definition execnodes.h:2398
static MinimalTuple TupleHashEntryGetTuple(TupleHashEntry entry)
Definition executor.h:179
TupleHashIterator hashiter
Definition nodeAgg.h:312
AttrNumber * hashGrpColIdxInput
Definition nodeAgg.h:319
bool * tts_isnull
Definition tuptable.h:133
Datum * tts_values
Definition tuptable.h:131
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476
static void slot_getallattrs(TupleTableSlot *slot)
Definition tuptable.h:390

References CHECK_FOR_INTERRUPTS, ExprContext::ecxt_outertuple, ExecClearTuple(), ExecStoreMinimalTuple(), ExecStoreVirtualTuple(), fb(), finalize_aggregates(), AggStatePerHashData::hashGrpColIdxInput, AggStatePerHashData::hashiter, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, i, AggStatePerHashData::numhashGrpCols, prepare_projection_slot(), project_aggregates(), ResetExprContext, ResetTupleHashIterator, ScanTupleHashTable, select_current_set(), slot_getallattrs(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TupleHashEntryGetAdditional(), and TupleHashEntryGetTuple().

Referenced by agg_retrieve_hash_table().

◆ AggCheckCallContext()

int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

Definition at line 4609 of file nodeAgg.c.

4610{
4611 if (fcinfo->context && IsA(fcinfo->context, AggState))
4612 {
4613 if (aggcontext)
4614 {
4615 AggState *aggstate = ((AggState *) fcinfo->context);
4616 ExprContext *cxt = aggstate->curaggcontext;
4617
4618 *aggcontext = cxt->ecxt_per_tuple_memory;
4619 }
4620 return AGG_CONTEXT_AGGREGATE;
4621 }
4622 if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4623 {
4624 if (aggcontext)
4625 *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4626 return AGG_CONTEXT_WINDOW;
4627 }
4628
4629 /* this is just to prevent "uninitialized variable" warnings */
4630 if (aggcontext)
4631 *aggcontext = NULL;
4632 return 0;
4633}
#define AGG_CONTEXT_WINDOW
Definition fmgr.h:815
#define AGG_CONTEXT_AGGREGATE
Definition fmgr.h:814
#define IsA(nodeptr, _type_)
Definition nodes.h:164
MemoryContext ecxt_per_tuple_memory
Definition execnodes.h:292

References AGG_CONTEXT_AGGREGATE, AGG_CONTEXT_WINDOW, FunctionCallInfoBaseData::context, ExprContext::ecxt_per_tuple_memory, fb(), and IsA.

Referenced by array_agg_array_combine(), array_agg_array_deserialize(), array_agg_array_finalfn(), array_agg_array_serialize(), array_agg_array_transfn(), array_agg_combine(), array_agg_deserialize(), array_agg_finalfn(), array_agg_serialize(), array_agg_transfn(), bytea_string_agg_finalfn(), bytea_string_agg_transfn(), fetch_array_arg_replace_nulls(), float4_accum(), float8_accum(), float8_combine(), float8_regr_accum(), float8_regr_combine(), hypothetical_dense_rank_final(), hypothetical_rank_common(), int2_avg_accum(), int2_avg_accum_inv(), int4_avg_accum(), int4_avg_accum_inv(), int4_avg_combine(), int8_avg_combine(), int8_avg_deserialize(), int8_avg_serialize(), interval_avg_deserialize(), interval_avg_serialize(), json_agg_finalfn(), json_agg_transfn_worker(), json_object_agg_finalfn(), json_object_agg_transfn_worker(), jsonb_agg_finalfn(), jsonb_agg_transfn_worker(), jsonb_object_agg_finalfn(), jsonb_object_agg_transfn_worker(), makeBoolAggState(), makeInt128AggState(), makeIntervalAggState(), makeNumericAggState(), makeStringAggState(), mode_final(), multirange_agg_transfn(), multirange_intersect_agg_transfn(), numeric_avg_combine(), numeric_avg_deserialize(), numeric_avg_serialize(), numeric_combine(), numeric_deserialize(), numeric_poly_combine(), numeric_poly_deserialize(), numeric_poly_serialize(), numeric_serialize(), ordered_set_startup(), percentile_cont_final_common(), percentile_cont_multi_final_common(), percentile_disc_final(), percentile_disc_multi_final(), range_agg_finalfn(), range_agg_transfn(), range_intersect_agg_transfn(), string_agg_combine(), string_agg_deserialize(), string_agg_finalfn(), and string_agg_serialize().

◆ AggGetAggref()

Aggref * AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4653 of file nodeAgg.c.

4654{
4655 if (fcinfo->context && IsA(fcinfo->context, AggState))
4656 {
4657 AggState *aggstate = (AggState *) fcinfo->context;
4658 AggStatePerAgg curperagg;
4659 AggStatePerTrans curpertrans;
4660
4661 /* check curperagg (valid when in a final function) */
4662 curperagg = aggstate->curperagg;
4663
4664 if (curperagg)
4665 return curperagg->aggref;
4666
4667 /* check curpertrans (valid when in a transition function) */
4668 curpertrans = aggstate->curpertrans;
4669
4670 if (curpertrans)
4671 return curpertrans->aggref;
4672 }
4673 return NULL;
4674}
Aggref * aggref
Definition nodeAgg.h:195

References AggStatePerTransData::aggref, AggStatePerAggData::aggref, FunctionCallInfoBaseData::context, fb(), and IsA.

Referenced by ordered_set_startup().

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4687 of file nodeAgg.c.

4688{
4689 if (fcinfo->context && IsA(fcinfo->context, AggState))
4690 {
4691 AggState *aggstate = (AggState *) fcinfo->context;
4692
4693 return aggstate->tmpcontext->ecxt_per_tuple_memory;
4694 }
4695 return NULL;
4696}

References FunctionCallInfoBaseData::context, fb(), and IsA.

◆ AggRegisterCallback()

void AggRegisterCallback ( FunctionCallInfo  fcinfo,
ExprContextCallbackFunction  func,
Datum  arg 
)

Definition at line 4752 of file nodeAgg.c.

4755{
4756 if (fcinfo->context && IsA(fcinfo->context, AggState))
4757 {
4758 AggState *aggstate = (AggState *) fcinfo->context;
4759 ExprContext *cxt = aggstate->curaggcontext;
4760
4761 RegisterExprContextCallback(cxt, func, arg);
4762
4763 return;
4764 }
4765 elog(ERROR, "aggregate function cannot register a callback in this context");
4766}
Datum arg
Definition elog.c:1322
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition execUtils.c:968

References arg, FunctionCallInfoBaseData::context, elog, ERROR, fb(), IsA, and RegisterExprContextCallback().

Referenced by ordered_set_startup().

◆ AggStateIsShared()

bool AggStateIsShared ( FunctionCallInfo  fcinfo)

Definition at line 4713 of file nodeAgg.c.

4714{
4715 if (fcinfo->context && IsA(fcinfo->context, AggState))
4716 {
4717 AggState *aggstate = (AggState *) fcinfo->context;
4718 AggStatePerAgg curperagg;
4719 AggStatePerTrans curpertrans;
4720
4721 /* check curperagg (valid when in a final function) */
4722 curperagg = aggstate->curperagg;
4723
4724 if (curperagg)
4725 return aggstate->pertrans[curperagg->transno].aggshared;
4726
4727 /* check curpertrans (valid when in a transition function) */
4728 curpertrans = aggstate->curpertrans;
4729
4730 if (curpertrans)
4731 return curpertrans->aggshared;
4732 }
4733 return true;
4734}

References AggStatePerTransData::aggshared, FunctionCallInfoBaseData::context, fb(), IsA, and AggStatePerAggData::transno.

Referenced by ordered_set_startup().

◆ build_hash_table()

static void build_hash_table ( AggState aggstate,
int  setno,
double  nbuckets 
)
static

Definition at line 1508 of file nodeAgg.c.

1509{
1510 AggStatePerHash perhash = &aggstate->perhash[setno];
1511 MemoryContext metacxt = aggstate->hash_metacxt;
1512 MemoryContext tuplescxt = aggstate->hash_tuplescxt;
1513 MemoryContext tmpcxt = aggstate->tmpcontext->ecxt_per_tuple_memory;
1514 Size additionalsize;
1515
1516 Assert(aggstate->aggstrategy == AGG_HASHED ||
1517 aggstate->aggstrategy == AGG_MIXED);
1518
1519 /*
1520 * Used to make sure initial hash table allocation does not exceed
1521 * hash_mem. Note that the estimate does not include space for
1522 * pass-by-reference transition data values, nor for the representative
1523 * tuple of each group.
1524 */
1525 additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1526
1527 perhash->hashtable = BuildTupleHashTable(&aggstate->ss.ps,
1528 perhash->hashslot->tts_tupleDescriptor,
1529 perhash->hashslot->tts_ops,
1530 perhash->numCols,
1531 perhash->hashGrpColIdxHash,
1532 perhash->eqfuncoids,
1533 perhash->hashfunctions,
1534 perhash->aggnode->grpCollations,
1535 nbuckets,
1536 additionalsize,
1537 metacxt,
1538 tuplescxt,
1539 tmpcxt,
1540 DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1541}
size_t Size
Definition c.h:691
TupleHashTable BuildTupleHashTable(PlanState *parent, TupleDesc inputDesc, const TupleTableSlotOps *inputOps, int numCols, AttrNumber *keyColIdx, const Oid *eqfuncoids, FmgrInfo *hashfunctions, Oid *collations, double nelements, Size additionalsize, MemoryContext metacxt, MemoryContext tuplescxt, MemoryContext tempcxt, bool use_variable_hash_iv)
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition nodes.h:396
@ AGG_HASHED
Definition nodes.h:366
FmgrInfo * hashfunctions
Definition nodeAgg.h:314
AttrNumber * hashGrpColIdxHash
Definition nodeAgg.h:320
TupleDesc tts_tupleDescriptor
Definition tuptable.h:129
const TupleTableSlotOps *const tts_ops
Definition tuptable.h:127

References AGG_HASHED, AGG_MIXED, AggStatePerHashData::aggnode, Assert, BuildTupleHashTable(), DO_AGGSPLIT_SKIPFINAL, AggStatePerHashData::eqfuncoids, fb(), AggStatePerHashData::hashfunctions, AggStatePerHashData::hashGrpColIdxHash, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, AggStatePerHashData::numCols, TupleTableSlot::tts_ops, and TupleTableSlot::tts_tupleDescriptor.

Referenced by build_hash_tables().

◆ build_hash_tables()

static void build_hash_tables ( AggState aggstate)
static

Definition at line 1467 of file nodeAgg.c.

1468{
1469 int setno;
1470
1471 for (setno = 0; setno < aggstate->num_hashes; ++setno)
1472 {
1473 AggStatePerHash perhash = &aggstate->perhash[setno];
1474 double nbuckets;
1475 Size memory;
1476
1477 if (perhash->hashtable != NULL)
1478 {
1480 continue;
1481 }
1482
1483 memory = aggstate->hash_mem_limit / aggstate->num_hashes;
1484
1485 /* choose reasonable number of buckets per hashtable */
1486 nbuckets = hash_choose_num_buckets(aggstate->hashentrysize,
1487 perhash->aggnode->numGroups,
1488 memory);
1489
1490#ifdef USE_INJECTION_POINTS
1491 if (IS_INJECTION_POINT_ATTACHED("hash-aggregate-oversize-table"))
1492 {
1493 nbuckets = memory / TupleHashEntrySize();
1494 INJECTION_POINT_CACHED("hash-aggregate-oversize-table", NULL);
1495 }
1496#endif
1497
1498 build_hash_table(aggstate, setno, nbuckets);
1499 }
1500
1501 aggstate->hash_ngroups_current = 0;
1502}
static size_t TupleHashEntrySize(void)
Definition executor.h:170
#define IS_INJECTION_POINT_ATTACHED(name)
#define INJECTION_POINT_CACHED(name, arg)
static void build_hash_table(AggState *aggstate, int setno, double nbuckets)
Definition nodeAgg.c:1508
static double hash_choose_num_buckets(double hashentrysize, double ngroups, Size memory)
Definition nodeAgg.c:2057
Cardinality numGroups
Definition plannodes.h:1226

References AggStatePerHashData::aggnode, build_hash_table(), fb(), hash_choose_num_buckets(), AggStatePerHashData::hashtable, INJECTION_POINT_CACHED, IS_INJECTION_POINT_ATTACHED, Agg::numGroups, ResetTupleHashTable(), and TupleHashEntrySize().

Referenced by ExecInitAgg(), and ExecReScanAgg().

◆ build_pertrans_for_aggref()

static void build_pertrans_for_aggref ( AggStatePerTrans  pertrans,
AggState aggstate,
EState estate,
Aggref aggref,
Oid  transfn_oid,
Oid  aggtranstype,
Oid  aggserialfn,
Oid  aggdeserialfn,
Datum  initValue,
bool  initValueIsNull,
Oid inputTypes,
int  numArguments 
)
static

Definition at line 4131 of file nodeAgg.c.

4138{
4139 int numGroupingSets = Max(aggstate->maxsets, 1);
4141 int numTransArgs;
4144 ListCell *lc;
4145 int numInputs;
4146 int numDirectArgs;
4147 List *sortlist;
4148 int numSortCols;
4149 int numDistinctCols;
4150 int i;
4151
4152 /* Begin filling in the pertrans data */
4153 pertrans->aggref = aggref;
4154 pertrans->aggshared = false;
4155 pertrans->aggCollation = aggref->inputcollid;
4156 pertrans->transfn_oid = transfn_oid;
4157 pertrans->serialfn_oid = aggserialfn;
4158 pertrans->deserialfn_oid = aggdeserialfn;
4159 pertrans->initValue = initValue;
4160 pertrans->initValueIsNull = initValueIsNull;
4161
4162 /* Count the "direct" arguments, if any */
4164
4165 /* Count the number of aggregated input columns */
4166 pertrans->numInputs = numInputs = list_length(aggref->args);
4167
4168 pertrans->aggtranstype = aggtranstype;
4169
4170 /* account for the current transition state */
4171 numTransArgs = pertrans->numTransInputs + 1;
4172
4173 /*
4174 * Set up infrastructure for calling the transfn. Note that invtransfn is
4175 * not needed here.
4176 */
4178 numArguments,
4180 aggref->aggvariadic,
4181 aggtranstype,
4182 aggref->inputcollid,
4183 transfn_oid,
4184 InvalidOid,
4185 &transfnexpr,
4186 NULL);
4187
4188 fmgr_info(transfn_oid, &pertrans->transfn);
4189 fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
4190
4191 pertrans->transfn_fcinfo =
4194 &pertrans->transfn,
4196 pertrans->aggCollation,
4197 (Node *) aggstate, NULL);
4198
4199 /* get info about the state value's datatype */
4200 get_typlenbyval(aggtranstype,
4201 &pertrans->transtypeLen,
4202 &pertrans->transtypeByVal);
4203
4205 {
4207 &serialfnexpr);
4208 fmgr_info(aggserialfn, &pertrans->serialfn);
4210
4211 pertrans->serialfn_fcinfo =
4214 &pertrans->serialfn,
4215 1,
4216 InvalidOid,
4217 (Node *) aggstate, NULL);
4218 }
4219
4221 {
4224 fmgr_info(aggdeserialfn, &pertrans->deserialfn);
4226
4227 pertrans->deserialfn_fcinfo =
4230 &pertrans->deserialfn,
4231 2,
4232 InvalidOid,
4233 (Node *) aggstate, NULL);
4234 }
4235
4236 /*
4237 * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
4238 * have a list of SortGroupClause nodes; fish out the data in them and
4239 * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
4240 * however; the agg's transfn and finalfn are responsible for that.
4241 *
4242 * When the planner has set the aggpresorted flag, the input to the
4243 * aggregate is already correctly sorted. For ORDER BY aggregates we can
4244 * simply treat these as normal aggregates. For presorted DISTINCT
4245 * aggregates an extra step must be added to remove duplicate consecutive
4246 * inputs.
4247 *
4248 * Note that by construction, if there is a DISTINCT clause then the ORDER
4249 * BY clause is a prefix of it (see transformDistinctClause).
4250 */
4251 if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4252 {
4253 sortlist = NIL;
4254 numSortCols = numDistinctCols = 0;
4255 pertrans->aggsortrequired = false;
4256 }
4257 else if (aggref->aggpresorted && aggref->aggdistinct == NIL)
4258 {
4259 sortlist = NIL;
4260 numSortCols = numDistinctCols = 0;
4261 pertrans->aggsortrequired = false;
4262 }
4263 else if (aggref->aggdistinct)
4264 {
4265 sortlist = aggref->aggdistinct;
4266 numSortCols = numDistinctCols = list_length(sortlist);
4267 Assert(numSortCols >= list_length(aggref->aggorder));
4268 pertrans->aggsortrequired = !aggref->aggpresorted;
4269 }
4270 else
4271 {
4272 sortlist = aggref->aggorder;
4273 numSortCols = list_length(sortlist);
4274 numDistinctCols = 0;
4275 pertrans->aggsortrequired = (numSortCols > 0);
4276 }
4277
4278 pertrans->numSortCols = numSortCols;
4279 pertrans->numDistinctCols = numDistinctCols;
4280
4281 /*
4282 * If we have either sorting or filtering to do, create a tupledesc and
4283 * slot corresponding to the aggregated inputs (including sort
4284 * expressions) of the agg.
4285 */
4286 if (numSortCols > 0 || aggref->aggfilter)
4287 {
4288 pertrans->sortdesc = ExecTypeFromTL(aggref->args);
4289 pertrans->sortslot =
4290 ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4292 }
4293
4294 if (numSortCols > 0)
4295 {
4296 /*
4297 * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
4298 * (yet)
4299 */
4300 Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
4301
4302 /* ORDER BY aggregates are not supported with partial aggregation */
4303 Assert(!DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
4304
4305 /* If we have only one input, we need its len/byval info. */
4306 if (numInputs == 1)
4307 {
4309 &pertrans->inputtypeLen,
4310 &pertrans->inputtypeByVal);
4311 }
4312 else if (numDistinctCols > 0)
4313 {
4314 /* we will need an extra slot to store prior values */
4315 pertrans->uniqslot =
4316 ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4318 }
4319
4320 /* Extract the sort information for use later */
4321 pertrans->sortColIdx =
4322 (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
4323 pertrans->sortOperators =
4324 (Oid *) palloc(numSortCols * sizeof(Oid));
4325 pertrans->sortCollations =
4326 (Oid *) palloc(numSortCols * sizeof(Oid));
4327 pertrans->sortNullsFirst =
4328 (bool *) palloc(numSortCols * sizeof(bool));
4329
4330 i = 0;
4331 foreach(lc, sortlist)
4332 {
4335
4336 /* the parser should have made sure of this */
4337 Assert(OidIsValid(sortcl->sortop));
4338
4339 pertrans->sortColIdx[i] = tle->resno;
4340 pertrans->sortOperators[i] = sortcl->sortop;
4341 pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
4342 pertrans->sortNullsFirst[i] = sortcl->nulls_first;
4343 i++;
4344 }
4345 Assert(i == numSortCols);
4346 }
4347
4348 if (aggref->aggdistinct)
4349 {
4350 Oid *ops;
4351
4352 Assert(numArguments > 0);
4353 Assert(list_length(aggref->aggdistinct) == numDistinctCols);
4354
4355 ops = palloc(numDistinctCols * sizeof(Oid));
4356
4357 i = 0;
4358 foreach(lc, aggref->aggdistinct)
4359 ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
4360
4361 /* lookup / build the necessary comparators */
4362 if (numDistinctCols == 1)
4363 fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
4364 else
4365 pertrans->equalfnMulti =
4367 numDistinctCols,
4368 pertrans->sortColIdx,
4369 ops,
4370 pertrans->sortCollations,
4371 &aggstate->ss.ps);
4372 pfree(ops);
4373 }
4374
4376}
int16 AttrNumber
Definition attnum.h:21
#define OidIsValid(objectId)
Definition c.h:860
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
const TupleTableSlotOps TTSOpsMinimalTuple
Definition execTuples.c:86
TupleDesc ExecTypeFromTL(List *targetList)
#define palloc0_array(type, count)
Definition fe_memutils.h:77
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:129
#define SizeForFunctionCallInfo(nargs)
Definition fmgr.h:102
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition fmgr.h:150
struct FunctionCallInfoBaseData * FunctionCallInfo
Definition fmgr.h:38
#define fmgr_info_set_expr(expr, finfo)
Definition fmgr.h:135
static int initValue(long lng_val)
Definition informix.c:702
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition lsyscache.c:2471
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1505
void * palloc(Size size)
Definition mcxt.c:1387
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
#define DO_AGGSPLIT_COMBINE(as)
Definition nodes.h:395
void build_aggregate_deserialfn_expr(Oid deserialfn_oid, Expr **deserialfnexpr)
Definition parse_agg.c:2325
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:2241
void build_aggregate_serialfn_expr(Oid serialfn_oid, Expr **serialfnexpr)
Definition parse_agg.c:2302
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
#define InvalidOid
unsigned int Oid
FmgrInfo serialfn
Definition nodeAgg.h:89
FmgrInfo equalfnOne
Definition nodeAgg.h:115
TupleDesc sortdesc
Definition nodeAgg.h:143
TupleTableSlot * sortslot
Definition nodeAgg.h:141
ExprState * equalfnMulti
Definition nodeAgg.h:116
Tuplesortstate ** sortstates
Definition nodeAgg.h:162
TupleTableSlot * uniqslot
Definition nodeAgg.h:142
FmgrInfo deserialfn
Definition nodeAgg.h:92
FunctionCallInfo deserialfn_fcinfo
Definition nodeAgg.h:175
AttrNumber * sortColIdx
Definition nodeAgg.h:105
FunctionCallInfo serialfn_fcinfo
Definition nodeAgg.h:173
List * aggdistinct
Definition primnodes.h:494
List * aggdirectargs
Definition primnodes.h:485
List * args
Definition primnodes.h:488
Expr * aggfilter
Definition primnodes.h:497
List * aggorder
Definition primnodes.h:491
Definition pg_list.h:54
Definition nodes.h:135
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition tlist.c:376

References AGG_HASHED, AGG_MIXED, AggStatePerTransData::aggCollation, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggorder, AggStatePerTransData::aggref, AggStatePerTransData::aggshared, AggStatePerTransData::aggsortrequired, AggStatePerTransData::aggtranstype, Aggref::args, Assert, build_aggregate_deserialfn_expr(), build_aggregate_serialfn_expr(), build_aggregate_transfn_expr(), AggStatePerTransData::deserialfn, AggStatePerTransData::deserialfn_fcinfo, AggStatePerTransData::deserialfn_oid, DO_AGGSPLIT_COMBINE, AggStatePerTransData::equalfnMulti, AggStatePerTransData::equalfnOne, ExecInitExtraTupleSlot(), execTuplesMatchPrepare(), ExecTypeFromTL(), exprCollation(), fb(), fmgr_info(), fmgr_info_set_expr, get_opcode(), get_sortgroupclause_tle(), get_typlenbyval(), i, InitFunctionCallInfoData, AggStatePerTransData::initValue, initValue(), AggStatePerTransData::initValueIsNull, AggStatePerTransData::inputtypeByVal, AggStatePerTransData::inputtypeLen, InvalidOid, lfirst, list_length(), Max, NIL, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numInputs, AggStatePerTransData::numSortCols, AggStatePerTransData::numTransInputs, OidIsValid, palloc(), palloc0_array, pfree(), AggStatePerTransData::serialfn, AggStatePerTransData::serialfn_fcinfo, AggStatePerTransData::serialfn_oid, SizeForFunctionCallInfo, AggStatePerTransData::sortColIdx, AggStatePerTransData::sortCollations, AggStatePerTransData::sortdesc, AggStatePerTransData::sortNullsFirst, AggStatePerTransData::sortOperators, AggStatePerTransData::sortslot, AggStatePerTransData::sortstates, AggStatePerTransData::transfn, AggStatePerTransData::transfn_fcinfo, AggStatePerTransData::transfn_oid, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, TTSOpsMinimalTuple, and AggStatePerTransData::uniqslot.

Referenced by ExecInitAgg().

◆ ExecAgg()

static TupleTableSlot * ExecAgg ( PlanState pstate)
static

Definition at line 2247 of file nodeAgg.c.

2248{
2249 AggState *node = castNode(AggState, pstate);
2250 TupleTableSlot *result = NULL;
2251
2253
2254 if (!node->agg_done)
2255 {
2256 /* Dispatch based on strategy */
2257 switch (node->phase->aggstrategy)
2258 {
2259 case AGG_HASHED:
2260 if (!node->table_filled)
2261 agg_fill_hash_table(node);
2263 case AGG_MIXED:
2264 result = agg_retrieve_hash_table(node);
2265 break;
2266 case AGG_PLAIN:
2267 case AGG_SORTED:
2268 result = agg_retrieve_direct(node);
2269 break;
2270 }
2271
2272 if (!TupIsNull(result))
2273 return result;
2274 }
2275
2276 return NULL;
2277}
#define pg_fallthrough
Definition c.h:152
static void agg_fill_hash_table(AggState *aggstate)
Definition nodeAgg.c:2629
static TupleTableSlot * agg_retrieve_direct(AggState *aggstate)
Definition nodeAgg.c:2283
@ AGG_SORTED
Definition nodes.h:365
#define castNode(_type_, nodeptr)
Definition nodes.h:182
AggStrategy aggstrategy
Definition nodeAgg.h:282
AggStatePerPhase phase
Definition execnodes.h:2410
bool table_filled
Definition execnodes.h:2444
bool agg_done
Definition execnodes.h:2424

References AggState::agg_done, agg_fill_hash_table(), AGG_HASHED, AGG_MIXED, AGG_PLAIN, agg_retrieve_direct(), agg_retrieve_hash_table(), AGG_SORTED, AggStatePerPhaseData::aggstrategy, castNode, CHECK_FOR_INTERRUPTS, fb(), pg_fallthrough, AggState::phase, AggState::table_filled, and TupIsNull.

Referenced by ExecInitAgg().

◆ ExecAggEstimate()

void ExecAggEstimate ( AggState node,
ParallelContext pcxt 
)

Definition at line 4781 of file nodeAgg.c.

4782{
4783 Size size;
4784
4785 /* don't need this if not instrumenting or no workers */
4786 if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4787 return;
4788
4789 size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4790 size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4791 shm_toc_estimate_chunk(&pcxt->estimator, size);
4793}
#define shm_toc_estimate_chunk(e, sz)
Definition shm_toc.h:51
#define shm_toc_estimate_keys(e, cnt)
Definition shm_toc.h:53
Size add_size(Size s1, Size s2)
Definition shmem.c:485
Size mul_size(Size s1, Size s2)
Definition shmem.c:500
ScanState ss
Definition execnodes.h:2404
shm_toc_estimator estimator
Definition parallel.h:43
Instrumentation * instrument
Definition execnodes.h:1187
PlanState ps
Definition execnodes.h:1633

References add_size(), ParallelContext::estimator, fb(), PlanState::instrument, mul_size(), ParallelContext::nworkers, ScanState::ps, shm_toc_estimate_chunk, shm_toc_estimate_keys, and AggState::ss.

Referenced by ExecParallelEstimate().

◆ ExecAggInitializeDSM()

void ExecAggInitializeDSM ( AggState node,
ParallelContext pcxt 
)

Definition at line 4802 of file nodeAgg.c.

4803{
4804 Size size;
4805
4806 /* don't need this if not instrumenting or no workers */
4807 if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4808 return;
4809
4810 size = offsetof(SharedAggInfo, sinstrument)
4811 + pcxt->nworkers * sizeof(AggregateInstrumentation);
4812 node->shared_info = shm_toc_allocate(pcxt->toc, size);
4813 /* ensure any unfilled slots will contain zeroes */
4814 memset(node->shared_info, 0, size);
4815 node->shared_info->num_workers = pcxt->nworkers;
4816 shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4817 node->shared_info);
4818}
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition shm_toc.c:171
SharedAggInfo * shared_info
Definition execnodes.h:2476
shm_toc * toc
Definition parallel.h:46
Plan * plan
Definition execnodes.h:1177
int plan_node_id
Definition plannodes.h:231

References fb(), PlanState::instrument, SharedAggInfo::num_workers, ParallelContext::nworkers, PlanState::plan, Plan::plan_node_id, ScanState::ps, AggState::shared_info, shm_toc_allocate(), shm_toc_insert(), AggState::ss, and ParallelContext::toc.

Referenced by ExecParallelInitializeDSM().

◆ ExecAggInitializeWorker()

void ExecAggInitializeWorker ( AggState node,
ParallelWorkerContext pwcxt 
)

Definition at line 4827 of file nodeAgg.c.

4828{
4829 node->shared_info =
4830 shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4831}
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition shm_toc.c:232

References fb(), PlanState::plan, Plan::plan_node_id, ScanState::ps, AggState::shared_info, shm_toc_lookup(), and AggState::ss.

Referenced by ExecParallelInitializeWorker().

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 4840 of file nodeAgg.c.

4841{
4842 Size size;
4844
4845 if (node->shared_info == NULL)
4846 return;
4847
4848 size = offsetof(SharedAggInfo, sinstrument)
4850 si = palloc(size);
4851 memcpy(si, node->shared_info, size);
4852 node->shared_info = si;
4853}

References fb(), SharedAggInfo::num_workers, palloc(), and AggState::shared_info.

Referenced by ExecParallelRetrieveInstrumentation().

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 4396 of file nodeAgg.c.

4397{
4399 int transno;
4400 int numGroupingSets = Max(node->maxsets, 1);
4401 int setno;
4402
4403 /*
4404 * When ending a parallel worker, copy the statistics gathered by the
4405 * worker back into shared memory so that it can be picked up by the main
4406 * process to report in EXPLAIN ANALYZE.
4407 */
4408 if (node->shared_info && IsParallelWorker())
4409 {
4411
4412 Assert(ParallelWorkerNumber < node->shared_info->num_workers);
4415 si->hash_disk_used = node->hash_disk_used;
4416 si->hash_mem_peak = node->hash_mem_peak;
4417 }
4418
4419 /* Make sure we have closed any open tuplesorts */
4420
4421 if (node->sort_in)
4422 tuplesort_end(node->sort_in);
4423 if (node->sort_out)
4424 tuplesort_end(node->sort_out);
4425
4427
4428 /* Release hash tables too */
4429 if (node->hash_metacxt != NULL)
4430 {
4432 node->hash_metacxt = NULL;
4433 }
4434 if (node->hash_tuplescxt != NULL)
4435 {
4437 node->hash_tuplescxt = NULL;
4438 }
4439
4440 for (transno = 0; transno < node->numtrans; transno++)
4441 {
4442 AggStatePerTrans pertrans = &node->pertrans[transno];
4443
4444 for (setno = 0; setno < numGroupingSets; setno++)
4445 {
4446 if (pertrans->sortstates[setno])
4447 tuplesort_end(pertrans->sortstates[setno]);
4448 }
4449 }
4450
4451 /* And ensure any agg shutdown callbacks have been called */
4452 for (setno = 0; setno < numGroupingSets; setno++)
4453 ReScanExprContext(node->aggcontexts[setno]);
4454 if (node->hashcontext)
4456
4457 outerPlan = outerPlanState(node);
4459}
int ParallelWorkerNumber
Definition parallel.c:117
void ExecEndNode(PlanState *node)
#define outerPlanState(node)
Definition execnodes.h:1273
#define IsParallelWorker()
Definition parallel.h:62
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
static void hashagg_reset_spill_state(AggState *aggstate)
Definition nodeAgg.c:3241
#define outerPlan(node)
Definition plannodes.h:265
MemoryContext hash_metacxt
Definition execnodes.h:2446
Tuplesortstate * sort_out
Definition execnodes.h:2437
uint64 hash_disk_used
Definition execnodes.h:2465
MemoryContext hash_tuplescxt
Definition execnodes.h:2447
AggStatePerTrans pertrans
Definition execnodes.h:2414
int numtrans
Definition execnodes.h:2407
ExprContext * hashcontext
Definition execnodes.h:2415
Size hash_mem_peak
Definition execnodes.h:2462
int hash_batches_used
Definition execnodes.h:2466
Tuplesortstate * sort_in
Definition execnodes.h:2436
int maxsets
Definition execnodes.h:2434
ExprContext ** aggcontexts
Definition execnodes.h:2416
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
void tuplesort_end(Tuplesortstate *state)
Definition tuplesort.c:847

References AggState::aggcontexts, Assert, ExecEndNode(), fb(), AggregateInstrumentation::hash_batches_used, AggState::hash_batches_used, AggState::hash_disk_used, AggState::hash_mem_peak, AggState::hash_metacxt, AggState::hash_tuplescxt, hashagg_reset_spill_state(), AggState::hashcontext, IsParallelWorker, Max, AggState::maxsets, MemoryContextDelete(), AggState::numtrans, outerPlan, outerPlanState, ParallelWorkerNumber, AggState::pertrans, ReScanExprContext(), AggState::shared_info, SharedAggInfo::sinstrument, AggState::sort_in, AggState::sort_out, AggStatePerTransData::sortstates, and tuplesort_end().

Referenced by ExecEndNode().

◆ ExecInitAgg()

AggState * ExecInitAgg ( Agg node,
EState estate,
int  eflags 
)

Definition at line 3281 of file nodeAgg.c.

3282{
3286 AggStatePerGroup *pergroups;
3287 Plan *outerPlan;
3288 ExprContext *econtext;
3290 int max_aggno;
3291 int max_transno;
3292 int numaggrefs;
3293 int numaggs;
3294 int numtrans;
3295 int phase;
3296 int phaseidx;
3297 ListCell *l;
3298 Bitmapset *all_grouped_cols = NULL;
3299 int numGroupingSets = 1;
3300 int numPhases;
3301 int numHashes;
3302 int i = 0;
3303 int j = 0;
3304 bool use_hashing = (node->aggstrategy == AGG_HASHED ||
3305 node->aggstrategy == AGG_MIXED);
3306
3307 /* check for unsupported flags */
3308 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
3309
3310 /*
3311 * create state structure
3312 */
3314 aggstate->ss.ps.plan = (Plan *) node;
3315 aggstate->ss.ps.state = estate;
3316 aggstate->ss.ps.ExecProcNode = ExecAgg;
3317
3318 aggstate->aggs = NIL;
3319 aggstate->numaggs = 0;
3320 aggstate->numtrans = 0;
3321 aggstate->aggstrategy = node->aggstrategy;
3322 aggstate->aggsplit = node->aggsplit;
3323 aggstate->maxsets = 0;
3324 aggstate->projected_set = -1;
3325 aggstate->current_set = 0;
3326 aggstate->peragg = NULL;
3327 aggstate->pertrans = NULL;
3328 aggstate->curperagg = NULL;
3329 aggstate->curpertrans = NULL;
3330 aggstate->input_done = false;
3331 aggstate->agg_done = false;
3332 aggstate->pergroups = NULL;
3333 aggstate->grp_firstTuple = NULL;
3334 aggstate->sort_in = NULL;
3335 aggstate->sort_out = NULL;
3336
3337 /*
3338 * phases[0] always exists, but is dummy in sorted/plain mode
3339 */
3340 numPhases = (use_hashing ? 1 : 2);
3341 numHashes = (use_hashing ? 1 : 0);
3342
3343 /*
3344 * Calculate the maximum number of grouping sets in any phase; this
3345 * determines the size of some allocations. Also calculate the number of
3346 * phases, since all hashed/mixed nodes contribute to only a single phase.
3347 */
3348 if (node->groupingSets)
3349 {
3351
3352 foreach(l, node->chain)
3353 {
3354 Agg *agg = lfirst(l);
3355
3357 list_length(agg->groupingSets));
3358
3359 /*
3360 * additional AGG_HASHED aggs become part of phase 0, but all
3361 * others add an extra phase.
3362 */
3363 if (agg->aggstrategy != AGG_HASHED)
3364 ++numPhases;
3365 else
3366 ++numHashes;
3367 }
3368 }
3369
3370 aggstate->maxsets = numGroupingSets;
3371 aggstate->numphases = numPhases;
3372
3374
3375 /*
3376 * Create expression contexts. We need three or more, one for
3377 * per-input-tuple processing, one for per-output-tuple processing, one
3378 * for all the hashtables, and one for each grouping set. The per-tuple
3379 * memory context of the per-grouping-set ExprContexts (aggcontexts)
3380 * replaces the standalone memory context formerly used to hold transition
3381 * values. We cheat a little by using ExecAssignExprContext() to build
3382 * all of them.
3383 *
3384 * NOTE: the details of what is stored in aggcontexts and what is stored
3385 * in the regular per-query memory context are driven by a simple
3386 * decision: we want to reset the aggcontext at group boundaries (if not
3387 * hashing) and in ExecReScanAgg to recover no-longer-wanted space.
3388 */
3389 ExecAssignExprContext(estate, &aggstate->ss.ps);
3390 aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
3391
3392 for (i = 0; i < numGroupingSets; ++i)
3393 {
3394 ExecAssignExprContext(estate, &aggstate->ss.ps);
3395 aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
3396 }
3397
3398 if (use_hashing)
3400
3401 ExecAssignExprContext(estate, &aggstate->ss.ps);
3402
3403 /*
3404 * Initialize child nodes.
3405 *
3406 * If we are doing a hashed aggregation then the child plan does not need
3407 * to handle REWIND efficiently; see ExecReScanAgg.
3408 */
3409 if (node->aggstrategy == AGG_HASHED)
3410 eflags &= ~EXEC_FLAG_REWIND;
3411 outerPlan = outerPlan(node);
3412 outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
3413
3414 /*
3415 * initialize source tuple type.
3416 */
3417 aggstate->ss.ps.outerops =
3419 &aggstate->ss.ps.outeropsfixed);
3420 aggstate->ss.ps.outeropsset = true;
3421
3423 aggstate->ss.ps.outerops);
3424 scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
3425
3426 /*
3427 * If there are more than two phases (including a potential dummy phase
3428 * 0), input will be resorted using tuplesort. Need a slot for that.
3429 */
3430 if (numPhases > 2)
3431 {
3432 aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
3434
3435 /*
3436 * The output of the tuplesort, and the output from the outer child
3437 * might not use the same type of slot. In most cases the child will
3438 * be a Sort, and thus return a TTSOpsMinimalTuple type slot - but the
3439 * input can also be presorted due an index, in which case it could be
3440 * a different type of slot.
3441 *
3442 * XXX: For efficiency it would be good to instead/additionally
3443 * generate expressions with corresponding settings of outerops* for
3444 * the individual phases - deforming is often a bottleneck for
3445 * aggregations with lots of rows per group. If there's multiple
3446 * sorts, we know that all but the first use TTSOpsMinimalTuple (via
3447 * the nodeAgg.c internal tuplesort).
3448 */
3449 if (aggstate->ss.ps.outeropsfixed &&
3450 aggstate->ss.ps.outerops != &TTSOpsMinimalTuple)
3451 aggstate->ss.ps.outeropsfixed = false;
3452 }
3453
3454 /*
3455 * Initialize result type, slot and projection.
3456 */
3459
3460 /*
3461 * initialize child expressions
3462 *
3463 * We expect the parser to have checked that no aggs contain other agg
3464 * calls in their arguments (and just to be sure, we verify it again while
3465 * initializing the plan node). This would make no sense under SQL
3466 * semantics, and it's forbidden by the spec. Because it is true, we
3467 * don't need to worry about evaluating the aggs in any particular order.
3468 *
3469 * Note: execExpr.c finds Aggrefs for us, and adds them to aggstate->aggs.
3470 * Aggrefs in the qual are found here; Aggrefs in the targetlist are found
3471 * during ExecAssignProjectionInfo, above.
3472 */
3473 aggstate->ss.ps.qual =
3475
3476 /*
3477 * We should now have found all Aggrefs in the targetlist and quals.
3478 */
3480 max_aggno = -1;
3481 max_transno = -1;
3482 foreach(l, aggstate->aggs)
3483 {
3484 Aggref *aggref = (Aggref *) lfirst(l);
3485
3486 max_aggno = Max(max_aggno, aggref->aggno);
3487 max_transno = Max(max_transno, aggref->aggtransno);
3488 }
3489 aggstate->numaggs = numaggs = max_aggno + 1;
3490 aggstate->numtrans = numtrans = max_transno + 1;
3491
3492 /*
3493 * For each phase, prepare grouping set data and fmgr lookup data for
3494 * compare functions. Accumulate all_grouped_cols in passing.
3495 */
3497
3498 aggstate->num_hashes = numHashes;
3499 if (numHashes)
3500 {
3502 aggstate->phases[0].numsets = 0;
3503 aggstate->phases[0].gset_lengths = palloc_array(int, numHashes);
3504 aggstate->phases[0].grouped_cols = palloc_array(Bitmapset *, numHashes);
3505 }
3506
3507 phase = 0;
3508 for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
3509 {
3510 Agg *aggnode;
3511 Sort *sortnode;
3512
3513 if (phaseidx > 0)
3514 {
3515 aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
3516 sortnode = castNode(Sort, outerPlan(aggnode));
3517 }
3518 else
3519 {
3520 aggnode = node;
3521 sortnode = NULL;
3522 }
3523
3524 Assert(phase <= 1 || sortnode);
3525
3526 if (aggnode->aggstrategy == AGG_HASHED
3527 || aggnode->aggstrategy == AGG_MIXED)
3528 {
3529 AggStatePerPhase phasedata = &aggstate->phases[0];
3530 AggStatePerHash perhash;
3531 Bitmapset *cols = NULL;
3532
3533 Assert(phase == 0);
3534 i = phasedata->numsets++;
3535 perhash = &aggstate->perhash[i];
3536
3537 /* phase 0 always points to the "real" Agg in the hash case */
3538 phasedata->aggnode = node;
3540
3541 /* but the actual Agg node representing this hash is saved here */
3542 perhash->aggnode = aggnode;
3543
3544 phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
3545
3546 for (j = 0; j < aggnode->numCols; ++j)
3547 cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3548
3549 phasedata->grouped_cols[i] = cols;
3550
3551 all_grouped_cols = bms_add_members(all_grouped_cols, cols);
3552 continue;
3553 }
3554 else
3555 {
3556 AggStatePerPhase phasedata = &aggstate->phases[++phase];
3557 int num_sets;
3558
3560
3561 if (num_sets)
3562 {
3563 phasedata->gset_lengths = palloc(num_sets * sizeof(int));
3564 phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
3565
3566 i = 0;
3567 foreach(l, aggnode->groupingSets)
3568 {
3570 Bitmapset *cols = NULL;
3571
3572 /* planner forces this to be correct */
3573 for (j = 0; j < current_length; ++j)
3574 cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3575
3576 phasedata->grouped_cols[i] = cols;
3577 phasedata->gset_lengths[i] = current_length;
3578
3579 ++i;
3580 }
3581
3582 all_grouped_cols = bms_add_members(all_grouped_cols,
3583 phasedata->grouped_cols[0]);
3584 }
3585 else
3586 {
3587 Assert(phaseidx == 0);
3588
3589 phasedata->gset_lengths = NULL;
3590 phasedata->grouped_cols = NULL;
3591 }
3592
3593 /*
3594 * If we are grouping, precompute fmgr lookup data for inner loop.
3595 */
3596 if (aggnode->aggstrategy == AGG_SORTED)
3597 {
3598 /*
3599 * Build a separate function for each subset of columns that
3600 * need to be compared.
3601 */
3602 phasedata->eqfunctions = palloc0_array(ExprState *, aggnode->numCols);
3603
3604 /* for each grouping set */
3605 for (int k = 0; k < phasedata->numsets; k++)
3606 {
3607 int length = phasedata->gset_lengths[k];
3608
3609 /* nothing to do for empty grouping set */
3610 if (length == 0)
3611 continue;
3612
3613 /* if we already had one of this length, it'll do */
3614 if (phasedata->eqfunctions[length - 1] != NULL)
3615 continue;
3616
3617 phasedata->eqfunctions[length - 1] =
3619 length,
3620 aggnode->grpColIdx,
3621 aggnode->grpOperators,
3622 aggnode->grpCollations,
3623 (PlanState *) aggstate);
3624 }
3625
3626 /* and for all grouped columns, unless already computed */
3627 if (aggnode->numCols > 0 &&
3628 phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
3629 {
3630 phasedata->eqfunctions[aggnode->numCols - 1] =
3632 aggnode->numCols,
3633 aggnode->grpColIdx,
3634 aggnode->grpOperators,
3635 aggnode->grpCollations,
3636 (PlanState *) aggstate);
3637 }
3638 }
3639
3640 phasedata->aggnode = aggnode;
3641 phasedata->aggstrategy = aggnode->aggstrategy;
3642 phasedata->sortnode = sortnode;
3643 }
3644 }
3645
3646 /*
3647 * Convert all_grouped_cols to a descending-order list.
3648 */
3649 i = -1;
3650 while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
3651 aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
3652
3653 /*
3654 * Set up aggregate-result storage in the output expr context, and also
3655 * allocate my private per-agg working storage
3656 */
3657 econtext = aggstate->ss.ps.ps_ExprContext;
3658 econtext->ecxt_aggvalues = palloc0_array(Datum, numaggs);
3659 econtext->ecxt_aggnulls = palloc0_array(bool, numaggs);
3660
3663
3664 aggstate->peragg = peraggs;
3665 aggstate->pertrans = pertransstates;
3666
3667
3669 pergroups = aggstate->all_pergroups;
3670
3671 if (node->aggstrategy != AGG_HASHED)
3672 {
3673 for (i = 0; i < numGroupingSets; i++)
3674 {
3675 pergroups[i] = palloc0_array(AggStatePerGroupData, numaggs);
3676 }
3677
3678 aggstate->pergroups = pergroups;
3679 pergroups += numGroupingSets;
3680 }
3681
3682 /*
3683 * Hashing can only appear in the initial phase.
3684 */
3685 if (use_hashing)
3686 {
3687 Plan *outerplan = outerPlan(node);
3688 double totalGroups = 0;
3689
3690 aggstate->hash_spill_rslot = ExecInitExtraTupleSlot(estate, scanDesc,
3692 aggstate->hash_spill_wslot = ExecInitExtraTupleSlot(estate, scanDesc,
3693 &TTSOpsVirtual);
3694
3695 /* this is an array of pointers, not structures */
3696 aggstate->hash_pergroup = pergroups;
3697
3698 aggstate->hashentrysize = hash_agg_entry_size(aggstate->numtrans,
3699 outerplan->plan_width,
3700 node->transitionSpace);
3701
3702 /*
3703 * Consider all of the grouping sets together when setting the limits
3704 * and estimating the number of partitions. This can be inaccurate
3705 * when there is more than one grouping set, but should still be
3706 * reasonable.
3707 */
3708 for (int k = 0; k < aggstate->num_hashes; k++)
3709 totalGroups += aggstate->perhash[k].aggnode->numGroups;
3710
3711 hash_agg_set_limits(aggstate->hashentrysize, totalGroups, 0,
3712 &aggstate->hash_mem_limit,
3713 &aggstate->hash_ngroups_limit,
3714 &aggstate->hash_planned_partitions);
3716
3717 /* Skip massive memory allocation if we are just doing EXPLAIN */
3718 if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
3720
3721 aggstate->table_filled = false;
3722
3723 /* Initialize this to 1, meaning nothing spilled, yet */
3724 aggstate->hash_batches_used = 1;
3725 }
3726
3727 /*
3728 * Initialize current phase-dependent values to initial phase. The initial
3729 * phase is 1 (first sort pass) for all strategies that use sorting (if
3730 * hashing is being done too, then phase 0 is processed last); but if only
3731 * hashing is being done, then phase 0 is all there is.
3732 */
3733 if (node->aggstrategy == AGG_HASHED)
3734 {
3735 aggstate->current_phase = 0;
3737 select_current_set(aggstate, 0, true);
3738 }
3739 else
3740 {
3741 aggstate->current_phase = 1;
3743 select_current_set(aggstate, 0, false);
3744 }
3745
3746 /*
3747 * Perform lookups of aggregate function info, and initialize the
3748 * unchanging fields of the per-agg and per-trans data.
3749 */
3750 foreach(l, aggstate->aggs)
3751 {
3752 Aggref *aggref = lfirst(l);
3753 AggStatePerAgg peragg;
3754 AggStatePerTrans pertrans;
3757 int numDirectArgs;
3761 Oid finalfn_oid;
3762 Oid serialfn_oid,
3763 deserialfn_oid;
3764 Oid aggOwner;
3766 Oid aggtranstype;
3767
3768 /* Planner should have assigned aggregate to correct level */
3769 Assert(aggref->agglevelsup == 0);
3770 /* ... and the split mode should match */
3771 Assert(aggref->aggsplit == aggstate->aggsplit);
3772
3773 peragg = &peraggs[aggref->aggno];
3774
3775 /* Check if we initialized the state for this aggregate already. */
3776 if (peragg->aggref != NULL)
3777 continue;
3778
3779 peragg->aggref = aggref;
3780 peragg->transno = aggref->aggtransno;
3781
3782 /* Fetch the pg_aggregate row */
3784 ObjectIdGetDatum(aggref->aggfnoid));
3786 elog(ERROR, "cache lookup failed for aggregate %u",
3787 aggref->aggfnoid);
3789
3790 /* Check permission to call aggregate function */
3792 ACL_EXECUTE);
3793 if (aclresult != ACLCHECK_OK)
3795 get_func_name(aggref->aggfnoid));
3797
3798 /* planner recorded transition state type in the Aggref itself */
3799 aggtranstype = aggref->aggtranstype;
3800 Assert(OidIsValid(aggtranstype));
3801
3802 /* Final function only required if we're finalizing the aggregates */
3803 if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
3804 peragg->finalfn_oid = finalfn_oid = InvalidOid;
3805 else
3806 peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
3807
3808 serialfn_oid = InvalidOid;
3809 deserialfn_oid = InvalidOid;
3810
3811 /*
3812 * Check if serialization/deserialization is required. We only do it
3813 * for aggregates that have transtype INTERNAL.
3814 */
3815 if (aggtranstype == INTERNALOID)
3816 {
3817 /*
3818 * The planner should only have generated a serialize agg node if
3819 * every aggregate with an INTERNAL state has a serialization
3820 * function. Verify that.
3821 */
3822 if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
3823 {
3824 /* serialization only valid when not running finalfn */
3826
3827 if (!OidIsValid(aggform->aggserialfn))
3828 elog(ERROR, "serialfunc not provided for serialization aggregation");
3829 serialfn_oid = aggform->aggserialfn;
3830 }
3831
3832 /* Likewise for deserialization functions */
3833 if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
3834 {
3835 /* deserialization only valid when combining states */
3837
3838 if (!OidIsValid(aggform->aggdeserialfn))
3839 elog(ERROR, "deserialfunc not provided for deserialization aggregation");
3840 deserialfn_oid = aggform->aggdeserialfn;
3841 }
3842 }
3843
3844 /* Check that aggregate owner has permission to call component fns */
3845 {
3847
3849 ObjectIdGetDatum(aggref->aggfnoid));
3851 elog(ERROR, "cache lookup failed for function %u",
3852 aggref->aggfnoid);
3855
3856 if (OidIsValid(finalfn_oid))
3857 {
3859 ACL_EXECUTE);
3860 if (aclresult != ACLCHECK_OK)
3862 get_func_name(finalfn_oid));
3863 InvokeFunctionExecuteHook(finalfn_oid);
3864 }
3865 if (OidIsValid(serialfn_oid))
3866 {
3868 ACL_EXECUTE);
3869 if (aclresult != ACLCHECK_OK)
3871 get_func_name(serialfn_oid));
3872 InvokeFunctionExecuteHook(serialfn_oid);
3873 }
3874 if (OidIsValid(deserialfn_oid))
3875 {
3877 ACL_EXECUTE);
3878 if (aclresult != ACLCHECK_OK)
3880 get_func_name(deserialfn_oid));
3881 InvokeFunctionExecuteHook(deserialfn_oid);
3882 }
3883 }
3884
3885 /*
3886 * Get actual datatypes of the (nominal) aggregate inputs. These
3887 * could be different from the agg's declared input types, when the
3888 * agg accepts ANY or a polymorphic type.
3889 */
3892
3893 /* Count the "direct" arguments, if any */
3895
3896 /* Detect how many arguments to pass to the finalfn */
3897 if (aggform->aggfinalextra)
3898 peragg->numFinalArgs = numAggTransFnArgs + 1;
3899 else
3900 peragg->numFinalArgs = numDirectArgs + 1;
3901
3902 /* Initialize any direct-argument expressions */
3904 (PlanState *) aggstate);
3905
3906 /*
3907 * build expression trees using actual argument & result types for the
3908 * finalfn, if it exists and is required.
3909 */
3910 if (OidIsValid(finalfn_oid))
3911 {
3913 peragg->numFinalArgs,
3914 aggtranstype,
3915 aggref->aggtype,
3916 aggref->inputcollid,
3917 finalfn_oid,
3918 &finalfnexpr);
3919 fmgr_info(finalfn_oid, &peragg->finalfn);
3921 }
3922
3923 /* get info about the output value's datatype */
3924 get_typlenbyval(aggref->aggtype,
3925 &peragg->resulttypeLen,
3926 &peragg->resulttypeByVal);
3927
3928 /*
3929 * Build working state for invoking the transition function, if we
3930 * haven't done it already.
3931 */
3932 pertrans = &pertransstates[aggref->aggtransno];
3933 if (pertrans->aggref == NULL)
3934 {
3937 bool initValueIsNull;
3938 Oid transfn_oid;
3939
3940 /*
3941 * If this aggregation is performing state combines, then instead
3942 * of using the transition function, we'll use the combine
3943 * function.
3944 */
3945 if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3946 {
3947 transfn_oid = aggform->aggcombinefn;
3948
3949 /* If not set then the planner messed up */
3950 if (!OidIsValid(transfn_oid))
3951 elog(ERROR, "combinefn not set for aggregate function");
3952 }
3953 else
3954 transfn_oid = aggform->aggtransfn;
3955
3957 if (aclresult != ACLCHECK_OK)
3959 get_func_name(transfn_oid));
3960 InvokeFunctionExecuteHook(transfn_oid);
3961
3962 /*
3963 * initval is potentially null, so don't try to access it as a
3964 * struct field. Must do it the hard way with SysCacheGetAttr.
3965 */
3968 &initValueIsNull);
3969 if (initValueIsNull)
3970 initValue = (Datum) 0;
3971 else
3972 initValue = GetAggInitVal(textInitVal, aggtranstype);
3973
3974 if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3975 {
3976 Oid combineFnInputTypes[] = {aggtranstype,
3977 aggtranstype};
3978
3979 /*
3980 * When combining there's only one input, the to-be-combined
3981 * transition value. The transition value is not counted
3982 * here.
3983 */
3984 pertrans->numTransInputs = 1;
3985
3986 /* aggcombinefn always has two arguments of aggtranstype */
3987 build_pertrans_for_aggref(pertrans, aggstate, estate,
3988 aggref, transfn_oid, aggtranstype,
3989 serialfn_oid, deserialfn_oid,
3990 initValue, initValueIsNull,
3992
3993 /*
3994 * Ensure that a combine function to combine INTERNAL states
3995 * is not strict. This should have been checked during CREATE
3996 * AGGREGATE, but the strict property could have been changed
3997 * since then.
3998 */
3999 if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
4000 ereport(ERROR,
4002 errmsg("combine function with transition type %s must not be declared STRICT",
4003 format_type_be(aggtranstype))));
4004 }
4005 else
4006 {
4007 /* Detect how many arguments to pass to the transfn */
4008 if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4009 pertrans->numTransInputs = list_length(aggref->args);
4010 else
4012
4013 build_pertrans_for_aggref(pertrans, aggstate, estate,
4014 aggref, transfn_oid, aggtranstype,
4015 serialfn_oid, deserialfn_oid,
4016 initValue, initValueIsNull,
4019
4020 /*
4021 * If the transfn is strict and the initval is NULL, make sure
4022 * input type and transtype are the same (or at least
4023 * binary-compatible), so that it's OK to use the first
4024 * aggregated input value as the initial transValue. This
4025 * should have been checked at agg definition time, but we
4026 * must check again in case the transfn's strictness property
4027 * has been changed.
4028 */
4029 if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
4030 {
4033 aggtranstype))
4034 ereport(ERROR,
4036 errmsg("aggregate %u needs to have compatible input type and transition type",
4037 aggref->aggfnoid)));
4038 }
4039 }
4040 }
4041 else
4042 pertrans->aggshared = true;
4044 }
4045
4046 /*
4047 * Last, check whether any more aggregates got added onto the node while
4048 * we processed the expressions for the aggregate arguments (including not
4049 * only the regular arguments and FILTER expressions handled immediately
4050 * above, but any direct arguments we might've handled earlier). If so,
4051 * we have nested aggregate functions, which is semantically nonsensical,
4052 * so complain. (This should have been caught by the parser, so we don't
4053 * need to work hard on a helpful error message; but we defend against it
4054 * here anyway, just to be sure.)
4055 */
4056 if (numaggrefs != list_length(aggstate->aggs))
4057 ereport(ERROR,
4059 errmsg("aggregate function calls cannot be nested")));
4060
4061 /*
4062 * Build expressions doing all the transition work at once. We build a
4063 * different one for each phase, as the number of transition function
4064 * invocation can differ between phases. Note this'll work both for
4065 * transition and combination functions (although there'll only be one
4066 * phase in the latter case).
4067 */
4068 for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
4069 {
4070 AggStatePerPhase phase = &aggstate->phases[phaseidx];
4071 bool dohash = false;
4072 bool dosort = false;
4073
4074 /* phase 0 doesn't necessarily exist */
4075 if (!phase->aggnode)
4076 continue;
4077
4078 if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 1)
4079 {
4080 /*
4081 * Phase one, and only phase one, in a mixed agg performs both
4082 * sorting and aggregation.
4083 */
4084 dohash = true;
4085 dosort = true;
4086 }
4087 else if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 0)
4088 {
4089 /*
4090 * No need to compute a transition function for an AGG_MIXED phase
4091 * 0 - the contents of the hashtables will have been computed
4092 * during phase 1.
4093 */
4094 continue;
4095 }
4096 else if (phase->aggstrategy == AGG_PLAIN ||
4097 phase->aggstrategy == AGG_SORTED)
4098 {
4099 dohash = false;
4100 dosort = true;
4101 }
4102 else if (phase->aggstrategy == AGG_HASHED)
4103 {
4104 dohash = true;
4105 dosort = false;
4106 }
4107 else
4108 Assert(false);
4109
4111 false);
4112
4113 /* cache compiled expression for outer slot without NULL check */
4114 phase->evaltrans_cache[0][0] = phase->evaltrans;
4115 }
4116
4117 return aggstate;
4118}
AclResult
Definition acl.h:183
@ ACLCHECK_OK
Definition acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3879
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1290
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:901
int errcode(int sqlerrcode)
Definition elog.c:874
#define ereport(elevel,...)
Definition elog.h:150
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition execExpr.c:250
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition execExpr.c:356
ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash, bool nullcheck)
Definition execExpr.c:3704
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
const TupleTableSlotOps TTSOpsVirtual
Definition execTuples.c:84
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition execUtils.c:709
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition execUtils.c:490
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition execUtils.c:588
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition execUtils.c:509
#define EXEC_FLAG_BACKWARD
Definition executor.h:70
#define EXEC_FLAG_EXPLAIN_ONLY
Definition executor.h:67
#define EXEC_FLAG_MARK
Definition executor.h:71
#define palloc_array(type, count)
Definition fe_memutils.h:76
char * format_type_be(Oid type_oid)
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
int j
Definition isn.c:78
List * lcons_int(int datum, List *list)
Definition list.c:513
char * get_func_name(Oid funcid)
Definition lsyscache.c:1828
Oid GetUserId(void)
Definition miscinit.c:470
static void find_hash_columns(AggState *aggstate)
Definition nodeAgg.c:1569
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition nodeAgg.c:4380
Size hash_agg_entry_size(int numTrans, Size tupleWidth, Size transitionSpace)
Definition nodeAgg.c:1700
static void build_pertrans_for_aggref(AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid transfn_oid, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
Definition nodeAgg.c:4131
static TupleTableSlot * ExecAgg(PlanState *pstate)
Definition nodeAgg.c:2247
static void build_hash_tables(AggState *aggstate)
Definition nodeAgg.c:1467
static void hash_create_memory(AggState *aggstate)
Definition nodeAgg.c:1999
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition nodes.h:398
#define DO_AGGSPLIT_SERIALIZE(as)
Definition nodes.h:397
#define makeNode(_type_)
Definition nodes.h:161
static char * errmsg
#define InvokeFunctionExecuteHook(objectId)
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:2349
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition parse_agg.c:2112
bool IsBinaryCoercible(Oid srctype, Oid targettype)
@ OBJECT_AGGREGATE
@ OBJECT_FUNCTION
#define ACL_EXECUTE
Definition parsenodes.h:83
END_CATALOG_STRUCT typedef FormData_pg_aggregate * Form_pg_aggregate
#define FUNC_MAX_ARGS
#define list_nth_node(type, list, n)
Definition pg_list.h:327
END_CATALOG_STRUCT typedef FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:140
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
FmgrInfo finalfn
Definition nodeAgg.h:207
List * aggdirectargs
Definition nodeAgg.h:218
ExprState * evaltrans
Definition nodeAgg.h:291
ExprState * evaltrans_cache[2][2]
Definition nodeAgg.h:299
AggSplit aggsplit
Definition plannodes.h:1213
List * chain
Definition plannodes.h:1240
List * groupingSets
Definition plannodes.h:1237
Plan plan
Definition plannodes.h:1207
uint64 transitionSpace
Definition plannodes.h:1229
Oid aggfnoid
Definition primnodes.h:464
Datum * ecxt_aggvalues
Definition execnodes.h:303
bool * ecxt_aggnulls
Definition execnodes.h:305
List * qual
Definition plannodes.h:235
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, AggStatePerAggData::aggdirectargs, Aggref::aggdirectargs, Aggref::aggfnoid, AggStatePerPhaseData::aggnode, AggStatePerHashData::aggnode, AggStatePerTransData::aggref, AggStatePerAggData::aggref, AggStatePerTransData::aggshared, Agg::aggsplit, AggStatePerPhaseData::aggstrategy, Agg::aggstrategy, Aggref::args, Assert, bms_add_member(), bms_add_members(), bms_next_member(), build_aggregate_finalfn_expr(), build_hash_tables(), build_pertrans_for_aggref(), castNode, Agg::chain, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_DESERIALIZE, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, elog, ereport, errcode(), errmsg, ERROR, AggStatePerPhaseData::evaltrans, AggStatePerPhaseData::evaltrans_cache, EXEC_FLAG_BACKWARD, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_MARK, ExecAgg(), ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecBuildAggTrans(), ExecCreateScanSlotFromOuterPlan(), ExecGetResultSlotOps(), ExecInitExprList(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), execTuplesMatchPrepare(), fb(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, find_hash_columns(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_strict, Form_pg_aggregate, Form_pg_proc, format_type_be(), FUNC_MAX_ARGS, get_aggregate_argtypes(), get_func_name(), get_typlenbyval(), GetAggInitVal(), GETSTRUCT(), GetUserId(), Agg::groupingSets, hash_agg_entry_size(), hash_agg_set_limits(), hash_create_memory(), HeapTupleIsValid, i, initialize_phase(), initValue(), AggStatePerTransData::initValueIsNull, InvalidOid, InvokeFunctionExecuteHook, IsBinaryCoercible(), j, lcons_int(), lfirst, list_length(), list_nth_node, makeNode, Max, NIL, AggStatePerHashData::numCols, Agg::numCols, AggStatePerAggData::numFinalArgs, AggStatePerPhaseData::numsets, AggStatePerTransData::numTransInputs, object_aclcheck(), OBJECT_AGGREGATE, OBJECT_FUNCTION, ObjectIdGetDatum(), OidIsValid, outerPlan, outerPlanState, palloc(), palloc0_array, palloc_array, Agg::plan, Plan::qual, ReleaseSysCache(), AggStatePerAggData::resulttypeByVal, AggStatePerAggData::resulttypeLen, SearchSysCache1(), select_current_set(), SysCacheGetAttr(), AggStatePerTransData::transfn, Agg::transitionSpace, AggStatePerAggData::transno, TTSOpsMinimalTuple, and TTSOpsVirtual.

Referenced by ExecInitNode().

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 4462 of file nodeAgg.c.

4463{
4464 ExprContext *econtext = node->ss.ps.ps_ExprContext;
4466 Agg *aggnode = (Agg *) node->ss.ps.plan;
4467 int transno;
4468 int numGroupingSets = Max(node->maxsets, 1);
4469 int setno;
4470
4471 node->agg_done = false;
4472
4473 if (node->aggstrategy == AGG_HASHED)
4474 {
4475 /*
4476 * In the hashed case, if we haven't yet built the hash table then we
4477 * can just return; nothing done yet, so nothing to undo. If subnode's
4478 * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4479 * else no reason to re-scan it at all.
4480 */
4481 if (!node->table_filled)
4482 return;
4483
4484 /*
4485 * If we do have the hash table, and it never spilled, and the subplan
4486 * does not have any parameter changes, and none of our own parameter
4487 * changes affect input expressions of the aggregated functions, then
4488 * we can just rescan the existing hash table; no need to build it
4489 * again.
4490 */
4491 if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4492 !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4493 {
4495 &node->perhash[0].hashiter);
4496 select_current_set(node, 0, true);
4497 return;
4498 }
4499 }
4500
4501 /* Make sure we have closed any open tuplesorts */
4502 for (transno = 0; transno < node->numtrans; transno++)
4503 {
4504 for (setno = 0; setno < numGroupingSets; setno++)
4505 {
4506 AggStatePerTrans pertrans = &node->pertrans[transno];
4507
4508 if (pertrans->sortstates[setno])
4509 {
4510 tuplesort_end(pertrans->sortstates[setno]);
4511 pertrans->sortstates[setno] = NULL;
4512 }
4513 }
4514 }
4515
4516 /*
4517 * We don't need to ReScanExprContext the output tuple context here;
4518 * ExecReScan already did it. But we do need to reset our per-grouping-set
4519 * contexts, which may have transvalues stored in them. (We use rescan
4520 * rather than just reset because transfns may have registered callbacks
4521 * that need to be run now.) For the AGG_HASHED case, see below.
4522 */
4523
4524 for (setno = 0; setno < numGroupingSets; setno++)
4525 {
4526 ReScanExprContext(node->aggcontexts[setno]);
4527 }
4528
4529 /* Release first tuple of group, if we have made a copy */
4530 if (node->grp_firstTuple != NULL)
4531 {
4533 node->grp_firstTuple = NULL;
4534 }
4536
4537 /* Forget current agg values */
4538 MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4539 MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4540
4541 /*
4542 * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4543 * the hashcontext. This used to be an issue, but now, resetting a context
4544 * automatically deletes sub-contexts too.
4545 */
4546 if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4547 {
4549
4550 node->hash_ever_spilled = false;
4551 node->hash_spill_mode = false;
4552 node->hash_ngroups_current = 0;
4553
4555 /* Rebuild empty hash table(s) */
4556 build_hash_tables(node);
4557 node->table_filled = false;
4558 /* iterator will be reset when the table is filled */
4559
4560 hashagg_recompile_expressions(node, false, false);
4561 }
4562
4563 if (node->aggstrategy != AGG_HASHED)
4564 {
4565 /*
4566 * Reset the per-group state (in particular, mark transvalues null)
4567 */
4568 for (setno = 0; setno < numGroupingSets; setno++)
4569 {
4570 MemSet(node->pergroups[setno], 0,
4571 sizeof(AggStatePerGroupData) * node->numaggs);
4572 }
4573
4574 /* reset to phase 1 */
4575 initialize_phase(node, 1);
4576
4577 node->input_done = false;
4578 node->projected_set = -1;
4579 }
4580
4581 if (outerPlan->chgParam == NULL)
4583}
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:575
void ExecReScan(PlanState *node)
Definition execAmi.c:78
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1384
HeapTuple grp_firstTuple
Definition execnodes.h:2442
AggStrategy aggstrategy
Definition execnodes.h:2408
int projected_set
Definition execnodes.h:2425
bool input_done
Definition execnodes.h:2423
bool hash_spill_mode
Definition execnodes.h:2455
AggStatePerGroup * pergroups
Definition execnodes.h:2440
AggStatePerHash perhash
Definition execnodes.h:2468
uint64 hash_ngroups_current
Definition execnodes.h:2463
bool hash_ever_spilled
Definition execnodes.h:2454
int numaggs
Definition execnodes.h:2406
Bitmapset * chgParam
Definition execnodes.h:1209
ExprContext * ps_ExprContext
Definition execnodes.h:1216
TupleTableSlot * ss_ScanTupleSlot
Definition execnodes.h:1636

References AggState::agg_done, AGG_HASHED, AGG_MIXED, AggState::aggcontexts, Agg::aggParams, AggState::aggstrategy, bms_overlap(), build_hash_tables(), PlanState::chgParam, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecClearTuple(), ExecReScan(), fb(), AggState::grp_firstTuple, AggState::hash_ever_spilled, AggState::hash_ngroups_current, AggState::hash_spill_mode, hashagg_recompile_expressions(), hashagg_reset_spill_state(), AggState::hashcontext, AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, heap_freetuple(), initialize_phase(), AggState::input_done, Max, AggState::maxsets, MemSet, AggState::numaggs, AggState::numtrans, outerPlan, outerPlanState, AggState::pergroups, AggState::perhash, AggState::pertrans, PlanState::plan, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, ReScanExprContext(), ResetTupleHashIterator, select_current_set(), AggStatePerTransData::sortstates, AggState::ss, ScanState::ss_ScanTupleSlot, AggState::table_filled, and tuplesort_end().

Referenced by ExecReScan().

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

Definition at line 550 of file nodeAgg.c.

551{
552 TupleTableSlot *slot;
553
554 if (aggstate->sort_in)
555 {
556 /* make sure we check for interrupts in either path through here */
558 if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
559 aggstate->sort_slot, NULL))
560 return NULL;
561 slot = aggstate->sort_slot;
562 }
563 else
565
566 if (!TupIsNull(slot) && aggstate->sort_out)
567 tuplesort_puttupleslot(aggstate->sort_out, slot);
568
569 return slot;
570}
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition executor.h:315
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)

References CHECK_FOR_INTERRUPTS, ExecProcNode(), fb(), outerPlanState, TupIsNull, tuplesort_gettupleslot(), and tuplesort_puttupleslot().

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

◆ finalize_aggregate()

static void finalize_aggregate ( AggState aggstate,
AggStatePerAgg  peragg,
AggStatePerGroup  pergroupstate,
Datum resultVal,
bool resultIsNull 
)
static

Definition at line 1046 of file nodeAgg.c.

1050{
1051 LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
1052 bool anynull = false;
1054 int i;
1055 ListCell *lc;
1056 AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1057
1058 oldContext = MemoryContextSwitchTo(aggstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
1059
1060 /*
1061 * Evaluate any direct arguments. We do this even if there's no finalfn
1062 * (which is unlikely anyway), so that side-effects happen as expected.
1063 * The direct arguments go into arg positions 1 and up, leaving position 0
1064 * for the transition state value.
1065 */
1066 i = 1;
1067 foreach(lc, peragg->aggdirectargs)
1068 {
1069 ExprState *expr = (ExprState *) lfirst(lc);
1070
1071 fcinfo->args[i].value = ExecEvalExpr(expr,
1072 aggstate->ss.ps.ps_ExprContext,
1073 &fcinfo->args[i].isnull);
1074 anynull |= fcinfo->args[i].isnull;
1075 i++;
1076 }
1077
1078 /*
1079 * Apply the agg's finalfn if one is provided, else return transValue.
1080 */
1081 if (OidIsValid(peragg->finalfn_oid))
1082 {
1083 int numFinalArgs = peragg->numFinalArgs;
1084
1085 /* set up aggstate->curperagg for AggGetAggref() */
1086 aggstate->curperagg = peragg;
1087
1088 InitFunctionCallInfoData(*fcinfo, &peragg->finalfn,
1089 numFinalArgs,
1090 pertrans->aggCollation,
1091 (Node *) aggstate, NULL);
1092
1093 /* Fill in the transition state value */
1094 fcinfo->args[0].value =
1096 pergroupstate->transValueIsNull,
1097 pertrans->transtypeLen);
1098 fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
1099 anynull |= pergroupstate->transValueIsNull;
1100
1101 /* Fill any remaining argument positions with nulls */
1102 for (; i < numFinalArgs; i++)
1103 {
1104 fcinfo->args[i].value = (Datum) 0;
1105 fcinfo->args[i].isnull = true;
1106 anynull = true;
1107 }
1108
1109 if (fcinfo->flinfo->fn_strict && anynull)
1110 {
1111 /* don't call a strict function with NULL inputs */
1112 *resultVal = (Datum) 0;
1113 *resultIsNull = true;
1114 }
1115 else
1116 {
1117 Datum result;
1118
1119 result = FunctionCallInvoke(fcinfo);
1120 *resultIsNull = fcinfo->isnull;
1122 fcinfo->isnull,
1123 peragg->resulttypeLen);
1124 }
1125 aggstate->curperagg = NULL;
1126 }
1127 else
1128 {
1129 *resultVal =
1131 pergroupstate->transValueIsNull,
1132 pertrans->transtypeLen);
1133 *resultIsNull = pergroupstate->transValueIsNull;
1134 }
1135
1137}
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:396
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
#define LOCAL_FCINFO(name, nargs)
Definition fmgr.h:110

References AggStatePerTransData::aggCollation, AggStatePerAggData::aggdirectargs, ExecEvalExpr(), fb(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, FUNC_MAX_ARGS, FunctionCallInvoke, i, InitFunctionCallInfoData, lfirst, LOCAL_FCINFO, MakeExpandedObjectReadOnly, MemoryContextSwitchTo(), AggStatePerAggData::numFinalArgs, OidIsValid, AggStatePerAggData::resulttypeLen, AggStatePerAggData::transno, and AggStatePerTransData::transtypeLen.

Referenced by finalize_aggregates().

◆ finalize_aggregates()

static void finalize_aggregates ( AggState aggstate,
AggStatePerAgg  peraggs,
AggStatePerGroup  pergroup 
)
static

Definition at line 1294 of file nodeAgg.c.

1297{
1298 ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1299 Datum *aggvalues = econtext->ecxt_aggvalues;
1300 bool *aggnulls = econtext->ecxt_aggnulls;
1301 int aggno;
1302
1303 /*
1304 * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1305 * inputs and run the transition functions.
1306 */
1307 for (int transno = 0; transno < aggstate->numtrans; transno++)
1308 {
1309 AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1311
1312 pergroupstate = &pergroup[transno];
1313
1314 if (pertrans->aggsortrequired)
1315 {
1316 Assert(aggstate->aggstrategy != AGG_HASHED &&
1317 aggstate->aggstrategy != AGG_MIXED);
1318
1319 if (pertrans->numInputs == 1)
1321 pertrans,
1323 else
1325 pertrans,
1327 }
1328 else if (pertrans->numDistinctCols > 0 && pertrans->haslast)
1329 {
1330 pertrans->haslast = false;
1331
1332 if (pertrans->numDistinctCols == 1)
1333 {
1334 if (!pertrans->inputtypeByVal && !pertrans->lastisnull)
1335 pfree(DatumGetPointer(pertrans->lastdatum));
1336
1337 pertrans->lastisnull = false;
1338 pertrans->lastdatum = (Datum) 0;
1339 }
1340 else
1341 ExecClearTuple(pertrans->uniqslot);
1342 }
1343 }
1344
1345 /*
1346 * Run the final functions.
1347 */
1348 for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1349 {
1350 AggStatePerAgg peragg = &peraggs[aggno];
1351 int transno = peragg->transno;
1353
1354 pergroupstate = &pergroup[transno];
1355
1356 if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1358 &aggvalues[aggno], &aggnulls[aggno]);
1359 else
1361 &aggvalues[aggno], &aggnulls[aggno]);
1362 }
1363}
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition nodeAgg.c:949
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition nodeAgg.c:1046
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition nodeAgg.c:848
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition nodeAgg.c:1146

References AGG_HASHED, AGG_MIXED, AggStatePerTransData::aggsortrequired, Assert, DatumGetPointer(), DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecClearTuple(), fb(), finalize_aggregate(), finalize_partialaggregate(), AggStatePerTransData::haslast, AggStatePerTransData::inputtypeByVal, AggStatePerTransData::lastdatum, AggStatePerTransData::lastisnull, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numInputs, pfree(), process_ordered_aggregate_multi(), process_ordered_aggregate_single(), AggStatePerAggData::transno, and AggStatePerTransData::uniqslot.

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table_in_memory().

◆ finalize_partialaggregate()

static void finalize_partialaggregate ( AggState aggstate,
AggStatePerAgg  peragg,
AggStatePerGroup  pergroupstate,
Datum resultVal,
bool resultIsNull 
)
static

Definition at line 1146 of file nodeAgg.c.

1150{
1151 AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1153
1154 oldContext = MemoryContextSwitchTo(aggstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
1155
1156 /*
1157 * serialfn_oid will be set if we must serialize the transvalue before
1158 * returning it
1159 */
1160 if (OidIsValid(pertrans->serialfn_oid))
1161 {
1162 /* Don't call a strict serialization function with NULL input. */
1163 if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
1164 {
1165 *resultVal = (Datum) 0;
1166 *resultIsNull = true;
1167 }
1168 else
1169 {
1170 FunctionCallInfo fcinfo = pertrans->serialfn_fcinfo;
1171 Datum result;
1172
1173 fcinfo->args[0].value =
1175 pergroupstate->transValueIsNull,
1176 pertrans->transtypeLen);
1177 fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
1178 fcinfo->isnull = false;
1179
1180 result = FunctionCallInvoke(fcinfo);
1181 *resultIsNull = fcinfo->isnull;
1183 fcinfo->isnull,
1184 peragg->resulttypeLen);
1185 }
1186 }
1187 else
1188 {
1189 *resultVal =
1191 pergroupstate->transValueIsNull,
1192 pertrans->transtypeLen);
1193 *resultIsNull = pergroupstate->transValueIsNull;
1194 }
1195
1197}

References FunctionCallInfoBaseData::args, fb(), FmgrInfo::fn_strict, FunctionCallInvoke, FunctionCallInfoBaseData::isnull, NullableDatum::isnull, MakeExpandedObjectReadOnly, MemoryContextSwitchTo(), OidIsValid, AggStatePerAggData::resulttypeLen, AggStatePerTransData::serialfn, AggStatePerTransData::serialfn_fcinfo, AggStatePerTransData::serialfn_oid, AggStatePerAggData::transno, AggStatePerTransData::transtypeLen, and NullableDatum::value.

Referenced by finalize_aggregates().

◆ find_cols()

static void find_cols ( AggState aggstate,
Bitmapset **  aggregated,
Bitmapset **  unaggregated 
)
static

Definition at line 1397 of file nodeAgg.c.

1398{
1399 Agg *agg = (Agg *) aggstate->ss.ps.plan;
1400 FindColsContext context;
1401
1402 context.is_aggref = false;
1403 context.aggregated = NULL;
1404 context.unaggregated = NULL;
1405
1406 /* Examine tlist and quals */
1407 (void) find_cols_walker((Node *) agg->plan.targetlist, &context);
1408 (void) find_cols_walker((Node *) agg->plan.qual, &context);
1409
1410 /* In some cases, grouping columns will not appear in the tlist */
1411 for (int i = 0; i < agg->numCols; i++)
1412 context.unaggregated = bms_add_member(context.unaggregated,
1413 agg->grpColIdx[i]);
1414
1415 *aggregated = context.aggregated;
1416 *unaggregated = context.unaggregated;
1417}
static bool find_cols_walker(Node *node, FindColsContext *context)
Definition nodeAgg.c:1420
Bitmapset * aggregated
Definition nodeAgg.c:365
Bitmapset * unaggregated
Definition nodeAgg.c:366

References FindColsContext::aggregated, bms_add_member(), fb(), find_cols_walker(), i, FindColsContext::is_aggref, Agg::plan, and FindColsContext::unaggregated.

Referenced by find_hash_columns().

◆ find_cols_walker()

static bool find_cols_walker ( Node node,
FindColsContext context 
)
static

Definition at line 1420 of file nodeAgg.c.

1421{
1422 if (node == NULL)
1423 return false;
1424 if (IsA(node, Var))
1425 {
1426 Var *var = (Var *) node;
1427
1428 /* setrefs.c should have set the varno to OUTER_VAR */
1429 Assert(var->varno == OUTER_VAR);
1430 Assert(var->varlevelsup == 0);
1431 if (context->is_aggref)
1432 context->aggregated = bms_add_member(context->aggregated,
1433 var->varattno);
1434 else
1435 context->unaggregated = bms_add_member(context->unaggregated,
1436 var->varattno);
1437 return false;
1438 }
1439 if (IsA(node, Aggref))
1440 {
1441 Assert(!context->is_aggref);
1442 context->is_aggref = true;
1444 context->is_aggref = false;
1445 return false;
1446 }
1447 return expression_tree_walker(node, find_cols_walker, context);
1448}
#define expression_tree_walker(n, w, c)
Definition nodeFuncs.h:153
#define OUTER_VAR
Definition primnodes.h:244
AttrNumber varattno
Definition primnodes.h:275
int varno
Definition primnodes.h:270
Index varlevelsup
Definition primnodes.h:295

References FindColsContext::aggregated, Assert, bms_add_member(), expression_tree_walker, fb(), find_cols_walker(), FindColsContext::is_aggref, IsA, OUTER_VAR, FindColsContext::unaggregated, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by find_cols(), and find_cols_walker().

◆ find_hash_columns()

static void find_hash_columns ( AggState aggstate)
static

Definition at line 1569 of file nodeAgg.c.

1570{
1573 TupleDesc scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
1574 List *outerTlist = outerPlanState(aggstate)->plan->targetlist;
1575 int numHashes = aggstate->num_hashes;
1576 EState *estate = aggstate->ss.ps.state;
1577 int j;
1578
1579 /* Find Vars that will be needed in tlist and qual */
1582 aggstate->max_colno_needed = 0;
1583 aggstate->all_cols_needed = true;
1584
1585 for (int i = 0; i < scanDesc->natts; i++)
1586 {
1587 int colno = i + 1;
1588
1589 if (bms_is_member(colno, aggstate->colnos_needed))
1590 aggstate->max_colno_needed = colno;
1591 else
1592 aggstate->all_cols_needed = false;
1593 }
1594
1595 for (j = 0; j < numHashes; ++j)
1596 {
1597 AggStatePerHash perhash = &aggstate->perhash[j];
1599 AttrNumber *grpColIdx = perhash->aggnode->grpColIdx;
1600 List *hashTlist = NIL;
1602 int maxCols;
1603 int i;
1604
1605 perhash->largestGrpColIdx = 0;
1606
1607 /*
1608 * If we're doing grouping sets, then some Vars might be referenced in
1609 * tlist/qual for the benefit of other grouping sets, but not needed
1610 * when hashing; i.e. prepare_projection_slot will null them out, so
1611 * there'd be no point storing them. Use prepare_projection_slot's
1612 * logic to determine which.
1613 */
1614 if (aggstate->phases[0].grouped_cols)
1615 {
1616 Bitmapset *grouped_cols = aggstate->phases[0].grouped_cols[j];
1617 ListCell *lc;
1618
1619 foreach(lc, aggstate->all_grouped_cols)
1620 {
1621 int attnum = lfirst_int(lc);
1622
1623 if (!bms_is_member(attnum, grouped_cols))
1625 }
1626 }
1627
1628 /*
1629 * Compute maximum number of input columns accounting for possible
1630 * duplications in the grpColIdx array, which can happen in some edge
1631 * cases where HashAggregate was generated as part of a semijoin or a
1632 * DISTINCT.
1633 */
1634 maxCols = bms_num_members(colnos) + perhash->numCols;
1635
1636 perhash->hashGrpColIdxInput =
1637 palloc(maxCols * sizeof(AttrNumber));
1638 perhash->hashGrpColIdxHash =
1639 palloc(perhash->numCols * sizeof(AttrNumber));
1640
1641 /* Add all the grouping columns to colnos */
1642 for (i = 0; i < perhash->numCols; i++)
1644
1645 /*
1646 * First build mapping for columns directly hashed. These are the
1647 * first, because they'll be accessed when computing hash values and
1648 * comparing tuples for exact matches. We also build simple mapping
1649 * for execGrouping, so it knows where to find the to-be-hashed /
1650 * compared columns in the input.
1651 */
1652 for (i = 0; i < perhash->numCols; i++)
1653 {
1654 perhash->hashGrpColIdxInput[i] = grpColIdx[i];
1655 perhash->hashGrpColIdxHash[i] = i + 1;
1656 perhash->numhashGrpCols++;
1657 /* delete already mapped columns */
1659 }
1660
1661 /* and add the remaining columns */
1662 i = -1;
1663 while ((i = bms_next_member(colnos, i)) >= 0)
1664 {
1665 perhash->hashGrpColIdxInput[perhash->numhashGrpCols] = i;
1666 perhash->numhashGrpCols++;
1667 }
1668
1669 /* and build a tuple descriptor for the hashtable */
1670 for (i = 0; i < perhash->numhashGrpCols; i++)
1671 {
1672 int varNumber = perhash->hashGrpColIdxInput[i] - 1;
1673
1675 perhash->largestGrpColIdx =
1676 Max(varNumber + 1, perhash->largestGrpColIdx);
1677 }
1678
1680
1682 perhash->aggnode->grpOperators,
1683 &perhash->eqfuncoids,
1684 &perhash->hashfunctions);
1685 perhash->hashslot =
1687 &TTSOpsMinimalTuple, 0);
1688
1691 }
1692
1694}
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition bitmapset.c:852
void bms_free(Bitmapset *a)
Definition bitmapset.c:239
int bms_num_members(const Bitmapset *a)
Definition bitmapset.c:744
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:251
Bitmapset * bms_copy(const Bitmapset *a)
Definition bitmapset.c:122
void execTuplesHashPrepare(int numCols, const Oid *eqOperators, Oid **eqFuncOids, FmgrInfo **hashFunctions)
TupleTableSlot * ExecAllocTableSlot(List **tupleTable, TupleDesc desc, const TupleTableSlotOps *tts_ops, uint16 flags)
List * lappend(List *list, void *datum)
Definition list.c:339
void list_free(List *list)
Definition list.c:1546
static void find_cols(AggState *aggstate, Bitmapset **aggregated, Bitmapset **unaggregated)
Definition nodeAgg.c:1397
int16 attnum
#define lfirst_int(lc)
Definition pg_list.h:173
static void * list_nth(const List *list, int n)
Definition pg_list.h:299
List * es_tupleTable
Definition execnodes.h:724

References AggStatePerHashData::aggnode, attnum, bms_add_member(), bms_copy(), bms_del_member(), bms_free(), bms_is_member(), bms_next_member(), bms_num_members(), bms_union(), AggStatePerHashData::eqfuncoids, EState::es_tupleTable, ExecAllocTableSlot(), execTuplesHashPrepare(), ExecTypeFromTL(), fb(), find_cols(), AggStatePerHashData::hashfunctions, AggStatePerHashData::hashGrpColIdxHash, AggStatePerHashData::hashGrpColIdxInput, AggStatePerHashData::hashslot, i, j, lappend(), AggStatePerHashData::largestGrpColIdx, lfirst_int, list_free(), list_nth(), Max, NIL, AggStatePerHashData::numCols, AggStatePerHashData::numhashGrpCols, outerPlanState, palloc(), and TTSOpsMinimalTuple.

Referenced by ExecInitAgg().

◆ GetAggInitVal()

static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 4380 of file nodeAgg.c.

4381{
4382 Oid typinput,
4383 typioparam;
4384 char *strInitVal;
4385 Datum initVal;
4386
4387 getTypeInputInfo(transtype, &typinput, &typioparam);
4390 typioparam, -1);
4392 return initVal;
4393}
#define TextDatumGetCString(d)
Definition builtins.h:99
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition fmgr.c:1755
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition lsyscache.c:3096

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

Referenced by ExecInitAgg().

◆ hash_agg_check_limits()

static void hash_agg_check_limits ( AggState aggstate)
static

Definition at line 1866 of file nodeAgg.c.

1867{
1868 uint64 ngroups = aggstate->hash_ngroups_current;
1870 true);
1872 true);
1873 Size tval_mem = MemoryContextMemAllocated(aggstate->hashcontext->ecxt_per_tuple_memory,
1874 true);
1876 bool do_spill = false;
1877
1878#ifdef USE_INJECTION_POINTS
1879 if (ngroups >= 1000)
1880 {
1881 if (IS_INJECTION_POINT_ATTACHED("hash-aggregate-spill-1000"))
1882 {
1883 do_spill = true;
1884 INJECTION_POINT_CACHED("hash-aggregate-spill-1000", NULL);
1885 }
1886 }
1887#endif
1888
1889 /*
1890 * Don't spill unless there's at least one group in the hash table so we
1891 * can be sure to make progress even in edge cases.
1892 */
1893 if (aggstate->hash_ngroups_current > 0 &&
1894 (total_mem > aggstate->hash_mem_limit ||
1895 ngroups > aggstate->hash_ngroups_limit))
1896 {
1897 do_spill = true;
1898 }
1899
1900 if (do_spill)
1902}
uint64_t uint64
Definition c.h:619
Size MemoryContextMemAllocated(MemoryContext context, bool recurse)
Definition mcxt.c:811
static void hash_agg_enter_spill_mode(AggState *aggstate)
Definition nodeAgg.c:1910

References fb(), hash_agg_enter_spill_mode(), INJECTION_POINT_CACHED, IS_INJECTION_POINT_ATTACHED, and MemoryContextMemAllocated().

Referenced by initialize_hash_entry().

◆ hash_agg_enter_spill_mode()

static void hash_agg_enter_spill_mode ( AggState aggstate)
static

Definition at line 1910 of file nodeAgg.c.

1911{
1912 INJECTION_POINT("hash-aggregate-enter-spill-mode", NULL);
1913 aggstate->hash_spill_mode = true;
1914 hashagg_recompile_expressions(aggstate, aggstate->table_filled, true);
1915
1916 if (!aggstate->hash_ever_spilled)
1917 {
1918 Assert(aggstate->hash_tapeset == NULL);
1919 Assert(aggstate->hash_spills == NULL);
1920
1921 aggstate->hash_ever_spilled = true;
1922
1923 aggstate->hash_tapeset = LogicalTapeSetCreate(true, NULL, -1);
1924
1925 aggstate->hash_spills = palloc_array(HashAggSpill, aggstate->num_hashes);
1926
1927 for (int setno = 0; setno < aggstate->num_hashes; setno++)
1928 {
1929 AggStatePerHash perhash = &aggstate->perhash[setno];
1930 HashAggSpill *spill = &aggstate->hash_spills[setno];
1931
1932 hashagg_spill_init(spill, aggstate->hash_tapeset, 0,
1933 perhash->aggnode->numGroups,
1934 aggstate->hashentrysize);
1935 }
1936 }
1937}
LogicalTapeSet * LogicalTapeSetCreate(bool preallocate, SharedFileSet *fileset, int worker)
Definition logtape.c:556

References AggStatePerHashData::aggnode, Assert, fb(), hashagg_recompile_expressions(), hashagg_spill_init(), INJECTION_POINT, LogicalTapeSetCreate(), Agg::numGroups, and palloc_array.

Referenced by hash_agg_check_limits().

◆ hash_agg_entry_size()

Size hash_agg_entry_size ( int  numTrans,
Size  tupleWidth,
Size  transitionSpace 
)

Definition at line 1700 of file nodeAgg.c.

1701{
1706 tupleWidth);
1708
1709 /*
1710 * Entries use the Bump allocator, so the chunk sizes are the same as the
1711 * requested sizes.
1712 */
1715
1716 /*
1717 * Transition values use AllocSet, which has a chunk header and also uses
1718 * power-of-two allocations.
1719 */
1720 if (transitionSpace > 0)
1722 else
1724
1725 return
1730}
#define MAXALIGN(LEN)
Definition c.h:898
#define SizeofMinimalTupleHeader
#define CHUNKHDRSZ
Definition nodeAgg.c:322
#define pg_nextpower2_size_t

References CHUNKHDRSZ, fb(), MAXALIGN, pg_nextpower2_size_t, SizeofMinimalTupleHeader, and TupleHashEntrySize().

Referenced by cost_agg(), estimate_hashagg_tablesize(), and ExecInitAgg().

◆ hash_agg_set_limits()

void hash_agg_set_limits ( double  hashentrysize,
double  input_groups,
int  used_bits,
Size mem_limit,
uint64 ngroups_limit,
int num_partitions 
)

Definition at line 1808 of file nodeAgg.c.

1811{
1812 int npartitions;
1814 Size hash_mem_limit = get_hash_memory_limit();
1815
1816 /* if not expected to spill, use all of hash_mem */
1817 if (input_groups * hashentrysize <= hash_mem_limit)
1818 {
1819 if (num_partitions != NULL)
1820 *num_partitions = 0;
1821 *mem_limit = hash_mem_limit;
1822 *ngroups_limit = hash_mem_limit / hashentrysize;
1823 return;
1824 }
1825
1826 /*
1827 * Calculate expected memory requirements for spilling, which is the size
1828 * of the buffers needed for all the tapes that need to be open at once.
1829 * Then, subtract that from the memory available for holding hash tables.
1830 */
1832 hashentrysize,
1833 used_bits,
1834 NULL);
1835 if (num_partitions != NULL)
1836 *num_partitions = npartitions;
1837
1840 HASHAGG_WRITE_BUFFER_SIZE * npartitions;
1841
1842 /*
1843 * Don't set the limit below 3/4 of hash_mem. In that case, we are at the
1844 * minimum number of partitions, so we aren't going to dramatically exceed
1845 * work mem anyway.
1846 */
1847 if (hash_mem_limit > 4 * partition_mem)
1848 *mem_limit = hash_mem_limit - partition_mem;
1849 else
1850 *mem_limit = hash_mem_limit * 0.75;
1851
1852 if (*mem_limit > hashentrysize)
1853 *ngroups_limit = *mem_limit / hashentrysize;
1854 else
1855 *ngroups_limit = 1;
1856}
#define HASHAGG_READ_BUFFER_SIZE
Definition nodeAgg.c:308
#define HASHAGG_WRITE_BUFFER_SIZE
Definition nodeAgg.c:309
static int hash_choose_num_partitions(double input_groups, double hashentrysize, int used_bits, int *log2_npartitions)
Definition nodeAgg.c:2086
size_t get_hash_memory_limit(void)
Definition nodeHash.c:3680

References fb(), get_hash_memory_limit(), hash_choose_num_partitions(), HASHAGG_READ_BUFFER_SIZE, and HASHAGG_WRITE_BUFFER_SIZE.

Referenced by agg_refill_hash_table(), cost_agg(), and ExecInitAgg().

◆ hash_agg_update_metrics()

static void hash_agg_update_metrics ( AggState aggstate,
bool  from_tape,
int  npartitions 
)
static

Definition at line 1946 of file nodeAgg.c.

1947{
1948 Size meta_mem;
1953
1954 if (aggstate->aggstrategy != AGG_MIXED &&
1955 aggstate->aggstrategy != AGG_HASHED)
1956 return;
1957
1958 /* memory for the hash table itself */
1959 meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt, true);
1960
1961 /* memory for hash entries */
1962 entry_mem = MemoryContextMemAllocated(aggstate->hash_tuplescxt, true);
1963
1964 /* memory for byref transition states */
1965 hashkey_mem = MemoryContextMemAllocated(aggstate->hashcontext->ecxt_per_tuple_memory, true);
1966
1967 /* memory for read/write tape buffers, if spilled */
1968 buffer_mem = npartitions * HASHAGG_WRITE_BUFFER_SIZE;
1969 if (from_tape)
1971
1972 /* update peak mem */
1974 if (total_mem > aggstate->hash_mem_peak)
1975 aggstate->hash_mem_peak = total_mem;
1976
1977 /* update disk usage */
1978 if (aggstate->hash_tapeset != NULL)
1979 {
1980 uint64 disk_used = LogicalTapeSetBlocks(aggstate->hash_tapeset) * (BLCKSZ / 1024);
1981
1982 if (aggstate->hash_disk_used < disk_used)
1983 aggstate->hash_disk_used = disk_used;
1984 }
1985
1986 /* update hashentrysize estimate based on contents */
1987 if (aggstate->hash_ngroups_current > 0)
1988 {
1989 aggstate->hashentrysize =
1991 (hashkey_mem / (double) aggstate->hash_ngroups_current);
1992 }
1993}
int64 LogicalTapeSetBlocks(LogicalTapeSet *lts)
Definition logtape.c:1181

References AGG_HASHED, AGG_MIXED, fb(), HASHAGG_READ_BUFFER_SIZE, HASHAGG_WRITE_BUFFER_SIZE, LogicalTapeSetBlocks(), MemoryContextMemAllocated(), and TupleHashEntrySize().

Referenced by agg_refill_hash_table(), and hashagg_finish_initial_spills().

◆ hash_choose_num_buckets()

static double hash_choose_num_buckets ( double  hashentrysize,
double  ngroups,
Size  memory 
)
static

Definition at line 2057 of file nodeAgg.c.

2058{
2059 double max_nbuckets;
2060 double nbuckets = ngroups;
2061
2062 max_nbuckets = memory / hashentrysize;
2063
2064 /*
2065 * Underestimating is better than overestimating. Too many buckets crowd
2066 * out space for group keys and transition state values.
2067 */
2068 max_nbuckets /= 2;
2069
2070 if (nbuckets > max_nbuckets)
2071 nbuckets = max_nbuckets;
2072
2073 /*
2074 * BuildTupleHashTable will clamp any obviously-insane result, so we don't
2075 * need to be too careful here.
2076 */
2077 return nbuckets;
2078}

References fb().

Referenced by build_hash_tables().

◆ hash_choose_num_partitions()

static int hash_choose_num_partitions ( double  input_groups,
double  hashentrysize,
int  used_bits,
int log2_npartitions 
)
static

Definition at line 2086 of file nodeAgg.c.

2088{
2089 Size hash_mem_limit = get_hash_memory_limit();
2090 double partition_limit;
2091 double mem_wanted;
2092 double dpartitions;
2093 int npartitions;
2094 int partition_bits;
2095
2096 /*
2097 * Avoid creating so many partitions that the memory requirements of the
2098 * open partition files are greater than 1/4 of hash_mem.
2099 */
2101 (hash_mem_limit * 0.25 - HASHAGG_READ_BUFFER_SIZE) /
2103
2105
2106 /* make enough partitions so that each one is likely to fit in memory */
2107 dpartitions = 1 + (mem_wanted / hash_mem_limit);
2108
2111
2116
2117 /* HASHAGG_MAX_PARTITIONS limit makes this safe */
2118 npartitions = (int) dpartitions;
2119
2120 /* ceil(log2(npartitions)) */
2121 partition_bits = pg_ceil_log2_32(npartitions);
2122
2123 /* make sure that we don't exhaust the hash bits */
2124 if (partition_bits + used_bits >= 32)
2125 partition_bits = 32 - used_bits;
2126
2127 if (log2_npartitions != NULL)
2129
2130 /* number of partitions will be a power of two */
2131 npartitions = 1 << partition_bits;
2132
2133 return npartitions;
2134}
#define HASHAGG_MAX_PARTITIONS
Definition nodeAgg.c:300
#define HASHAGG_MIN_PARTITIONS
Definition nodeAgg.c:299
#define HASHAGG_PARTITION_FACTOR
Definition nodeAgg.c:298
static uint32 pg_ceil_log2_32(uint32 num)

References fb(), get_hash_memory_limit(), HASHAGG_MAX_PARTITIONS, HASHAGG_MIN_PARTITIONS, HASHAGG_PARTITION_FACTOR, HASHAGG_READ_BUFFER_SIZE, HASHAGG_WRITE_BUFFER_SIZE, and pg_ceil_log2_32().

Referenced by hash_agg_set_limits(), and hashagg_spill_init().

◆ hash_create_memory()

static void hash_create_memory ( AggState aggstate)
static

Definition at line 1999 of file nodeAgg.c.

2000{
2001 Size maxBlockSize = ALLOCSET_DEFAULT_MAXSIZE;
2002
2003 /*
2004 * The hashcontext's per-tuple memory will be used for byref transition
2005 * values and returned by AggCheckCallContext().
2006 */
2007 aggstate->hashcontext = CreateWorkExprContext(aggstate->ss.ps.state);
2008
2009 /*
2010 * The meta context will be used for the bucket array of
2011 * TupleHashEntryData (or arrays, in the case of grouping sets). As the
2012 * hash table grows, the bucket array will double in size and the old one
2013 * will be freed, so an AllocSet is appropriate. For large bucket arrays,
2014 * the large allocation path will be used, so it's not worth worrying
2015 * about wasting space due to power-of-two allocations.
2016 */
2017 aggstate->hash_metacxt = AllocSetContextCreate(aggstate->ss.ps.state->es_query_cxt,
2018 "HashAgg meta context",
2020
2021 /*
2022 * The hash entries themselves, which include the grouping key
2023 * (firstTuple) and pergroup data, are stored in the table context. The
2024 * bump allocator can be used because the entries are not freed until the
2025 * entire hash table is reset. The bump allocator is faster for
2026 * allocations and avoids wasting space on the chunk header or
2027 * power-of-two allocations.
2028 *
2029 * Like CreateWorkExprContext(), use smaller sizings for smaller work_mem,
2030 * to avoid large jumps in memory usage.
2031 */
2032
2033 /*
2034 * Like CreateWorkExprContext(), use smaller sizings for smaller work_mem,
2035 * to avoid large jumps in memory usage.
2036 */
2037 maxBlockSize = pg_prevpower2_size_t(work_mem * (Size) 1024 / 16);
2038
2039 /* But no bigger than ALLOCSET_DEFAULT_MAXSIZE */
2040 maxBlockSize = Min(maxBlockSize, ALLOCSET_DEFAULT_MAXSIZE);
2041
2042 /* and no smaller than ALLOCSET_DEFAULT_INITSIZE */
2043 maxBlockSize = Max(maxBlockSize, ALLOCSET_DEFAULT_INITSIZE);
2044
2045 aggstate->hash_tuplescxt = BumpContextCreate(aggstate->ss.ps.state->es_query_cxt,
2046 "HashAgg hashed tuples",
2049 maxBlockSize);
2050
2051}
MemoryContext BumpContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition bump.c:133
#define Min(x, y)
Definition c.h:1093
ExprContext * CreateWorkExprContext(EState *estate)
Definition execUtils.c:327
int work_mem
Definition globals.c:131
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_MAXSIZE
Definition memutils.h:159
#define ALLOCSET_DEFAULT_MINSIZE
Definition memutils.h:157
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define ALLOCSET_DEFAULT_INITSIZE
Definition memutils.h:158
#define pg_prevpower2_size_t

References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, BumpContextCreate(), CreateWorkExprContext(), fb(), Max, Min, pg_prevpower2_size_t, and work_mem.

Referenced by ExecInitAgg().

◆ hashagg_batch_new()

static HashAggBatch * hashagg_batch_new ( LogicalTape input_tape,
int  setno,
int64  input_tuples,
double  input_card,
int  used_bits 
)
static

Definition at line 3099 of file nodeAgg.c.

3101{
3103
3104 batch->setno = setno;
3105 batch->used_bits = used_bits;
3106 batch->input_tape = input_tape;
3107 batch->input_tuples = input_tuples;
3108 batch->input_card = input_card;
3109
3110 return batch;
3111}
#define palloc0_object(type)
Definition fe_memutils.h:75

References fb(), and palloc0_object.

Referenced by hashagg_spill_finish().

◆ hashagg_batch_read()

static MinimalTuple hashagg_batch_read ( HashAggBatch batch,
uint32 hashp 
)
static

Definition at line 3118 of file nodeAgg.c.

3119{
3120 LogicalTape *tape = batch->input_tape;
3121 MinimalTuple tuple;
3122 uint32 t_len;
3123 size_t nread;
3124 uint32 hash;
3125
3126 nread = LogicalTapeRead(tape, &hash, sizeof(uint32));
3127 if (nread == 0)
3128 return NULL;
3129 if (nread != sizeof(uint32))
3130 ereport(ERROR,
3132 errmsg_internal("unexpected EOF for tape %p: requested %zu bytes, read %zu bytes",
3133 tape, sizeof(uint32), nread)));
3134 if (hashp != NULL)
3135 *hashp = hash;
3136
3137 nread = LogicalTapeRead(tape, &t_len, sizeof(t_len));
3138 if (nread != sizeof(uint32))
3139 ereport(ERROR,
3141 errmsg_internal("unexpected EOF for tape %p: requested %zu bytes, read %zu bytes",
3142 tape, sizeof(uint32), nread)));
3143
3144 tuple = (MinimalTuple) palloc(t_len);
3145 tuple->t_len = t_len;
3146
3148 (char *) tuple + sizeof(uint32),
3149 t_len - sizeof(uint32));
3150 if (nread != t_len - sizeof(uint32))
3151 ereport(ERROR,
3153 errmsg_internal("unexpected EOF for tape %p: requested %zu bytes, read %zu bytes",
3154 tape, t_len - sizeof(uint32), nread)));
3155
3156 return tuple;
3157}
int errcode_for_file_access(void)
Definition elog.c:897
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
MinimalTupleData * MinimalTuple
Definition htup.h:27
size_t LogicalTapeRead(LogicalTape *lt, void *ptr, size_t size)
Definition logtape.c:928

References ereport, errcode_for_file_access(), errmsg_internal(), ERROR, fb(), hash(), LogicalTapeRead(), palloc(), and MinimalTupleData::t_len.

Referenced by agg_refill_hash_table().

◆ hashagg_finish_initial_spills()

static void hashagg_finish_initial_spills ( AggState aggstate)
static

Definition at line 3167 of file nodeAgg.c.

3168{
3169 int setno;
3170 int total_npartitions = 0;
3171
3172 if (aggstate->hash_spills != NULL)
3173 {
3174 for (setno = 0; setno < aggstate->num_hashes; setno++)
3175 {
3176 HashAggSpill *spill = &aggstate->hash_spills[setno];
3177
3180 }
3181
3182 /*
3183 * We're not processing tuples from outer plan any more; only
3184 * processing batches of spilled tuples. The initial spill structures
3185 * are no longer needed.
3186 */
3187 pfree(aggstate->hash_spills);
3188 aggstate->hash_spills = NULL;
3189 }
3190
3192 aggstate->hash_spill_mode = false;
3193}
int npartitions
Definition nodeAgg.c:335

References fb(), hash_agg_update_metrics(), hashagg_spill_finish(), HashAggSpill::npartitions, and pfree().

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

◆ hashagg_recompile_expressions()

static void hashagg_recompile_expressions ( AggState aggstate,
bool  minslot,
bool  nullcheck 
)
static

Definition at line 1751 of file nodeAgg.c.

1752{
1753 AggStatePerPhase phase;
1754 int i = minslot ? 1 : 0;
1755 int j = nullcheck ? 1 : 0;
1756
1757 Assert(aggstate->aggstrategy == AGG_HASHED ||
1758 aggstate->aggstrategy == AGG_MIXED);
1759
1760 if (aggstate->aggstrategy == AGG_HASHED)
1761 phase = &aggstate->phases[0];
1762 else /* AGG_MIXED */
1763 phase = &aggstate->phases[1];
1764
1765 if (phase->evaltrans_cache[i][j] == NULL)
1766 {
1767 const TupleTableSlotOps *outerops = aggstate->ss.ps.outerops;
1768 bool outerfixed = aggstate->ss.ps.outeropsfixed;
1769 bool dohash = true;
1770 bool dosort = false;
1771
1772 /*
1773 * If minslot is true, that means we are processing a spilled batch
1774 * (inside agg_refill_hash_table()), and we must not advance the
1775 * sorted grouping sets.
1776 */
1777 if (aggstate->aggstrategy == AGG_MIXED && !minslot)
1778 dosort = true;
1779
1780 /* temporarily change the outerops while compiling the expression */
1781 if (minslot)
1782 {
1783 aggstate->ss.ps.outerops = &TTSOpsMinimalTuple;
1784 aggstate->ss.ps.outeropsfixed = true;
1785 }
1786
1787 phase->evaltrans_cache[i][j] = ExecBuildAggTrans(aggstate, phase,
1788 dosort, dohash,
1789 nullcheck);
1790
1791 /* change back */
1792 aggstate->ss.ps.outerops = outerops;
1793 aggstate->ss.ps.outeropsfixed = outerfixed;
1794 }
1795
1796 phase->evaltrans = phase->evaltrans_cache[i][j];
1797}

References AGG_HASHED, AGG_MIXED, Assert, AggStatePerPhaseData::evaltrans, AggStatePerPhaseData::evaltrans_cache, ExecBuildAggTrans(), fb(), i, j, and TTSOpsMinimalTuple.

Referenced by agg_refill_hash_table(), ExecReScanAgg(), and hash_agg_enter_spill_mode().

◆ hashagg_reset_spill_state()

static void hashagg_reset_spill_state ( AggState aggstate)
static

Definition at line 3241 of file nodeAgg.c.

3242{
3243 /* free spills from initial pass */
3244 if (aggstate->hash_spills != NULL)
3245 {
3246 int setno;
3247
3248 for (setno = 0; setno < aggstate->num_hashes; setno++)
3249 {
3250 HashAggSpill *spill = &aggstate->hash_spills[setno];
3251
3252 pfree(spill->ntuples);
3253 pfree(spill->partitions);
3254 }
3255 pfree(aggstate->hash_spills);
3256 aggstate->hash_spills = NULL;
3257 }
3258
3259 /* free batches */
3260 list_free_deep(aggstate->hash_batches);
3261 aggstate->hash_batches = NIL;
3262
3263 /* close tape set */
3264 if (aggstate->hash_tapeset != NULL)
3265 {
3266 LogicalTapeSetClose(aggstate->hash_tapeset);
3267 aggstate->hash_tapeset = NULL;
3268 }
3269}
void list_free_deep(List *list)
Definition list.c:1560
void LogicalTapeSetClose(LogicalTapeSet *lts)
Definition logtape.c:667

References fb(), list_free_deep(), LogicalTapeSetClose(), NIL, and pfree().

Referenced by ExecEndAgg(), and ExecReScanAgg().

◆ hashagg_spill_finish()

static void hashagg_spill_finish ( AggState aggstate,
HashAggSpill spill,
int  setno 
)
static

Definition at line 3201 of file nodeAgg.c.

3202{
3203 int i;
3204 int used_bits = 32 - spill->shift;
3205
3206 if (spill->npartitions == 0)
3207 return; /* didn't spill */
3208
3209 for (i = 0; i < spill->npartitions; i++)
3210 {
3211 LogicalTape *tape = spill->partitions[i];
3213 double cardinality;
3214
3215 /* if the partition is empty, don't create a new batch of work */
3216 if (spill->ntuples[i] == 0)
3217 continue;
3218
3219 cardinality = estimateHyperLogLog(&spill->hll_card[i]);
3220 freeHyperLogLog(&spill->hll_card[i]);
3221
3222 /* rewinding frees the buffer while not in use */
3224
3226 spill->ntuples[i], cardinality,
3227 used_bits);
3228 aggstate->hash_batches = lappend(aggstate->hash_batches, new_batch);
3229 aggstate->hash_batches_used++;
3230 }
3231
3232 pfree(spill->ntuples);
3233 pfree(spill->hll_card);
3234 pfree(spill->partitions);
3235}
double estimateHyperLogLog(hyperLogLogState *cState)
void freeHyperLogLog(hyperLogLogState *cState)
void LogicalTapeRewindForRead(LogicalTape *lt, size_t buffer_size)
Definition logtape.c:846
static HashAggBatch * hashagg_batch_new(LogicalTape *input_tape, int setno, int64 input_tuples, double input_card, int used_bits)
Definition nodeAgg.c:3099

References estimateHyperLogLog(), fb(), freeHyperLogLog(), hashagg_batch_new(), HASHAGG_READ_BUFFER_SIZE, i, lappend(), LogicalTapeRewindForRead(), and pfree().

Referenced by agg_refill_hash_table(), and hashagg_finish_initial_spills().

◆ hashagg_spill_init()

static void hashagg_spill_init ( HashAggSpill spill,
LogicalTapeSet tapeset,
int  used_bits,
double  input_groups,
double  hashentrysize 
)
static

Definition at line 2986 of file nodeAgg.c.

2988{
2989 int npartitions;
2990 int partition_bits;
2991
2992 npartitions = hash_choose_num_partitions(input_groups, hashentrysize,
2993 used_bits, &partition_bits);
2994
2995#ifdef USE_INJECTION_POINTS
2996 if (IS_INJECTION_POINT_ATTACHED("hash-aggregate-single-partition"))
2997 {
2998 npartitions = 1;
2999 partition_bits = 0;
3000 INJECTION_POINT_CACHED("hash-aggregate-single-partition", NULL);
3001 }
3002#endif
3003
3004 spill->partitions = palloc0_array(LogicalTape *, npartitions);
3005 spill->ntuples = palloc0_array(int64, npartitions);
3006 spill->hll_card = palloc0_array(hyperLogLogState, npartitions);
3007
3008 for (int i = 0; i < npartitions; i++)
3009 spill->partitions[i] = LogicalTapeCreate(tapeset);
3010
3011 spill->shift = 32 - used_bits - partition_bits;
3012 if (spill->shift < 32)
3013 spill->mask = (npartitions - 1) << spill->shift;
3014 else
3015 spill->mask = 0;
3016 spill->npartitions = npartitions;
3017
3018 for (int i = 0; i < npartitions; i++)
3020}
int64_t int64
Definition c.h:615
void initHyperLogLog(hyperLogLogState *cState, uint8 bwidth)
Definition hyperloglog.c:66
LogicalTape * LogicalTapeCreate(LogicalTapeSet *lts)
Definition logtape.c:680
#define HASHAGG_HLL_BIT_WIDTH
Definition nodeAgg.c:317

References fb(), hash_choose_num_partitions(), HASHAGG_HLL_BIT_WIDTH, i, initHyperLogLog(), INJECTION_POINT_CACHED, IS_INJECTION_POINT_ATTACHED, LogicalTapeCreate(), and palloc0_array.

Referenced by agg_refill_hash_table(), hash_agg_enter_spill_mode(), and lookup_hash_entries().

◆ hashagg_spill_tuple()

static Size hashagg_spill_tuple ( AggState aggstate,
HashAggSpill spill,
TupleTableSlot inputslot,
uint32  hash 
)
static

Definition at line 3029 of file nodeAgg.c.

3031{
3033 int partition;
3034 MinimalTuple tuple;
3036 int total_written = 0;
3037 bool shouldFree;
3038
3039 Assert(spill->partitions != NULL);
3040
3041 /* spill only attributes that we actually need */
3042 if (!aggstate->all_cols_needed)
3043 {
3044 spillslot = aggstate->hash_spill_wslot;
3045 slot_getsomeattrs(inputslot, aggstate->max_colno_needed);
3047 for (int i = 0; i < spillslot->tts_tupleDescriptor->natts; i++)
3048 {
3049 if (bms_is_member(i + 1, aggstate->colnos_needed))
3050 {
3051 spillslot->tts_values[i] = inputslot->tts_values[i];
3052 spillslot->tts_isnull[i] = inputslot->tts_isnull[i];
3053 }
3054 else
3055 spillslot->tts_isnull[i] = true;
3056 }
3058 }
3059 else
3060 spillslot = inputslot;
3061
3063
3064 if (spill->shift < 32)
3065 partition = (hash & spill->mask) >> spill->shift;
3066 else
3067 partition = 0;
3068
3069 spill->ntuples[partition]++;
3070
3071 /*
3072 * All hash values destined for a given partition have some bits in
3073 * common, which causes bad HLL cardinality estimates. Hash the hash to
3074 * get a more uniform distribution.
3075 */
3077
3078 tape = spill->partitions[partition];
3079
3080 LogicalTapeWrite(tape, &hash, sizeof(uint32));
3081 total_written += sizeof(uint32);
3082
3083 LogicalTapeWrite(tape, tuple, tuple->t_len);
3084 total_written += tuple->t_len;
3085
3086 if (shouldFree)
3087 pfree(tuple);
3088
3089 return total_written;
3090}
MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot, bool *shouldFree)
uint32 hash_bytes_uint32(uint32 k)
Definition hashfn.c:610
void addHyperLogLog(hyperLogLogState *cState, uint32 hash)
void LogicalTapeWrite(LogicalTape *lt, const void *ptr, size_t size)
Definition logtape.c:761
static void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition tuptable.h:376

References addHyperLogLog(), Assert, bms_is_member(), ExecClearTuple(), ExecFetchSlotMinimalTuple(), ExecStoreVirtualTuple(), fb(), hash(), hash_bytes_uint32(), i, LogicalTapeWrite(), pfree(), slot_getsomeattrs(), MinimalTupleData::t_len, TupleTableSlot::tts_isnull, and TupleTableSlot::tts_values.

Referenced by agg_refill_hash_table(), and lookup_hash_entries().

◆ initialize_aggregate()

static void initialize_aggregate ( AggState aggstate,
AggStatePerTrans  pertrans,
AggStatePerGroup  pergroupstate 
)
static

Definition at line 581 of file nodeAgg.c.

583{
584 /*
585 * Start a fresh sort operation for each DISTINCT/ORDER BY aggregate.
586 */
587 if (pertrans->aggsortrequired)
588 {
589 /*
590 * In case of rescan, maybe there could be an uncompleted sort
591 * operation? Clean it up if so.
592 */
593 if (pertrans->sortstates[aggstate->current_set])
594 tuplesort_end(pertrans->sortstates[aggstate->current_set]);
595
596
597 /*
598 * We use a plain Datum sorter when there's a single input column;
599 * otherwise sort the full tuple. (See comments for
600 * process_ordered_aggregate_single.)
601 */
602 if (pertrans->numInputs == 1)
603 {
604 Form_pg_attribute attr = TupleDescAttr(pertrans->sortdesc, 0);
605
606 pertrans->sortstates[aggstate->current_set] =
607 tuplesort_begin_datum(attr->atttypid,
608 pertrans->sortOperators[0],
609 pertrans->sortCollations[0],
610 pertrans->sortNullsFirst[0],
612 }
613 else
614 pertrans->sortstates[aggstate->current_set] =
616 pertrans->numSortCols,
617 pertrans->sortColIdx,
618 pertrans->sortOperators,
619 pertrans->sortCollations,
620 pertrans->sortNullsFirst,
622 }
623
624 /*
625 * (Re)set transValue to the initial value.
626 *
627 * Note that when the initial value is pass-by-ref, we must copy it (into
628 * the aggcontext) since we will pfree the transValue later.
629 */
630 if (pertrans->initValueIsNull)
631 pergroupstate->transValue = pertrans->initValue;
632 else
633 {
635
636 oldContext = MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
637 pergroupstate->transValue = datumCopy(pertrans->initValue,
638 pertrans->transtypeByVal,
639 pertrans->transtypeLen);
641 }
642 pergroupstate->transValueIsNull = pertrans->initValueIsNull;
643
644 /*
645 * If the initial value for the transition state doesn't exist in the
646 * pg_aggregate table then we will let the first non-NULL value returned
647 * from the outer procNode become the initial value. (This is useful for
648 * aggregates like max() and min().) The noTransValue flag signals that we
649 * still need to do this.
650 */
651 pergroupstate->noTransValue = pertrans->initValueIsNull;
652}
FormData_pg_attribute * Form_pg_attribute
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
#define TUPLESORT_NONE
Definition tuplesort.h:67
Tuplesortstate * tuplesort_begin_heap(TupleDesc tupDesc, int nkeys, AttrNumber *attNums, Oid *sortOperators, Oid *sortCollations, bool *nullsFirstFlags, int workMem, SortCoordinate coordinate, int sortopt)
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, SortCoordinate coordinate, int sortopt)

References AggStatePerTransData::aggsortrequired, datumCopy(), fb(), AggStatePerTransData::initValue, AggStatePerTransData::initValueIsNull, MemoryContextSwitchTo(), AggStatePerTransData::numInputs, AggStatePerTransData::numSortCols, AggStatePerTransData::sortColIdx, AggStatePerTransData::sortCollations, AggStatePerTransData::sortdesc, AggStatePerTransData::sortNullsFirst, AggStatePerTransData::sortOperators, AggStatePerTransData::sortstates, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, TupleDescAttr(), tuplesort_begin_datum(), tuplesort_begin_heap(), tuplesort_end(), TUPLESORT_NONE, and work_mem.

Referenced by initialize_aggregates(), and initialize_hash_entry().

◆ initialize_aggregates()

static void initialize_aggregates ( AggState aggstate,
AggStatePerGroup pergroups,
int  numReset 
)
static

Definition at line 668 of file nodeAgg.c.

671{
672 int transno;
673 int numGroupingSets = Max(aggstate->phase->numsets, 1);
674 int setno = 0;
675 int numTrans = aggstate->numtrans;
677
678 if (numReset == 0)
680
681 for (setno = 0; setno < numReset; setno++)
682 {
683 AggStatePerGroup pergroup = pergroups[setno];
684
685 select_current_set(aggstate, setno, false);
686
687 for (transno = 0; transno < numTrans; transno++)
688 {
689 AggStatePerTrans pertrans = &transstates[transno];
691
693 }
694 }
695}
static void initialize_aggregate(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition nodeAgg.c:581

References fb(), initialize_aggregate(), Max, and select_current_set().

Referenced by agg_retrieve_direct().

◆ initialize_hash_entry()

static void initialize_hash_entry ( AggState aggstate,
TupleHashTable  hashtable,
TupleHashEntry  entry 
)
static

Definition at line 2140 of file nodeAgg.c.

2142{
2144 int transno;
2145
2146 aggstate->hash_ngroups_current++;
2148
2149 /* no need to allocate or initialize per-group state */
2150 if (aggstate->numtrans == 0)
2151 return;
2152
2154
2155 /*
2156 * Initialize aggregates for new tuple group, lookup_hash_entries()
2157 * already has selected the relevant grouping set.
2158 */
2159 for (transno = 0; transno < aggstate->numtrans; transno++)
2160 {
2161 AggStatePerTrans pertrans = &aggstate->pertrans[transno];
2163
2165 }
2166}
static void hash_agg_check_limits(AggState *aggstate)
Definition nodeAgg.c:1866

References fb(), hash_agg_check_limits(), initialize_aggregate(), and TupleHashEntryGetAdditional().

Referenced by agg_refill_hash_table(), and lookup_hash_entries().

◆ initialize_phase()

static void initialize_phase ( AggState aggstate,
int  newphase 
)
static

Definition at line 480 of file nodeAgg.c.

481{
483
484 /*
485 * Whatever the previous state, we're now done with whatever input
486 * tuplesort was in use.
487 */
488 if (aggstate->sort_in)
489 {
490 tuplesort_end(aggstate->sort_in);
491 aggstate->sort_in = NULL;
492 }
493
494 if (newphase <= 1)
495 {
496 /*
497 * Discard any existing output tuplesort.
498 */
499 if (aggstate->sort_out)
500 {
501 tuplesort_end(aggstate->sort_out);
502 aggstate->sort_out = NULL;
503 }
504 }
505 else
506 {
507 /*
508 * The old output tuplesort becomes the new input one, and this is the
509 * right time to actually sort it.
510 */
511 aggstate->sort_in = aggstate->sort_out;
512 aggstate->sort_out = NULL;
513 Assert(aggstate->sort_in);
515 }
516
517 /*
518 * If this isn't the last phase, we need to sort appropriately for the
519 * next phase in sequence.
520 */
521 if (newphase > 0 && newphase < aggstate->numphases - 1)
522 {
523 Sort *sortnode = aggstate->phases[newphase + 1].sortnode;
526
527 aggstate->sort_out = tuplesort_begin_heap(tupDesc,
528 sortnode->numCols,
529 sortnode->sortColIdx,
530 sortnode->sortOperators,
531 sortnode->collations,
532 sortnode->nullsFirst,
533 work_mem,
535 }
536
537 aggstate->current_phase = newphase;
538 aggstate->phase = &aggstate->phases[newphase];
539}
TupleDesc ExecGetResultType(PlanState *planstate)
Definition execUtils.c:500
int numCols
Definition plannodes.h:1144
void tuplesort_performsort(Tuplesortstate *state)
Definition tuplesort.c:1259

References Assert, ExecGetResultType(), fb(), Sort::numCols, outerPlanState, tuplesort_begin_heap(), tuplesort_end(), TUPLESORT_NONE, tuplesort_performsort(), and work_mem.

Referenced by agg_retrieve_direct(), ExecInitAgg(), and ExecReScanAgg().

◆ lookup_hash_entries()

static void lookup_hash_entries ( AggState aggstate)
static

Definition at line 2184 of file nodeAgg.c.

2185{
2186 AggStatePerGroup *pergroup = aggstate->hash_pergroup;
2187 TupleTableSlot *outerslot = aggstate->tmpcontext->ecxt_outertuple;
2188 int setno;
2189
2190 for (setno = 0; setno < aggstate->num_hashes; setno++)
2191 {
2192 AggStatePerHash perhash = &aggstate->perhash[setno];
2193 TupleHashTable hashtable = perhash->hashtable;
2194 TupleTableSlot *hashslot = perhash->hashslot;
2195 TupleHashEntry entry;
2196 uint32 hash;
2197 bool isnew = false;
2198 bool *p_isnew;
2199
2200 /* if hash table already spilled, don't create new entries */
2201 p_isnew = aggstate->hash_spill_mode ? NULL : &isnew;
2202
2203 select_current_set(aggstate, setno, true);
2204 prepare_hash_slot(perhash,
2205 outerslot,
2206 hashslot);
2207
2208 entry = LookupTupleHashEntry(hashtable, hashslot,
2209 p_isnew, &hash);
2210
2211 if (entry != NULL)
2212 {
2213 if (isnew)
2214 initialize_hash_entry(aggstate, hashtable, entry);
2215 pergroup[setno] = TupleHashEntryGetAdditional(hashtable, entry);
2216 }
2217 else
2218 {
2219 HashAggSpill *spill = &aggstate->hash_spills[setno];
2220 TupleTableSlot *slot = aggstate->tmpcontext->ecxt_outertuple;
2221
2222 if (spill->partitions == NULL)
2223 hashagg_spill_init(spill, aggstate->hash_tapeset, 0,
2224 perhash->aggnode->numGroups,
2225 aggstate->hashentrysize);
2226
2228 pergroup[setno] = NULL;
2229 }
2230 }
2231}
TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 *hash)

References AggStatePerHashData::aggnode, fb(), hash(), hashagg_spill_init(), hashagg_spill_tuple(), AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, initialize_hash_entry(), LookupTupleHashEntry(), Agg::numGroups, prepare_hash_slot(), select_current_set(), and TupleHashEntryGetAdditional().

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

◆ prepare_hash_slot()

static void prepare_hash_slot ( AggStatePerHash  perhash,
TupleTableSlot inputslot,
TupleTableSlot hashslot 
)
inlinestatic

Definition at line 1204 of file nodeAgg.c.

1207{
1208 int i;
1209
1210 /* transfer just the needed columns into hashslot */
1211 slot_getsomeattrs(inputslot, perhash->largestGrpColIdx);
1212 ExecClearTuple(hashslot);
1213
1214 for (i = 0; i < perhash->numhashGrpCols; i++)
1215 {
1216 int varNumber = perhash->hashGrpColIdxInput[i] - 1;
1217
1218 hashslot->tts_values[i] = inputslot->tts_values[varNumber];
1219 hashslot->tts_isnull[i] = inputslot->tts_isnull[varNumber];
1220 }
1221 ExecStoreVirtualTuple(hashslot);
1222}

References ExecClearTuple(), ExecStoreVirtualTuple(), fb(), AggStatePerHashData::hashGrpColIdxInput, i, AggStatePerHashData::largestGrpColIdx, AggStatePerHashData::numhashGrpCols, slot_getsomeattrs(), TupleTableSlot::tts_isnull, and TupleTableSlot::tts_values.

Referenced by agg_refill_hash_table(), and lookup_hash_entries().

◆ prepare_projection_slot()

static void prepare_projection_slot ( AggState aggstate,
TupleTableSlot slot,
int  currentSet 
)
static

Definition at line 1249 of file nodeAgg.c.

1250{
1251 if (aggstate->phase->grouped_cols)
1252 {
1253 Bitmapset *grouped_cols = aggstate->phase->grouped_cols[currentSet];
1254
1255 aggstate->grouped_cols = grouped_cols;
1256
1257 if (TTS_EMPTY(slot))
1258 {
1259 /*
1260 * Force all values to be NULL if working on an empty input tuple
1261 * (i.e. an empty grouping set for which no input rows were
1262 * supplied).
1263 */
1265 }
1266 else if (aggstate->all_grouped_cols)
1267 {
1268 ListCell *lc;
1269
1270 /* all_grouped_cols is arranged in desc order */
1271 slot_getsomeattrs(slot, linitial_int(aggstate->all_grouped_cols));
1272
1273 foreach(lc, aggstate->all_grouped_cols)
1274 {
1275 int attnum = lfirst_int(lc);
1276
1277 if (!bms_is_member(attnum, grouped_cols))
1278 slot->tts_isnull[attnum - 1] = true;
1279 }
1280 }
1281 }
1282}
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
#define linitial_int(l)
Definition pg_list.h:179
#define TTS_EMPTY(slot)
Definition tuptable.h:92

References attnum, bms_is_member(), ExecStoreAllNullTuple(), fb(), lfirst_int, linitial_int, slot_getsomeattrs(), TTS_EMPTY, and TupleTableSlot::tts_isnull.

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table_in_memory().

◆ process_ordered_aggregate_multi()

static void process_ordered_aggregate_multi ( AggState aggstate,
AggStatePerTrans  pertrans,
AggStatePerGroup  pergroupstate 
)
static

Definition at line 949 of file nodeAgg.c.

952{
953 ExprContext *tmpcontext = aggstate->tmpcontext;
954 FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
955 TupleTableSlot *slot1 = pertrans->sortslot;
956 TupleTableSlot *slot2 = pertrans->uniqslot;
957 int numTransInputs = pertrans->numTransInputs;
958 int numDistinctCols = pertrans->numDistinctCols;
961 bool haveOldValue = false;
962 TupleTableSlot *save = aggstate->tmpcontext->ecxt_outertuple;
963 int i;
964
965 tuplesort_performsort(pertrans->sortstates[aggstate->current_set]);
966
968 if (slot2)
970
971 while (tuplesort_gettupleslot(pertrans->sortstates[aggstate->current_set],
972 true, true, slot1, &newAbbrevVal))
973 {
975
976 tmpcontext->ecxt_outertuple = slot1;
977 tmpcontext->ecxt_innertuple = slot2;
978
979 if (numDistinctCols == 0 ||
980 !haveOldValue ||
982 !ExecQual(pertrans->equalfnMulti, tmpcontext))
983 {
984 /*
985 * Extract the first numTransInputs columns as datums to pass to
986 * the transfn.
987 */
988 slot_getsomeattrs(slot1, numTransInputs);
989
990 /* Load values into fcinfo */
991 /* Start from 1, since the 0th arg will be the transition value */
992 for (i = 0; i < numTransInputs; i++)
993 {
994 fcinfo->args[i + 1].value = slot1->tts_values[i];
995 fcinfo->args[i + 1].isnull = slot1->tts_isnull[i];
996 }
997
999
1000 if (numDistinctCols > 0)
1001 {
1002 /* swap the slot pointers to retain the current tuple */
1004
1005 slot2 = slot1;
1006 slot1 = tmpslot;
1007 /* avoid ExecQual() calls by reusing abbreviated keys */
1009 haveOldValue = true;
1010 }
1011 }
1012
1013 /* Reset context each time */
1014 ResetExprContext(tmpcontext);
1015
1017 }
1018
1019 if (slot2)
1021
1022 tuplesort_end(pertrans->sortstates[aggstate->current_set]);
1023 pertrans->sortstates[aggstate->current_set] = NULL;
1024
1025 /* restore previous slot, potentially in use for grouping sets */
1026 tmpcontext->ecxt_outertuple = save;
1027}
static void advance_transition_function(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition nodeAgg.c:709

References advance_transition_function(), FunctionCallInfoBaseData::args, CHECK_FOR_INTERRUPTS, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, AggStatePerTransData::equalfnMulti, ExecClearTuple(), ExecQual(), fb(), i, NullableDatum::isnull, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numTransInputs, ResetExprContext, slot_getsomeattrs(), AggStatePerTransData::sortslot, AggStatePerTransData::sortstates, AggStatePerTransData::transfn_fcinfo, tuplesort_end(), tuplesort_gettupleslot(), tuplesort_performsort(), AggStatePerTransData::uniqslot, and NullableDatum::value.

Referenced by finalize_aggregates().

◆ process_ordered_aggregate_single()

static void process_ordered_aggregate_single ( AggState aggstate,
AggStatePerTrans  pertrans,
AggStatePerGroup  pergroupstate 
)
static

Definition at line 848 of file nodeAgg.c.

851{
852 Datum oldVal = (Datum) 0;
853 bool oldIsNull = true;
854 bool haveOldVal = false;
855 MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory;
857 bool isDistinct = (pertrans->numDistinctCols > 0);
860 FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
861 Datum *newVal;
862 bool *isNull;
863
864 Assert(pertrans->numDistinctCols < 2);
865
866 tuplesort_performsort(pertrans->sortstates[aggstate->current_set]);
867
868 /* Load the column into argument 1 (arg 0 will be transition value) */
869 newVal = &fcinfo->args[1].value;
870 isNull = &fcinfo->args[1].isnull;
871
872 /*
873 * Note: if input type is pass-by-ref, the datums returned by the sort are
874 * freshly palloc'd in the per-query context, so we must be careful to
875 * pfree them when they are no longer needed.
876 */
877
878 while (tuplesort_getdatum(pertrans->sortstates[aggstate->current_set],
879 true, false, newVal, isNull, &newAbbrevVal))
880 {
881 /*
882 * Clear and select the working context for evaluation of the equality
883 * function and transition function.
884 */
887
888 /*
889 * If DISTINCT mode, and not distinct from prior, skip it.
890 */
891 if (isDistinct &&
892 haveOldVal &&
893 ((oldIsNull && *isNull) ||
894 (!oldIsNull && !*isNull &&
897 pertrans->aggCollation,
898 oldVal, *newVal)))))
899 {
901 continue;
902 }
903 else
904 {
906
908
909 /*
910 * Forget the old value, if any, and remember the new one for
911 * subsequent equality checks.
912 */
913 if (!pertrans->inputtypeByVal)
914 {
915 if (!oldIsNull)
916 pfree(DatumGetPointer(oldVal));
917 if (!*isNull)
918 oldVal = datumCopy(*newVal, pertrans->inputtypeByVal,
919 pertrans->inputtypeLen);
920 }
921 else
922 oldVal = *newVal;
924 oldIsNull = *isNull;
925 haveOldVal = true;
926 }
927 }
928
929 if (!oldIsNull && !pertrans->inputtypeByVal)
930 pfree(DatumGetPointer(oldVal));
931
932 tuplesort_end(pertrans->sortstates[aggstate->current_set]);
933 pertrans->sortstates[aggstate->current_set] = NULL;
934}
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1151
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
static bool DatumGetBool(Datum X)
Definition postgres.h:100
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, bool copy, Datum *val, bool *isNull, Datum *abbrev)

References advance_transition_function(), AggStatePerTransData::aggCollation, FunctionCallInfoBaseData::args, Assert, datumCopy(), DatumGetBool(), DatumGetPointer(), AggStatePerTransData::equalfnOne, fb(), FunctionCall2Coll(), AggStatePerTransData::inputtypeByVal, AggStatePerTransData::inputtypeLen, NullableDatum::isnull, MemoryContextReset(), MemoryContextSwitchTo(), AggStatePerTransData::numDistinctCols, pfree(), AggStatePerTransData::sortstates, AggStatePerTransData::transfn_fcinfo, tuplesort_end(), tuplesort_getdatum(), tuplesort_performsort(), and NullableDatum::value.

Referenced by finalize_aggregates().

◆ project_aggregates()

static TupleTableSlot * project_aggregates ( AggState aggstate)
static

Definition at line 1371 of file nodeAgg.c.

1372{
1373 ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1374
1375 /*
1376 * Check the qual (HAVING clause); if the group does not match, ignore it.
1377 */
1378 if (ExecQual(aggstate->ss.ps.qual, econtext))
1379 {
1380 /*
1381 * Form and return projection tuple using the aggregate results and
1382 * the representative input tuple.
1383 */
1384 return ExecProject(aggstate->ss.ps.ps_ProjInfo);
1385 }
1386 else
1388
1389 return NULL;
1390}
#define InstrCountFiltered1(node, delta)
Definition execnodes.h:1281
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition executor.h:486

References ExecProject(), ExecQual(), fb(), and InstrCountFiltered1.

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table_in_memory().

◆ select_current_set()

static void select_current_set ( AggState aggstate,
int  setno,
bool  is_hash 
)
static

Definition at line 458 of file nodeAgg.c.

459{
460 /*
461 * When changing this, also adapt ExecAggPlainTransByVal() and
462 * ExecAggPlainTransByRef().
463 */
464 if (is_hash)
465 aggstate->curaggcontext = aggstate->hashcontext;
466 else
467 aggstate->curaggcontext = aggstate->aggcontexts[setno];
468
469 aggstate->current_set = setno;
470}

References fb().

Referenced by agg_fill_hash_table(), agg_refill_hash_table(), agg_retrieve_direct(), agg_retrieve_hash_table_in_memory(), ExecInitAgg(), ExecReScanAgg(), initialize_aggregates(), and lookup_hash_entries().