PostgreSQL Source Code  git master
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/nodeAgg.h"
#include "lib/hyperloglog.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/dynahash.h"
#include "utils/expandeddatum.h"
#include "utils/logtape.h"
#include "utils/lsyscache.h"
#include "utils/memutils.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  HashTapeInfo
 
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   16
 

Typedefs

typedef struct HashTapeInfo HashTapeInfo
 
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 peragg, 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, long nbuckets)
 
static void hashagg_recompile_expressions (AggState *aggstate, bool minslot, bool nullcheck)
 
static long hash_choose_num_buckets (double hashentrysize, long estimated_nbuckets, Size memory)
 
static int hash_choose_num_partitions (double input_groups, double hashentrysize, int used_bits, int *log2_npartittions)
 
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 (LogicalTapeSet *tapeset, int input_tapenum, 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, HashTapeInfo *tapeinfo, int used_bits, double input_groups, double hashentrysize)
 
static Size hashagg_spill_tuple (AggState *aggstate, HashAggSpill *spill, TupleTableSlot *slot, uint32 hash)
 
static void hashagg_spill_finish (AggState *aggstate, HashAggSpill *spill, int setno)
 
static void hashagg_tapeinfo_init (AggState *aggstate)
 
static void hashagg_tapeinfo_assign (HashTapeInfo *tapeinfo, int *dest, int ndest)
 
static void hashagg_tapeinfo_release (HashTapeInfo *tapeinfo, int tapenum)
 
static Datum GetAggInitVal (Datum textInitVal, Oid transtype)
 
static void build_pertrans_for_aggref (AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid aggtransfn, 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   16

Definition at line 312 of file nodeAgg.c.

Referenced by hash_agg_entry_size().

◆ HASHAGG_HLL_BIT_WIDTH

#define HASHAGG_HLL_BIT_WIDTH   5

Definition at line 306 of file nodeAgg.c.

Referenced by hashagg_spill_init().

◆ HASHAGG_MAX_PARTITIONS

#define HASHAGG_MAX_PARTITIONS   1024

Definition at line 289 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_MIN_PARTITIONS

#define HASHAGG_MIN_PARTITIONS   4

Definition at line 288 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_PARTITION_FACTOR

#define HASHAGG_PARTITION_FACTOR   1.50

Definition at line 287 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_READ_BUFFER_SIZE

#define HASHAGG_READ_BUFFER_SIZE   BLCKSZ

◆ HASHAGG_WRITE_BUFFER_SIZE

#define HASHAGG_WRITE_BUFFER_SIZE   BLCKSZ

Typedef Documentation

◆ FindColsContext

◆ HashAggBatch

typedef struct HashAggBatch HashAggBatch

◆ HashAggSpill

typedef struct HashAggSpill HashAggSpill

◆ HashTapeInfo

typedef struct HashTapeInfo HashTapeInfo

Function Documentation

◆ advance_aggregates()

static void advance_aggregates ( AggState aggstate)
static

Definition at line 838 of file nodeAgg.c.

References AggStatePerPhaseData::evaltrans, ExecEvalExprSwitchContext(), AggState::phase, and AggState::tmpcontext.

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

839 {
840  bool dummynull;
841 
843  aggstate->tmpcontext,
844  &dummynull);
845 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:330
ExprState * evaltrans
Definition: nodeAgg.h:283
ExprContext * tmpcontext
Definition: execnodes.h:2284
AggStatePerPhase phase
Definition: execnodes.h:2277

◆ advance_transition_function()

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

Definition at line 726 of file nodeAgg.c.

References FunctionCallInfoBaseData::args, AggState::curaggcontext, AggState::curpertrans, datumCopy(), DatumGetPointer, ExprContext::ecxt_per_tuple_memory, ExecAggTransReparent(), FmgrInfo::fn_strict, FunctionCallInvoke, i, FunctionCallInfoBaseData::isnull, NullableDatum::isnull, MemoryContextSwitchTo(), AggStatePerGroupData::noTransValue, AggStatePerTransData::numTransInputs, AggState::tmpcontext, AggStatePerTransData::transfn, AggStatePerTransData::transfn_fcinfo, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, AggStatePerGroupData::transValue, AggStatePerGroupData::transValueIsNull, and NullableDatum::value.

Referenced by process_ordered_aggregate_multi(), and process_ordered_aggregate_single().

729 {
730  FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
731  MemoryContext oldContext;
732  Datum newVal;
733 
734  if (pertrans->transfn.fn_strict)
735  {
736  /*
737  * For a strict transfn, nothing happens when there's a NULL input; we
738  * just keep the prior transValue.
739  */
740  int numTransInputs = pertrans->numTransInputs;
741  int i;
742 
743  for (i = 1; i <= numTransInputs; i++)
744  {
745  if (fcinfo->args[i].isnull)
746  return;
747  }
748  if (pergroupstate->noTransValue)
749  {
750  /*
751  * transValue has not been initialized. This is the first non-NULL
752  * input value. We use it as the initial value for transValue. (We
753  * already checked that the agg's input type is binary-compatible
754  * with its transtype, so straight copy here is OK.)
755  *
756  * We must copy the datum into aggcontext if it is pass-by-ref. We
757  * do not need to pfree the old transValue, since it's NULL.
758  */
760  pergroupstate->transValue = datumCopy(fcinfo->args[1].value,
761  pertrans->transtypeByVal,
762  pertrans->transtypeLen);
763  pergroupstate->transValueIsNull = false;
764  pergroupstate->noTransValue = false;
765  MemoryContextSwitchTo(oldContext);
766  return;
767  }
768  if (pergroupstate->transValueIsNull)
769  {
770  /*
771  * Don't call a strict function with NULL inputs. Note it is
772  * possible to get here despite the above tests, if the transfn is
773  * strict *and* returned a NULL on a prior cycle. If that happens
774  * we will propagate the NULL all the way to the end.
775  */
776  return;
777  }
778  }
779 
780  /* We run the transition functions in per-input-tuple memory context */
781  oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
782 
783  /* set up aggstate->curpertrans for AggGetAggref() */
784  aggstate->curpertrans = pertrans;
785 
786  /*
787  * OK to call the transition function
788  */
789  fcinfo->args[0].value = pergroupstate->transValue;
790  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
791  fcinfo->isnull = false; /* just in case transfn doesn't set it */
792 
793  newVal = FunctionCallInvoke(fcinfo);
794 
795  aggstate->curpertrans = NULL;
796 
797  /*
798  * If pass-by-ref datatype, must copy the new value into aggcontext and
799  * free the prior transValue. But if transfn returned a pointer to its
800  * first input, we don't need to do anything. Also, if transfn returned a
801  * pointer to a R/W expanded object that is already a child of the
802  * aggcontext, assume we can adopt that value without copying it.
803  *
804  * It's safe to compare newVal with pergroup->transValue without regard
805  * for either being NULL, because ExecAggTransReparent() takes care to set
806  * transValue to 0 when NULL. Otherwise we could end up accidentally not
807  * reparenting, when the transValue has the same numerical value as
808  * newValue, despite being NULL. This is a somewhat hot path, making it
809  * undesirable to instead solve this with another branch for the common
810  * case of the transition function returning its (modified) input
811  * argument.
812  */
813  if (!pertrans->transtypeByVal &&
814  DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
815  newVal = ExecAggTransReparent(aggstate, pertrans,
816  newVal, fcinfo->isnull,
817  pergroupstate->transValue,
818  pergroupstate->transValueIsNull);
819 
820  pergroupstate->transValue = newVal;
821  pergroupstate->transValueIsNull = fcinfo->isnull;
822 
823  MemoryContextSwitchTo(oldContext);
824 }
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:162
Datum ExecAggTransReparent(AggState *aggstate, AggStatePerTrans pertrans, Datum newValue, bool newValueIsNull, Datum oldValue, bool oldValueIsNull)
ExprContext * tmpcontext
Definition: execnodes.h:2284
FmgrInfo transfn
Definition: nodeAgg.h:81
bool fn_strict
Definition: fmgr.h:61
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
Datum value
Definition: postgres.h:422
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
ExprContext * curaggcontext
Definition: execnodes.h:2286
uintptr_t Datum
Definition: postgres.h:411
#define DatumGetPointer(X)
Definition: postgres.h:593
int i
AggStatePerTrans curpertrans
Definition: execnodes.h:2289

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

Definition at line 2535 of file nodeAgg.c.

References advance_aggregates(), ExprContext::ecxt_outertuple, fetch_input_tuple(), hashagg_finish_initial_spills(), AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, lookup_hash_entries(), AggState::perhash, ResetExprContext, ResetTupleHashIterator, select_current_set(), AggState::table_filled, AggState::tmpcontext, and TupIsNull.

Referenced by ExecAgg().

2536 {
2537  TupleTableSlot *outerslot;
2538  ExprContext *tmpcontext = aggstate->tmpcontext;
2539 
2540  /*
2541  * Process each outer-plan tuple, and then fetch the next one, until we
2542  * exhaust the outer plan.
2543  */
2544  for (;;)
2545  {
2546  outerslot = fetch_input_tuple(aggstate);
2547  if (TupIsNull(outerslot))
2548  break;
2549 
2550  /* set up for lookup_hash_entries and advance_aggregates */
2551  tmpcontext->ecxt_outertuple = outerslot;
2552 
2553  /* Find or build hashtable entries */
2554  lookup_hash_entries(aggstate);
2555 
2556  /* Advance the aggregates (or combine functions) */
2557  advance_aggregates(aggstate);
2558 
2559  /*
2560  * Reset per-input-tuple context after each tuple, but note that the
2561  * hash lookups do this too
2562  */
2563  ResetExprContext(aggstate->tmpcontext);
2564  }
2565 
2566  /* finalize spills, if any */
2568 
2569  aggstate->table_filled = true;
2570  /* Initialize to walk the first hash table */
2571  select_current_set(aggstate, 0, true);
2573  &aggstate->perhash[0].hashiter);
2574 }
static TupleTableSlot * fetch_input_tuple(AggState *aggstate)
Definition: nodeAgg.c:567
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:475
static void hashagg_finish_initial_spills(AggState *aggstate)
Definition: nodeAgg.c:3117
static void advance_aggregates(AggState *aggstate)
Definition: nodeAgg.c:838
ExprContext * tmpcontext
Definition: execnodes.h:2284
bool table_filled
Definition: execnodes.h:2311
#define TupIsNull(slot)
Definition: tuptable.h:292
AggStatePerHash perhash
Definition: execnodes.h:2334
TupleHashIterator hashiter
Definition: nodeAgg.h:304
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:767
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:230
TupleHashTable hashtable
Definition: nodeAgg.h:303
static void lookup_hash_entries(AggState *aggstate)
Definition: nodeAgg.c:2090
#define ResetExprContext(econtext)
Definition: executor.h:526

◆ agg_refill_hash_table()

static bool agg_refill_hash_table ( AggState aggstate)
static

Definition at line 2589 of file nodeAgg.c.

References TupleHashEntryData::additional, advance_aggregates(), AGG_MIXED, AggStatePerPhaseData::aggstrategy, Assert, CHECK_FOR_INTERRUPTS, AggState::current_phase, AggState::current_set, ExprContext::ecxt_outertuple, ExecStoreMinimalTuple(), hash(), hash_agg_set_limits(), hash_agg_update_metrics(), AggState::hash_batches, AggState::hash_mem_limit, AggState::hash_ngroups_current, AggState::hash_ngroups_limit, AggState::hash_pergroup, AggState::hash_spill_mode, AggState::hash_spill_rslot, AggState::hash_tapeinfo, hashagg_batch_read(), hashagg_recompile_expressions(), hashagg_spill_finish(), hashagg_spill_init(), hashagg_spill_tuple(), hashagg_tapeinfo_release(), AggState::hashcontext, AggState::hashentrysize, AggStatePerHashData::hashiter, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, initialize_hash_entry(), HashAggBatch::input_card, HashAggBatch::input_tapenum, linitial, list_delete_first(), LookupTupleHashEntryHash(), MemSet, NIL, HashAggSpill::npartitions, AggState::num_hashes, AggState::perhash, pfree(), AggState::phase, AggState::phases, prepare_hash_slot(), ReScanExprContext(), ResetExprContext, ResetTupleHashIterator, ResetTupleHashTable(), select_current_set(), HashAggBatch::setno, AggState::tmpcontext, and HashAggBatch::used_bits.

Referenced by agg_retrieve_hash_table().

2590 {
2591  HashAggBatch *batch;
2592  AggStatePerHash perhash;
2593  HashAggSpill spill;
2594  HashTapeInfo *tapeinfo = aggstate->hash_tapeinfo;
2595  bool spill_initialized = false;
2596 
2597  if (aggstate->hash_batches == NIL)
2598  return false;
2599 
2600  batch = linitial(aggstate->hash_batches);
2601  aggstate->hash_batches = list_delete_first(aggstate->hash_batches);
2602 
2603  hash_agg_set_limits(aggstate->hashentrysize, batch->input_card,
2604  batch->used_bits, &aggstate->hash_mem_limit,
2605  &aggstate->hash_ngroups_limit, NULL);
2606 
2607  /*
2608  * Each batch only processes one grouping set; set the rest to NULL so
2609  * that advance_aggregates() knows to ignore them. We don't touch
2610  * pergroups for sorted grouping sets here, because they will be needed if
2611  * we rescan later. The expressions for sorted grouping sets will not be
2612  * evaluated after we recompile anyway.
2613  */
2614  MemSet(aggstate->hash_pergroup, 0,
2615  sizeof(AggStatePerGroup) * aggstate->num_hashes);
2616 
2617  /* free memory and reset hash tables */
2618  ReScanExprContext(aggstate->hashcontext);
2619  for (int setno = 0; setno < aggstate->num_hashes; setno++)
2620  ResetTupleHashTable(aggstate->perhash[setno].hashtable);
2621 
2622  aggstate->hash_ngroups_current = 0;
2623 
2624  /*
2625  * In AGG_MIXED mode, hash aggregation happens in phase 1 and the output
2626  * happens in phase 0. So, we switch to phase 1 when processing a batch,
2627  * and back to phase 0 after the batch is done.
2628  */
2629  Assert(aggstate->current_phase == 0);
2630  if (aggstate->phase->aggstrategy == AGG_MIXED)
2631  {
2632  aggstate->current_phase = 1;
2633  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2634  }
2635 
2636  select_current_set(aggstate, batch->setno, true);
2637 
2638  perhash = &aggstate->perhash[aggstate->current_set];
2639 
2640  /*
2641  * Spilled tuples are always read back as MinimalTuples, which may be
2642  * different from the outer plan, so recompile the aggregate expressions.
2643  *
2644  * We still need the NULL check, because we are only processing one
2645  * grouping set at a time and the rest will be NULL.
2646  */
2647  hashagg_recompile_expressions(aggstate, true, true);
2648 
2649  for (;;)
2650  {
2651  TupleTableSlot *spillslot = aggstate->hash_spill_rslot;
2652  TupleTableSlot *hashslot = perhash->hashslot;
2653  TupleHashEntry entry;
2654  MinimalTuple tuple;
2655  uint32 hash;
2656  bool isnew = false;
2657  bool *p_isnew = aggstate->hash_spill_mode ? NULL : &isnew;
2658 
2660 
2661  tuple = hashagg_batch_read(batch, &hash);
2662  if (tuple == NULL)
2663  break;
2664 
2665  ExecStoreMinimalTuple(tuple, spillslot, true);
2666  aggstate->tmpcontext->ecxt_outertuple = spillslot;
2667 
2668  prepare_hash_slot(perhash,
2669  aggstate->tmpcontext->ecxt_outertuple,
2670  hashslot);
2671  entry = LookupTupleHashEntryHash(
2672  perhash->hashtable, hashslot, p_isnew, hash);
2673 
2674  if (entry != NULL)
2675  {
2676  if (isnew)
2677  initialize_hash_entry(aggstate, perhash->hashtable, entry);
2678  aggstate->hash_pergroup[batch->setno] = entry->additional;
2679  advance_aggregates(aggstate);
2680  }
2681  else
2682  {
2683  if (!spill_initialized)
2684  {
2685  /*
2686  * Avoid initializing the spill until we actually need it so
2687  * that we don't assign tapes that will never be used.
2688  */
2689  spill_initialized = true;
2690  hashagg_spill_init(&spill, tapeinfo, batch->used_bits,
2691  batch->input_card, aggstate->hashentrysize);
2692  }
2693  /* no memory for a new group, spill */
2694  hashagg_spill_tuple(aggstate, &spill, spillslot, hash);
2695 
2696  aggstate->hash_pergroup[batch->setno] = NULL;
2697  }
2698 
2699  /*
2700  * Reset per-input-tuple context after each tuple, but note that the
2701  * hash lookups do this too
2702  */
2703  ResetExprContext(aggstate->tmpcontext);
2704  }
2705 
2706  hashagg_tapeinfo_release(tapeinfo, batch->input_tapenum);
2707 
2708  /* change back to phase 0 */
2709  aggstate->current_phase = 0;
2710  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2711 
2712  if (spill_initialized)
2713  {
2714  hashagg_spill_finish(aggstate, &spill, batch->setno);
2715  hash_agg_update_metrics(aggstate, true, spill.npartitions);
2716  }
2717  else
2718  hash_agg_update_metrics(aggstate, true, 0);
2719 
2720  aggstate->hash_spill_mode = false;
2721 
2722  /* prepare to walk the first hash table */
2723  select_current_set(aggstate, batch->setno, true);
2724  ResetTupleHashIterator(aggstate->perhash[batch->setno].hashtable,
2725  &aggstate->perhash[batch->setno].hashiter);
2726 
2727  pfree(batch);
2728 
2729  return true;
2730 }
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2335
#define NIL
Definition: pg_list.h:65
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:475
AggStatePerPhase phases
Definition: execnodes.h:2302
double hashentrysize
Definition: execnodes.h:2327
static void hashagg_tapeinfo_release(HashTapeInfo *tapeinfo, int tapenum)
Definition: nodeAgg.c:2929
static void hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
Definition: nodeAgg.c:1916
TupleHashEntry LookupTupleHashEntryHash(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 hash)
Definition: execGrouping.c:359
uint64 hash_ngroups_limit
Definition: execnodes.h:2324
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1446
static void hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
Definition: nodeAgg.c:3151
int current_phase
Definition: execnodes.h:2279
#define MemSet(start, val, len)
Definition: c.h:1008
TupleTableSlot * hash_spill_rslot
Definition: execnodes.h:2317
static void advance_aggregates(AggState *aggstate)
Definition: nodeAgg.c:838
int current_set
Definition: execnodes.h:2294
static void hashagg_spill_init(HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits, double input_groups, double hashentrysize)
Definition: nodeAgg.c:2949
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:283
ExprContext * tmpcontext
Definition: execnodes.h:2284
bool hash_spill_mode
Definition: execnodes.h:2321
List * hash_batches
Definition: execnodes.h:2319
void pfree(void *pointer)
Definition: mcxt.c:1169
#define linitial(l)
Definition: pg_list.h:174
int npartitions
Definition: nodeAgg.c:347
static Size hashagg_spill_tuple(AggState *aggstate, HashAggSpill *spill, TupleTableSlot *slot, uint32 hash)
Definition: nodeAgg.c:2980
int used_bits
Definition: nodeAgg.c:367
unsigned int uint32
Definition: c.h:441
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2314
AggStatePerHash perhash
Definition: execnodes.h:2334
AggStrategy aggstrategy
Definition: nodeAgg.h:274
double input_card
Definition: nodeAgg.c:371
TupleHashIterator hashiter
Definition: nodeAgg.h:304
int num_hashes
Definition: execnodes.h:2312
ExprContext * hashcontext
Definition: execnodes.h:2282
AggStatePerPhase phase
Definition: execnodes.h:2277
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:767
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1740
static void prepare_hash_slot(AggStatePerHash perhash, TupleTableSlot *inputslot, TupleTableSlot *hashslot)
Definition: nodeAgg.c:1219
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:230
#define Assert(condition)
Definition: c.h:804
int input_tapenum
Definition: nodeAgg.c:369
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:438
Size hash_mem_limit
Definition: execnodes.h:2323
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:1797
static MinimalTuple hashagg_batch_read(HashAggBatch *batch, uint32 *hashp)
Definition: nodeAgg.c:3067
uint64 hash_ngroups_current
Definition: execnodes.h:2329
static void initialize_hash_entry(AggState *aggstate, TupleHashTable hashtable, TupleHashEntry entry)
Definition: nodeAgg.c:2040
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:102
TupleTableSlot * hashslot
Definition: nodeAgg.h:305
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:719
TupleHashTable hashtable
Definition: nodeAgg.h:303
#define ResetExprContext(econtext)
Definition: executor.h:526
List * list_delete_first(List *list)
Definition: list.c:875

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

Definition at line 2189 of file nodeAgg.c.

References advance_aggregates(), AggState::agg_done, AGG_MIXED, AGG_PLAIN, agg_retrieve_hash_table(), AggState::aggcontexts, AggStatePerPhaseData::aggnode, Agg::aggstrategy, AggState::aggstrategy, Assert, AggState::current_phase, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, AggStatePerPhaseData::eqfunctions, ExecCopySlotHeapTuple(), ExecForceStoreHeapTuple(), ExecQual(), ExecQualAndReset(), fetch_input_tuple(), finalize_aggregates(), AggState::grp_firstTuple, AggStatePerPhaseData::gset_lengths, hashagg_finish_initial_spills(), AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, i, initialize_aggregates(), initialize_phase(), AggState::input_done, lookup_hash_entries(), Max, Agg::numCols, AggState::numphases, AggStatePerPhaseData::numsets, AggState::peragg, AggState::pergroups, AggState::perhash, AggState::phase, prepare_projection_slot(), project_aggregates(), AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, ReScanExprContext(), ResetExprContext, ResetTupleHashIterator, select_current_set(), AggState::ss, ScanState::ss_ScanTupleSlot, AggState::table_filled, AggState::tmpcontext, and TupIsNull.

Referenced by ExecAgg().

2190 {
2191  Agg *node = aggstate->phase->aggnode;
2192  ExprContext *econtext;
2193  ExprContext *tmpcontext;
2194  AggStatePerAgg peragg;
2195  AggStatePerGroup *pergroups;
2196  TupleTableSlot *outerslot;
2197  TupleTableSlot *firstSlot;
2198  TupleTableSlot *result;
2199  bool hasGroupingSets = aggstate->phase->numsets > 0;
2200  int numGroupingSets = Max(aggstate->phase->numsets, 1);
2201  int currentSet;
2202  int nextSetSize;
2203  int numReset;
2204  int i;
2205 
2206  /*
2207  * get state info from node
2208  *
2209  * econtext is the per-output-tuple expression context
2210  *
2211  * tmpcontext is the per-input-tuple expression context
2212  */
2213  econtext = aggstate->ss.ps.ps_ExprContext;
2214  tmpcontext = aggstate->tmpcontext;
2215 
2216  peragg = aggstate->peragg;
2217  pergroups = aggstate->pergroups;
2218  firstSlot = aggstate->ss.ss_ScanTupleSlot;
2219 
2220  /*
2221  * We loop retrieving groups until we find one matching
2222  * aggstate->ss.ps.qual
2223  *
2224  * For grouping sets, we have the invariant that aggstate->projected_set
2225  * is either -1 (initial call) or the index (starting from 0) in
2226  * gset_lengths for the group we just completed (either by projecting a
2227  * row or by discarding it in the qual).
2228  */
2229  while (!aggstate->agg_done)
2230  {
2231  /*
2232  * Clear the per-output-tuple context for each group, as well as
2233  * aggcontext (which contains any pass-by-ref transvalues of the old
2234  * group). Some aggregate functions store working state in child
2235  * contexts; those now get reset automatically without us needing to
2236  * do anything special.
2237  *
2238  * We use ReScanExprContext not just ResetExprContext because we want
2239  * any registered shutdown callbacks to be called. That allows
2240  * aggregate functions to ensure they've cleaned up any non-memory
2241  * resources.
2242  */
2243  ReScanExprContext(econtext);
2244 
2245  /*
2246  * Determine how many grouping sets need to be reset at this boundary.
2247  */
2248  if (aggstate->projected_set >= 0 &&
2249  aggstate->projected_set < numGroupingSets)
2250  numReset = aggstate->projected_set + 1;
2251  else
2252  numReset = numGroupingSets;
2253 
2254  /*
2255  * numReset can change on a phase boundary, but that's OK; we want to
2256  * reset the contexts used in _this_ phase, and later, after possibly
2257  * changing phase, initialize the right number of aggregates for the
2258  * _new_ phase.
2259  */
2260 
2261  for (i = 0; i < numReset; i++)
2262  {
2263  ReScanExprContext(aggstate->aggcontexts[i]);
2264  }
2265 
2266  /*
2267  * Check if input is complete and there are no more groups to project
2268  * in this phase; move to next phase or mark as done.
2269  */
2270  if (aggstate->input_done == true &&
2271  aggstate->projected_set >= (numGroupingSets - 1))
2272  {
2273  if (aggstate->current_phase < aggstate->numphases - 1)
2274  {
2275  initialize_phase(aggstate, aggstate->current_phase + 1);
2276  aggstate->input_done = false;
2277  aggstate->projected_set = -1;
2278  numGroupingSets = Max(aggstate->phase->numsets, 1);
2279  node = aggstate->phase->aggnode;
2280  numReset = numGroupingSets;
2281  }
2282  else if (aggstate->aggstrategy == AGG_MIXED)
2283  {
2284  /*
2285  * Mixed mode; we've output all the grouped stuff and have
2286  * full hashtables, so switch to outputting those.
2287  */
2288  initialize_phase(aggstate, 0);
2289  aggstate->table_filled = true;
2291  &aggstate->perhash[0].hashiter);
2292  select_current_set(aggstate, 0, true);
2293  return agg_retrieve_hash_table(aggstate);
2294  }
2295  else
2296  {
2297  aggstate->agg_done = true;
2298  break;
2299  }
2300  }
2301 
2302  /*
2303  * Get the number of columns in the next grouping set after the last
2304  * projected one (if any). This is the number of columns to compare to
2305  * see if we reached the boundary of that set too.
2306  */
2307  if (aggstate->projected_set >= 0 &&
2308  aggstate->projected_set < (numGroupingSets - 1))
2309  nextSetSize = aggstate->phase->gset_lengths[aggstate->projected_set + 1];
2310  else
2311  nextSetSize = 0;
2312 
2313  /*----------
2314  * If a subgroup for the current grouping set is present, project it.
2315  *
2316  * We have a new group if:
2317  * - we're out of input but haven't projected all grouping sets
2318  * (checked above)
2319  * OR
2320  * - we already projected a row that wasn't from the last grouping
2321  * set
2322  * AND
2323  * - the next grouping set has at least one grouping column (since
2324  * empty grouping sets project only once input is exhausted)
2325  * AND
2326  * - the previous and pending rows differ on the grouping columns
2327  * of the next grouping set
2328  *----------
2329  */
2330  tmpcontext->ecxt_innertuple = econtext->ecxt_outertuple;
2331  if (aggstate->input_done ||
2332  (node->aggstrategy != AGG_PLAIN &&
2333  aggstate->projected_set != -1 &&
2334  aggstate->projected_set < (numGroupingSets - 1) &&
2335  nextSetSize > 0 &&
2336  !ExecQualAndReset(aggstate->phase->eqfunctions[nextSetSize - 1],
2337  tmpcontext)))
2338  {
2339  aggstate->projected_set += 1;
2340 
2341  Assert(aggstate->projected_set < numGroupingSets);
2342  Assert(nextSetSize > 0 || aggstate->input_done);
2343  }
2344  else
2345  {
2346  /*
2347  * We no longer care what group we just projected, the next
2348  * projection will always be the first (or only) grouping set
2349  * (unless the input proves to be empty).
2350  */
2351  aggstate->projected_set = 0;
2352 
2353  /*
2354  * If we don't already have the first tuple of the new group,
2355  * fetch it from the outer plan.
2356  */
2357  if (aggstate->grp_firstTuple == NULL)
2358  {
2359  outerslot = fetch_input_tuple(aggstate);
2360  if (!TupIsNull(outerslot))
2361  {
2362  /*
2363  * Make a copy of the first input tuple; we will use this
2364  * for comparisons (in group mode) and for projection.
2365  */
2366  aggstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
2367  }
2368  else
2369  {
2370  /* outer plan produced no tuples at all */
2371  if (hasGroupingSets)
2372  {
2373  /*
2374  * If there was no input at all, we need to project
2375  * rows only if there are grouping sets of size 0.
2376  * Note that this implies that there can't be any
2377  * references to ungrouped Vars, which would otherwise
2378  * cause issues with the empty output slot.
2379  *
2380  * XXX: This is no longer true, we currently deal with
2381  * this in finalize_aggregates().
2382  */
2383  aggstate->input_done = true;
2384 
2385  while (aggstate->phase->gset_lengths[aggstate->projected_set] > 0)
2386  {
2387  aggstate->projected_set += 1;
2388  if (aggstate->projected_set >= numGroupingSets)
2389  {
2390  /*
2391  * We can't set agg_done here because we might
2392  * have more phases to do, even though the
2393  * input is empty. So we need to restart the
2394  * whole outer loop.
2395  */
2396  break;
2397  }
2398  }
2399 
2400  if (aggstate->projected_set >= numGroupingSets)
2401  continue;
2402  }
2403  else
2404  {
2405  aggstate->agg_done = true;
2406  /* If we are grouping, we should produce no tuples too */
2407  if (node->aggstrategy != AGG_PLAIN)
2408  return NULL;
2409  }
2410  }
2411  }
2412 
2413  /*
2414  * Initialize working state for a new input tuple group.
2415  */
2416  initialize_aggregates(aggstate, pergroups, numReset);
2417 
2418  if (aggstate->grp_firstTuple != NULL)
2419  {
2420  /*
2421  * Store the copied first input tuple in the tuple table slot
2422  * reserved for it. The tuple will be deleted when it is
2423  * cleared from the slot.
2424  */
2426  firstSlot, true);
2427  aggstate->grp_firstTuple = NULL; /* don't keep two pointers */
2428 
2429  /* set up for first advance_aggregates call */
2430  tmpcontext->ecxt_outertuple = firstSlot;
2431 
2432  /*
2433  * Process each outer-plan tuple, and then fetch the next one,
2434  * until we exhaust the outer plan or cross a group boundary.
2435  */
2436  for (;;)
2437  {
2438  /*
2439  * During phase 1 only of a mixed agg, we need to update
2440  * hashtables as well in advance_aggregates.
2441  */
2442  if (aggstate->aggstrategy == AGG_MIXED &&
2443  aggstate->current_phase == 1)
2444  {
2445  lookup_hash_entries(aggstate);
2446  }
2447 
2448  /* Advance the aggregates (or combine functions) */
2449  advance_aggregates(aggstate);
2450 
2451  /* Reset per-input-tuple context after each tuple */
2452  ResetExprContext(tmpcontext);
2453 
2454  outerslot = fetch_input_tuple(aggstate);
2455  if (TupIsNull(outerslot))
2456  {
2457  /* no more outer-plan tuples available */
2458 
2459  /* if we built hash tables, finalize any spills */
2460  if (aggstate->aggstrategy == AGG_MIXED &&
2461  aggstate->current_phase == 1)
2463 
2464  if (hasGroupingSets)
2465  {
2466  aggstate->input_done = true;
2467  break;
2468  }
2469  else
2470  {
2471  aggstate->agg_done = true;
2472  break;
2473  }
2474  }
2475  /* set up for next advance_aggregates call */
2476  tmpcontext->ecxt_outertuple = outerslot;
2477 
2478  /*
2479  * If we are grouping, check whether we've crossed a group
2480  * boundary.
2481  */
2482  if (node->aggstrategy != AGG_PLAIN)
2483  {
2484  tmpcontext->ecxt_innertuple = firstSlot;
2485  if (!ExecQual(aggstate->phase->eqfunctions[node->numCols - 1],
2486  tmpcontext))
2487  {
2488  aggstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
2489  break;
2490  }
2491  }
2492  }
2493  }
2494 
2495  /*
2496  * Use the representative input tuple for any references to
2497  * non-aggregated input columns in aggregate direct args, the node
2498  * qual, and the tlist. (If we are not grouping, and there are no
2499  * input rows at all, we will come here with an empty firstSlot
2500  * ... but if not grouping, there can't be any references to
2501  * non-aggregated input columns, so no problem.)
2502  */
2503  econtext->ecxt_outertuple = firstSlot;
2504  }
2505 
2506  Assert(aggstate->projected_set >= 0);
2507 
2508  currentSet = aggstate->projected_set;
2509 
2510  prepare_projection_slot(aggstate, econtext->ecxt_outertuple, currentSet);
2511 
2512  select_current_set(aggstate, currentSet, false);
2513 
2514  finalize_aggregates(aggstate,
2515  peragg,
2516  pergroups[currentSet]);
2517 
2518  /*
2519  * If there's no row to project right now, we must continue rather
2520  * than returning a null since there might be more groups.
2521  */
2522  result = project_aggregates(aggstate);
2523  if (result)
2524  return result;
2525  }
2526 
2527  /* No more groups */
2528  return NULL;
2529 }
ExprState ** eqfunctions
Definition: nodeAgg.h:278
static TupleTableSlot * fetch_input_tuple(AggState *aggstate)
Definition: nodeAgg.c:567
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:475
int numCols
Definition: plannodes.h:861
bool agg_done
Definition: execnodes.h:2291
ScanState ss
Definition: execnodes.h:2271
ExprContext * ps_ExprContext
Definition: execnodes.h:1003
int current_phase
Definition: execnodes.h:2279
static void hashagg_finish_initial_spills(AggState *aggstate)
Definition: nodeAgg.c:3117
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1376
int projected_set
Definition: execnodes.h:2292
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:395
HeapTuple grp_firstTuple
Definition: execnodes.h:2309
static TupleTableSlot * project_aggregates(AggState *aggstate)
Definition: nodeAgg.c:1372
static void advance_aggregates(AggState *aggstate)
Definition: nodeAgg.c:838
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1469
ExprContext * tmpcontext
Definition: execnodes.h:2284
static void prepare_projection_slot(AggState *aggstate, TupleTableSlot *slot, int currentSet)
Definition: nodeAgg.c:1264
PlanState ps
Definition: execnodes.h:1373
AggStrategy aggstrategy
Definition: plannodes.h:859
bool table_filled
Definition: execnodes.h:2311
AggStrategy aggstrategy
Definition: execnodes.h:2275
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2740
static void finalize_aggregates(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1309
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:228
#define TupIsNull(slot)
Definition: tuptable.h:292
AggStatePerHash perhash
Definition: execnodes.h:2334
static void initialize_aggregates(AggState *aggstate, AggStatePerGroup *pergroups, int numReset)
Definition: nodeAgg.c:685
TupleHashIterator hashiter
Definition: nodeAgg.h:304
bool input_done
Definition: execnodes.h:2290
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:422
AggStatePerPhase phase
Definition: execnodes.h:2277
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:497
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:767
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition: tuptable.h:452
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2283
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:230
#define Assert(condition)
Definition: c.h:804
AggStatePerGroup * pergroups
Definition: execnodes.h:2307
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:438
int numphases
Definition: execnodes.h:2278
AggStatePerAgg peragg
Definition: execnodes.h:2280
int i
Definition: plannodes.h:856
TupleHashTable hashtable
Definition: nodeAgg.h:303
static void lookup_hash_entries(AggState *aggstate)
Definition: nodeAgg.c:2090
#define ResetExprContext(econtext)
Definition: executor.h:526

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

Definition at line 2740 of file nodeAgg.c.

References AggState::agg_done, agg_refill_hash_table(), and agg_retrieve_hash_table_in_memory().

Referenced by agg_retrieve_direct(), and ExecAgg().

2741 {
2742  TupleTableSlot *result = NULL;
2743 
2744  while (result == NULL)
2745  {
2746  result = agg_retrieve_hash_table_in_memory(aggstate);
2747  if (result == NULL)
2748  {
2749  if (!agg_refill_hash_table(aggstate))
2750  {
2751  aggstate->agg_done = true;
2752  break;
2753  }
2754  }
2755  }
2756 
2757  return result;
2758 }
bool agg_done
Definition: execnodes.h:2291
static bool agg_refill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2589
static TupleTableSlot * agg_retrieve_hash_table_in_memory(AggState *aggstate)
Definition: nodeAgg.c:2765

◆ agg_retrieve_hash_table_in_memory()

static TupleTableSlot * agg_retrieve_hash_table_in_memory ( AggState aggstate)
static

Definition at line 2765 of file nodeAgg.c.

References TupleHashEntryData::additional, CHECK_FOR_INTERRUPTS, AggState::current_set, ExprContext::ecxt_outertuple, ExecClearTuple(), ExecStoreMinimalTuple(), ExecStoreVirtualTuple(), finalize_aggregates(), TupleHashEntryData::firstTuple, AggStatePerHashData::hashGrpColIdxInput, AggStatePerHashData::hashiter, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, i, TupleDescData::natts, AggStatePerHashData::numhashGrpCols, AggState::peragg, AggState::perhash, prepare_projection_slot(), project_aggregates(), ScanState::ps, PlanState::ps_ExprContext, ResetExprContext, ResetTupleHashIterator, ScanTupleHashTable, select_current_set(), slot_getallattrs(), AggState::ss, ScanState::ss_ScanTupleSlot, TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, and TupleTableSlot::tts_values.

Referenced by agg_retrieve_hash_table().

2766 {
2767  ExprContext *econtext;
2768  AggStatePerAgg peragg;
2769  AggStatePerGroup pergroup;
2770  TupleHashEntryData *entry;
2771  TupleTableSlot *firstSlot;
2772  TupleTableSlot *result;
2773  AggStatePerHash perhash;
2774 
2775  /*
2776  * get state info from node.
2777  *
2778  * econtext is the per-output-tuple expression context.
2779  */
2780  econtext = aggstate->ss.ps.ps_ExprContext;
2781  peragg = aggstate->peragg;
2782  firstSlot = aggstate->ss.ss_ScanTupleSlot;
2783 
2784  /*
2785  * Note that perhash (and therefore anything accessed through it) can
2786  * change inside the loop, as we change between grouping sets.
2787  */
2788  perhash = &aggstate->perhash[aggstate->current_set];
2789 
2790  /*
2791  * We loop retrieving groups until we find one satisfying
2792  * aggstate->ss.ps.qual
2793  */
2794  for (;;)
2795  {
2796  TupleTableSlot *hashslot = perhash->hashslot;
2797  int i;
2798 
2800 
2801  /*
2802  * Find the next entry in the hash table
2803  */
2804  entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);
2805  if (entry == NULL)
2806  {
2807  int nextset = aggstate->current_set + 1;
2808 
2809  if (nextset < aggstate->num_hashes)
2810  {
2811  /*
2812  * Switch to next grouping set, reinitialize, and restart the
2813  * loop.
2814  */
2815  select_current_set(aggstate, nextset, true);
2816 
2817  perhash = &aggstate->perhash[aggstate->current_set];
2818 
2819  ResetTupleHashIterator(perhash->hashtable, &perhash->hashiter);
2820 
2821  continue;
2822  }
2823  else
2824  {
2825  return NULL;
2826  }
2827  }
2828 
2829  /*
2830  * Clear the per-output-tuple context for each group
2831  *
2832  * We intentionally don't use ReScanExprContext here; if any aggs have
2833  * registered shutdown callbacks, they mustn't be called yet, since we
2834  * might not be done with that agg.
2835  */
2836  ResetExprContext(econtext);
2837 
2838  /*
2839  * Transform representative tuple back into one with the right
2840  * columns.
2841  */
2842  ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);
2843  slot_getallattrs(hashslot);
2844 
2845  ExecClearTuple(firstSlot);
2846  memset(firstSlot->tts_isnull, true,
2847  firstSlot->tts_tupleDescriptor->natts * sizeof(bool));
2848 
2849  for (i = 0; i < perhash->numhashGrpCols; i++)
2850  {
2851  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
2852 
2853  firstSlot->tts_values[varNumber] = hashslot->tts_values[i];
2854  firstSlot->tts_isnull[varNumber] = hashslot->tts_isnull[i];
2855  }
2856  ExecStoreVirtualTuple(firstSlot);
2857 
2858  pergroup = (AggStatePerGroup) entry->additional;
2859 
2860  /*
2861  * Use the representative input tuple for any references to
2862  * non-aggregated input columns in the qual and tlist.
2863  */
2864  econtext->ecxt_outertuple = firstSlot;
2865 
2866  prepare_projection_slot(aggstate,
2867  econtext->ecxt_outertuple,
2868  aggstate->current_set);
2869 
2870  finalize_aggregates(aggstate, peragg, pergroup);
2871 
2872  result = project_aggregates(aggstate);
2873  if (result)
2874  return result;
2875  }
2876 
2877  /* No more groups */
2878  return NULL;
2879 }
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2265
#define ScanTupleHashTable(htable, iter)
Definition: execnodes.h:769
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:475
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.h:311
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1446
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
ScanState ss
Definition: execnodes.h:2271
ExprContext * ps_ExprContext
Definition: execnodes.h:1003
MinimalTuple firstTuple
Definition: execnodes.h:722
Datum * tts_values
Definition: tuptable.h:126
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1376
static TupleTableSlot * project_aggregates(AggState *aggstate)
Definition: nodeAgg.c:1372
int current_set
Definition: execnodes.h:2294
static void prepare_projection_slot(AggState *aggstate, TupleTableSlot *slot, int currentSet)
Definition: nodeAgg.c:1264
PlanState ps
Definition: execnodes.h:1373
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:354
static void finalize_aggregates(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1309
bool * tts_isnull
Definition: tuptable.h:128
AggStatePerHash perhash
Definition: execnodes.h:2334
TupleHashIterator hashiter
Definition: nodeAgg.h:304
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:767
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:230
AggStatePerAgg peragg
Definition: execnodes.h:2280
int i
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:102
TupleTableSlot * hashslot
Definition: nodeAgg.h:305
TupleHashTable hashtable
Definition: nodeAgg.h:303
#define ResetExprContext(econtext)
Definition: executor.h:526
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1552

◆ AggCheckCallContext()

int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

Definition at line 4587 of file nodeAgg.c.

References AGG_CONTEXT_AGGREGATE, AGG_CONTEXT_WINDOW, FunctionCallInfoBaseData::context, AggState::curaggcontext, ExprContext::ecxt_per_tuple_memory, and IsA.

Referenced by array_agg_array_finalfn(), array_agg_array_transfn(), array_agg_finalfn(), array_agg_transfn(), bytea_string_agg_finalfn(), 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(), int2_sum(), int4_avg_accum(), int4_avg_accum_inv(), int4_avg_combine(), int4_sum(), int8_avg_combine(), int8_avg_deserialize(), int8_avg_serialize(), int8dec(), int8inc(), json_agg_finalfn(), json_agg_transfn(), json_object_agg_finalfn(), json_object_agg_transfn(), jsonb_agg_finalfn(), jsonb_agg_transfn(), jsonb_object_agg_finalfn(), jsonb_object_agg_transfn(), makeBoolAggState(), makeNumericAggState(), makeStringAggState(), mode_final(), multirange_intersect_agg_transfn(), numeric_accum_inv(), 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(), and string_agg_finalfn().

4588 {
4589  if (fcinfo->context && IsA(fcinfo->context, AggState))
4590  {
4591  if (aggcontext)
4592  {
4593  AggState *aggstate = ((AggState *) fcinfo->context);
4594  ExprContext *cxt = aggstate->curaggcontext;
4595 
4596  *aggcontext = cxt->ecxt_per_tuple_memory;
4597  }
4598  return AGG_CONTEXT_AGGREGATE;
4599  }
4600  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4601  {
4602  if (aggcontext)
4603  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4604  return AGG_CONTEXT_WINDOW;
4605  }
4606 
4607  /* this is just to prevent "uninitialized variable" warnings */
4608  if (aggcontext)
4609  *aggcontext = NULL;
4610  return 0;
4611 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
fmNodePtr context
Definition: fmgr.h:88
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:738
ExprContext * curaggcontext
Definition: execnodes.h:2286
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:739

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4631 of file nodeAgg.c.

References AggStatePerTransData::aggref, AggStatePerAggData::aggref, FunctionCallInfoBaseData::context, AggState::curperagg, AggState::curpertrans, and IsA.

Referenced by ordered_set_startup().

4632 {
4633  if (fcinfo->context && IsA(fcinfo->context, AggState))
4634  {
4635  AggState *aggstate = (AggState *) fcinfo->context;
4636  AggStatePerAgg curperagg;
4637  AggStatePerTrans curpertrans;
4638 
4639  /* check curperagg (valid when in a final function) */
4640  curperagg = aggstate->curperagg;
4641 
4642  if (curperagg)
4643  return curperagg->aggref;
4644 
4645  /* check curpertrans (valid when in a transition function) */
4646  curpertrans = aggstate->curpertrans;
4647 
4648  if (curpertrans)
4649  return curpertrans->aggref;
4650  }
4651  return NULL;
4652 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
fmNodePtr context
Definition: fmgr.h:88
Aggref * aggref
Definition: nodeAgg.h:187
Aggref * aggref
Definition: nodeAgg.h:44
AggStatePerAgg curperagg
Definition: execnodes.h:2287
AggStatePerTrans curpertrans
Definition: execnodes.h:2289

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4665 of file nodeAgg.c.

References FunctionCallInfoBaseData::context, ExprContext::ecxt_per_tuple_memory, IsA, and AggState::tmpcontext.

4666 {
4667  if (fcinfo->context && IsA(fcinfo->context, AggState))
4668  {
4669  AggState *aggstate = (AggState *) fcinfo->context;
4670 
4671  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4672  }
4673  return NULL;
4674 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
fmNodePtr context
Definition: fmgr.h:88
ExprContext * tmpcontext
Definition: execnodes.h:2284

◆ AggRegisterCallback()

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

Definition at line 4730 of file nodeAgg.c.

References FunctionCallInfoBaseData::context, AggState::curaggcontext, elog, ERROR, IsA, and RegisterExprContextCallback().

Referenced by ordered_set_startup().

4733 {
4734  if (fcinfo->context && IsA(fcinfo->context, AggState))
4735  {
4736  AggState *aggstate = (AggState *) fcinfo->context;
4737  ExprContext *cxt = aggstate->curaggcontext;
4738 
4739  RegisterExprContextCallback(cxt, func, arg);
4740 
4741  return;
4742  }
4743  elog(ERROR, "aggregate function cannot register a callback in this context");
4744 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
fmNodePtr context
Definition: fmgr.h:88
#define ERROR
Definition: elog.h:46
ExprContext * curaggcontext
Definition: execnodes.h:2286
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:925
#define elog(elevel,...)
Definition: elog.h:232
void * arg

◆ AggStateIsShared()

bool AggStateIsShared ( FunctionCallInfo  fcinfo)

Definition at line 4691 of file nodeAgg.c.

References AggStatePerTransData::aggshared, FunctionCallInfoBaseData::context, AggState::curperagg, AggState::curpertrans, IsA, and AggState::pertrans.

Referenced by ordered_set_startup().

4692 {
4693  if (fcinfo->context && IsA(fcinfo->context, AggState))
4694  {
4695  AggState *aggstate = (AggState *) fcinfo->context;
4696  AggStatePerAgg curperagg;
4697  AggStatePerTrans curpertrans;
4698 
4699  /* check curperagg (valid when in a final function) */
4700  curperagg = aggstate->curperagg;
4701 
4702  if (curperagg)
4703  return aggstate->pertrans[curperagg->transno].aggshared;
4704 
4705  /* check curpertrans (valid when in a transition function) */
4706  curpertrans = aggstate->curpertrans;
4707 
4708  if (curpertrans)
4709  return curpertrans->aggshared;
4710  }
4711  return true;
4712 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
fmNodePtr context
Definition: fmgr.h:88
AggStatePerTrans pertrans
Definition: execnodes.h:2281
AggStatePerAgg curperagg
Definition: execnodes.h:2287
AggStatePerTrans curpertrans
Definition: execnodes.h:2289

◆ build_hash_table()

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

Definition at line 1504 of file nodeAgg.c.

References AGG_HASHED, AGG_MIXED, AggStatePerHashData::aggnode, AggState::aggsplit, AggState::aggstrategy, Assert, BuildTupleHashTableExt(), DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_per_tuple_memory, AggStatePerHashData::eqfuncoids, Agg::grpCollations, AggState::hash_metacxt, AggState::hashcontext, AggStatePerHashData::hashfunctions, AggStatePerHashData::hashGrpColIdxHash, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, AggStatePerHashData::numCols, AggState::numtrans, AggState::perhash, ScanState::ps, AggState::ss, AggState::tmpcontext, and TupleTableSlot::tts_tupleDescriptor.

Referenced by build_hash_tables().

1505 {
1506  AggStatePerHash perhash = &aggstate->perhash[setno];
1507  MemoryContext metacxt = aggstate->hash_metacxt;
1508  MemoryContext hashcxt = aggstate->hashcontext->ecxt_per_tuple_memory;
1509  MemoryContext tmpcxt = aggstate->tmpcontext->ecxt_per_tuple_memory;
1510  Size additionalsize;
1511 
1512  Assert(aggstate->aggstrategy == AGG_HASHED ||
1513  aggstate->aggstrategy == AGG_MIXED);
1514 
1515  /*
1516  * Used to make sure initial hash table allocation does not exceed
1517  * hash_mem. Note that the estimate does not include space for
1518  * pass-by-reference transition data values, nor for the representative
1519  * tuple of each group.
1520  */
1521  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1522 
1523  perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
1524  perhash->hashslot->tts_tupleDescriptor,
1525  perhash->numCols,
1526  perhash->hashGrpColIdxHash,
1527  perhash->eqfuncoids,
1528  perhash->hashfunctions,
1529  perhash->aggnode->grpCollations,
1530  nbuckets,
1531  additionalsize,
1532  metacxt,
1533  hashcxt,
1534  tmpcxt,
1535  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1536 }
TupleHashTable BuildTupleHashTableExt(PlanState *parent, TupleDesc inputDesc, int numCols, AttrNumber *keyColIdx, const Oid *eqfuncoids, FmgrInfo *hashfunctions, Oid *collations, long nbuckets, Size additionalsize, MemoryContext metacxt, MemoryContext tablecxt, MemoryContext tempcxt, bool use_variable_hash_iv)
Definition: execGrouping.c:154
Oid * grpCollations
Definition: plannodes.h:864
ScanState ss
Definition: execnodes.h:2271
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
AggSplit aggsplit
Definition: execnodes.h:2276
int numtrans
Definition: execnodes.h:2274
ExprContext * tmpcontext
Definition: execnodes.h:2284
PlanState ps
Definition: execnodes.h:1373
AggStrategy aggstrategy
Definition: execnodes.h:2275
MemoryContext hash_metacxt
Definition: execnodes.h:2313
struct AggStatePerGroupData AggStatePerGroupData
AggStatePerHash perhash
Definition: execnodes.h:2334
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:312
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2282
FmgrInfo * hashfunctions
Definition: nodeAgg.h:306
#define Assert(condition)
Definition: c.h:804
size_t Size
Definition: c.h:540
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:802
TupleTableSlot * hashslot
Definition: nodeAgg.h:305
TupleHashTable hashtable
Definition: nodeAgg.h:303

◆ build_hash_tables()

static void build_hash_tables ( AggState aggstate)
static

Definition at line 1469 of file nodeAgg.c.

References AggStatePerHashData::aggnode, Assert, build_hash_table(), hash_choose_num_buckets(), AggState::hash_mem_limit, AggState::hash_ngroups_current, AggState::hashentrysize, AggStatePerHashData::hashtable, AggState::num_hashes, Agg::numGroups, AggState::perhash, and ResetTupleHashTable().

Referenced by ExecInitAgg(), and ExecReScanAgg().

1470 {
1471  int setno;
1472 
1473  for (setno = 0; setno < aggstate->num_hashes; ++setno)
1474  {
1475  AggStatePerHash perhash = &aggstate->perhash[setno];
1476  long nbuckets;
1477  Size memory;
1478 
1479  if (perhash->hashtable != NULL)
1480  {
1481  ResetTupleHashTable(perhash->hashtable);
1482  continue;
1483  }
1484 
1485  Assert(perhash->aggnode->numGroups > 0);
1486 
1487  memory = aggstate->hash_mem_limit / aggstate->num_hashes;
1488 
1489  /* choose reasonable number of buckets per hashtable */
1490  nbuckets = hash_choose_num_buckets(aggstate->hashentrysize,
1491  perhash->aggnode->numGroups,
1492  memory);
1493 
1494  build_hash_table(aggstate, setno, nbuckets);
1495  }
1496 
1497  aggstate->hash_ngroups_current = 0;
1498 }
double hashentrysize
Definition: execnodes.h:2327
static long hash_choose_num_buckets(double hashentrysize, long estimated_nbuckets, Size memory)
Definition: nodeAgg.c:1965
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:283
static void build_hash_table(AggState *aggstate, int setno, long nbuckets)
Definition: nodeAgg.c:1504
AggStatePerHash perhash
Definition: execnodes.h:2334
int num_hashes
Definition: execnodes.h:2312
#define Assert(condition)
Definition: c.h:804
size_t Size
Definition: c.h:540
long numGroups
Definition: plannodes.h:865
Size hash_mem_limit
Definition: execnodes.h:2323
uint64 hash_ngroups_current
Definition: execnodes.h:2329
TupleHashTable hashtable
Definition: nodeAgg.h:303

◆ build_pertrans_for_aggref()

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

Definition at line 4046 of file nodeAgg.c.

References AGG_HASHED, AGG_MIXED, AggStatePerTransData::aggCollation, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggkind, Aggref::aggorder, AggStatePerTransData::aggref, AggStatePerTransData::aggshared, AggState::aggsplit, AggState::aggstrategy, AggStatePerTransData::aggtranstype, Aggref::aggvariadic, Aggref::args, Assert, build_aggregate_combinefn_expr(), 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, ereport, errcode(), errmsg(), ERROR, ExecInitExtraTupleSlot(), execTuplesMatchPrepare(), ExecTypeFromTL(), TargetEntry::expr, exprCollation(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_strict, format_type_be(), get_opcode(), get_sortgroupclause_tle(), get_typlenbyval(), i, InitFunctionCallInfoData, AggStatePerTransData::initValue, initValue(), AggStatePerTransData::initValueIsNull, Aggref::inputcollid, AggStatePerTransData::inputtypeByVal, AggStatePerTransData::inputtypeLen, InvalidOid, IsBinaryCoercible(), lfirst, list_length(), Max, AggState::maxsets, NIL, SortGroupClause::nulls_first, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numInputs, AggStatePerTransData::numSortCols, AggStatePerTransData::numTransInputs, OidIsValid, palloc(), palloc0(), pfree(), ScanState::ps, TargetEntry::resno, AggStatePerTransData::serialfn, AggStatePerTransData::serialfn_fcinfo, AggStatePerTransData::serialfn_oid, SizeForFunctionCallInfo, AggStatePerTransData::sortColIdx, AggStatePerTransData::sortCollations, AggStatePerTransData::sortdesc, AggStatePerTransData::sortNullsFirst, SortGroupClause::sortop, AggStatePerTransData::sortOperators, AggStatePerTransData::sortslot, AggStatePerTransData::sortstates, AggState::ss, AggStatePerTransData::transfn, AggStatePerTransData::transfn_fcinfo, AggStatePerTransData::transfn_oid, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, TTSOpsMinimalTuple, and AggStatePerTransData::uniqslot.

Referenced by ExecInitAgg().

4053 {
4054  int numGroupingSets = Max(aggstate->maxsets, 1);
4055  Expr *serialfnexpr = NULL;
4056  Expr *deserialfnexpr = NULL;
4057  ListCell *lc;
4058  int numInputs;
4059  int numDirectArgs;
4060  List *sortlist;
4061  int numSortCols;
4062  int numDistinctCols;
4063  int i;
4064 
4065  /* Begin filling in the pertrans data */
4066  pertrans->aggref = aggref;
4067  pertrans->aggshared = false;
4068  pertrans->aggCollation = aggref->inputcollid;
4069  pertrans->transfn_oid = aggtransfn;
4070  pertrans->serialfn_oid = aggserialfn;
4071  pertrans->deserialfn_oid = aggdeserialfn;
4072  pertrans->initValue = initValue;
4073  pertrans->initValueIsNull = initValueIsNull;
4074 
4075  /* Count the "direct" arguments, if any */
4076  numDirectArgs = list_length(aggref->aggdirectargs);
4077 
4078  /* Count the number of aggregated input columns */
4079  pertrans->numInputs = numInputs = list_length(aggref->args);
4080 
4081  pertrans->aggtranstype = aggtranstype;
4082 
4083  /*
4084  * When combining states, we have no use at all for the aggregate
4085  * function's transfn. Instead we use the combinefn. In this case, the
4086  * transfn and transfn_oid fields of pertrans refer to the combine
4087  * function rather than the transition function.
4088  */
4089  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
4090  {
4091  Expr *combinefnexpr;
4092  size_t numTransArgs;
4093 
4094  /*
4095  * When combining there's only one input, the to-be-combined added
4096  * transition value from below (this node's transition value is
4097  * counted separately).
4098  */
4099  pertrans->numTransInputs = 1;
4100 
4101  /* account for the current transition state */
4102  numTransArgs = pertrans->numTransInputs + 1;
4103 
4104  build_aggregate_combinefn_expr(aggtranstype,
4105  aggref->inputcollid,
4106  aggtransfn,
4107  &combinefnexpr);
4108  fmgr_info(aggtransfn, &pertrans->transfn);
4109  fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
4110 
4111  pertrans->transfn_fcinfo =
4114  &pertrans->transfn,
4115  numTransArgs,
4116  pertrans->aggCollation,
4117  (void *) aggstate, NULL);
4118 
4119  /*
4120  * Ensure that a combine function to combine INTERNAL states is not
4121  * strict. This should have been checked during CREATE AGGREGATE, but
4122  * the strict property could have been changed since then.
4123  */
4124  if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
4125  ereport(ERROR,
4126  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4127  errmsg("combine function with transition type %s must not be declared STRICT",
4128  format_type_be(aggtranstype))));
4129  }
4130  else
4131  {
4132  Expr *transfnexpr;
4133  size_t numTransArgs;
4134 
4135  /* Detect how many arguments to pass to the transfn */
4136  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4137  pertrans->numTransInputs = numInputs;
4138  else
4139  pertrans->numTransInputs = numArguments;
4140 
4141  /* account for the current transition state */
4142  numTransArgs = pertrans->numTransInputs + 1;
4143 
4144  /*
4145  * Set up infrastructure for calling the transfn. Note that
4146  * invtransfn is not needed here.
4147  */
4148  build_aggregate_transfn_expr(inputTypes,
4149  numArguments,
4150  numDirectArgs,
4151  aggref->aggvariadic,
4152  aggtranstype,
4153  aggref->inputcollid,
4154  aggtransfn,
4155  InvalidOid,
4156  &transfnexpr,
4157  NULL);
4158  fmgr_info(aggtransfn, &pertrans->transfn);
4159  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
4160 
4161  pertrans->transfn_fcinfo =
4164  &pertrans->transfn,
4165  numTransArgs,
4166  pertrans->aggCollation,
4167  (void *) aggstate, NULL);
4168 
4169  /*
4170  * If the transfn is strict and the initval is NULL, make sure input
4171  * type and transtype are the same (or at least binary-compatible), so
4172  * that it's OK to use the first aggregated input value as the initial
4173  * transValue. This should have been checked at agg definition time,
4174  * but we must check again in case the transfn's strictness property
4175  * has been changed.
4176  */
4177  if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
4178  {
4179  if (numArguments <= numDirectArgs ||
4180  !IsBinaryCoercible(inputTypes[numDirectArgs],
4181  aggtranstype))
4182  ereport(ERROR,
4183  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4184  errmsg("aggregate %u needs to have compatible input type and transition type",
4185  aggref->aggfnoid)));
4186  }
4187  }
4188 
4189  /* get info about the state value's datatype */
4190  get_typlenbyval(aggtranstype,
4191  &pertrans->transtypeLen,
4192  &pertrans->transtypeByVal);
4193 
4194  if (OidIsValid(aggserialfn))
4195  {
4196  build_aggregate_serialfn_expr(aggserialfn,
4197  &serialfnexpr);
4198  fmgr_info(aggserialfn, &pertrans->serialfn);
4199  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
4200 
4201  pertrans->serialfn_fcinfo =
4204  &pertrans->serialfn,
4205  1,
4206  InvalidOid,
4207  (void *) aggstate, NULL);
4208  }
4209 
4210  if (OidIsValid(aggdeserialfn))
4211  {
4212  build_aggregate_deserialfn_expr(aggdeserialfn,
4213  &deserialfnexpr);
4214  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
4215  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
4216 
4217  pertrans->deserialfn_fcinfo =
4220  &pertrans->deserialfn,
4221  2,
4222  InvalidOid,
4223  (void *) aggstate, NULL);
4224 
4225  }
4226 
4227  /*
4228  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
4229  * have a list of SortGroupClause nodes; fish out the data in them and
4230  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
4231  * however; the agg's transfn and finalfn are responsible for that.
4232  *
4233  * Note that by construction, if there is a DISTINCT clause then the ORDER
4234  * BY clause is a prefix of it (see transformDistinctClause).
4235  */
4236  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4237  {
4238  sortlist = NIL;
4239  numSortCols = numDistinctCols = 0;
4240  }
4241  else if (aggref->aggdistinct)
4242  {
4243  sortlist = aggref->aggdistinct;
4244  numSortCols = numDistinctCols = list_length(sortlist);
4245  Assert(numSortCols >= list_length(aggref->aggorder));
4246  }
4247  else
4248  {
4249  sortlist = aggref->aggorder;
4250  numSortCols = list_length(sortlist);
4251  numDistinctCols = 0;
4252  }
4253 
4254  pertrans->numSortCols = numSortCols;
4255  pertrans->numDistinctCols = numDistinctCols;
4256 
4257  /*
4258  * If we have either sorting or filtering to do, create a tupledesc and
4259  * slot corresponding to the aggregated inputs (including sort
4260  * expressions) of the agg.
4261  */
4262  if (numSortCols > 0 || aggref->aggfilter)
4263  {
4264  pertrans->sortdesc = ExecTypeFromTL(aggref->args);
4265  pertrans->sortslot =
4266  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4268  }
4269 
4270  if (numSortCols > 0)
4271  {
4272  /*
4273  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
4274  * (yet)
4275  */
4276  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
4277 
4278  /* If we have only one input, we need its len/byval info. */
4279  if (numInputs == 1)
4280  {
4281  get_typlenbyval(inputTypes[numDirectArgs],
4282  &pertrans->inputtypeLen,
4283  &pertrans->inputtypeByVal);
4284  }
4285  else if (numDistinctCols > 0)
4286  {
4287  /* we will need an extra slot to store prior values */
4288  pertrans->uniqslot =
4289  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4291  }
4292 
4293  /* Extract the sort information for use later */
4294  pertrans->sortColIdx =
4295  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
4296  pertrans->sortOperators =
4297  (Oid *) palloc(numSortCols * sizeof(Oid));
4298  pertrans->sortCollations =
4299  (Oid *) palloc(numSortCols * sizeof(Oid));
4300  pertrans->sortNullsFirst =
4301  (bool *) palloc(numSortCols * sizeof(bool));
4302 
4303  i = 0;
4304  foreach(lc, sortlist)
4305  {
4306  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
4307  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
4308 
4309  /* the parser should have made sure of this */
4310  Assert(OidIsValid(sortcl->sortop));
4311 
4312  pertrans->sortColIdx[i] = tle->resno;
4313  pertrans->sortOperators[i] = sortcl->sortop;
4314  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
4315  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
4316  i++;
4317  }
4318  Assert(i == numSortCols);
4319  }
4320 
4321  if (aggref->aggdistinct)
4322  {
4323  Oid *ops;
4324 
4325  Assert(numArguments > 0);
4326  Assert(list_length(aggref->aggdistinct) == numDistinctCols);
4327 
4328  ops = palloc(numDistinctCols * sizeof(Oid));
4329 
4330  i = 0;
4331  foreach(lc, aggref->aggdistinct)
4332  ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
4333 
4334  /* lookup / build the necessary comparators */
4335  if (numDistinctCols == 1)
4336  fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
4337  else
4338  pertrans->equalfnMulti =
4339  execTuplesMatchPrepare(pertrans->sortdesc,
4340  numDistinctCols,
4341  pertrans->sortColIdx,
4342  ops,
4343  pertrans->sortCollations,
4344  &aggstate->ss.ps);
4345  pfree(ops);
4346  }
4347 
4348  pertrans->sortstates = (Tuplesortstate **)
4349  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
4350 }
List * aggdistinct
Definition: primnodes.h:332
#define NIL
Definition: pg_list.h:65
bool aggvariadic
Definition: primnodes.h:335
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:356
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1831
ScanState ss
Definition: execnodes.h:2271
FmgrInfo equalfnOne
Definition: nodeAgg.h:110
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
Oid inputcollid
Definition: primnodes.h:326
Definition: nodes.h:539
AggSplit aggsplit
Definition: execnodes.h:2276
int errcode(int sqlerrcode)
Definition: elog.c:698
List * args
Definition: primnodes.h:330
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
void build_aggregate_deserialfn_expr(Oid deserialfn_oid, Expr **deserialfnexpr)
Definition: parse_agg.c:2080
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:801
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:162
TupleDesc sortdesc
Definition: nodeAgg.h:138
FmgrInfo transfn
Definition: nodeAgg.h:81
Aggref * aggref
Definition: nodeAgg.h:44
PlanState ps
Definition: execnodes.h:1373
int maxsets
Definition: execnodes.h:2301
void pfree(void *pointer)
Definition: mcxt.c:1169
AggStrategy aggstrategy
Definition: execnodes.h:2275
#define ERROR
Definition: elog.h:46
bool fn_strict
Definition: fmgr.h:61
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
ExprState * equalfnMulti
Definition: nodeAgg.h:111
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
static int initValue(long lng_val)
Definition: informix.c:677
List * aggorder
Definition: primnodes.h:331
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
AttrNumber resno
Definition: primnodes.h:1445
List * aggdirectargs
Definition: primnodes.h:329
AttrNumber * sortColIdx
Definition: nodeAgg.h:100
void build_aggregate_combinefn_expr(Oid agg_state_type, Oid agg_input_collation, Oid combinefn_oid, Expr **combinefnexpr)
Definition: parse_agg.c:2028
bool IsBinaryCoercible(Oid srctype, Oid targettype)
void * palloc0(Size size)
Definition: mcxt.c:1093
struct FunctionCallInfoBaseData * FunctionCallInfo
Definition: fmgr.h:38
FmgrInfo deserialfn
Definition: nodeAgg.h:87
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1256
Oid aggfnoid
Definition: primnodes.h:323
#define ereport(elevel,...)
Definition: elog.h:157
#define Max(x, y)
Definition: c.h:980
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
FmgrInfo serialfn
Definition: nodeAgg.h:84
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:167
void build_aggregate_serialfn_expr(Oid serialfn_oid, Expr **serialfnexpr)
Definition: parse_agg.c:2057
Expr * expr
Definition: primnodes.h:1444
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:1967
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
FunctionCallInfo serialfn_fcinfo
Definition: nodeAgg.h:165
static int list_length(const List *l)
Definition: pg_list.h:149
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:759
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2198
Expr * aggfilter
Definition: primnodes.h:333
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1938
TupleTableSlot * uniqslot
Definition: nodeAgg.h:137
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
char aggkind
Definition: primnodes.h:337
TupleTableSlot * sortslot
Definition: nodeAgg.h:136
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
bool * sortNullsFirst
Definition: nodeAgg.h:103

◆ ExecAgg()

static TupleTableSlot* ExecAgg ( PlanState pstate)
static

Definition at line 2153 of file nodeAgg.c.

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, AggState::phase, AggState::table_filled, and TupIsNull.

Referenced by ExecInitAgg().

2154 {
2155  AggState *node = castNode(AggState, pstate);
2156  TupleTableSlot *result = NULL;
2157 
2159 
2160  if (!node->agg_done)
2161  {
2162  /* Dispatch based on strategy */
2163  switch (node->phase->aggstrategy)
2164  {
2165  case AGG_HASHED:
2166  if (!node->table_filled)
2167  agg_fill_hash_table(node);
2168  /* FALLTHROUGH */
2169  case AGG_MIXED:
2170  result = agg_retrieve_hash_table(node);
2171  break;
2172  case AGG_PLAIN:
2173  case AGG_SORTED:
2174  result = agg_retrieve_direct(node);
2175  break;
2176  }
2177 
2178  if (!TupIsNull(result))
2179  return result;
2180  }
2181 
2182  return NULL;
2183 }
static void agg_fill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2535
bool agg_done
Definition: execnodes.h:2291
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
bool table_filled
Definition: execnodes.h:2311
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2740
static TupleTableSlot * agg_retrieve_direct(AggState *aggstate)
Definition: nodeAgg.c:2189
#define TupIsNull(slot)
Definition: tuptable.h:292
AggStrategy aggstrategy
Definition: nodeAgg.h:274
AggStatePerPhase phase
Definition: execnodes.h:2277
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:102

◆ ExecAggEstimate()

void ExecAggEstimate ( AggState node,
ParallelContext pcxt 
)

Definition at line 4759 of file nodeAgg.c.

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

Referenced by ExecParallelEstimate().

4760 {
4761  Size size;
4762 
4763  /* don't need this if not instrumenting or no workers */
4764  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4765  return;
4766 
4767  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4768  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4769  shm_toc_estimate_chunk(&pcxt->estimator, size);
4770  shm_toc_estimate_keys(&pcxt->estimator, 1);
4771 }
Instrumentation * instrument
Definition: execnodes.h:974
ScanState ss
Definition: execnodes.h:2271
shm_toc_estimator estimator
Definition: parallel.h:42
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
PlanState ps
Definition: execnodes.h:1373
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
size_t Size
Definition: c.h:540
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
#define offsetof(type, field)
Definition: c.h:727

◆ ExecAggInitializeDSM()

void ExecAggInitializeDSM ( AggState node,
ParallelContext pcxt 
)

Definition at line 4780 of file nodeAgg.c.

References PlanState::instrument, SharedAggInfo::num_workers, ParallelContext::nworkers, offsetof, 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().

4781 {
4782  Size size;
4783 
4784  /* don't need this if not instrumenting or no workers */
4785  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4786  return;
4787 
4788  size = offsetof(SharedAggInfo, sinstrument)
4789  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4790  node->shared_info = shm_toc_allocate(pcxt->toc, size);
4791  /* ensure any unfilled slots will contain zeroes */
4792  memset(node->shared_info, 0, size);
4793  node->shared_info->num_workers = pcxt->nworkers;
4794  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4795  node->shared_info);
4796 }
Instrumentation * instrument
Definition: execnodes.h:974
ScanState ss
Definition: execnodes.h:2271
int plan_node_id
Definition: plannodes.h:140
PlanState ps
Definition: execnodes.h:1373
struct AggregateInstrumentation AggregateInstrumentation
Plan * plan
Definition: execnodes.h:964
size_t Size
Definition: c.h:540
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:2343
#define offsetof(type, field)
Definition: c.h:727
shm_toc * toc
Definition: parallel.h:45

◆ ExecAggInitializeWorker()

void ExecAggInitializeWorker ( AggState node,
ParallelWorkerContext pwcxt 
)

Definition at line 4805 of file nodeAgg.c.

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

Referenced by ExecParallelInitializeWorker().

4806 {
4807  node->shared_info =
4808  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4809 }
ScanState ss
Definition: execnodes.h:2271
int plan_node_id
Definition: plannodes.h:140
PlanState ps
Definition: execnodes.h:1373
Plan * plan
Definition: execnodes.h:964
SharedAggInfo * shared_info
Definition: execnodes.h:2343
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 4818 of file nodeAgg.c.

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

Referenced by ExecParallelRetrieveInstrumentation().

4819 {
4820  Size size;
4821  SharedAggInfo *si;
4822 
4823  if (node->shared_info == NULL)
4824  return;
4825 
4826  size = offsetof(SharedAggInfo, sinstrument)
4828  si = palloc(size);
4829  memcpy(si, node->shared_info, size);
4830  node->shared_info = si;
4831 }
struct AggregateInstrumentation AggregateInstrumentation
size_t Size
Definition: c.h:540
void * palloc(Size size)
Definition: mcxt.c:1062
SharedAggInfo * shared_info
Definition: execnodes.h:2343
#define offsetof(type, field)
Definition: c.h:727

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 4370 of file nodeAgg.c.

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

Referenced by ExecEndNode().

4371 {
4373  int transno;
4374  int numGroupingSets = Max(node->maxsets, 1);
4375  int setno;
4376 
4377  /*
4378  * When ending a parallel worker, copy the statistics gathered by the
4379  * worker back into shared memory so that it can be picked up by the main
4380  * process to report in EXPLAIN ANALYZE.
4381  */
4382  if (node->shared_info && IsParallelWorker())
4383  {
4385 
4386  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4389  si->hash_disk_used = node->hash_disk_used;
4390  si->hash_mem_peak = node->hash_mem_peak;
4391  }
4392 
4393  /* Make sure we have closed any open tuplesorts */
4394 
4395  if (node->sort_in)
4396  tuplesort_end(node->sort_in);
4397  if (node->sort_out)
4398  tuplesort_end(node->sort_out);
4399 
4401 
4402  if (node->hash_metacxt != NULL)
4403  {
4405  node->hash_metacxt = NULL;
4406  }
4407 
4408  for (transno = 0; transno < node->numtrans; transno++)
4409  {
4410  AggStatePerTrans pertrans = &node->pertrans[transno];
4411 
4412  for (setno = 0; setno < numGroupingSets; setno++)
4413  {
4414  if (pertrans->sortstates[setno])
4415  tuplesort_end(pertrans->sortstates[setno]);
4416  }
4417  }
4418 
4419  /* And ensure any agg shutdown callbacks have been called */
4420  for (setno = 0; setno < numGroupingSets; setno++)
4421  ReScanExprContext(node->aggcontexts[setno]);
4422  if (node->hashcontext)
4424 
4425  /*
4426  * We don't actually free any ExprContexts here (see comment in
4427  * ExecFreeExprContext), just unlinking the output one from the plan node
4428  * suffices.
4429  */
4430  ExecFreeExprContext(&node->ss.ps);
4431 
4432  /* clean up tuple table */
4434 
4435  outerPlan = outerPlanState(node);
4436  ExecEndNode(outerPlan);
4437 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3193
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:555
Tuplesortstate * sort_out
Definition: execnodes.h:2304
ScanState ss
Definition: execnodes.h:2271
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1376
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2247
AggStatePerTrans pertrans
Definition: execnodes.h:2281
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
int numtrans
Definition: execnodes.h:2274
PlanState ps
Definition: execnodes.h:1373
int maxsets
Definition: execnodes.h:2301
MemoryContext hash_metacxt
Definition: execnodes.h:2313
Tuplesortstate * sort_in
Definition: execnodes.h:2303
#define outerPlanState(node)
Definition: execnodes.h:1058
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
int ParallelWorkerNumber
Definition: parallel.c:112
#define IsParallelWorker()
Definition: parallel.h:61
int hash_batches_used
Definition: execnodes.h:2332
#define outerPlan(node)
Definition: plannodes.h:171
ExprContext * hashcontext
Definition: execnodes.h:2282
uint64 hash_disk_used
Definition: execnodes.h:2331
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2283
#define Assert(condition)
Definition: c.h:804
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:438
Size hash_mem_peak
Definition: execnodes.h:2328
SharedAggInfo * shared_info
Definition: execnodes.h:2343
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1464

◆ ExecInitAgg()

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

Definition at line 3245 of file nodeAgg.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, AggState::agg_done, AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, AggState::aggcontexts, AggStatePerAggData::aggdirectargs, Aggref::aggdirectargs, AGGFNOID, Aggref::aggfnoid, Aggref::agglevelsup, Aggref::aggno, AggStatePerPhaseData::aggnode, AggStatePerHashData::aggnode, AggStatePerTransData::aggref, AggStatePerAggData::aggref, AggState::aggs, AggStatePerTransData::aggshared, Aggref::aggsplit, Agg::aggsplit, AggState::aggsplit, AggStatePerPhaseData::aggstrategy, Agg::aggstrategy, AggState::aggstrategy, Aggref::aggtransno, Aggref::aggtranstype, Aggref::aggtype, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, bms_add_member(), bms_add_members(), bms_next_member(), build_aggregate_finalfn_expr(), build_hash_tables(), build_pertrans_for_aggref(), castNode, Agg::chain, CreateWorkExprContext(), AggState::curperagg, AggState::curpertrans, AggState::current_set, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_DESERIALIZE, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, elog, AggStatePerPhaseData::eqfunctions, ereport, errcode(), errmsg(), ERROR, EState::es_query_cxt, AggStatePerPhaseData::evaltrans, AggStatePerPhaseData::evaltrans_cache, EXEC_FLAG_BACKWARD, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_MARK, EXEC_FLAG_REWIND, ExecAgg(), ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecBuildAggTrans(), ExecCreateScanSlotFromOuterPlan(), ExecGetResultSlotOps(), ExecInitExprList(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), PlanState::ExecProcNode, execTuplesMatchPrepare(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, find_hash_columns(), fmgr_info(), fmgr_info_set_expr, FUNC_MAX_ARGS, get_aggregate_argtypes(), get_func_name(), get_typlenbyval(), GetAggInitVal(), GETSTRUCT, GetUserId(), AggStatePerPhaseData::grouped_cols, Agg::groupingSets, AggState::grp_firstTuple, Agg::grpColIdx, Agg::grpCollations, Agg::grpOperators, AggStatePerPhaseData::gset_lengths, hash_agg_entry_size(), hash_agg_set_limits(), AggState::hashcontext, HeapTupleIsValid, i, initialize_phase(), initValue(), AggState::input_done, Aggref::inputcollid, InvalidOid, InvokeFunctionExecuteHook, lcons_int(), Plan::lefttree, lfirst, list_length(), list_nth_node, makeNode, Max, AggState::maxsets, NIL, AggState::numaggs, AggStatePerHashData::numCols, Agg::numCols, AggStatePerAggData::numFinalArgs, AggState::numphases, AggStatePerPhaseData::numsets, AggState::numtrans, OBJECT_AGGREGATE, OBJECT_FUNCTION, ObjectIdGetDatum, OidIsValid, PlanState::outerops, PlanState::outeropsfixed, PlanState::outeropsset, outerPlan, outerPlanState, palloc(), palloc0(), AggState::peragg, AggState::pergroups, AggState::pertrans, pg_proc_aclcheck(), Agg::plan, PlanState::plan, Plan::plan_width, PROCOID, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, Plan::qual, PlanState::qual, ReleaseSysCache(), AggStatePerAggData::resulttypeByVal, AggStatePerAggData::resulttypeLen, SearchSysCache1(), select_current_set(), AggState::sort_in, AggState::sort_out, AggState::sort_slot, AggStatePerPhaseData::sortnode, AggState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, SysCacheGetAttr(), AggState::tmpcontext, Agg::transitionSpace, AggStatePerAggData::transno, TupleTableSlot::tts_tupleDescriptor, TTSOpsMinimalTuple, and TTSOpsVirtual.

Referenced by ExecInitNode().

3246 {
3247  AggState *aggstate;
3248  AggStatePerAgg peraggs;
3249  AggStatePerTrans pertransstates;
3250  AggStatePerGroup *pergroups;
3251  Plan *outerPlan;
3252  ExprContext *econtext;
3253  TupleDesc scanDesc;
3254  int max_aggno;
3255  int max_transno;
3256  int numaggrefs;
3257  int numaggs;
3258  int numtrans;
3259  int phase;
3260  int phaseidx;
3261  ListCell *l;
3262  Bitmapset *all_grouped_cols = NULL;
3263  int numGroupingSets = 1;
3264  int numPhases;
3265  int numHashes;
3266  int i = 0;
3267  int j = 0;
3268  bool use_hashing = (node->aggstrategy == AGG_HASHED ||
3269  node->aggstrategy == AGG_MIXED);
3270 
3271  /* check for unsupported flags */
3272  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
3273 
3274  /*
3275  * create state structure
3276  */
3277  aggstate = makeNode(AggState);
3278  aggstate->ss.ps.plan = (Plan *) node;
3279  aggstate->ss.ps.state = estate;
3280  aggstate->ss.ps.ExecProcNode = ExecAgg;
3281 
3282  aggstate->aggs = NIL;
3283  aggstate->numaggs = 0;
3284  aggstate->numtrans = 0;
3285  aggstate->aggstrategy = node->aggstrategy;
3286  aggstate->aggsplit = node->aggsplit;
3287  aggstate->maxsets = 0;
3288  aggstate->projected_set = -1;
3289  aggstate->current_set = 0;
3290  aggstate->peragg = NULL;
3291  aggstate->pertrans = NULL;
3292  aggstate->curperagg = NULL;
3293  aggstate->curpertrans = NULL;
3294  aggstate->input_done = false;
3295  aggstate->agg_done = false;
3296  aggstate->pergroups = NULL;
3297  aggstate->grp_firstTuple = NULL;
3298  aggstate->sort_in = NULL;
3299  aggstate->sort_out = NULL;
3300 
3301  /*
3302  * phases[0] always exists, but is dummy in sorted/plain mode
3303  */
3304  numPhases = (use_hashing ? 1 : 2);
3305  numHashes = (use_hashing ? 1 : 0);
3306 
3307  /*
3308  * Calculate the maximum number of grouping sets in any phase; this
3309  * determines the size of some allocations. Also calculate the number of
3310  * phases, since all hashed/mixed nodes contribute to only a single phase.
3311  */
3312  if (node->groupingSets)
3313  {
3314  numGroupingSets = list_length(node->groupingSets);
3315 
3316  foreach(l, node->chain)
3317  {
3318  Agg *agg = lfirst(l);
3319 
3320  numGroupingSets = Max(numGroupingSets,
3321  list_length(agg->groupingSets));
3322 
3323  /*
3324  * additional AGG_HASHED aggs become part of phase 0, but all
3325  * others add an extra phase.
3326  */
3327  if (agg->aggstrategy != AGG_HASHED)
3328  ++numPhases;
3329  else
3330  ++numHashes;
3331  }
3332  }
3333 
3334  aggstate->maxsets = numGroupingSets;
3335  aggstate->numphases = numPhases;
3336 
3337  aggstate->aggcontexts = (ExprContext **)
3338  palloc0(sizeof(ExprContext *) * numGroupingSets);
3339 
3340  /*
3341  * Create expression contexts. We need three or more, one for
3342  * per-input-tuple processing, one for per-output-tuple processing, one
3343  * for all the hashtables, and one for each grouping set. The per-tuple
3344  * memory context of the per-grouping-set ExprContexts (aggcontexts)
3345  * replaces the standalone memory context formerly used to hold transition
3346  * values. We cheat a little by using ExecAssignExprContext() to build
3347  * all of them.
3348  *
3349  * NOTE: the details of what is stored in aggcontexts and what is stored
3350  * in the regular per-query memory context are driven by a simple
3351  * decision: we want to reset the aggcontext at group boundaries (if not
3352  * hashing) and in ExecReScanAgg to recover no-longer-wanted space.
3353  */
3354  ExecAssignExprContext(estate, &aggstate->ss.ps);
3355  aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
3356 
3357  for (i = 0; i < numGroupingSets; ++i)
3358  {
3359  ExecAssignExprContext(estate, &aggstate->ss.ps);
3360  aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
3361  }
3362 
3363  if (use_hashing)
3364  aggstate->hashcontext = CreateWorkExprContext(estate);
3365 
3366  ExecAssignExprContext(estate, &aggstate->ss.ps);
3367 
3368  /*
3369  * Initialize child nodes.
3370  *
3371  * If we are doing a hashed aggregation then the child plan does not need
3372  * to handle REWIND efficiently; see ExecReScanAgg.
3373  */
3374  if (node->aggstrategy == AGG_HASHED)
3375  eflags &= ~EXEC_FLAG_REWIND;
3376  outerPlan = outerPlan(node);
3377  outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
3378 
3379  /*
3380  * initialize source tuple type.
3381  */
3382  aggstate->ss.ps.outerops =
3384  &aggstate->ss.ps.outeropsfixed);
3385  aggstate->ss.ps.outeropsset = true;
3386 
3387  ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
3388  aggstate->ss.ps.outerops);
3389  scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
3390 
3391  /*
3392  * If there are more than two phases (including a potential dummy phase
3393  * 0), input will be resorted using tuplesort. Need a slot for that.
3394  */
3395  if (numPhases > 2)
3396  {
3397  aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
3399 
3400  /*
3401  * The output of the tuplesort, and the output from the outer child
3402  * might not use the same type of slot. In most cases the child will
3403  * be a Sort, and thus return a TTSOpsMinimalTuple type slot - but the
3404  * input can also be presorted due an index, in which case it could be
3405  * a different type of slot.
3406  *
3407  * XXX: For efficiency it would be good to instead/additionally
3408  * generate expressions with corresponding settings of outerops* for
3409  * the individual phases - deforming is often a bottleneck for
3410  * aggregations with lots of rows per group. If there's multiple
3411  * sorts, we know that all but the first use TTSOpsMinimalTuple (via
3412  * the nodeAgg.c internal tuplesort).
3413  */
3414  if (aggstate->ss.ps.outeropsfixed &&
3415  aggstate->ss.ps.outerops != &TTSOpsMinimalTuple)
3416  aggstate->ss.ps.outeropsfixed = false;
3417  }
3418 
3419  /*
3420  * Initialize result type, slot and projection.
3421  */
3423  ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
3424 
3425  /*
3426  * initialize child expressions
3427  *
3428  * We expect the parser to have checked that no aggs contain other agg
3429  * calls in their arguments (and just to be sure, we verify it again while
3430  * initializing the plan node). This would make no sense under SQL
3431  * semantics, and it's forbidden by the spec. Because it is true, we
3432  * don't need to worry about evaluating the aggs in any particular order.
3433  *
3434  * Note: execExpr.c finds Aggrefs for us, and adds them to aggstate->aggs.
3435  * Aggrefs in the qual are found here; Aggrefs in the targetlist are found
3436  * during ExecAssignProjectionInfo, above.
3437  */
3438  aggstate->ss.ps.qual =
3439  ExecInitQual(node->plan.qual, (PlanState *) aggstate);
3440 
3441  /*
3442  * We should now have found all Aggrefs in the targetlist and quals.
3443  */
3444  numaggrefs = list_length(aggstate->aggs);
3445  max_aggno = -1;
3446  max_transno = -1;
3447  foreach(l, aggstate->aggs)
3448  {
3449  Aggref *aggref = (Aggref *) lfirst(l);
3450 
3451  max_aggno = Max(max_aggno, aggref->aggno);
3452  max_transno = Max(max_transno, aggref->aggtransno);
3453  }
3454  numaggs = max_aggno + 1;
3455  numtrans = max_transno + 1;
3456 
3457  /*
3458  * For each phase, prepare grouping set data and fmgr lookup data for
3459  * compare functions. Accumulate all_grouped_cols in passing.
3460  */
3461  aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
3462 
3463  aggstate->num_hashes = numHashes;
3464  if (numHashes)
3465  {
3466  aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
3467  aggstate->phases[0].numsets = 0;
3468  aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
3469  aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
3470  }
3471 
3472  phase = 0;
3473  for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
3474  {
3475  Agg *aggnode;
3476  Sort *sortnode;
3477 
3478  if (phaseidx > 0)
3479  {
3480  aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
3481  sortnode = castNode(Sort, aggnode->plan.lefttree);
3482  }
3483  else
3484  {
3485  aggnode = node;
3486  sortnode = NULL;
3487  }
3488 
3489  Assert(phase <= 1 || sortnode);
3490 
3491  if (aggnode->aggstrategy == AGG_HASHED
3492  || aggnode->aggstrategy == AGG_MIXED)
3493  {
3494  AggStatePerPhase phasedata = &aggstate->phases[0];
3495  AggStatePerHash perhash;
3496  Bitmapset *cols = NULL;
3497 
3498  Assert(phase == 0);
3499  i = phasedata->numsets++;
3500  perhash = &aggstate->perhash[i];
3501 
3502  /* phase 0 always points to the "real" Agg in the hash case */
3503  phasedata->aggnode = node;
3504  phasedata->aggstrategy = node->aggstrategy;
3505 
3506  /* but the actual Agg node representing this hash is saved here */
3507  perhash->aggnode = aggnode;
3508 
3509  phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
3510 
3511  for (j = 0; j < aggnode->numCols; ++j)
3512  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3513 
3514  phasedata->grouped_cols[i] = cols;
3515 
3516  all_grouped_cols = bms_add_members(all_grouped_cols, cols);
3517  continue;
3518  }
3519  else
3520  {
3521  AggStatePerPhase phasedata = &aggstate->phases[++phase];
3522  int num_sets;
3523 
3524  phasedata->numsets = num_sets = list_length(aggnode->groupingSets);
3525 
3526  if (num_sets)
3527  {
3528  phasedata->gset_lengths = palloc(num_sets * sizeof(int));
3529  phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
3530 
3531  i = 0;
3532  foreach(l, aggnode->groupingSets)
3533  {
3534  int current_length = list_length(lfirst(l));
3535  Bitmapset *cols = NULL;
3536 
3537  /* planner forces this to be correct */
3538  for (j = 0; j < current_length; ++j)
3539  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
3540 
3541  phasedata->grouped_cols[i] = cols;
3542  phasedata->gset_lengths[i] = current_length;
3543 
3544  ++i;
3545  }
3546 
3547  all_grouped_cols = bms_add_members(all_grouped_cols,
3548  phasedata->grouped_cols[0]);
3549  }
3550  else
3551  {
3552  Assert(phaseidx == 0);
3553 
3554  phasedata->gset_lengths = NULL;
3555  phasedata->grouped_cols = NULL;
3556  }
3557 
3558  /*
3559  * If we are grouping, precompute fmgr lookup data for inner loop.
3560  */
3561  if (aggnode->aggstrategy == AGG_SORTED)
3562  {
3563  int i = 0;
3564 
3565  Assert(aggnode->numCols > 0);
3566 
3567  /*
3568  * Build a separate function for each subset of columns that
3569  * need to be compared.
3570  */
3571  phasedata->eqfunctions =
3572  (ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *));
3573 
3574  /* for each grouping set */
3575  for (i = 0; i < phasedata->numsets; i++)
3576  {
3577  int length = phasedata->gset_lengths[i];
3578 
3579  if (phasedata->eqfunctions[length - 1] != NULL)
3580  continue;
3581 
3582  phasedata->eqfunctions[length - 1] =
3583  execTuplesMatchPrepare(scanDesc,
3584  length,
3585  aggnode->grpColIdx,
3586  aggnode->grpOperators,
3587  aggnode->grpCollations,
3588  (PlanState *) aggstate);
3589  }
3590 
3591  /* and for all grouped columns, unless already computed */
3592  if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
3593  {
3594  phasedata->eqfunctions[aggnode->numCols - 1] =
3595  execTuplesMatchPrepare(scanDesc,
3596  aggnode->numCols,
3597  aggnode->grpColIdx,
3598  aggnode->grpOperators,
3599  aggnode->grpCollations,
3600  (PlanState *) aggstate);
3601  }
3602  }
3603 
3604  phasedata->aggnode = aggnode;
3605  phasedata->aggstrategy = aggnode->aggstrategy;
3606  phasedata->sortnode = sortnode;
3607  }
3608  }
3609 
3610  /*
3611  * Convert all_grouped_cols to a descending-order list.
3612  */
3613  i = -1;
3614  while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
3615  aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
3616 
3617  /*
3618  * Set up aggregate-result storage in the output expr context, and also
3619  * allocate my private per-agg working storage
3620  */
3621  econtext = aggstate->ss.ps.ps_ExprContext;
3622  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
3623  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
3624 
3625  peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
3626  pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numtrans);
3627 
3628  aggstate->peragg = peraggs;
3629  aggstate->pertrans = pertransstates;
3630 
3631 
3632  aggstate->all_pergroups =
3634  * (numGroupingSets + numHashes));
3635  pergroups = aggstate->all_pergroups;
3636 
3637  if (node->aggstrategy != AGG_HASHED)
3638  {
3639  for (i = 0; i < numGroupingSets; i++)
3640  {
3641  pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
3642  * numaggs);
3643  }
3644 
3645  aggstate->pergroups = pergroups;
3646  pergroups += numGroupingSets;
3647  }
3648 
3649  /*
3650  * Hashing can only appear in the initial phase.
3651  */
3652  if (use_hashing)
3653  {
3654  Plan *outerplan = outerPlan(node);
3655  uint64 totalGroups = 0;
3656  int i;
3657 
3658  aggstate->hash_metacxt = AllocSetContextCreate(aggstate->ss.ps.state->es_query_cxt,
3659  "HashAgg meta context",
3661  aggstate->hash_spill_rslot = ExecInitExtraTupleSlot(estate, scanDesc,
3663  aggstate->hash_spill_wslot = ExecInitExtraTupleSlot(estate, scanDesc,
3664  &TTSOpsVirtual);
3665 
3666  /* this is an array of pointers, not structures */
3667  aggstate->hash_pergroup = pergroups;
3668 
3669  aggstate->hashentrysize = hash_agg_entry_size(aggstate->numtrans,
3670  outerplan->plan_width,
3671  node->transitionSpace);
3672 
3673  /*
3674  * Consider all of the grouping sets together when setting the limits
3675  * and estimating the number of partitions. This can be inaccurate
3676  * when there is more than one grouping set, but should still be
3677  * reasonable.
3678  */
3679  for (i = 0; i < aggstate->num_hashes; i++)
3680  totalGroups += aggstate->perhash[i].aggnode->numGroups;
3681 
3682  hash_agg_set_limits(aggstate->hashentrysize, totalGroups, 0,
3683  &aggstate->hash_mem_limit,
3684  &aggstate->hash_ngroups_limit,
3685  &aggstate->hash_planned_partitions);
3686  find_hash_columns(aggstate);
3687 
3688  /* Skip massive memory allocation if we are just doing EXPLAIN */
3689  if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
3690  build_hash_tables(aggstate);
3691 
3692  aggstate->table_filled = false;
3693 
3694  /* Initialize this to 1, meaning nothing spilled, yet */
3695  aggstate->hash_batches_used = 1;
3696  }
3697 
3698  /*
3699  * Initialize current phase-dependent values to initial phase. The initial
3700  * phase is 1 (first sort pass) for all strategies that use sorting (if
3701  * hashing is being done too, then phase 0 is processed last); but if only
3702  * hashing is being done, then phase 0 is all there is.
3703  */
3704  if (node->aggstrategy == AGG_HASHED)
3705  {
3706  aggstate->current_phase = 0;
3707  initialize_phase(aggstate, 0);
3708  select_current_set(aggstate, 0, true);
3709  }
3710  else
3711  {
3712  aggstate->current_phase = 1;
3713  initialize_phase(aggstate, 1);
3714  select_current_set(aggstate, 0, false);
3715  }
3716 
3717  /*
3718  * Perform lookups of aggregate function info, and initialize the
3719  * unchanging fields of the per-agg and per-trans data.
3720  */
3721  foreach(l, aggstate->aggs)
3722  {
3723  Aggref *aggref = lfirst(l);
3724  AggStatePerAgg peragg;
3725  AggStatePerTrans pertrans;
3726  Oid inputTypes[FUNC_MAX_ARGS];
3727  int numArguments;
3728  int numDirectArgs;
3729  HeapTuple aggTuple;
3730  Form_pg_aggregate aggform;
3731  AclResult aclresult;
3732  Oid finalfn_oid;
3733  Oid serialfn_oid,
3734  deserialfn_oid;
3735  Oid aggOwner;
3736  Expr *finalfnexpr;
3737  Oid aggtranstype;
3738 
3739  /* Planner should have assigned aggregate to correct level */
3740  Assert(aggref->agglevelsup == 0);
3741  /* ... and the split mode should match */
3742  Assert(aggref->aggsplit == aggstate->aggsplit);
3743 
3744  peragg = &peraggs[aggref->aggno];
3745 
3746  /* Check if we initialized the state for this aggregate already. */
3747  if (peragg->aggref != NULL)
3748  continue;
3749 
3750  peragg->aggref = aggref;
3751  peragg->transno = aggref->aggtransno;
3752 
3753  /* Fetch the pg_aggregate row */
3754  aggTuple = SearchSysCache1(AGGFNOID,
3755  ObjectIdGetDatum(aggref->aggfnoid));
3756  if (!HeapTupleIsValid(aggTuple))
3757  elog(ERROR, "cache lookup failed for aggregate %u",
3758  aggref->aggfnoid);
3759  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
3760 
3761  /* Check permission to call aggregate function */
3762  aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
3763  ACL_EXECUTE);
3764  if (aclresult != ACLCHECK_OK)
3765  aclcheck_error(aclresult, OBJECT_AGGREGATE,
3766  get_func_name(aggref->aggfnoid));
3768 
3769  /* planner recorded transition state type in the Aggref itself */
3770  aggtranstype = aggref->aggtranstype;
3771  Assert(OidIsValid(aggtranstype));
3772 
3773  /* Final function only required if we're finalizing the aggregates */
3774  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
3775  peragg->finalfn_oid = finalfn_oid = InvalidOid;
3776  else
3777  peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
3778 
3779  serialfn_oid = InvalidOid;
3780  deserialfn_oid = InvalidOid;
3781 
3782  /*
3783  * Check if serialization/deserialization is required. We only do it
3784  * for aggregates that have transtype INTERNAL.
3785  */
3786  if (aggtranstype == INTERNALOID)
3787  {
3788  /*
3789  * The planner should only have generated a serialize agg node if
3790  * every aggregate with an INTERNAL state has a serialization
3791  * function. Verify that.
3792  */
3793  if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
3794  {
3795  /* serialization only valid when not running finalfn */
3797 
3798  if (!OidIsValid(aggform->aggserialfn))
3799  elog(ERROR, "serialfunc not provided for serialization aggregation");
3800  serialfn_oid = aggform->aggserialfn;
3801  }
3802 
3803  /* Likewise for deserialization functions */
3804  if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
3805  {
3806  /* deserialization only valid when combining states */
3807  Assert(DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
3808 
3809  if (!OidIsValid(aggform->aggdeserialfn))
3810  elog(ERROR, "deserialfunc not provided for deserialization aggregation");
3811  deserialfn_oid = aggform->aggdeserialfn;
3812  }
3813  }
3814 
3815  /* Check that aggregate owner has permission to call component fns */
3816  {
3817  HeapTuple procTuple;
3818 
3819  procTuple = SearchSysCache1(PROCOID,
3820  ObjectIdGetDatum(aggref->aggfnoid));
3821  if (!HeapTupleIsValid(procTuple))
3822  elog(ERROR, "cache lookup failed for function %u",
3823  aggref->aggfnoid);
3824  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
3825  ReleaseSysCache(procTuple);
3826 
3827  if (OidIsValid(finalfn_oid))
3828  {
3829  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
3830  ACL_EXECUTE);
3831  if (aclresult != ACLCHECK_OK)
3832  aclcheck_error(aclresult, OBJECT_FUNCTION,
3833  get_func_name(finalfn_oid));
3834  InvokeFunctionExecuteHook(finalfn_oid);
3835  }
3836  if (OidIsValid(serialfn_oid))
3837  {
3838  aclresult = pg_proc_aclcheck(serialfn_oid, aggOwner,
3839  ACL_EXECUTE);
3840  if (aclresult != ACLCHECK_OK)
3841  aclcheck_error(aclresult, OBJECT_FUNCTION,
3842  get_func_name(serialfn_oid));
3843  InvokeFunctionExecuteHook(serialfn_oid);
3844  }
3845  if (OidIsValid(deserialfn_oid))
3846  {
3847  aclresult = pg_proc_aclcheck(deserialfn_oid, aggOwner,
3848  ACL_EXECUTE);
3849  if (aclresult != ACLCHECK_OK)
3850  aclcheck_error(aclresult, OBJECT_FUNCTION,
3851  get_func_name(deserialfn_oid));
3852  InvokeFunctionExecuteHook(deserialfn_oid);
3853  }
3854  }
3855 
3856  /*
3857  * Get actual datatypes of the (nominal) aggregate inputs. These
3858  * could be different from the agg's declared input types, when the
3859  * agg accepts ANY or a polymorphic type.
3860  */
3861  numArguments = get_aggregate_argtypes(aggref, inputTypes);
3862 
3863  /* Count the "direct" arguments, if any */
3864  numDirectArgs = list_length(aggref->aggdirectargs);
3865 
3866  /* Detect how many arguments to pass to the finalfn */
3867  if (aggform->aggfinalextra)
3868  peragg->numFinalArgs = numArguments + 1;
3869  else
3870  peragg->numFinalArgs = numDirectArgs + 1;
3871 
3872  /* Initialize any direct-argument expressions */
3873  peragg->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
3874  (PlanState *) aggstate);
3875 
3876  /*
3877  * build expression trees using actual argument & result types for the
3878  * finalfn, if it exists and is required.
3879  */
3880  if (OidIsValid(finalfn_oid))
3881  {
3882  build_aggregate_finalfn_expr(inputTypes,
3883  peragg->numFinalArgs,
3884  aggtranstype,
3885  aggref->aggtype,
3886  aggref->inputcollid,
3887  finalfn_oid,
3888  &finalfnexpr);
3889  fmgr_info(finalfn_oid, &peragg->finalfn);
3890  fmgr_info_set_expr((Node *) finalfnexpr, &peragg->finalfn);
3891  }
3892 
3893  /* get info about the output value's datatype */
3894  get_typlenbyval(aggref->aggtype,
3895  &peragg->resulttypeLen,
3896  &peragg->resulttypeByVal);
3897 
3898  /*
3899  * Build working state for invoking the transition function, if we
3900  * haven't done it already.
3901  */
3902  pertrans = &pertransstates[aggref->aggtransno];
3903  if (pertrans->aggref == NULL)
3904  {
3905  Datum textInitVal;
3906  Datum initValue;
3907  bool initValueIsNull;
3908  Oid transfn_oid;
3909 
3910  /*
3911  * If this aggregation is performing state combines, then instead
3912  * of using the transition function, we'll use the combine
3913  * function
3914  */
3915  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3916  {
3917  transfn_oid = aggform->aggcombinefn;
3918 
3919  /* If not set then the planner messed up */
3920  if (!OidIsValid(transfn_oid))
3921  elog(ERROR, "combinefn not set for aggregate function");
3922  }
3923  else
3924  transfn_oid = aggform->aggtransfn;
3925 
3926  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
3927  ACL_EXECUTE);
3928  if (aclresult != ACLCHECK_OK)
3929  aclcheck_error(aclresult, OBJECT_FUNCTION,
3930  get_func_name(transfn_oid));
3931  InvokeFunctionExecuteHook(transfn_oid);
3932 
3933  /*
3934  * initval is potentially null, so don't try to access it as a
3935  * struct field. Must do it the hard way with SysCacheGetAttr.
3936  */
3937  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
3938  Anum_pg_aggregate_agginitval,
3939  &initValueIsNull);
3940  if (initValueIsNull)
3941  initValue = (Datum) 0;
3942  else
3943  initValue = GetAggInitVal(textInitVal, aggtranstype);
3944 
3945  build_pertrans_for_aggref(pertrans, aggstate, estate,
3946  aggref, transfn_oid, aggtranstype,
3947  serialfn_oid, deserialfn_oid,
3948  initValue, initValueIsNull,
3949  inputTypes, numArguments);
3950  }
3951  else
3952  pertrans->aggshared = true;
3953  ReleaseSysCache(aggTuple);
3954  }
3955 
3956  /*
3957  * Update aggstate->numaggs to be the number of unique aggregates found.
3958  * Also set numstates to the number of unique transition states found.
3959  */
3960  aggstate->numaggs = numaggs;
3961  aggstate->numtrans = numtrans;
3962 
3963  /*
3964  * Last, check whether any more aggregates got added onto the node while
3965  * we processed the expressions for the aggregate arguments (including not
3966  * only the regular arguments and FILTER expressions handled immediately
3967  * above, but any direct arguments we might've handled earlier). If so,
3968  * we have nested aggregate functions, which is semantically nonsensical,
3969  * so complain. (This should have been caught by the parser, so we don't
3970  * need to work hard on a helpful error message; but we defend against it
3971  * here anyway, just to be sure.)
3972  */
3973  if (numaggrefs != list_length(aggstate->aggs))
3974  ereport(ERROR,
3975  (errcode(ERRCODE_GROUPING_ERROR),
3976  errmsg("aggregate function calls cannot be nested")));
3977 
3978  /*
3979  * Build expressions doing all the transition work at once. We build a
3980  * different one for each phase, as the number of transition function
3981  * invocation can differ between phases. Note this'll work both for
3982  * transition and combination functions (although there'll only be one
3983  * phase in the latter case).
3984  */
3985  for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
3986  {
3987  AggStatePerPhase phase = &aggstate->phases[phaseidx];
3988  bool dohash = false;
3989  bool dosort = false;
3990 
3991  /* phase 0 doesn't necessarily exist */
3992  if (!phase->aggnode)
3993  continue;
3994 
3995  if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 1)
3996  {
3997  /*
3998  * Phase one, and only phase one, in a mixed agg performs both
3999  * sorting and aggregation.
4000  */
4001  dohash = true;
4002  dosort = true;
4003  }
4004  else if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 0)
4005  {
4006  /*
4007  * No need to compute a transition function for an AGG_MIXED phase
4008  * 0 - the contents of the hashtables will have been computed
4009  * during phase 1.
4010  */
4011  continue;
4012  }
4013  else if (phase->aggstrategy == AGG_PLAIN ||
4014  phase->aggstrategy == AGG_SORTED)
4015  {
4016  dohash = false;
4017  dosort = true;
4018  }
4019  else if (phase->aggstrategy == AGG_HASHED)
4020  {
4021  dohash = true;
4022  dosort = false;
4023  }
4024  else
4025  Assert(false);
4026 
4027  phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash,
4028  false);
4029 
4030  /* cache compiled expression for outer slot without NULL check */
4031  phase->evaltrans_cache[0][0] = phase->evaltrans;
4032  }
4033 
4034  return aggstate;
4035 }
struct AggStatePerTransData * AggStatePerTrans
Definition: execnodes.h:2264
ExprState ** eqfunctions
Definition: nodeAgg.h:278
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2335
#define NIL
Definition: pg_list.h:65
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2265
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:475
int numCols
Definition: plannodes.h:861
List * qual
Definition: plannodes.h:142
AggStatePerPhase phases
Definition: execnodes.h:2302
double hashentrysize
Definition: execnodes.h:2327
#define AllocSetContextCreate
Definition: memutils.h:173
Datum * ecxt_aggvalues
Definition: execnodes.h:245
uint64 hash_ngroups_limit
Definition: execnodes.h:2324
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1831
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
AttrNumber * grpColIdx
Definition: plannodes.h:862
uint64 transitionSpace
Definition: plannodes.h:866
int aggtransno
Definition: primnodes.h:341
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:499
List * lcons_int(int datum, List *list)
Definition: list.c:486
int numaggs
Definition: execnodes.h:2273
Oid GetUserId(void)
Definition: miscinit.c:478
bool agg_done
Definition: execnodes.h:2291
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Oid * grpCollations
Definition: plannodes.h:864
TupleTableSlot * sort_slot
Definition: execnodes.h:2305
List * all_grouped_cols
Definition: execnodes.h:2296
Tuplesortstate * sort_out
Definition: execnodes.h:2304
ScanState ss
Definition: execnodes.h:2271
ExprContext * ps_ExprContext
Definition: execnodes.h:1003
ExprState * evaltrans
Definition: nodeAgg.h:283
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
Oid inputcollid
Definition: primnodes.h:326
int current_phase
Definition: execnodes.h:2279
Definition: nodes.h:539
AggSplit aggsplit
Definition: execnodes.h:2276
static TupleTableSlot * ExecAgg(PlanState *pstate)
Definition: nodeAgg.c:2153
int errcode(int sqlerrcode)
Definition: elog.c:698
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1376
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:2104
TupleTableSlot * hash_spill_rslot
Definition: execnodes.h:2317
AggStatePerTrans pertrans
Definition: execnodes.h:2281
EState * state
Definition: execnodes.h:966
int projected_set
Definition: execnodes.h:2292
unsigned int Oid
Definition: postgres_ext.h:31
HeapTuple grp_firstTuple
Definition: execnodes.h:2309
Aggref * aggref
Definition: nodeAgg.h:187
int current_set
Definition: execnodes.h:2294
#define OidIsValid(objectId)
Definition: c.h:710
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:801
int numtrans
Definition: execnodes.h:2274
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:209
ExprContext * tmpcontext
Definition: execnodes.h:2284
#define FUNC_MAX_ARGS
Aggref * aggref
Definition: nodeAgg.h:44
Bitmapset ** grouped_cols
Definition: nodeAgg.h:277
PlanState ps
Definition: execnodes.h:1373
int maxsets
Definition: execnodes.h:2301
Size hash_agg_entry_size(int numTrans, Size tupleWidth, Size transitionSpace)
Definition: nodeAgg.c:1693
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3313
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:803
MemoryContext es_query_cxt
Definition: execnodes.h:598
AggStrategy aggstrategy
Definition: plannodes.h:859
bool table_filled
Definition: execnodes.h:2311
AggStrategy aggstrategy
Definition: execnodes.h:2275
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1579
MemoryContext hash_metacxt
Definition: execnodes.h:2313
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
static void find_hash_columns(AggState *aggstate)
Definition: nodeAgg.c:1564
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
Tuplesortstate * sort_in
Definition: execnodes.h:2303
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define outerPlanState(node)
Definition: execnodes.h:1058
#define list_nth_node(type, list, n)
Definition: pg_list.h:306
static int initValue(long lng_val)
Definition: informix.c:677
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:535
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:318
Index agglevelsup
Definition: primnodes.h:338
int hash_planned_partitions
Definition: execnodes.h:2325
List * aggdirectargs
Definition: primnodes.h:329
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: nodeAgg.c:4354
AggStatePerAgg curperagg
Definition: execnodes.h:2287
AggStatePerHash perhash
Definition: execnodes.h:2334
bool outeropsset
Definition: execnodes.h:1045
AggStrategy aggstrategy
Definition: nodeAgg.h:274
ExprState * evaltrans_cache[2][2]
Definition: nodeAgg.h:291
#define EXEC_FLAG_REWIND
Definition: executor.h:57
int hash_batches_used
Definition: execnodes.h:2332
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
#define outerPlan(node)
Definition: plannodes.h:171
int num_hashes
Definition: execnodes.h:2312
Plan plan
Definition: plannodes.h:858
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
bool input_done
Definition: execnodes.h:2290
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2282
bool * ecxt_aggnulls
Definition: execnodes.h:247
void * palloc0(Size size)
Definition: mcxt.c:1093
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:970
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1388
List * groupingSets
Definition: plannodes.h:869
int16 resulttypeLen
Definition: nodeAgg.h:216
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:497
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
Plan * plan
Definition: execnodes.h:964
#define InvalidOid
Definition: postgres_ext.h:36
Oid aggfnoid
Definition: primnodes.h:323
#define ereport(elevel,...)
Definition: elog.h:157
int aggno
Definition: primnodes.h:340
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2283
#define makeNode(_type_)
Definition: nodes.h:587
int plan_width
Definition: plannodes.h:124
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:804
#define lfirst(lc)
Definition: pg_list.h:169
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
#define EXEC_FLAG_MARK
Definition: executor.h:59
AggSplit aggsplit
Definition: plannodes.h:860
struct AggStatePerAggData * AggStatePerAgg
Definition: execnodes.h:2263
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
AggSplit aggsplit
Definition: primnodes.h:339
AggStatePerGroup * pergroups
Definition: execnodes.h:2307
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:480
static int list_length(const List *l)
Definition: pg_list.h:149
long numGroups
Definition: plannodes.h:865
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:802
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2198
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1799
bool outeropsfixed
Definition: execnodes.h:1041
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:804
Size hash_mem_limit
Definition: execnodes.h:2323
struct Plan * lefttree
Definition: plannodes.h:143
int numphases
Definition: execnodes.h:2278
ExprState * qual
Definition: execnodes.h:985
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:1797
Oid * grpOperators
Definition: plannodes.h:863
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
List * chain
Definition: plannodes.h:870
AggStatePerAgg peragg
Definition: execnodes.h:2280
#define ACL_EXECUTE
Definition: parsenodes.h:89
#define elog(elevel,...)
Definition: elog.h:232
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4723
int i
List * aggdirectargs
Definition: nodeAgg.h:210
Oid aggtranstype
Definition: primnodes.h:327
AggStatePerTrans curpertrans
Definition: execnodes.h:2289
Oid aggtype
Definition: primnodes.h:324
bool resulttypeByVal
Definition: nodeAgg.h:217
Definition: plannodes.h:856
ExprContext * CreateWorkExprContext(EState *estate)
Definition: execUtils.c:316
List * aggs
Definition: execnodes.h:2272
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:682
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1886
static void build_pertrans_for_aggref(AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
Definition: nodeAgg.c:4046
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:141
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:56
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
FmgrInfo finalfn
Definition: nodeAgg.h:199
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
TupleTableSlot * hash_spill_wslot
Definition: execnodes.h:2318
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1469
const TupleTableSlotOps * outerops
Definition: execnodes.h:1037
ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash, bool nullcheck)
Definition: execExpr.c:3211
AggStatePerGroup * all_pergroups
Definition: execnodes.h:2340

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 4440 of file nodeAgg.c.

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(), 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().

4441 {
4442  ExprContext *econtext = node->ss.ps.ps_ExprContext;
4444  Agg *aggnode = (Agg *) node->ss.ps.plan;
4445  int transno;
4446  int numGroupingSets = Max(node->maxsets, 1);
4447  int setno;
4448 
4449  node->agg_done = false;
4450 
4451  if (node->aggstrategy == AGG_HASHED)
4452  {
4453  /*
4454  * In the hashed case, if we haven't yet built the hash table then we
4455  * can just return; nothing done yet, so nothing to undo. If subnode's
4456  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4457  * else no reason to re-scan it at all.
4458  */
4459  if (!node->table_filled)
4460  return;
4461 
4462  /*
4463  * If we do have the hash table, and it never spilled, and the subplan
4464  * does not have any parameter changes, and none of our own parameter
4465  * changes affect input expressions of the aggregated functions, then
4466  * we can just rescan the existing hash table; no need to build it
4467  * again.
4468  */
4469  if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4470  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4471  {
4473  &node->perhash[0].hashiter);
4474  select_current_set(node, 0, true);
4475  return;
4476  }
4477  }
4478 
4479  /* Make sure we have closed any open tuplesorts */
4480  for (transno = 0; transno < node->numtrans; transno++)
4481  {
4482  for (setno = 0; setno < numGroupingSets; setno++)
4483  {
4484  AggStatePerTrans pertrans = &node->pertrans[transno];
4485 
4486  if (pertrans->sortstates[setno])
4487  {
4488  tuplesort_end(pertrans->sortstates[setno]);
4489  pertrans->sortstates[setno] = NULL;
4490  }
4491  }
4492  }
4493 
4494  /*
4495  * We don't need to ReScanExprContext the output tuple context here;
4496  * ExecReScan already did it. But we do need to reset our per-grouping-set
4497  * contexts, which may have transvalues stored in them. (We use rescan
4498  * rather than just reset because transfns may have registered callbacks
4499  * that need to be run now.) For the AGG_HASHED case, see below.
4500  */
4501 
4502  for (setno = 0; setno < numGroupingSets; setno++)
4503  {
4504  ReScanExprContext(node->aggcontexts[setno]);
4505  }
4506 
4507  /* Release first tuple of group, if we have made a copy */
4508  if (node->grp_firstTuple != NULL)
4509  {
4511  node->grp_firstTuple = NULL;
4512  }
4514 
4515  /* Forget current agg values */
4516  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4517  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4518 
4519  /*
4520  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4521  * the hashcontext. This used to be an issue, but now, resetting a context
4522  * automatically deletes sub-contexts too.
4523  */
4524  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4525  {
4527 
4528  node->hash_ever_spilled = false;
4529  node->hash_spill_mode = false;
4530  node->hash_ngroups_current = 0;
4531 
4533  /* Rebuild an empty hash table */
4534  build_hash_tables(node);
4535  node->table_filled = false;
4536  /* iterator will be reset when the table is filled */
4537 
4538  hashagg_recompile_expressions(node, false, false);
4539  }
4540 
4541  if (node->aggstrategy != AGG_HASHED)
4542  {
4543  /*
4544  * Reset the per-group state (in particular, mark transvalues null)
4545  */
4546  for (setno = 0; setno < numGroupingSets; setno++)
4547  {
4548  MemSet(node->pergroups[setno], 0,
4549  sizeof(AggStatePerGroupData) * node->numaggs);
4550  }
4551 
4552  /* reset to phase 1 */
4553  initialize_phase(node, 1);
4554 
4555  node->input_done = false;
4556  node->projected_set = -1;
4557  }
4558 
4559  if (outerPlan->chgParam == NULL)
4560  ExecReScan(outerPlan);
4561 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3193
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:475
Datum * ecxt_aggvalues
Definition: execnodes.h:245
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2273
bool agg_done
Definition: execnodes.h:2291
ScanState ss
Definition: execnodes.h:2271
ExprContext * ps_ExprContext
Definition: execnodes.h:1003
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
#define MemSet(start, val, len)
Definition: c.h:1008
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1376
AggStatePerTrans pertrans
Definition: execnodes.h:2281
int projected_set
Definition: execnodes.h:2292
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2309
int numtrans
Definition: execnodes.h:2274
bool hash_spill_mode
Definition: execnodes.h:2321
PlanState ps
Definition: execnodes.h:1373
int maxsets
Definition: execnodes.h:2301
bool table_filled
Definition: execnodes.h:2311
AggStrategy aggstrategy
Definition: execnodes.h:2275
#define outerPlanState(node)
Definition: execnodes.h:1058
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
Bitmapset * aggParams
Definition: plannodes.h:867
AggStatePerHash perhash
Definition: execnodes.h:2334
Bitmapset * chgParam
Definition: execnodes.h:996
#define outerPlan(node)
Definition: plannodes.h:171
TupleHashIterator hashiter
Definition: nodeAgg.h:304
bool input_done
Definition: execnodes.h:2290
ExprContext * hashcontext
Definition: execnodes.h:2282
bool * ecxt_aggnulls
Definition: execnodes.h:247
uintptr_t Datum
Definition: postgres.h:411
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:497
Plan * plan
Definition: execnodes.h:964
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:767
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1740
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2283
bool hash_ever_spilled
Definition: execnodes.h:2320
AggStatePerGroup * pergroups
Definition: execnodes.h:2307
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:438
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
uint64 hash_ngroups_current
Definition: execnodes.h:2329
Definition: plannodes.h:856
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1464
TupleHashTable hashtable
Definition: nodeAgg.h:303
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1469

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

Definition at line 567 of file nodeAgg.c.

References CHECK_FOR_INTERRUPTS, ExecProcNode(), outerPlanState, AggState::sort_in, AggState::sort_out, AggState::sort_slot, TupIsNull, tuplesort_gettupleslot(), and tuplesort_puttupleslot().

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

568 {
569  TupleTableSlot *slot;
570 
571  if (aggstate->sort_in)
572  {
573  /* make sure we check for interrupts in either path through here */
575  if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
576  aggstate->sort_slot, NULL))
577  return NULL;
578  slot = aggstate->sort_slot;
579  }
580  else
581  slot = ExecProcNode(outerPlanState(aggstate));
582 
583  if (!TupIsNull(slot) && aggstate->sort_out)
584  tuplesort_puttupleslot(aggstate->sort_out, slot);
585 
586  return slot;
587 }
TupleTableSlot * sort_slot
Definition: execnodes.h:2305
Tuplesortstate * sort_out
Definition: execnodes.h:2304
Tuplesortstate * sort_in
Definition: execnodes.h:2303
#define outerPlanState(node)
Definition: execnodes.h:1058
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2408
#define TupIsNull(slot)
Definition: tuptable.h:292
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:252
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:102
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1684

◆ finalize_aggregate()

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

Definition at line 1056 of file nodeAgg.c.

References AggStatePerTransData::aggCollation, AggStatePerAggData::aggdirectargs, AggState::curperagg, CurrentMemoryContext, datumCopy(), DatumGetPointer, ExprContext::ecxt_per_tuple_memory, ExecEvalExpr(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, FUNC_MAX_ARGS, FunctionCallInvoke, i, InitFunctionCallInfoData, lfirst, LOCAL_FCINFO, MakeExpandedObjectReadOnly, MemoryContextContains(), MemoryContextSwitchTo(), AggStatePerAggData::numFinalArgs, OidIsValid, AggState::pertrans, ScanState::ps, PlanState::ps_ExprContext, AggStatePerAggData::resulttypeByVal, AggStatePerAggData::resulttypeLen, AggState::ss, AggStatePerAggData::transno, AggStatePerTransData::transtypeLen, AggStatePerGroupData::transValue, and AggStatePerGroupData::transValueIsNull.

Referenced by finalize_aggregates().

1060 {
1061  LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
1062  bool anynull = false;
1063  MemoryContext oldContext;
1064  int i;
1065  ListCell *lc;
1066  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1067 
1069 
1070  /*
1071  * Evaluate any direct arguments. We do this even if there's no finalfn
1072  * (which is unlikely anyway), so that side-effects happen as expected.
1073  * The direct arguments go into arg positions 1 and up, leaving position 0
1074  * for the transition state value.
1075  */
1076  i = 1;
1077  foreach(lc, peragg->aggdirectargs)
1078  {
1079  ExprState *expr = (ExprState *) lfirst(lc);
1080 
1081  fcinfo->args[i].value = ExecEvalExpr(expr,
1082  aggstate->ss.ps.ps_ExprContext,
1083  &fcinfo->args[i].isnull);
1084  anynull |= fcinfo->args[i].isnull;
1085  i++;
1086  }
1087 
1088  /*
1089  * Apply the agg's finalfn if one is provided, else return transValue.
1090  */
1091  if (OidIsValid(peragg->finalfn_oid))
1092  {
1093  int numFinalArgs = peragg->numFinalArgs;
1094 
1095  /* set up aggstate->curperagg for AggGetAggref() */
1096  aggstate->curperagg = peragg;
1097 
1098  InitFunctionCallInfoData(*fcinfo, &peragg->finalfn,
1099  numFinalArgs,
1100  pertrans->aggCollation,
1101  (void *) aggstate, NULL);
1102 
1103  /* Fill in the transition state value */
1104  fcinfo->args[0].value =
1105  MakeExpandedObjectReadOnly(pergroupstate->transValue,
1106  pergroupstate->transValueIsNull,
1107  pertrans->transtypeLen);
1108  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
1109  anynull |= pergroupstate->transValueIsNull;
1110 
1111  /* Fill any remaining argument positions with nulls */
1112  for (; i < numFinalArgs; i++)
1113  {
1114  fcinfo->args[i].value = (Datum) 0;
1115  fcinfo->args[i].isnull = true;
1116  anynull = true;
1117  }
1118 
1119  if (fcinfo->flinfo->fn_strict && anynull)
1120  {
1121  /* don't call a strict function with NULL inputs */
1122  *resultVal = (Datum) 0;
1123  *resultIsNull = true;
1124  }
1125  else
1126  {
1127  *resultVal = FunctionCallInvoke(fcinfo);
1128  *resultIsNull = fcinfo->isnull;
1129  }
1130  aggstate->curperagg = NULL;
1131  }
1132  else
1133  {
1134  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1135  *resultVal = pergroupstate->transValue;
1136  *resultIsNull = pergroupstate->transValueIsNull;
1137  }
1138 
1139  /*
1140  * If result is pass-by-ref, make sure it is in the right context.
1141  */
1142  if (!peragg->resulttypeByVal && !*resultIsNull &&
1144  DatumGetPointer(*resultVal)))
1145  *resultVal = datumCopy(*resultVal,
1146  peragg->resulttypeByVal,
1147  peragg->resulttypeLen);
1148 
1149  MemoryContextSwitchTo(oldContext);
1150 }
ScanState ss
Definition: execnodes.h:2271
ExprContext * ps_ExprContext
Definition: execnodes.h:1003
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:2281
#define OidIsValid(objectId)
Definition: c.h:710
#define FUNC_MAX_ARGS
PlanState ps
Definition: execnodes.h:1373
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:315
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
AggStatePerAgg curperagg
Definition: execnodes.h:2287
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
uintptr_t Datum
Definition: postgres.h:411
int16 resulttypeLen
Definition: nodeAgg.h:216
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define lfirst(lc)
Definition: pg_list.h:169
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:758
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define DatumGetPointer(X)
Definition: postgres.h:593
int i
List * aggdirectargs
Definition: nodeAgg.h:210
bool resulttypeByVal
Definition: nodeAgg.h:217
FmgrInfo finalfn
Definition: nodeAgg.h:199

◆ finalize_aggregates()

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

Definition at line 1309 of file nodeAgg.c.

References AGG_HASHED, AGG_MIXED, AggState::aggsplit, AggState::aggstrategy, Assert, DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, finalize_aggregate(), finalize_partialaggregate(), AggState::numaggs, AggStatePerTransData::numInputs, AggStatePerTransData::numSortCols, AggState::numtrans, AggState::pertrans, process_ordered_aggregate_multi(), process_ordered_aggregate_single(), ScanState::ps, PlanState::ps_ExprContext, AggState::ss, and AggStatePerAggData::transno.

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table_in_memory().

1312 {
1313  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1314  Datum *aggvalues = econtext->ecxt_aggvalues;
1315  bool *aggnulls = econtext->ecxt_aggnulls;
1316  int aggno;
1317  int transno;
1318 
1319  /*
1320  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1321  * inputs and run the transition functions.
1322  */
1323  for (transno = 0; transno < aggstate->numtrans; transno++)
1324  {
1325  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1326  AggStatePerGroup pergroupstate;
1327 
1328  pergroupstate = &pergroup[transno];
1329 
1330  if (pertrans->numSortCols > 0)
1331  {
1332  Assert(aggstate->aggstrategy != AGG_HASHED &&
1333  aggstate->aggstrategy != AGG_MIXED);
1334 
1335  if (pertrans->numInputs == 1)
1337  pertrans,
1338  pergroupstate);
1339  else
1341  pertrans,
1342  pergroupstate);
1343  }
1344  }
1345 
1346  /*
1347  * Run the final functions.
1348  */
1349  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1350  {
1351  AggStatePerAgg peragg = &peraggs[aggno];
1352  int transno = peragg->transno;
1353  AggStatePerGroup pergroupstate;
1354 
1355  pergroupstate = &pergroup[transno];
1356 
1357  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1358  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1359  &aggvalues[aggno], &aggnulls[aggno]);
1360  else
1361  finalize_aggregate(aggstate, peragg, pergroupstate,
1362  &aggvalues[aggno], &aggnulls[aggno]);
1363  }
1364 }
Datum * ecxt_aggvalues
Definition: execnodes.h:245
int numaggs
Definition: execnodes.h:2273
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1159
ScanState ss
Definition: execnodes.h:2271
ExprContext * ps_ExprContext
Definition: execnodes.h:1003
AggSplit aggsplit
Definition: execnodes.h:2276
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1056
AggStatePerTrans pertrans
Definition: execnodes.h:2281
int numtrans
Definition: execnodes.h:2274
PlanState ps
Definition: execnodes.h:1373
AggStrategy aggstrategy
Definition: execnodes.h:2275
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:962
bool * ecxt_aggnulls
Definition: execnodes.h:247
uintptr_t Datum
Definition: postgres.h:411
#define Assert(condition)
Definition: c.h:804
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:802
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:870

◆ finalize_partialaggregate()

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

Definition at line 1159 of file nodeAgg.c.

References FunctionCallInfoBaseData::args, CurrentMemoryContext, datumCopy(), DatumGetPointer, ExprContext::ecxt_per_tuple_memory, FmgrInfo::fn_strict, FunctionCallInvoke, FunctionCallInfoBaseData::isnull, NullableDatum::isnull, MakeExpandedObjectReadOnly, MemoryContextContains(), MemoryContextSwitchTo(), OidIsValid, AggState::pertrans, ScanState::ps, PlanState::ps_ExprContext, AggStatePerAggData::resulttypeByVal, AggStatePerAggData::resulttypeLen, AggStatePerTransData::serialfn, AggStatePerTransData::serialfn_fcinfo, AggStatePerTransData::serialfn_oid, AggState::ss, AggStatePerAggData::transno, AggStatePerTransData::transtypeLen, AggStatePerGroupData::transValue, AggStatePerGroupData::transValueIsNull, and NullableDatum::value.

Referenced by finalize_aggregates().

1163 {
1164  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1165  MemoryContext oldContext;
1166 
1168 
1169  /*
1170  * serialfn_oid will be set if we must serialize the transvalue before
1171  * returning it
1172  */
1173  if (OidIsValid(pertrans->serialfn_oid))
1174  {
1175  /* Don't call a strict serialization function with NULL input. */
1176  if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
1177  {
1178  *resultVal = (Datum) 0;
1179  *resultIsNull = true;
1180  }
1181  else
1182  {
1183  FunctionCallInfo fcinfo = pertrans->serialfn_fcinfo;
1184 
1185  fcinfo->args[0].value =
1186  MakeExpandedObjectReadOnly(pergroupstate->transValue,
1187  pergroupstate->transValueIsNull,
1188  pertrans->transtypeLen);
1189  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
1190  fcinfo->isnull = false;
1191 
1192  *resultVal = FunctionCallInvoke(fcinfo);
1193  *resultIsNull = fcinfo->isnull;
1194  }
1195  }
1196  else
1197  {
1198  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1199  *resultVal = pergroupstate->transValue;
1200  *resultIsNull = pergroupstate->transValueIsNull;
1201  }
1202 
1203  /* If result is pass-by-ref, make sure it is in the right context. */
1204  if (!peragg->resulttypeByVal && !*resultIsNull &&
1206  DatumGetPointer(*resultVal)))
1207  *resultVal = datumCopy(*resultVal,
1208  peragg->resulttypeByVal,
1209  peragg->resulttypeLen);
1210 
1211  MemoryContextSwitchTo(oldContext);
1212 }
ScanState ss
Definition: execnodes.h:2271
ExprContext * ps_ExprContext
Definition: execnodes.h:1003
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:2281
#define OidIsValid(objectId)
Definition: c.h:710
PlanState ps
Definition: execnodes.h:1373
bool fn_strict
Definition: fmgr.h:61
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
Datum value
Definition: postgres.h:422
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
uintptr_t Datum
Definition: postgres.h:411
int16 resulttypeLen
Definition: nodeAgg.h:216
FmgrInfo serialfn
Definition: nodeAgg.h:84
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:758
FunctionCallInfo serialfn_fcinfo
Definition: nodeAgg.h:165
#define DatumGetPointer(X)
Definition: postgres.h:593
bool resulttypeByVal
Definition: nodeAgg.h:217

◆ find_cols()

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

Definition at line 1398 of file nodeAgg.c.

References bms_add_member(), find_cols_walker(), Agg::grpColIdx, i, FindColsContext::is_aggref, Agg::numCols, Agg::plan, PlanState::plan, ScanState::ps, Plan::qual, AggState::ss, and Plan::targetlist.

Referenced by find_hash_columns().

1399 {
1400  Agg *agg = (Agg *) aggstate->ss.ps.plan;
1401  FindColsContext context;
1402 
1403  context.is_aggref = false;
1404  context.aggregated = NULL;
1405  context.unaggregated = NULL;
1406 
1407  /* Examine tlist and quals */
1408  (void) find_cols_walker((Node *) agg->plan.targetlist, &context);
1409  (void) find_cols_walker((Node *) agg->plan.qual, &context);
1410 
1411  /* In some cases, grouping columns will not appear in the tlist */
1412  for (int i = 0; i < agg->numCols; i++)
1413  context.unaggregated = bms_add_member(context.unaggregated,
1414  agg->grpColIdx[i]);
1415 
1416  *aggregated = context.aggregated;
1417  *unaggregated = context.unaggregated;
1418 }
int numCols
Definition: plannodes.h:861
List * qual
Definition: plannodes.h:142
AttrNumber * grpColIdx
Definition: plannodes.h:862
ScanState ss
Definition: execnodes.h:2271
Definition: nodes.h:539
PlanState ps
Definition: execnodes.h:1373
static bool find_cols_walker(Node *node, FindColsContext *context)
Definition: nodeAgg.c:1421
Plan plan
Definition: plannodes.h:858
Plan * plan
Definition: execnodes.h:964
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
List * targetlist
Definition: plannodes.h:141
int i
Definition: plannodes.h:856
bool is_aggref
Definition: nodeAgg.c:377

◆ find_cols_walker()

static bool find_cols_walker ( Node node,
FindColsContext context 
)
static

Definition at line 1421 of file nodeAgg.c.

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

Referenced by find_cols().

1422 {
1423  if (node == NULL)
1424  return false;
1425  if (IsA(node, Var))
1426  {
1427  Var *var = (Var *) node;
1428 
1429  /* setrefs.c should have set the varno to OUTER_VAR */
1430  Assert(var->varno == OUTER_VAR);
1431  Assert(var->varlevelsup == 0);
1432  if (context->is_aggref)
1433  context->aggregated = bms_add_member(context->aggregated,
1434  var->varattno);
1435  else
1436  context->unaggregated = bms_add_member(context->unaggregated,
1437  var->varattno);
1438  return false;
1439  }
1440  if (IsA(node, Aggref))
1441  {
1442  Assert(!context->is_aggref);
1443  context->is_aggref = true;
1444  expression_tree_walker(node, find_cols_walker, (void *) context);
1445  context->is_aggref = false;
1446  return false;
1447  }
1449  (void *) context);
1450 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
Index varlevelsup
Definition: primnodes.h:196
AttrNumber varattno
Definition: primnodes.h:191
Definition: primnodes.h:186
static bool find_cols_walker(Node *node, FindColsContext *context)
Definition: nodeAgg.c:1421
Bitmapset * unaggregated
Definition: nodeAgg.c:379
Bitmapset * aggregated
Definition: nodeAgg.c:378
Index varno
Definition: primnodes.h:189
#define Assert(condition)
Definition: c.h:804
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1904
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
bool is_aggref
Definition: nodeAgg.c:377
#define OUTER_VAR
Definition: primnodes.h:176

◆ find_hash_columns()

static void find_hash_columns ( AggState aggstate)
static

Definition at line 1564 of file nodeAgg.c.

References AggStatePerHashData::aggnode, AggState::all_cols_needed, AggState::all_grouped_cols, attnum, bms_add_member(), bms_copy(), bms_del_member(), bms_first_member(), bms_free(), bms_is_member(), bms_num_members(), bms_union(), AggState::colnos_needed, AggStatePerHashData::eqfuncoids, EState::es_tupleTable, ExecAllocTableSlot(), execTuplesHashPrepare(), ExecTypeFromTL(), find_cols(), AggStatePerPhaseData::grouped_cols, Agg::grpColIdx, Agg::grpOperators, AggStatePerHashData::hashfunctions, AggStatePerHashData::hashGrpColIdxHash, AggStatePerHashData::hashGrpColIdxInput, AggStatePerHashData::hashslot, i, lappend(), AggStatePerHashData::largestGrpColIdx, lfirst_int, list_free(), list_nth(), Max, AggState::max_colno_needed, TupleDescData::natts, NIL, AggState::num_hashes, AggStatePerHashData::numCols, AggStatePerHashData::numhashGrpCols, outerPlanState, palloc(), AggState::perhash, AggState::phases, ScanState::ps, AggState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, TupleTableSlot::tts_tupleDescriptor, and TTSOpsMinimalTuple.

Referenced by ExecInitAgg().

1565 {
1566  Bitmapset *base_colnos;
1567  Bitmapset *aggregated_colnos;
1568  TupleDesc scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
1569  List *outerTlist = outerPlanState(aggstate)->plan->targetlist;
1570  int numHashes = aggstate->num_hashes;
1571  EState *estate = aggstate->ss.ps.state;
1572  int j;
1573 
1574  /* Find Vars that will be needed in tlist and qual */
1575  find_cols(aggstate, &aggregated_colnos, &base_colnos);
1576  aggstate->colnos_needed = bms_union(base_colnos, aggregated_colnos);
1577  aggstate->max_colno_needed = 0;
1578  aggstate->all_cols_needed = true;
1579 
1580  for (int i = 0; i < scanDesc->natts; i++)
1581  {
1582  int colno = i + 1;
1583  if (bms_is_member(colno, aggstate->colnos_needed))
1584  aggstate->max_colno_needed = colno;
1585  else
1586  aggstate->all_cols_needed = false;
1587  }
1588 
1589  for (j = 0; j < numHashes; ++j)
1590  {
1591  AggStatePerHash perhash = &aggstate->perhash[j];
1592  Bitmapset *colnos = bms_copy(base_colnos);
1593  AttrNumber *grpColIdx = perhash->aggnode->grpColIdx;
1594  List *hashTlist = NIL;
1595  TupleDesc hashDesc;
1596  int maxCols;
1597  int i;
1598 
1599  perhash->largestGrpColIdx = 0;
1600 
1601  /*
1602  * If we're doing grouping sets, then some Vars might be referenced in
1603  * tlist/qual for the benefit of other grouping sets, but not needed
1604  * when hashing; i.e. prepare_projection_slot will null them out, so
1605  * there'd be no point storing them. Use prepare_projection_slot's
1606  * logic to determine which.
1607  */
1608  if (aggstate->phases[0].grouped_cols)
1609  {
1610  Bitmapset *grouped_cols = aggstate->phases[0].grouped_cols[j];
1611  ListCell *lc;
1612 
1613  foreach(lc, aggstate->all_grouped_cols)
1614  {
1615  int attnum = lfirst_int(lc);
1616 
1617  if (!bms_is_member(attnum, grouped_cols))
1618  colnos = bms_del_member(colnos, attnum);
1619  }
1620  }
1621 
1622  /*
1623  * Compute maximum number of input columns accounting for possible
1624  * duplications in the grpColIdx array, which can happen in some edge
1625  * cases where HashAggregate was generated as part of a semijoin or a
1626  * DISTINCT.
1627  */
1628  maxCols = bms_num_members(colnos) + perhash->numCols;
1629 
1630  perhash->hashGrpColIdxInput =
1631  palloc(maxCols * sizeof(AttrNumber));
1632  perhash->hashGrpColIdxHash =
1633  palloc(perhash->numCols * sizeof(AttrNumber));
1634 
1635  /* Add all the grouping columns to colnos */
1636  for (i = 0; i < perhash->numCols; i++)
1637  colnos = bms_add_member(colnos, grpColIdx[i]);
1638 
1639  /*
1640  * First build mapping for columns directly hashed. These are the
1641  * first, because they'll be accessed when computing hash values and
1642  * comparing tuples for exact matches. We also build simple mapping
1643  * for execGrouping, so it knows where to find the to-be-hashed /
1644  * compared columns in the input.
1645  */
1646  for (i = 0; i < perhash->numCols; i++)
1647  {
1648  perhash->hashGrpColIdxInput[i] = grpColIdx[i];
1649  perhash->hashGrpColIdxHash[i] = i + 1;
1650  perhash->numhashGrpCols++;
1651  /* delete already mapped columns */
1652  bms_del_member(colnos, grpColIdx[i]);
1653  }
1654 
1655  /* and add the remaining columns */
1656  while ((i = bms_first_member(colnos)) >= 0)
1657  {
1658  perhash->hashGrpColIdxInput[perhash->numhashGrpCols] = i;
1659  perhash->numhashGrpCols++;
1660  }
1661 
1662  /* and build a tuple descriptor for the hashtable */
1663  for (i = 0; i < perhash->numhashGrpCols; i++)
1664  {
1665  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
1666 
1667  hashTlist = lappend(hashTlist, list_nth(outerTlist, varNumber));
1668  perhash->largestGrpColIdx =
1669  Max(varNumber + 1, perhash->largestGrpColIdx);
1670  }
1671 
1672  hashDesc = ExecTypeFromTL(hashTlist);
1673 
1674  execTuplesHashPrepare(perhash->numCols,
1675  perhash->aggnode->grpOperators,
1676  &perhash->eqfuncoids,
1677  &perhash->hashfunctions);
1678  perhash->hashslot =
1679  ExecAllocTableSlot(&estate->es_tupleTable, hashDesc,
1681 
1682  list_free(hashTlist);
1683  bms_free(colnos);
1684  }
1685 
1686  bms_free(base_colnos);
1687 }
#define NIL
Definition: pg_list.h:65
int bms_first_member(Bitmapset *a)
Definition: bitmapset.c:996
AggStatePerPhase phases
Definition: execnodes.h:2302
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.h:311
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
AttrNumber * grpColIdx
Definition: plannodes.h:862
Bitmapset * colnos_needed
Definition: execnodes.h:2297
List * all_grouped_cols
Definition: execnodes.h:2296
ScanState ss
Definition: execnodes.h:2271
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1376
bool all_cols_needed
Definition: execnodes.h:2299
EState * state
Definition: execnodes.h:966
void execTuplesHashPrepare(int numCols, const Oid *eqOperators, Oid **eqFuncOids, FmgrInfo **hashFunctions)
Definition: execGrouping.c:96
int max_colno_needed
Definition: execnodes.h:2298
Bitmapset ** grouped_cols
Definition: nodeAgg.h:277
PlanState ps
Definition: execnodes.h:1373
static void find_cols(AggState *aggstate, Bitmapset **aggregated, Bitmapset **unaggregated)
Definition: nodeAgg.c:1398
#define lfirst_int(lc)
Definition: pg_list.h:170
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
#define outerPlanState(node)
Definition: execnodes.h:1058
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
AggStatePerHash perhash
Definition: execnodes.h:2334
TupleTableSlot * ExecAllocTableSlot(List **tupleTable, TupleDesc desc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1171
List * lappend(List *list, void *datum)
Definition: list.c:336
int num_hashes
Definition: execnodes.h:2312
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:312
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
List * es_tupleTable
Definition: execnodes.h:600
int16 attnum
Definition: pg_attribute.h:83
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define Max(x, y)
Definition: c.h:980
FmgrInfo * hashfunctions
Definition: nodeAgg.h:306
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:225
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1938
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
Oid * grpOperators
Definition: plannodes.h:863
void * palloc(Size size)
Definition: mcxt.c:1062
void list_free(List *list)
Definition: list.c:1391
int i
TupleTableSlot * hashslot
Definition: nodeAgg.h:305
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:773
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
int16 AttrNumber
Definition: attnum.h:21
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85

◆ GetAggInitVal()

static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 4354 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

4355 {
4356  Oid typinput,
4357  typioparam;
4358  char *strInitVal;
4359  Datum initVal;
4360 
4361  getTypeInputInfo(transtype, &typinput, &typioparam);
4362  strInitVal = TextDatumGetCString(textInitVal);
4363  initVal = OidInputFunctionCall(typinput, strInitVal,
4364  typioparam, -1);
4365  pfree(strInitVal);
4366  return initVal;
4367 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:1169
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2821
#define TextDatumGetCString(d)
Definition: builtins.h:83
uintptr_t Datum
Definition: postgres.h:411
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1644

◆ hash_agg_check_limits()

static void hash_agg_check_limits ( AggState aggstate)
static

Definition at line 1855 of file nodeAgg.c.

References ExprContext::ecxt_per_tuple_memory, hash_agg_enter_spill_mode(), AggState::hash_mem_limit, AggState::hash_metacxt, AggState::hash_ngroups_current, AggState::hash_ngroups_limit, AggState::hashcontext, and MemoryContextMemAllocated().

Referenced by initialize_hash_entry().

1856 {
1857  uint64 ngroups = aggstate->hash_ngroups_current;
1858  Size meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt,
1859  true);
1861  true);
1862 
1863  /*
1864  * Don't spill unless there's at least one group in the hash table so we
1865  * can be sure to make progress even in edge cases.
1866  */
1867  if (aggstate->hash_ngroups_current > 0 &&
1868  (meta_mem + hashkey_mem > aggstate->hash_mem_limit ||
1869  ngroups > aggstate->hash_ngroups_limit))
1870  {
1871  hash_agg_enter_spill_mode(aggstate);
1872  }
1873 }
uint64 hash_ngroups_limit
Definition: execnodes.h:2324
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
static void hash_agg_enter_spill_mode(AggState *aggstate)
Definition: nodeAgg.c:1881
MemoryContext hash_metacxt
Definition: execnodes.h:2313
ExprContext * hashcontext
Definition: execnodes.h:2282
Size MemoryContextMemAllocated(MemoryContext context, bool recurse)
Definition: mcxt.c:477
size_t Size
Definition: c.h:540
Size hash_mem_limit
Definition: execnodes.h:2323
uint64 hash_ngroups_current
Definition: execnodes.h:2329

◆ hash_agg_enter_spill_mode()

static void hash_agg_enter_spill_mode ( AggState aggstate)
static

Definition at line 1881 of file nodeAgg.c.

References AggStatePerHashData::aggnode, Assert, AggState::hash_ever_spilled, AggState::hash_spill_mode, AggState::hash_spills, AggState::hash_tapeinfo, hashagg_recompile_expressions(), hashagg_spill_init(), hashagg_tapeinfo_init(), AggState::hashentrysize, AggState::num_hashes, Agg::numGroups, palloc(), AggState::perhash, and AggState::table_filled.

Referenced by hash_agg_check_limits().

1882 {
1883  aggstate->hash_spill_mode = true;
1884  hashagg_recompile_expressions(aggstate, aggstate->table_filled, true);
1885 
1886  if (!aggstate->hash_ever_spilled)
1887  {
1888  Assert(aggstate->hash_tapeinfo == NULL);
1889  Assert(aggstate->hash_spills == NULL);
1890 
1891  aggstate->hash_ever_spilled = true;
1892 
1893  hashagg_tapeinfo_init(aggstate);
1894 
1895  aggstate->hash_spills = palloc(sizeof(HashAggSpill) * aggstate->num_hashes);
1896 
1897  for (int setno = 0; setno < aggstate->num_hashes; setno++)
1898  {
1899  AggStatePerHash perhash = &aggstate->perhash[setno];
1900  HashAggSpill *spill = &aggstate->hash_spills[setno];
1901 
1902  hashagg_spill_init(spill, aggstate->hash_tapeinfo, 0,
1903  perhash->aggnode->numGroups,
1904  aggstate->hashentrysize);
1905  }
1906  }
1907 }
struct HashAggSpill * hash_spills
Definition: execnodes.h:2315
double hashentrysize
Definition: execnodes.h:2327
static void hashagg_spill_init(HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits, double input_groups, double hashentrysize)
Definition: nodeAgg.c:2949
bool hash_spill_mode
Definition: execnodes.h:2321
static void hashagg_tapeinfo_init(AggState *aggstate)
Definition: nodeAgg.c:2885
bool table_filled
Definition: execnodes.h:2311
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2314
AggStatePerHash perhash
Definition: execnodes.h:2334
int num_hashes
Definition: execnodes.h:2312
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1740
#define Assert(condition)
Definition: c.h:804
bool hash_ever_spilled
Definition: execnodes.h:2320
long numGroups
Definition: plannodes.h:865
void * palloc(Size size)
Definition: mcxt.c:1062

◆ hash_agg_entry_size()

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

Definition at line 1693 of file nodeAgg.c.

References CHUNKHDRSZ, MAXALIGN, and SizeofMinimalTupleHeader.

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

1694 {
1695  Size tupleChunkSize;
1696  Size pergroupChunkSize;
1697  Size transitionChunkSize;
1698  Size tupleSize = (MAXALIGN(SizeofMinimalTupleHeader) +
1699  tupleWidth);
1700  Size pergroupSize = numTrans * sizeof(AggStatePerGroupData);
1701 
1702  tupleChunkSize = CHUNKHDRSZ + tupleSize;
1703 
1704  if (pergroupSize > 0)
1705  pergroupChunkSize = CHUNKHDRSZ + pergroupSize;
1706  else
1707  pergroupChunkSize = 0;
1708 
1709  if (transitionSpace > 0)
1710  transitionChunkSize = CHUNKHDRSZ + transitionSpace;
1711  else
1712  transitionChunkSize = 0;
1713 
1714  return
1715  sizeof(TupleHashEntryData) +
1716  tupleChunkSize +
1717  pergroupChunkSize +
1718  transitionChunkSize;
1719 }
struct TupleHashEntryData TupleHashEntryData
struct AggStatePerGroupData AggStatePerGroupData
#define SizeofMinimalTupleHeader
Definition: htup_details.h:648
size_t Size
Definition: c.h:540
#define MAXALIGN(LEN)
Definition: c.h:757
#define CHUNKHDRSZ
Definition: nodeAgg.c:312

◆ 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 1797 of file nodeAgg.c.

References get_hash_mem(), hash_choose_num_partitions(), HASHAGG_READ_BUFFER_SIZE, and HASHAGG_WRITE_BUFFER_SIZE.

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

1800 {
1801  int npartitions;
1802  Size partition_mem;
1803  int hash_mem = get_hash_mem();
1804 
1805  /* if not expected to spill, use all of hash_mem */
1806  if (input_groups * hashentrysize < hash_mem * 1024L)
1807  {
1808  if (num_partitions != NULL)
1809  *num_partitions = 0;
1810  *mem_limit = hash_mem * 1024L;
1811  *ngroups_limit = *mem_limit / hashentrysize;
1812  return;
1813  }
1814 
1815  /*
1816  * Calculate expected memory requirements for spilling, which is the size
1817  * of the buffers needed for all the tapes that need to be open at once.
1818  * Then, subtract that from the memory available for holding hash tables.
1819  */
1820  npartitions = hash_choose_num_partitions(input_groups,
1821  hashentrysize,
1822  used_bits,
1823  NULL);
1824  if (num_partitions != NULL)
1825  *num_partitions = npartitions;
1826 
1827  partition_mem =
1829  HASHAGG_WRITE_BUFFER_SIZE * npartitions;
1830 
1831  /*
1832  * Don't set the limit below 3/4 of hash_mem. In that case, we are at the
1833  * minimum number of partitions, so we aren't going to dramatically exceed
1834  * work mem anyway.
1835  */
1836  if (hash_mem * 1024L > 4 * partition_mem)
1837  *mem_limit = hash_mem * 1024L - partition_mem;
1838  else
1839  *mem_limit = hash_mem * 1024L * 0.75;
1840 
1841  if (*mem_limit > hashentrysize)
1842  *ngroups_limit = *mem_limit / hashentrysize;
1843  else
1844  *ngroups_limit = 1;
1845 }
static int hash_choose_num_partitions(double input_groups, double hashentrysize, int used_bits, int *log2_npartittions)
Definition: nodeAgg.c:1990
#define HASHAGG_READ_BUFFER_SIZE
Definition: nodeAgg.c:297
size_t Size
Definition: c.h:540
#define HASHAGG_WRITE_BUFFER_SIZE
Definition: nodeAgg.c:298
int get_hash_mem(void)
Definition: nodeHash.c:3389

◆ hash_agg_update_metrics()

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

Definition at line 1916 of file nodeAgg.c.

References AGG_HASHED, AGG_MIXED, AggState::aggstrategy, ExprContext::ecxt_per_tuple_memory, AggState::hash_disk_used, AggState::hash_mem_peak, AggState::hash_metacxt, AggState::hash_ngroups_current, AggState::hash_tapeinfo, HASHAGG_READ_BUFFER_SIZE, HASHAGG_WRITE_BUFFER_SIZE, AggState::hashcontext, AggState::hashentrysize, LogicalTapeSetBlocks(), MemoryContextMemAllocated(), and HashTapeInfo::tapeset.

Referenced by agg_refill_hash_table(), and hashagg_finish_initial_spills().

1917 {
1918  Size meta_mem;
1919  Size hashkey_mem;
1920  Size buffer_mem;
1921  Size total_mem;
1922 
1923  if (aggstate->aggstrategy != AGG_MIXED &&
1924  aggstate->aggstrategy != AGG_HASHED)
1925  return;
1926 
1927  /* memory for the hash table itself */
1928  meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt, true);
1929 
1930  /* memory for the group keys and transition states */
1931  hashkey_mem = MemoryContextMemAllocated(aggstate->hashcontext->ecxt_per_tuple_memory, true);
1932 
1933  /* memory for read/write tape buffers, if spilled */
1934  buffer_mem = npartitions * HASHAGG_WRITE_BUFFER_SIZE;
1935  if (from_tape)
1936  buffer_mem += HASHAGG_READ_BUFFER_SIZE;
1937 
1938  /* update peak mem */
1939  total_mem = meta_mem + hashkey_mem + buffer_mem;
1940  if (total_mem > aggstate->hash_mem_peak)
1941  aggstate->hash_mem_peak = total_mem;
1942 
1943  /* update disk usage */
1944  if (aggstate->hash_tapeinfo != NULL)
1945  {
1946  uint64 disk_used = LogicalTapeSetBlocks(aggstate->hash_tapeinfo->tapeset) * (BLCKSZ / 1024);
1947 
1948  if (aggstate->hash_disk_used < disk_used)
1949  aggstate->hash_disk_used = disk_used;
1950  }
1951 
1952  /* update hashentrysize estimate based on contents */
1953  if (aggstate->hash_ngroups_current > 0)
1954  {
1955  aggstate->hashentrysize =
1956  sizeof(TupleHashEntryData) +
1957  (hashkey_mem / (double) aggstate->hash_ngroups_current);
1958  }
1959 }
double hashentrysize
Definition: execnodes.h:2327
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
AggStrategy aggstrategy
Definition: execnodes.h:2275
MemoryContext hash_metacxt
Definition: execnodes.h:2313
struct TupleHashEntryData TupleHashEntryData
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2314
ExprContext * hashcontext
Definition: execnodes.h:2282
#define HASHAGG_READ_BUFFER_SIZE
Definition: nodeAgg.c:297
LogicalTapeSet * tapeset
Definition: nodeAgg.c:328
uint64 hash_disk_used
Definition: execnodes.h:2331
Size MemoryContextMemAllocated(MemoryContext context, bool recurse)
Definition: mcxt.c:477
size_t Size
Definition: c.h:540
#define HASHAGG_WRITE_BUFFER_SIZE
Definition: nodeAgg.c:298
Size hash_mem_peak
Definition: execnodes.h:2328
uint64 hash_ngroups_current
Definition: execnodes.h:2329
long LogicalTapeSetBlocks(LogicalTapeSet *lts)
Definition: logtape.c:1272