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

Go to the source code of this file.

Data Structures

struct  HashTapeInfo
 
struct  HashAggSpill
 
struct  HashAggBatch
 
struct  FindColsContext
 

Macros

#define HASHAGG_PARTITION_FACTOR   1.50
 
#define HASHAGG_MIN_PARTITIONS   4
 
#define HASHAGG_MAX_PARTITIONS   1024
 
#define HASHAGG_READ_BUFFER_SIZE   BLCKSZ
 
#define HASHAGG_WRITE_BUFFER_SIZE   BLCKSZ
 
#define HASHAGG_HLL_BIT_WIDTH   5
 
#define CHUNKHDRSZ   16
 

Typedefs

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

Functions

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

Macro Definition Documentation

◆ CHUNKHDRSZ

#define CHUNKHDRSZ   16

Definition at line 312 of file nodeAgg.c.

Referenced by hash_agg_entry_size().

◆ HASHAGG_HLL_BIT_WIDTH

#define HASHAGG_HLL_BIT_WIDTH   5

Definition at line 306 of file nodeAgg.c.

Referenced by hashagg_spill_init().

◆ HASHAGG_MAX_PARTITIONS

#define HASHAGG_MAX_PARTITIONS   1024

Definition at line 289 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_MIN_PARTITIONS

#define HASHAGG_MIN_PARTITIONS   4

Definition at line 288 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_PARTITION_FACTOR

#define HASHAGG_PARTITION_FACTOR   1.50

Definition at line 287 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_READ_BUFFER_SIZE

#define HASHAGG_READ_BUFFER_SIZE   BLCKSZ

◆ HASHAGG_WRITE_BUFFER_SIZE

#define HASHAGG_WRITE_BUFFER_SIZE   BLCKSZ

Typedef Documentation

◆ FindColsContext

◆ HashAggBatch

typedef struct HashAggBatch HashAggBatch

◆ HashAggSpill

typedef struct HashAggSpill HashAggSpill

◆ HashTapeInfo

typedef struct HashTapeInfo HashTapeInfo

Function Documentation

◆ advance_aggregates()

static void advance_aggregates ( AggState aggstate)
static

Definition at line 838 of file nodeAgg.c.

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

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

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

◆ advance_transition_function()

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

Definition at line 726 of file nodeAgg.c.

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

Referenced by process_ordered_aggregate_multi(), and process_ordered_aggregate_single().

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

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

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

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

◆ agg_refill_hash_table()

static bool agg_refill_hash_table ( AggState aggstate)
static

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

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

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

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

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

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

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

2736 {
2737  TupleTableSlot *result = NULL;
2738 
2739  while (result == NULL)
2740  {
2741  result = agg_retrieve_hash_table_in_memory(aggstate);
2742  if (result == NULL)
2743  {
2744  if (!agg_refill_hash_table(aggstate))
2745  {
2746  aggstate->agg_done = true;
2747  break;
2748  }
2749  }
2750  }
2751 
2752  return result;
2753 }
bool agg_done
Definition: execnodes.h:2152
static bool agg_refill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2584
static TupleTableSlot * agg_retrieve_hash_table_in_memory(AggState *aggstate)
Definition: nodeAgg.c:2760

◆ agg_retrieve_hash_table_in_memory()

static TupleTableSlot * agg_retrieve_hash_table_in_memory ( AggState aggstate)
static

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

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

◆ AggCheckCallContext()

int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

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

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

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4626 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

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

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4660 of file nodeAgg.c.

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

4661 {
4662  if (fcinfo->context && IsA(fcinfo->context, AggState))
4663  {
4664  AggState *aggstate = (AggState *) fcinfo->context;
4665 
4666  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4667  }
4668  return NULL;
4669 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:233
fmNodePtr context
Definition: fmgr.h:88
ExprContext * tmpcontext
Definition: execnodes.h:2145

◆ AggRegisterCallback()

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

Definition at line 4725 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4728 {
4729  if (fcinfo->context && IsA(fcinfo->context, AggState))
4730  {
4731  AggState *aggstate = (AggState *) fcinfo->context;
4732  ExprContext *cxt = aggstate->curaggcontext;
4733 
4734  RegisterExprContextCallback(cxt, func, arg);
4735 
4736  return;
4737  }
4738  elog(ERROR, "aggregate function cannot register a callback in this context");
4739 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
fmNodePtr context
Definition: fmgr.h:88
#define ERROR
Definition: elog.h:45
ExprContext * curaggcontext
Definition: execnodes.h:2147
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:924
#define elog(elevel,...)
Definition: elog.h:228
void * arg

◆ AggStateIsShared()

bool AggStateIsShared ( FunctionCallInfo  fcinfo)

Definition at line 4686 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

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

◆ build_hash_table()

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

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

1499 {
1500  AggStatePerHash perhash = &aggstate->perhash[setno];
1501  MemoryContext metacxt = aggstate->hash_metacxt;
1502  MemoryContext hashcxt = aggstate->hashcontext->ecxt_per_tuple_memory;
1503  MemoryContext tmpcxt = aggstate->tmpcontext->ecxt_per_tuple_memory;
1504  Size additionalsize;
1505 
1506  Assert(aggstate->aggstrategy == AGG_HASHED ||
1507  aggstate->aggstrategy == AGG_MIXED);
1508 
1509  /*
1510  * Used to make sure initial hash table allocation does not exceed
1511  * hash_mem. Note that the estimate does not include space for
1512  * pass-by-reference transition data values, nor for the representative
1513  * tuple of each group.
1514  */
1515  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1516 
1517  perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
1518  perhash->hashslot->tts_tupleDescriptor,
1519  perhash->numCols,
1520  perhash->hashGrpColIdxHash,
1521  perhash->eqfuncoids,
1522  perhash->hashfunctions,
1523  perhash->aggnode->grpCollations,
1524  nbuckets,
1525  additionalsize,
1526  metacxt,
1527  hashcxt,
1528  tmpcxt,
1529  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1530 }
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:824
ScanState ss
Definition: execnodes.h:2132
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:233
AggSplit aggsplit
Definition: execnodes.h:2137
int numtrans
Definition: execnodes.h:2135
ExprContext * tmpcontext
Definition: execnodes.h:2145
PlanState ps
Definition: execnodes.h:1317
AggStrategy aggstrategy
Definition: execnodes.h:2136
MemoryContext hash_metacxt
Definition: execnodes.h:2174
struct AggStatePerGroupData AggStatePerGroupData
AggStatePerHash perhash
Definition: execnodes.h:2195
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:312
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2143
FmgrInfo * hashfunctions
Definition: nodeAgg.h:306
#define Assert(condition)
Definition: c.h:792
size_t Size
Definition: c.h:528
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:791
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 1463 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().

1464 {
1465  int setno;
1466 
1467  for (setno = 0; setno < aggstate->num_hashes; ++setno)
1468  {
1469  AggStatePerHash perhash = &aggstate->perhash[setno];
1470  long nbuckets;
1471  Size memory;
1472 
1473  if (perhash->hashtable != NULL)
1474  {
1475  ResetTupleHashTable(perhash->hashtable);
1476  continue;
1477  }
1478 
1479  Assert(perhash->aggnode->numGroups > 0);
1480 
1481  memory = aggstate->hash_mem_limit / aggstate->num_hashes;
1482 
1483  /* choose reasonable number of buckets per hashtable */
1484  nbuckets = hash_choose_num_buckets(aggstate->hashentrysize,
1485  perhash->aggnode->numGroups,
1486  memory);
1487 
1488  build_hash_table(aggstate, setno, nbuckets);
1489  }
1490 
1491  aggstate->hash_ngroups_current = 0;
1492 }
double hashentrysize
Definition: execnodes.h:2188
static long hash_choose_num_buckets(double hashentrysize, long estimated_nbuckets, Size memory)
Definition: nodeAgg.c:1959
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:283
static void build_hash_table(AggState *aggstate, int setno, long nbuckets)
Definition: nodeAgg.c:1498
AggStatePerHash perhash
Definition: execnodes.h:2195
int num_hashes
Definition: execnodes.h:2173
#define Assert(condition)
Definition: c.h:792
size_t Size
Definition: c.h:528
long numGroups
Definition: plannodes.h:825
Size hash_mem_limit
Definition: execnodes.h:2184
uint64 hash_ngroups_current
Definition: execnodes.h:2190
TupleHashTable hashtable
Definition: nodeAgg.h:303

◆ build_pertrans_for_aggref()

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

Definition at line 4041 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

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

2149 {
2150  AggState *node = castNode(AggState, pstate);
2151  TupleTableSlot *result = NULL;
2152 
2154 
2155  if (!node->agg_done)
2156  {
2157  /* Dispatch based on strategy */
2158  switch (node->phase->aggstrategy)
2159  {
2160  case AGG_HASHED:
2161  if (!node->table_filled)
2162  agg_fill_hash_table(node);
2163  /* FALLTHROUGH */
2164  case AGG_MIXED:
2165  result = agg_retrieve_hash_table(node);
2166  break;
2167  case AGG_PLAIN:
2168  case AGG_SORTED:
2169  result = agg_retrieve_direct(node);
2170  break;
2171  }
2172 
2173  if (!TupIsNull(result))
2174  return result;
2175  }
2176 
2177  return NULL;
2178 }
static void agg_fill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2530
bool agg_done
Definition: execnodes.h:2152
#define castNode(_type_, nodeptr)
Definition: nodes.h:597
bool table_filled
Definition: execnodes.h:2172
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2735
static TupleTableSlot * agg_retrieve_direct(AggState *aggstate)
Definition: nodeAgg.c:2184
#define TupIsNull(slot)
Definition: tuptable.h:292
AggStrategy aggstrategy
Definition: nodeAgg.h:274
AggStatePerPhase phase
Definition: execnodes.h:2138
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:100

◆ ExecAggEstimate()

void ExecAggEstimate ( AggState node,
ParallelContext pcxt 
)

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

4755 {
4756  Size size;
4757 
4758  /* don't need this if not instrumenting or no workers */
4759  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4760  return;
4761 
4762  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4763  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4764  shm_toc_estimate_chunk(&pcxt->estimator, size);
4765  shm_toc_estimate_keys(&pcxt->estimator, 1);
4766 }
Instrumentation * instrument
Definition: execnodes.h:938
ScanState ss
Definition: execnodes.h:2132
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:1317
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:528
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
#define offsetof(type, field)
Definition: c.h:715

◆ ExecAggInitializeDSM()

void ExecAggInitializeDSM ( AggState node,
ParallelContext pcxt 
)

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

4776 {
4777  Size size;
4778 
4779  /* don't need this if not instrumenting or no workers */
4780  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4781  return;
4782 
4783  size = offsetof(SharedAggInfo, sinstrument)
4784  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4785  node->shared_info = shm_toc_allocate(pcxt->toc, size);
4786  /* ensure any unfilled slots will contain zeroes */
4787  memset(node->shared_info, 0, size);
4788  node->shared_info->num_workers = pcxt->nworkers;
4789  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4790  node->shared_info);
4791 }
Instrumentation * instrument
Definition: execnodes.h:938
ScanState ss
Definition: execnodes.h:2132
int plan_node_id
Definition: plannodes.h:135
PlanState ps
Definition: execnodes.h:1317
struct AggregateInstrumentation AggregateInstrumentation
Plan * plan
Definition: execnodes.h:928
size_t Size
Definition: c.h:528
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:2204
#define offsetof(type, field)
Definition: c.h:715
shm_toc * toc
Definition: parallel.h:45

◆ ExecAggInitializeWorker()

void ExecAggInitializeWorker ( AggState node,
ParallelWorkerContext pwcxt 
)

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

4801 {
4802  node->shared_info =
4803  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4804 }
ScanState ss
Definition: execnodes.h:2132
int plan_node_id
Definition: plannodes.h:135
PlanState ps
Definition: execnodes.h:1317
Plan * plan
Definition: execnodes.h:928
SharedAggInfo * shared_info
Definition: execnodes.h:2204
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 4813 of file nodeAgg.c.

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

Referenced by ExecParallelRetrieveInstrumentation().

4814 {
4815  Size size;
4816  SharedAggInfo *si;
4817 
4818  if (node->shared_info == NULL)
4819  return;
4820 
4821  size = offsetof(SharedAggInfo, sinstrument)
4823  si = palloc(size);
4824  memcpy(si, node->shared_info, size);
4825  node->shared_info = si;
4826 }
struct AggregateInstrumentation AggregateInstrumentation
size_t Size
Definition: c.h:528
void * palloc(Size size)
Definition: mcxt.c:950
SharedAggInfo * shared_info
Definition: execnodes.h:2204
#define offsetof(type, field)
Definition: c.h:715

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

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

4366 {
4368  int transno;
4369  int numGroupingSets = Max(node->maxsets, 1);
4370  int setno;
4371 
4372  /*
4373  * When ending a parallel worker, copy the statistics gathered by the
4374  * worker back into shared memory so that it can be picked up by the main
4375  * process to report in EXPLAIN ANALYZE.
4376  */
4377  if (node->shared_info && IsParallelWorker())
4378  {
4380 
4381  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4384  si->hash_disk_used = node->hash_disk_used;
4385  si->hash_mem_peak = node->hash_mem_peak;
4386  }
4387 
4388  /* Make sure we have closed any open tuplesorts */
4389 
4390  if (node->sort_in)
4391  tuplesort_end(node->sort_in);
4392  if (node->sort_out)
4393  tuplesort_end(node->sort_out);
4394 
4396 
4397  if (node->hash_metacxt != NULL)
4398  {
4400  node->hash_metacxt = NULL;
4401  }
4402 
4403  for (transno = 0; transno < node->numtrans; transno++)
4404  {
4405  AggStatePerTrans pertrans = &node->pertrans[transno];
4406 
4407  for (setno = 0; setno < numGroupingSets; setno++)
4408  {
4409  if (pertrans->sortstates[setno])
4410  tuplesort_end(pertrans->sortstates[setno]);
4411  }
4412  }
4413 
4414  /* And ensure any agg shutdown callbacks have been called */
4415  for (setno = 0; setno < numGroupingSets; setno++)
4416  ReScanExprContext(node->aggcontexts[setno]);
4417  if (node->hashcontext)
4419 
4420  /*
4421  * We don't actually free any ExprContexts here (see comment in
4422  * ExecFreeExprContext), just unlinking the output one from the plan node
4423  * suffices.
4424  */
4425  ExecFreeExprContext(&node->ss.ps);
4426 
4427  /* clean up tuple table */
4429 
4430  outerPlan = outerPlanState(node);
4431  ExecEndNode(outerPlan);
4432 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3188
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:212
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:543
Tuplesortstate * sort_out
Definition: execnodes.h:2165
ScanState ss
Definition: execnodes.h:2132
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1320
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2108
AggStatePerTrans pertrans
Definition: execnodes.h:2142
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:649
int numtrans
Definition: execnodes.h:2135
PlanState ps
Definition: execnodes.h:1317
int maxsets
Definition: execnodes.h:2162
MemoryContext hash_metacxt
Definition: execnodes.h:2174
Tuplesortstate * sort_in
Definition: execnodes.h:2164
#define outerPlanState(node)
Definition: execnodes.h:1022
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:2193
#define outerPlan(node)
Definition: plannodes.h:166
ExprContext * hashcontext
Definition: execnodes.h:2143
uint64 hash_disk_used
Definition: execnodes.h:2192
#define Max(x, y)
Definition: c.h:968
ExprContext ** aggcontexts
Definition: execnodes.h:2144
#define Assert(condition)
Definition: c.h:792
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:437
Size hash_mem_peak
Definition: execnodes.h:2189
SharedAggInfo * shared_info
Definition: execnodes.h:2204
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1445

◆ ExecInitAgg()

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

Definition at line 3240 of file nodeAgg.c.

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

Referenced by ExecInitNode().

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

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

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

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

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

Definition at line 567 of file nodeAgg.c.

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

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

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

◆ finalize_aggregate()

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

Definition at line 1056 of file nodeAgg.c.

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

Referenced by finalize_aggregates().

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

◆ finalize_aggregates()

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

Definition at line 1309 of file nodeAgg.c.

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

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table_in_memory().

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

◆ finalize_partialaggregate()

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

Definition at line 1159 of file nodeAgg.c.

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

Referenced by finalize_aggregates().

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

◆ find_cols()

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

Definition at line 1398 of file nodeAgg.c.

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

Referenced by find_hash_columns().

1399 {
1400  Agg *agg = (Agg *) aggstate->ss.ps.plan;
1401  FindColsContext context;
1402 
1403  context.is_aggref = false;
1404  context.aggregated = NULL;
1405  context.unaggregated = NULL;
1406 
1407  (void) find_cols_walker((Node *) agg->plan.targetlist, &context);
1408  (void) find_cols_walker((Node *) agg->plan.qual, &context);
1409 
1410  *aggregated = context.aggregated;
1411  *unaggregated = context.unaggregated;
1412 }
List * qual
Definition: plannodes.h:137
ScanState ss
Definition: execnodes.h:2132
Definition: nodes.h:528
PlanState ps
Definition: execnodes.h:1317
static bool find_cols_walker(Node *node, FindColsContext *context)
Definition: nodeAgg.c:1415
Plan plan
Definition: plannodes.h:818
Plan * plan
Definition: execnodes.h:928
List * targetlist
Definition: plannodes.h:136
Definition: plannodes.h:816
bool is_aggref
Definition: nodeAgg.c:377

◆ find_cols_walker()

static bool find_cols_walker ( Node node,
FindColsContext context 
)
static

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

1416 {
1417  if (node == NULL)
1418  return false;
1419  if (IsA(node, Var))
1420  {
1421  Var *var = (Var *) node;
1422 
1423  /* setrefs.c should have set the varno to OUTER_VAR */
1424  Assert(var->varno == OUTER_VAR);
1425  Assert(var->varlevelsup == 0);
1426  if (context->is_aggref)
1427  context->aggregated = bms_add_member(context->aggregated,
1428  var->varattno);
1429  else
1430  context->unaggregated = bms_add_member(context->unaggregated,
1431  var->varattno);
1432  return false;
1433  }
1434  if (IsA(node, Aggref))
1435  {
1436  Assert(!context->is_aggref);
1437  context->is_aggref = true;
1438  expression_tree_walker(node, find_cols_walker, (void *) context);
1439  context->is_aggref = false;
1440  return false;
1441  }
1443  (void *) context);
1444 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Index varlevelsup
Definition: primnodes.h:191
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
static bool find_cols_walker(Node *node, FindColsContext *context)
Definition: nodeAgg.c:1415
Bitmapset * unaggregated
Definition: nodeAgg.c:379
Bitmapset * aggregated
Definition: nodeAgg.c:378
Index varno
Definition: primnodes.h:184
#define Assert(condition)
Definition: c.h:792
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1879
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:172

◆ find_hash_columns()

static void find_hash_columns ( AggState aggstate)
static

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

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

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

Referenced by ExecInitAgg().

4350 {
4351  Oid typinput,
4352  typioparam;
4353  char *strInitVal;
4354  Datum initVal;
4355 
4356  getTypeInputInfo(transtype, &typinput, &typioparam);
4357  strInitVal = TextDatumGetCString(textInitVal);
4358  initVal = OidInputFunctionCall(typinput, strInitVal,
4359  typioparam, -1);
4360  pfree(strInitVal);
4361  return initVal;
4362 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:1057
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2794
#define TextDatumGetCString(d)
Definition: builtins.h:83
uintptr_t Datum
Definition: postgres.h:367
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1647

◆ hash_agg_check_limits()

static void hash_agg_check_limits ( AggState aggstate)
static

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

1850 {
1851  uint64 ngroups = aggstate->hash_ngroups_current;
1852  Size meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt,
1853  true);
1855  true);
1856 
1857  /*
1858  * Don't spill unless there's at least one group in the hash table so we
1859  * can be sure to make progress even in edge cases.
1860  */
1861  if (aggstate->hash_ngroups_current > 0 &&
1862  (meta_mem + hashkey_mem > aggstate->hash_mem_limit ||
1863  ngroups > aggstate->hash_ngroups_limit))
1864  {
1865  hash_agg_enter_spill_mode(aggstate);
1866  }
1867 }
uint64 hash_ngroups_limit
Definition: execnodes.h:2185
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:233
static void hash_agg_enter_spill_mode(AggState *aggstate)
Definition: nodeAgg.c:1875
MemoryContext hash_metacxt
Definition: execnodes.h:2174
ExprContext * hashcontext
Definition: execnodes.h:2143
Size MemoryContextMemAllocated(MemoryContext context, bool recurse)
Definition: mcxt.c:471
size_t Size
Definition: c.h:528
Size hash_mem_limit
Definition: execnodes.h:2184
uint64 hash_ngroups_current
Definition: execnodes.h:2190

◆ hash_agg_enter_spill_mode()

static void hash_agg_enter_spill_mode ( AggState aggstate)
static

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

1876 {
1877  aggstate->hash_spill_mode = true;
1878  hashagg_recompile_expressions(aggstate, aggstate->table_filled, true);
1879 
1880  if (!aggstate->hash_ever_spilled)
1881  {
1882  Assert(aggstate->hash_tapeinfo == NULL);
1883  Assert(aggstate->hash_spills == NULL);
1884 
1885  aggstate->hash_ever_spilled = true;
1886 
1887  hashagg_tapeinfo_init(aggstate);
1888 
1889  aggstate->hash_spills = palloc(sizeof(HashAggSpill) * aggstate->num_hashes);
1890 
1891  for (int setno = 0; setno < aggstate->num_hashes; setno++)
1892  {
1893  AggStatePerHash perhash = &aggstate->perhash[setno];
1894  HashAggSpill *spill = &aggstate->hash_spills[setno];
1895 
1896  hashagg_spill_init(spill, aggstate->hash_tapeinfo, 0,
1897  perhash->aggnode->numGroups,
1898  aggstate->hashentrysize);
1899  }
1900  }
1901 }
struct HashAggSpill * hash_spills
Definition: execnodes.h:2176
double hashentrysize
Definition: execnodes.h:2188
static void hashagg_spill_init(HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits, double input_groups, double hashentrysize)
Definition: nodeAgg.c:2944
bool hash_spill_mode
Definition: execnodes.h:2182
static void hashagg_tapeinfo_init(AggState *aggstate)
Definition: nodeAgg.c:2880
bool table_filled
Definition: execnodes.h:2172
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2175
AggStatePerHash perhash
Definition: execnodes.h:2195
int num_hashes
Definition: execnodes.h:2173
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1734
#define Assert(condition)
Definition: c.h:792
bool hash_ever_spilled
Definition: execnodes.h:2181
long numGroups
Definition: plannodes.h:825
void * palloc(Size size)
Definition: mcxt.c:950

◆ hash_agg_entry_size()

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

Definition at line 1687 of file nodeAgg.c.

References CHUNKHDRSZ, MAXALIGN, and SizeofMinimalTupleHeader.

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

1688 {
1689  Size tupleChunkSize;
1690  Size pergroupChunkSize;
1691  Size transitionChunkSize;
1692  Size tupleSize = (MAXALIGN(SizeofMinimalTupleHeader) +
1693  tupleWidth);
1694  Size pergroupSize = numTrans * sizeof(AggStatePerGroupData);
1695 
1696  tupleChunkSize = CHUNKHDRSZ + tupleSize;
1697 
1698  if (pergroupSize > 0)
1699  pergroupChunkSize = CHUNKHDRSZ + pergroupSize;
1700  else
1701  pergroupChunkSize = 0;
1702 
1703  if (transitionSpace > 0)
1704  transitionChunkSize = CHUNKHDRSZ + transitionSpace;
1705  else
1706  transitionChunkSize = 0;
1707 
1708  return
1709  sizeof(TupleHashEntryData) +
1710  tupleChunkSize +
1711  pergroupChunkSize +
1712  transitionChunkSize;
1713 }
struct TupleHashEntryData TupleHashEntryData
struct AggStatePerGroupData AggStatePerGroupData
#define SizeofMinimalTupleHeader
Definition: htup_details.h:649
size_t Size
Definition: c.h:528
#define MAXALIGN(LEN)
Definition: c.h:745
#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 1791 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().

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

1911 {
1912  Size meta_mem;
1913  Size hashkey_mem;
1914  Size buffer_mem;
1915  Size total_mem;
1916 
1917  if (aggstate->aggstrategy != AGG_MIXED &&
1918  aggstate->aggstrategy != AGG_HASHED)
1919  return;
1920 
1921  /* memory for the hash table itself */
1922  meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt, true);
1923 
1924  /* memory for the group keys and transition states */
1925  hashkey_mem = MemoryContextMemAllocated(aggstate->hashcontext->ecxt_per_tuple_memory, true);
1926 
1927  /* memory for read/write tape buffers, if spilled */
1928  buffer_mem = npartitions * HASHAGG_WRITE_BUFFER_SIZE;
1929  if (from_tape)
1930  buffer_mem += HASHAGG_READ_BUFFER_SIZE;
1931 
1932  /* update peak mem */
1933  total_mem = meta_mem + hashkey_mem + buffer_mem;
1934  if (total_mem > aggstate->hash_mem_peak)
1935  aggstate->hash_mem_peak = total_mem;
1936 
1937  /* update disk usage */
1938  if (aggstate->hash_tapeinfo != NULL)
1939  {
1940  uint64 disk_used = LogicalTapeSetBlocks(aggstate->hash_tapeinfo->tapeset) * (BLCKSZ / 1024);
1941 
1942  if (aggstate->hash_disk_used < disk_used)
1943  aggstate->hash_disk_used = disk_used;
1944  }
1945 
1946  /* update hashentrysize estimate based on contents */
1947  if (aggstate->hash_ngroups_current > 0)
1948  {
1949  aggstate->hashentrysize =
1950  sizeof(TupleHashEntryData) +
1951  (hashkey_mem / (double) aggstate->hash_ngroups_current);
1952  }
1953 }
double hashentrysize
Definition: execnodes.h:2188
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:233
AggStrategy aggstrategy
Definition: execnodes.h:2136
MemoryContext hash_metacxt
Definition: execnodes.h:2174
struct TupleHashEntryData TupleHashEntryData
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2175
ExprContext * hashcontext
Definition: execnodes.h:2143
#define HASHAGG_READ_BUFFER_SIZE
Definition: nodeAgg.c:297
LogicalTapeSet * tapeset
Definition: nodeAgg.c:328
uint64 hash_disk_used
Definition: execnodes.h:2192
Size MemoryContextMemAllocated(MemoryContext context, bool recurse)
Definition: mcxt.c:471
size_t Size
Definition: c.h:528
#define HASHAGG_WRITE_BUFFER_SIZE
Definition: nodeAgg.c:298
Size hash_mem_peak
Definition: execnodes.h:2189
uint64 hash_ngroups_current
Definition: execnodes.h:2190
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 1959 of file nodeAgg.c.

References Max.

Referenced by build_hash_tables().

1960 {
1961  long max_nbuckets;
1962  long nbuckets = ngroups;
1963 
1964  max_nbuckets = memory / hashentrysize;
1965 
1966  /*
1967  * Underestimating is better than overestimating. Too many buckets crowd
1968  * out space for group keys and transition state values.
1969  */
1970  max_nbuckets >>= 1;
1971