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 transfn_oid, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
 
static void initialize_aggregate (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void find_hash_columns (AggState *aggstate)
 
Size hash_agg_entry_size (int numTrans, Size tupleWidth, Size transitionSpace)
 
void hash_agg_set_limits (double hashentrysize, double input_groups, int used_bits, Size *mem_limit, uint64 *ngroups_limit, int *num_partitions)
 
static TupleTableSlotExecAgg (PlanState *pstate)
 
AggStateExecInitAgg (Agg *node, EState *estate, int eflags)
 
void ExecEndAgg (AggState *node)
 
void ExecReScanAgg (AggState *node)
 
int AggCheckCallContext (FunctionCallInfo fcinfo, MemoryContext *aggcontext)
 
AggrefAggGetAggref (FunctionCallInfo fcinfo)
 
MemoryContext AggGetTempMemoryContext (FunctionCallInfo fcinfo)
 
bool AggStateIsShared (FunctionCallInfo fcinfo)
 
void AggRegisterCallback (FunctionCallInfo fcinfo, ExprContextCallbackFunction func, Datum arg)
 
void ExecAggEstimate (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeDSM (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeWorker (AggState *node, ParallelWorkerContext *pwcxt)
 
void ExecAggRetrieveInstrumentation (AggState *node)
 

Macro Definition Documentation

◆ CHUNKHDRSZ

#define CHUNKHDRSZ   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 839 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().

840 {
841  bool dummynull;
842 
844  aggstate->tmpcontext,
845  &dummynull);
846 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:331
ExprState * evaltrans
Definition: nodeAgg.h:283
ExprContext * tmpcontext
Definition: execnodes.h:2289
AggStatePerPhase phase
Definition: execnodes.h:2282

◆ advance_transition_function()

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

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

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

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

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

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

◆ agg_refill_hash_table()

static bool agg_refill_hash_table ( AggState aggstate)
static

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

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

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

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

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

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

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

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

◆ agg_retrieve_hash_table_in_memory()

static TupleTableSlot * agg_retrieve_hash_table_in_memory ( AggState aggstate)
static

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

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

◆ AggCheckCallContext()

int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

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

4581 {
4582  if (fcinfo->context && IsA(fcinfo->context, AggState))
4583  {
4584  if (aggcontext)
4585  {
4586  AggState *aggstate = ((AggState *) fcinfo->context);
4587  ExprContext *cxt = aggstate->curaggcontext;
4588 
4589  *aggcontext = cxt->ecxt_per_tuple_memory;
4590  }
4591  return AGG_CONTEXT_AGGREGATE;
4592  }
4593  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4594  {
4595  if (aggcontext)
4596  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4597  return AGG_CONTEXT_WINDOW;
4598  }
4599 
4600  /* this is just to prevent "uninitialized variable" warnings */
4601  if (aggcontext)
4602  *aggcontext = NULL;
4603  return 0;
4604 }
#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:2291
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:739

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4624 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4625 {
4626  if (fcinfo->context && IsA(fcinfo->context, AggState))
4627  {
4628  AggState *aggstate = (AggState *) fcinfo->context;
4629  AggStatePerAgg curperagg;
4630  AggStatePerTrans curpertrans;
4631 
4632  /* check curperagg (valid when in a final function) */
4633  curperagg = aggstate->curperagg;
4634 
4635  if (curperagg)
4636  return curperagg->aggref;
4637 
4638  /* check curpertrans (valid when in a transition function) */
4639  curpertrans = aggstate->curpertrans;
4640 
4641  if (curpertrans)
4642  return curpertrans->aggref;
4643  }
4644  return NULL;
4645 }
#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:2292
AggStatePerTrans curpertrans
Definition: execnodes.h:2294

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4658 of file nodeAgg.c.

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

4659 {
4660  if (fcinfo->context && IsA(fcinfo->context, AggState))
4661  {
4662  AggState *aggstate = (AggState *) fcinfo->context;
4663 
4664  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4665  }
4666  return NULL;
4667 }
#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:2289

◆ AggRegisterCallback()

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

Definition at line 4723 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4726 {
4727  if (fcinfo->context && IsA(fcinfo->context, AggState))
4728  {
4729  AggState *aggstate = (AggState *) fcinfo->context;
4730  ExprContext *cxt = aggstate->curaggcontext;
4731 
4732  RegisterExprContextCallback(cxt, func, arg);
4733 
4734  return;
4735  }
4736  elog(ERROR, "aggregate function cannot register a callback in this context");
4737 }
#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:2291
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 4684 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4685 {
4686  if (fcinfo->context && IsA(fcinfo->context, AggState))
4687  {
4688  AggState *aggstate = (AggState *) fcinfo->context;
4689  AggStatePerAgg curperagg;
4690  AggStatePerTrans curpertrans;
4691 
4692  /* check curperagg (valid when in a final function) */
4693  curperagg = aggstate->curperagg;
4694 
4695  if (curperagg)
4696  return aggstate->pertrans[curperagg->transno].aggshared;
4697 
4698  /* check curpertrans (valid when in a transition function) */
4699  curpertrans = aggstate->curpertrans;
4700 
4701  if (curpertrans)
4702  return curpertrans->aggshared;
4703  }
4704  return true;
4705 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:590
fmNodePtr context
Definition: fmgr.h:88
AggStatePerTrans pertrans
Definition: execnodes.h:2286
AggStatePerAgg curperagg
Definition: execnodes.h:2292
AggStatePerTrans curpertrans
Definition: execnodes.h:2294

◆ build_hash_table()

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

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

1506 {
1507  AggStatePerHash perhash = &aggstate->perhash[setno];
1508  MemoryContext metacxt = aggstate->hash_metacxt;
1509  MemoryContext hashcxt = aggstate->hashcontext->ecxt_per_tuple_memory;
1510  MemoryContext tmpcxt = aggstate->tmpcontext->ecxt_per_tuple_memory;
1511  Size additionalsize;
1512 
1513  Assert(aggstate->aggstrategy == AGG_HASHED ||
1514  aggstate->aggstrategy == AGG_MIXED);
1515 
1516  /*
1517  * Used to make sure initial hash table allocation does not exceed
1518  * hash_mem. Note that the estimate does not include space for
1519  * pass-by-reference transition data values, nor for the representative
1520  * tuple of each group.
1521  */
1522  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1523 
1524  perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
1525  perhash->hashslot->tts_tupleDescriptor,
1526  perhash->numCols,
1527  perhash->hashGrpColIdxHash,
1528  perhash->eqfuncoids,
1529  perhash->hashfunctions,
1530  perhash->aggnode->grpCollations,
1531  nbuckets,
1532  additionalsize,
1533  metacxt,
1534  hashcxt,
1535  tmpcxt,
1536  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1537 }
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:865
ScanState ss
Definition: execnodes.h:2276
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
AggSplit aggsplit
Definition: execnodes.h:2281
int numtrans
Definition: execnodes.h:2279
ExprContext * tmpcontext
Definition: execnodes.h:2289
PlanState ps
Definition: execnodes.h:1377
AggStrategy aggstrategy
Definition: execnodes.h:2280
MemoryContext hash_metacxt
Definition: execnodes.h:2318
struct AggStatePerGroupData AggStatePerGroupData
AggStatePerHash perhash
Definition: execnodes.h:2339
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:312
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2287
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 1470 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().

1471 {
1472  int setno;
1473 
1474  for (setno = 0; setno < aggstate->num_hashes; ++setno)
1475  {
1476  AggStatePerHash perhash = &aggstate->perhash[setno];
1477  long nbuckets;
1478  Size memory;
1479 
1480  if (perhash->hashtable != NULL)
1481  {
1482  ResetTupleHashTable(perhash->hashtable);
1483  continue;
1484  }
1485 
1486  Assert(perhash->aggnode->numGroups > 0);
1487 
1488  memory = aggstate->hash_mem_limit / aggstate->num_hashes;
1489 
1490  /* choose reasonable number of buckets per hashtable */
1491  nbuckets = hash_choose_num_buckets(aggstate->hashentrysize,
1492  perhash->aggnode->numGroups,
1493  memory);
1494 
1495  build_hash_table(aggstate, setno, nbuckets);
1496  }
1497 
1498  aggstate->hash_ngroups_current = 0;
1499 }
double hashentrysize
Definition: execnodes.h:2332
static long hash_choose_num_buckets(double hashentrysize, long estimated_nbuckets, Size memory)
Definition: nodeAgg.c:1967
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:283
static void build_hash_table(AggState *aggstate, int setno, long nbuckets)
Definition: nodeAgg.c:1505
AggStatePerHash perhash
Definition: execnodes.h:2339
int num_hashes
Definition: execnodes.h:2317
#define Assert(condition)
Definition: c.h:804
size_t Size
Definition: c.h:540
long numGroups
Definition: plannodes.h:866
Size hash_mem_limit
Definition: execnodes.h:2328
uint64 hash_ngroups_current
Definition: execnodes.h:2334
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  transfn_oid,
Oid  aggtranstype,
Oid  aggserialfn,
Oid  aggdeserialfn,
Datum  initValue,
bool  initValueIsNull,
Oid inputTypes,
int  numArguments 
)
static

Definition at line 4111 of file nodeAgg.c.

References AGG_HASHED, AGG_MIXED, AggStatePerTransData::aggCollation, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggkind, Aggref::aggorder, AggStatePerTransData::aggref, AggStatePerTransData::aggshared, AggStatePerTransData::aggtranstype, Aggref::aggvariadic, Aggref::args, Assert, build_aggregate_deserialfn_expr(), build_aggregate_serialfn_expr(), build_aggregate_transfn_expr(), AggStatePerTransData::deserialfn, AggStatePerTransData::deserialfn_fcinfo, AggStatePerTransData::deserialfn_oid, DO_AGGSPLIT_COMBINE, AggStatePerTransData::equalfnMulti, AggStatePerTransData::equalfnOne, ExecInitExtraTupleSlot(), execTuplesMatchPrepare(), ExecTypeFromTL(), TargetEntry::expr, exprCollation(), fmgr_info(), fmgr_info_set_expr, get_opcode(), get_sortgroupclause_tle(), get_typlenbyval(), i, InitFunctionCallInfoData, AggStatePerTransData::initValue, initValue(), AggStatePerTransData::initValueIsNull, Aggref::inputcollid, AggStatePerTransData::inputtypeByVal, AggStatePerTransData::inputtypeLen, InvalidOid, lfirst, list_length(), Max, AggState::maxsets, NIL, SortGroupClause::nulls_first, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numInputs, AggStatePerTransData::numSortCols, AggStatePerTransData::numTransInputs, OidIsValid, palloc(), palloc0(), pfree(), 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, AggStatePerTransData::transfn, AggStatePerTransData::transfn_fcinfo, AggStatePerTransData::transfn_oid, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, TTSOpsMinimalTuple, and AggStatePerTransData::uniqslot.

Referenced by ExecInitAgg().

4118 {
4119  int numGroupingSets = Max(aggstate->maxsets, 1);
4120  Expr *transfnexpr;
4121  int numTransArgs;
4122  Expr *serialfnexpr = NULL;
4123  Expr *deserialfnexpr = NULL;
4124  ListCell *lc;
4125  int numInputs;
4126  int numDirectArgs;
4127  List *sortlist;
4128  int numSortCols;
4129  int numDistinctCols;
4130  int i;
4131 
4132  /* Begin filling in the pertrans data */
4133  pertrans->aggref = aggref;
4134  pertrans->aggshared = false;
4135  pertrans->aggCollation = aggref->inputcollid;
4136  pertrans->transfn_oid = transfn_oid;
4137  pertrans->serialfn_oid = aggserialfn;
4138  pertrans->deserialfn_oid = aggdeserialfn;
4139  pertrans->initValue = initValue;
4140  pertrans->initValueIsNull = initValueIsNull;
4141 
4142  /* Count the "direct" arguments, if any */
4143  numDirectArgs = list_length(aggref->aggdirectargs);
4144 
4145  /* Count the number of aggregated input columns */
4146  pertrans->numInputs = numInputs = list_length(aggref->args);
4147 
4148  pertrans->aggtranstype = aggtranstype;
4149 
4150  /* account for the current transition state */
4151  numTransArgs = pertrans->numTransInputs + 1;
4152 
4153  /*
4154  * Set up infrastructure for calling the transfn. Note that invtrans is
4155  * not needed here.
4156  */
4157  build_aggregate_transfn_expr(inputTypes,
4158  numArguments,
4159  numDirectArgs,
4160  aggref->aggvariadic,
4161  aggtranstype,
4162  aggref->inputcollid,
4163  transfn_oid,
4164  InvalidOid,
4165  &transfnexpr,
4166  NULL);
4167 
4168  fmgr_info(transfn_oid, &pertrans->transfn);
4169  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
4170 
4171  pertrans->transfn_fcinfo =
4174  &pertrans->transfn,
4175  numTransArgs,
4176  pertrans->aggCollation,
4177  (void *) aggstate, NULL);
4178 
4179  /* get info about the state value's datatype */
4180  get_typlenbyval(aggtranstype,
4181  &pertrans->transtypeLen,
4182  &pertrans->transtypeByVal);
4183 
4184  if (OidIsValid(aggserialfn))
4185  {
4186  build_aggregate_serialfn_expr(aggserialfn,
4187  &serialfnexpr);
4188  fmgr_info(aggserialfn, &pertrans->serialfn);
4189  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
4190 
4191  pertrans->serialfn_fcinfo =
4194  &pertrans->serialfn,
4195  1,
4196  InvalidOid,
4197  (void *) aggstate, NULL);
4198  }
4199 
4200  if (OidIsValid(aggdeserialfn))
4201  {
4202  build_aggregate_deserialfn_expr(aggdeserialfn,
4203  &deserialfnexpr);
4204  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
4205  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
4206 
4207  pertrans->deserialfn_fcinfo =
4210  &pertrans->deserialfn,
4211  2,
4212  InvalidOid,
4213  (void *) aggstate, NULL);
4214 
4215  }
4216 
4217  /*
4218  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
4219  * have a list of SortGroupClause nodes; fish out the data in them and
4220  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
4221  * however; the agg's transfn and finalfn are responsible for that.
4222  *
4223  * Note that by construction, if there is a DISTINCT clause then the ORDER
4224  * BY clause is a prefix of it (see transformDistinctClause).
4225  */
4226  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4227  {
4228  sortlist = NIL;
4229  numSortCols = numDistinctCols = 0;
4230  }
4231  else if (aggref->aggdistinct)
4232  {
4233  sortlist = aggref->aggdistinct;
4234  numSortCols = numDistinctCols = list_length(sortlist);
4235  Assert(numSortCols >= list_length(aggref->aggorder));
4236  }
4237  else
4238  {
4239  sortlist = aggref->aggorder;
4240  numSortCols = list_length(sortlist);
4241  numDistinctCols = 0;
4242  }
4243 
4244  pertrans->numSortCols = numSortCols;
4245  pertrans->numDistinctCols = numDistinctCols;
4246 
4247  /*
4248  * If we have either sorting or filtering to do, create a tupledesc and
4249  * slot corresponding to the aggregated inputs (including sort
4250  * expressions) of the agg.
4251  */
4252  if (numSortCols > 0 || aggref->aggfilter)
4253  {
4254  pertrans->sortdesc = ExecTypeFromTL(aggref->args);
4255  pertrans->sortslot =
4256  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4258  }
4259 
4260  if (numSortCols > 0)
4261  {
4262  /*
4263  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
4264  * (yet)
4265  */
4266  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
4267 
4268  /* ORDER BY aggregates are not supported with partial aggregation */
4269  Assert(!DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
4270 
4271  /* If we have only one input, we need its len/byval info. */
4272  if (numInputs == 1)
4273  {
4274  get_typlenbyval(inputTypes[numDirectArgs],
4275  &pertrans->inputtypeLen,
4276  &pertrans->inputtypeByVal);
4277  }
4278  else if (numDistinctCols > 0)
4279  {
4280  /* we will need an extra slot to store prior values */
4281  pertrans->uniqslot =
4282  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4284  }
4285 
4286  /* Extract the sort information for use later */
4287  pertrans->sortColIdx =
4288  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
4289  pertrans->sortOperators =
4290  (Oid *) palloc(numSortCols * sizeof(Oid));
4291  pertrans->sortCollations =
4292  (Oid *) palloc(numSortCols * sizeof(Oid));
4293  pertrans->sortNullsFirst =
4294  (bool *) palloc(numSortCols * sizeof(bool));
4295 
4296  i = 0;
4297  foreach(lc, sortlist)
4298  {
4299  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
4300  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
4301 
4302  /* the parser should have made sure of this */
4303  Assert(OidIsValid(sortcl->sortop));
4304 
4305  pertrans->sortColIdx[i] = tle->resno;
4306  pertrans->sortOperators[i] = sortcl->sortop;
4307  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
4308  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
4309  i++;
4310  }
4311  Assert(i == numSortCols);
4312  }
4313 
4314  if (aggref->aggdistinct)
4315  {
4316  Oid *ops;
4317 
4318  Assert(numArguments > 0);
4319  Assert(list_length(aggref->aggdistinct) == numDistinctCols);
4320 
4321  ops = palloc(numDistinctCols * sizeof(Oid));
4322 
4323  i = 0;
4324  foreach(lc, aggref->aggdistinct)
4325  ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
4326 
4327  /* lookup / build the necessary comparators */
4328  if (numDistinctCols == 1)
4329  fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
4330  else
4331  pertrans->equalfnMulti =
4332  execTuplesMatchPrepare(pertrans->sortdesc,
4333  numDistinctCols,
4334  pertrans->sortColIdx,
4335  ops,
4336  pertrans->sortCollations,
4337  &aggstate->ss.ps);
4338  pfree(ops);
4339  }
4340 
4341  pertrans->sortstates = (Tuplesortstate **)
4342  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
4343 }
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:2276
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:2281
List * args
Definition: primnodes.h:330
void build_aggregate_deserialfn_expr(Oid deserialfn_oid, Expr **deserialfnexpr)
Definition: parse_agg.c:2057
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:1377
int maxsets
Definition: execnodes.h:2306
void pfree(void *pointer)
Definition: mcxt.c:1169
AggStrategy aggstrategy
Definition: execnodes.h:2280
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:1455
List * aggdirectargs
Definition: primnodes.h:329
AttrNumber * sortColIdx
Definition: nodeAgg.h:100
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
#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:2034
Expr * expr
Definition: primnodes.h:1454
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:1973
#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 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 2155 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().

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

◆ ExecAggEstimate()

void ExecAggEstimate ( AggState node,
ParallelContext pcxt 
)

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

4753 {
4754  Size size;
4755 
4756  /* don't need this if not instrumenting or no workers */
4757  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4758  return;
4759 
4760  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4761  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4762  shm_toc_estimate_chunk(&pcxt->estimator, size);
4763  shm_toc_estimate_keys(&pcxt->estimator, 1);
4764 }
Instrumentation * instrument
Definition: execnodes.h:976
ScanState ss
Definition: execnodes.h:2276
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:1377
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 4773 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().

4774 {
4775  Size size;
4776 
4777  /* don't need this if not instrumenting or no workers */
4778  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4779  return;
4780 
4781  size = offsetof(SharedAggInfo, sinstrument)
4782  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4783  node->shared_info = shm_toc_allocate(pcxt->toc, size);
4784  /* ensure any unfilled slots will contain zeroes */
4785  memset(node->shared_info, 0, size);
4786  node->shared_info->num_workers = pcxt->nworkers;
4787  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4788  node->shared_info);
4789 }
Instrumentation * instrument
Definition: execnodes.h:976
ScanState ss
Definition: execnodes.h:2276
int plan_node_id
Definition: plannodes.h:140
PlanState ps
Definition: execnodes.h:1377
struct AggregateInstrumentation AggregateInstrumentation
Plan * plan
Definition: execnodes.h:966
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:2348
#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 4798 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().

4799 {
4800  node->shared_info =
4801  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4802 }
ScanState ss
Definition: execnodes.h:2276
int plan_node_id
Definition: plannodes.h:140
PlanState ps
Definition: execnodes.h:1377
Plan * plan
Definition: execnodes.h:966
SharedAggInfo * shared_info
Definition: execnodes.h:2348
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 4811 of file nodeAgg.c.

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

Referenced by ExecParallelRetrieveInstrumentation().

4812 {
4813  Size size;
4814  SharedAggInfo *si;
4815 
4816  if (node->shared_info == NULL)
4817  return;
4818 
4819  size = offsetof(SharedAggInfo, sinstrument)
4821  si = palloc(size);
4822  memcpy(si, node->shared_info, size);
4823  node->shared_info = si;
4824 }
struct AggregateInstrumentation AggregateInstrumentation
size_t Size
Definition: c.h:540
void * palloc(Size size)
Definition: mcxt.c:1062
SharedAggInfo * shared_info
Definition: execnodes.h:2348
#define offsetof(type, field)
Definition: c.h:727

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

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

4364 {
4366  int transno;
4367  int numGroupingSets = Max(node->maxsets, 1);
4368  int setno;
4369 
4370  /*
4371  * When ending a parallel worker, copy the statistics gathered by the
4372  * worker back into shared memory so that it can be picked up by the main
4373  * process to report in EXPLAIN ANALYZE.
4374  */
4375  if (node->shared_info && IsParallelWorker())
4376  {
4378 
4379  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4382  si->hash_disk_used = node->hash_disk_used;
4383  si->hash_mem_peak = node->hash_mem_peak;
4384  }
4385 
4386  /* Make sure we have closed any open tuplesorts */
4387 
4388  if (node->sort_in)
4389  tuplesort_end(node->sort_in);
4390  if (node->sort_out)
4391  tuplesort_end(node->sort_out);
4392 
4394 
4395  if (node->hash_metacxt != NULL)
4396  {
4398  node->hash_metacxt = NULL;
4399  }
4400 
4401  for (transno = 0; transno < node->numtrans; transno++)
4402  {
4403  AggStatePerTrans pertrans = &node->pertrans[transno];
4404 
4405  for (setno = 0; setno < numGroupingSets; setno++)
4406  {
4407  if (pertrans->sortstates[setno])
4408  tuplesort_end(pertrans->sortstates[setno]);
4409  }
4410  }
4411 
4412  /* And ensure any agg shutdown callbacks have been called */
4413  for (setno = 0; setno < numGroupingSets; setno++)
4414  ReScanExprContext(node->aggcontexts[setno]);
4415  if (node->hashcontext)
4417 
4418  /*
4419  * We don't actually free any ExprContexts here (see comment in
4420  * ExecFreeExprContext), just unlinking the output one from the plan node
4421  * suffices.
4422  */
4423  ExecFreeExprContext(&node->ss.ps);
4424 
4425  /* clean up tuple table */
4427 
4428  outerPlan = outerPlanState(node);
4429  ExecEndNode(outerPlan);
4430 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3195
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:556
Tuplesortstate * sort_out
Definition: execnodes.h:2309
ScanState ss
Definition: execnodes.h:2276
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1380
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2252
AggStatePerTrans pertrans
Definition: execnodes.h:2286
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
int numtrans
Definition: execnodes.h:2279
PlanState ps
Definition: execnodes.h:1377
int maxsets
Definition: execnodes.h:2306
MemoryContext hash_metacxt
Definition: execnodes.h:2318
Tuplesortstate * sort_in
Definition: execnodes.h:2308
#define outerPlanState(node)
Definition: execnodes.h:1062
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:2337
#define outerPlan(node)
Definition: plannodes.h:171
ExprContext * hashcontext
Definition: execnodes.h:2287
uint64 hash_disk_used
Definition: execnodes.h:2336
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2288
#define Assert(condition)
Definition: c.h:804
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:438
Size hash_mem_peak
Definition: execnodes.h:2333
SharedAggInfo * shared_info
Definition: execnodes.h:2348
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1464

◆ ExecInitAgg()

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

Definition at line 3247 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::aggkind, 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, Aggref::args, Assert, bms_add_member(), bms_add_members(), bms_next_member(), build_aggregate_finalfn_expr(), build_hash_tables(), build_pertrans_for_aggref(), castNode, Agg::chain, 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, FmgrInfo::fn_strict, format_type_be(), 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(), AggStatePerTransData::initValueIsNull, AggState::input_done, Aggref::inputcollid, InvalidOid, InvokeFunctionExecuteHook, IsBinaryCoercible(), 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, AggStatePerTransData::numTransInputs, 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, AggStatePerTransData::transfn, Agg::transitionSpace, AggStatePerAggData::transno, TupleTableSlot::tts_tupleDescriptor, TTSOpsMinimalTuple, and TTSOpsVirtual.

Referenced by ExecInitNode().

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

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

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

4434 {
4435  ExprContext *econtext = node->ss.ps.ps_ExprContext;
4437  Agg *aggnode = (Agg *) node->ss.ps.plan;
4438  int transno;
4439  int numGroupingSets = Max(node->maxsets, 1);
4440  int setno;
4441 
4442  node->agg_done = false;
4443 
4444  if (node->aggstrategy == AGG_HASHED)
4445  {
4446  /*
4447  * In the hashed case, if we haven't yet built the hash table then we
4448  * can just return; nothing done yet, so nothing to undo. If subnode's
4449  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4450  * else no reason to re-scan it at all.
4451  */
4452  if (!node->table_filled)
4453  return;
4454 
4455  /*
4456  * If we do have the hash table, and it never spilled, and the subplan
4457  * does not have any parameter changes, and none of our own parameter
4458  * changes affect input expressions of the aggregated functions, then
4459  * we can just rescan the existing hash table; no need to build it
4460  * again.
4461  */
4462  if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4463  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4464  {
4466  &node->perhash[0].hashiter);
4467  select_current_set(node, 0, true);
4468  return;
4469  }
4470  }
4471 
4472  /* Make sure we have closed any open tuplesorts */
4473  for (transno = 0; transno < node->numtrans; transno++)
4474  {
4475  for (setno = 0; setno < numGroupingSets; setno++)
4476  {
4477  AggStatePerTrans pertrans = &node->pertrans[transno];
4478 
4479  if (pertrans->sortstates[setno])
4480  {
4481  tuplesort_end(pertrans->sortstates[setno]);
4482  pertrans->sortstates[setno] = NULL;
4483  }
4484  }
4485  }
4486 
4487  /*
4488  * We don't need to ReScanExprContext the output tuple context here;
4489  * ExecReScan already did it. But we do need to reset our per-grouping-set
4490  * contexts, which may have transvalues stored in them. (We use rescan
4491  * rather than just reset because transfns may have registered callbacks
4492  * that need to be run now.) For the AGG_HASHED case, see below.
4493  */
4494 
4495  for (setno = 0; setno < numGroupingSets; setno++)
4496  {
4497  ReScanExprContext(node->aggcontexts[setno]);
4498  }
4499 
4500  /* Release first tuple of group, if we have made a copy */
4501  if (node->grp_firstTuple != NULL)
4502  {
4504  node->grp_firstTuple = NULL;
4505  }
4507 
4508  /* Forget current agg values */
4509  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4510  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4511 
4512  /*
4513  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4514  * the hashcontext. This used to be an issue, but now, resetting a context
4515  * automatically deletes sub-contexts too.
4516  */
4517  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4518  {
4520 
4521  node->hash_ever_spilled = false;
4522  node->hash_spill_mode = false;
4523  node->hash_ngroups_current = 0;
4524 
4526  /* Rebuild an empty hash table */
4527  build_hash_tables(node);
4528  node->table_filled = false;
4529  /* iterator will be reset when the table is filled */
4530 
4531  hashagg_recompile_expressions(node, false, false);
4532  }
4533 
4534  if (node->aggstrategy != AGG_HASHED)
4535  {
4536  /*
4537  * Reset the per-group state (in particular, mark transvalues null)
4538  */
4539  for (setno = 0; setno < numGroupingSets; setno++)
4540  {
4541  MemSet(node->pergroups[setno], 0,
4542  sizeof(AggStatePerGroupData) * node->numaggs);
4543  }
4544 
4545  /* reset to phase 1 */
4546  initialize_phase(node, 1);
4547 
4548  node->input_done = false;
4549  node->projected_set = -1;
4550  }
4551 
4552  if (outerPlan->chgParam == NULL)
4553  ExecReScan(outerPlan);
4554 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3195
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:476
Datum * ecxt_aggvalues
Definition: execnodes.h:245
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2278
bool agg_done
Definition: execnodes.h:2296
ScanState ss
Definition: execnodes.h:2276
ExprContext * ps_ExprContext
Definition: execnodes.h:1005
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
#define MemSet(start, val, len)
Definition: c.h:1008
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1380
AggStatePerTrans pertrans
Definition: execnodes.h:2286
int projected_set
Definition: execnodes.h:2297
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2314
int numtrans
Definition: execnodes.h:2279
bool hash_spill_mode
Definition: execnodes.h:2326
PlanState ps
Definition: execnodes.h:1377
int maxsets
Definition: execnodes.h:2306
bool table_filled
Definition: execnodes.h:2316
AggStrategy aggstrategy
Definition: execnodes.h:2280
#define outerPlanState(node)
Definition: execnodes.h:1062
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
Bitmapset * aggParams
Definition: plannodes.h:868
AggStatePerHash perhash
Definition: execnodes.h:2339
Bitmapset * chgParam
Definition: execnodes.h:998
#define outerPlan(node)
Definition: plannodes.h:171
TupleHashIterator hashiter
Definition: nodeAgg.h:304
bool input_done
Definition: execnodes.h:2295
ExprContext * hashcontext
Definition: execnodes.h:2287
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:498
Plan * plan
Definition: execnodes.h:966
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:769
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1742
#define Max(x, y)
Definition: c.h:980
ExprContext ** aggcontexts
Definition: execnodes.h:2288
bool hash_ever_spilled
Definition: execnodes.h:2325
AggStatePerGroup * pergroups
Definition: execnodes.h:2312
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:2334
Definition: plannodes.h:857
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:1470

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

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

569 {
570  TupleTableSlot *slot;
571 
572  if (aggstate->sort_in)
573  {
574  /* make sure we check for interrupts in either path through here */
576  if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
577  aggstate->sort_slot, NULL))
578  return NULL;
579  slot = aggstate->sort_slot;
580  }
581  else
582  slot = ExecProcNode(outerPlanState(aggstate));
583 
584  if (!TupIsNull(slot) && aggstate->sort_out)
585  tuplesort_puttupleslot(aggstate->sort_out, slot);
586 
587  return slot;
588 }
TupleTableSlot * sort_slot
Definition: execnodes.h:2310
Tuplesortstate * sort_out
Definition: execnodes.h:2309
Tuplesortstate * sort_in
Definition: execnodes.h:2308
#define outerPlanState(node)
Definition: execnodes.h:1062
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:120
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 1057 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().

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

1313 {
1314  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1315  Datum *aggvalues = econtext->ecxt_aggvalues;
1316  bool *aggnulls = econtext->ecxt_aggnulls;
1317  int aggno;
1318  int transno;
1319 
1320  /*
1321  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1322  * inputs and run the transition functions.
1323  */
1324  for (transno = 0; transno < aggstate->numtrans; transno++)
1325  {
1326  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1327  AggStatePerGroup pergroupstate;
1328 
1329  pergroupstate = &pergroup[transno];
1330 
1331  if (pertrans->numSortCols > 0)
1332  {
1333  Assert(aggstate->aggstrategy != AGG_HASHED &&
1334  aggstate->aggstrategy != AGG_MIXED);
1335 
1336  if (pertrans->numInputs == 1)
1338  pertrans,
1339  pergroupstate);
1340  else
1342  pertrans,
1343  pergroupstate);
1344  }
1345  }
1346 
1347  /*
1348  * Run the final functions.
1349  */
1350  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1351  {
1352  AggStatePerAgg peragg = &peraggs[aggno];
1353  int transno = peragg->transno;
1354  AggStatePerGroup pergroupstate;
1355 
1356  pergroupstate = &pergroup[transno];
1357 
1358  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1359  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1360  &aggvalues[aggno], &aggnulls[aggno]);
1361  else
1362  finalize_aggregate(aggstate, peragg, pergroupstate,
1363  &aggvalues[aggno], &aggnulls[aggno]);
1364  }
1365 }
Datum * ecxt_aggvalues
Definition: execnodes.h:245
int numaggs
Definition: execnodes.h:2278
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1160
ScanState ss
Definition: execnodes.h:2276
ExprContext * ps_ExprContext
Definition: execnodes.h:1005
AggSplit aggsplit
Definition: execnodes.h:2281
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1057
AggStatePerTrans pertrans
Definition: execnodes.h:2286
int numtrans
Definition: execnodes.h:2279
PlanState ps
Definition: execnodes.h:1377
AggStrategy aggstrategy
Definition: execnodes.h:2280
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:963
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:871

◆ finalize_partialaggregate()

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

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

1164 {
1165  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1166  MemoryContext oldContext;
1167 
1169 
1170  /*
1171  * serialfn_oid will be set if we must serialize the transvalue before
1172  * returning it
1173  */
1174  if (OidIsValid(pertrans->serialfn_oid))
1175  {
1176  /* Don't call a strict serialization function with NULL input. */
1177  if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
1178  {
1179  *resultVal = (Datum) 0;
1180  *resultIsNull = true;
1181  }
1182  else
1183  {
1184  FunctionCallInfo fcinfo = pertrans->serialfn_fcinfo;
1185 
1186  fcinfo->args[0].value =
1187  MakeExpandedObjectReadOnly(pergroupstate->transValue,
1188  pergroupstate->transValueIsNull,
1189  pertrans->transtypeLen);
1190  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
1191  fcinfo->isnull = false;
1192 
1193  *resultVal = FunctionCallInvoke(fcinfo);
1194  *resultIsNull = fcinfo->isnull;
1195  }
1196  }
1197  else
1198  {
1199  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1200  *resultVal = pergroupstate->transValue;
1201  *resultIsNull = pergroupstate->transValueIsNull;
1202  }
1203 
1204  /* If result is pass-by-ref, make sure it is in the right context. */
1205  if (!peragg->resulttypeByVal && !*resultIsNull &&
1207  DatumGetPointer(*resultVal)))
1208  *resultVal = datumCopy(*resultVal,
1209  peragg->resulttypeByVal,
1210  peragg->resulttypeLen);
1211 
1212  MemoryContextSwitchTo(oldContext);
1213 }
ScanState ss
Definition: execnodes.h:2276
ExprContext * ps_ExprContext
Definition: execnodes.h:1005
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:2286
#define OidIsValid(objectId)
Definition: c.h:710
PlanState ps
Definition: execnodes.h:1377
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 1399 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().

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

◆ find_cols_walker()

static bool find_cols_walker ( Node node,
FindColsContext context 
)
static

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

1423 {
1424  if (node == NULL)
1425  return false;
1426  if (IsA(node, Var))
1427  {
1428  Var *var = (Var *) node;
1429 
1430  /* setrefs.c should have set the varno to OUTER_VAR */
1431  Assert(var->varno == OUTER_VAR);
1432  Assert(var->varlevelsup == 0);
1433  if (context->is_aggref)
1434  context->aggregated = bms_add_member(context->aggregated,
1435  var->varattno);
1436  else
1437  context->unaggregated = bms_add_member(context->unaggregated,
1438  var->varattno);
1439  return false;
1440  }
1441  if (IsA(node, Aggref))
1442  {
1443  Assert(!context->is_aggref);
1444  context->is_aggref = true;
1445  expression_tree_walker(node, find_cols_walker, (void *) context);
1446  context->is_aggref = false;
1447  return false;
1448  }
1450  (void *) context);
1451 }
#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:1422
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 1565 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().

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

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

Referenced by ExecInitAgg().

4348 {
4349  Oid typinput,
4350  typioparam;
4351  char *strInitVal;
4352  Datum initVal;
4353 
4354  getTypeInputInfo(transtype, &typinput, &typioparam);
4355  strInitVal = TextDatumGetCString(textInitVal);
4356  initVal = OidInputFunctionCall(typinput, strInitVal,
4357  typioparam, -1);
4358  pfree(strInitVal);
4359  return initVal;
4360 }
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 1857 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().

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

◆ hash_agg_enter_spill_mode()

static void hash_agg_enter_spill_mode ( AggState aggstate)
static

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

1884 {
1885  aggstate->hash_spill_mode = true;
1886  hashagg_recompile_expressions(aggstate, aggstate->table_filled, true);
1887 
1888  if (!aggstate->hash_ever_spilled)
1889  {
1890  Assert(aggstate->hash_tapeinfo == NULL);
1891  Assert(aggstate->hash_spills == NULL);
1892 
1893  aggstate->hash_ever_spilled = true;
1894 
1895  hashagg_tapeinfo_init(aggstate);
1896 
1897  aggstate->hash_spills = palloc(sizeof(HashAggSpill) * aggstate->num_hashes);
1898 
1899  for (int setno = 0; setno < aggstate->num_hashes; setno++)
1900  {
1901  AggStatePerHash perhash = &aggstate->perhash[setno];
1902  HashAggSpill *spill = &aggstate->hash_spills[setno];
1903 
1904  hashagg_spill_init(spill, aggstate->hash_tapeinfo, 0,
1905  perhash->aggnode->numGroups,
1906  aggstate->hashentrysize);
1907  }
1908  }
1909 }
struct HashAggSpill * hash_spills
Definition: execnodes.h:2320
double hashentrysize
Definition: execnodes.h:2332
static void hashagg_spill_init(HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits, double input_groups, double hashentrysize)
Definition: nodeAgg.c:2951
bool hash_spill_mode
Definition: execnodes.h:2326
static void hashagg_tapeinfo_init(AggState *aggstate)
Definition: nodeAgg.c:2887
bool table_filled
Definition: execnodes.h:2316
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2319
AggStatePerHash perhash
Definition: execnodes.h:2339
int num_hashes
Definition: execnodes.h:2317
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1742
#define Assert(condition)
Definition: c.h:804
bool hash_ever_spilled
Definition: execnodes.h:2325
long numGroups
Definition: plannodes.h:866
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 1695 of file nodeAgg.c.

References CHUNKHDRSZ, MAXALIGN, and SizeofMinimalTupleHeader.

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

1696 {
1697  Size tupleChunkSize;
1698  Size pergroupChunkSize;
1699  Size transitionChunkSize;
1700  Size tupleSize = (MAXALIGN(SizeofMinimalTupleHeader) +
1701  tupleWidth);
1702  Size pergroupSize = numTrans * sizeof(AggStatePerGroupData);
1703 
1704  tupleChunkSize = CHUNKHDRSZ + tupleSize;
1705 
1706  if (pergroupSize > 0)
1707  pergroupChunkSize = CHUNKHDRSZ + pergroupSize;
1708  else
1709  pergroupChunkSize = 0;
1710 
1711  if (transitionSpace > 0)
1712  transitionChunkSize = CHUNKHDRSZ + transitionSpace;
1713  else
1714  transitionChunkSize = 0;
1715 
1716  return
1717  sizeof(TupleHashEntryData) +
1718  tupleChunkSize +
1719  pergroupChunkSize +
1720  transitionChunkSize;
1721 }
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 1799 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().

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

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

◆ hash_choose_num_buckets()

static long hash_choose_num_buckets ( double  hashentrysize,
long  estimated_nbuckets,
Size  memory 
)
static

Definition at line 1967 of file nodeAgg.c.

References Max.

Referenced by build_hash_tables().

1968 {
1969  long max_nbuckets;
1970  long nbuckets = ngroups;
1971 
1972  max_nbuckets = memory / hashentrysize;
1973 
1974  /*