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  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 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 (LogicalTape *input_tape, int setno, int64 input_tuples, double input_card, int used_bits)
 
static MinimalTuple hashagg_batch_read (HashAggBatch *batch, uint32 *hashp)
 
static void hashagg_spill_init (HashAggSpill *spill, LogicalTapeSet *lts, 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 Datum GetAggInitVal (Datum textInitVal, Oid transtype)
 
static void build_pertrans_for_aggref (AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid transfn_oid, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
 
static void initialize_aggregate (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void find_hash_columns (AggState *aggstate)
 
Size hash_agg_entry_size (int numTrans, Size tupleWidth, Size transitionSpace)
 
void hash_agg_set_limits (double hashentrysize, double input_groups, int used_bits, Size *mem_limit, uint64 *ngroups_limit, int *num_partitions)
 
static TupleTableSlotExecAgg (PlanState *pstate)
 
AggStateExecInitAgg (Agg *node, EState *estate, int eflags)
 
void ExecEndAgg (AggState *node)
 
void ExecReScanAgg (AggState *node)
 
int AggCheckCallContext (FunctionCallInfo fcinfo, MemoryContext *aggcontext)
 
AggrefAggGetAggref (FunctionCallInfo fcinfo)
 
MemoryContext AggGetTempMemoryContext (FunctionCallInfo fcinfo)
 
bool AggStateIsShared (FunctionCallInfo fcinfo)
 
void AggRegisterCallback (FunctionCallInfo fcinfo, ExprContextCallbackFunction func, Datum arg)
 
void ExecAggEstimate (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeDSM (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeWorker (AggState *node, ParallelWorkerContext *pwcxt)
 
void ExecAggRetrieveInstrumentation (AggState *node)
 

Macro Definition Documentation

◆ CHUNKHDRSZ

#define CHUNKHDRSZ   16

Definition at line 321 of file nodeAgg.c.

◆ HASHAGG_HLL_BIT_WIDTH

#define HASHAGG_HLL_BIT_WIDTH   5

Definition at line 315 of file nodeAgg.c.

◆ HASHAGG_MAX_PARTITIONS

#define HASHAGG_MAX_PARTITIONS   1024

Definition at line 298 of file nodeAgg.c.

◆ HASHAGG_MIN_PARTITIONS

#define HASHAGG_MIN_PARTITIONS   4

Definition at line 297 of file nodeAgg.c.

◆ HASHAGG_PARTITION_FACTOR

#define HASHAGG_PARTITION_FACTOR   1.50

Definition at line 296 of file nodeAgg.c.

◆ HASHAGG_READ_BUFFER_SIZE

#define HASHAGG_READ_BUFFER_SIZE   BLCKSZ

Definition at line 306 of file nodeAgg.c.

◆ HASHAGG_WRITE_BUFFER_SIZE

#define HASHAGG_WRITE_BUFFER_SIZE   BLCKSZ

Definition at line 307 of file nodeAgg.c.

Typedef Documentation

◆ FindColsContext

◆ HashAggBatch

typedef struct HashAggBatch HashAggBatch

◆ HashAggSpill

typedef struct HashAggSpill HashAggSpill

Function Documentation

◆ advance_aggregates()

static void advance_aggregates ( AggState aggstate)
static

Definition at line 820 of file nodeAgg.c.

821 {
822  bool dummynull;
823 
825  aggstate->tmpcontext,
826  &dummynull);
827 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:335
ExprState * evaltrans
Definition: nodeAgg.h:283
AggStatePerPhase phase
Definition: execnodes.h:2332
ExprContext * tmpcontext
Definition: execnodes.h:2339

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

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

◆ advance_transition_function()

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

Definition at line 708 of file nodeAgg.c.

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

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

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

Definition at line 2522 of file nodeAgg.c.

2523 {
2524  TupleTableSlot *outerslot;
2525  ExprContext *tmpcontext = aggstate->tmpcontext;
2526 
2527  /*
2528  * Process each outer-plan tuple, and then fetch the next one, until we
2529  * exhaust the outer plan.
2530  */
2531  for (;;)
2532  {
2533  outerslot = fetch_input_tuple(aggstate);
2534  if (TupIsNull(outerslot))
2535  break;
2536 
2537  /* set up for lookup_hash_entries and advance_aggregates */
2538  tmpcontext->ecxt_outertuple = outerslot;
2539 
2540  /* Find or build hashtable entries */
2541  lookup_hash_entries(aggstate);
2542 
2543  /* Advance the aggregates (or combine functions) */
2544  advance_aggregates(aggstate);
2545 
2546  /*
2547  * Reset per-input-tuple context after each tuple, but note that the
2548  * hash lookups do this too
2549  */
2550  ResetExprContext(aggstate->tmpcontext);
2551  }
2552 
2553  /* finalize spills, if any */
2555 
2556  aggstate->table_filled = true;
2557  /* Initialize to walk the first hash table */
2558  select_current_set(aggstate, 0, true);
2560  &aggstate->perhash[0].hashiter);
2561 }
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:801
#define ResetExprContext(econtext)
Definition: executor.h:531
static void hashagg_finish_initial_spills(AggState *aggstate)
Definition: nodeAgg.c:3041
static TupleTableSlot * fetch_input_tuple(AggState *aggstate)
Definition: nodeAgg.c:549
static void lookup_hash_entries(AggState *aggstate)
Definition: nodeAgg.c:2077
static void advance_aggregates(AggState *aggstate)
Definition: nodeAgg.c:820
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:457
TupleHashTable hashtable
Definition: nodeAgg.h:303
TupleHashIterator hashiter
Definition: nodeAgg.h:304
bool table_filled
Definition: execnodes.h:2366
AggStatePerHash perhash
Definition: execnodes.h:2389
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:236
#define TupIsNull(slot)
Definition: tuptable.h:292

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

◆ agg_refill_hash_table()

static bool agg_refill_hash_table ( AggState aggstate)
static

Definition at line 2576 of file nodeAgg.c.

2577 {
2578  HashAggBatch *batch;
2579  AggStatePerHash perhash;
2580  HashAggSpill spill;
2581  LogicalTapeSet *tapeset = aggstate->hash_tapeset;
2582  bool spill_initialized = false;
2583 
2584  if (aggstate->hash_batches == NIL)
2585  return false;
2586 
2587  /* hash_batches is a stack, with the top item at the end of the list */
2588  batch = llast(aggstate->hash_batches);
2589  aggstate->hash_batches = list_delete_last(aggstate->hash_batches);
2590 
2591  hash_agg_set_limits(aggstate->hashentrysize, batch->input_card,
2592  batch->used_bits, &aggstate->hash_mem_limit,
2593  &aggstate->hash_ngroups_limit, NULL);
2594 
2595  /*
2596  * Each batch only processes one grouping set; set the rest to NULL so
2597  * that advance_aggregates() knows to ignore them. We don't touch
2598  * pergroups for sorted grouping sets here, because they will be needed if
2599  * we rescan later. The expressions for sorted grouping sets will not be
2600  * evaluated after we recompile anyway.
2601  */
2602  MemSet(aggstate->hash_pergroup, 0,
2603  sizeof(AggStatePerGroup) * aggstate->num_hashes);
2604 
2605  /* free memory and reset hash tables */
2606  ReScanExprContext(aggstate->hashcontext);
2607  for (int setno = 0; setno < aggstate->num_hashes; setno++)
2608  ResetTupleHashTable(aggstate->perhash[setno].hashtable);
2609 
2610  aggstate->hash_ngroups_current = 0;
2611 
2612  /*
2613  * In AGG_MIXED mode, hash aggregation happens in phase 1 and the output
2614  * happens in phase 0. So, we switch to phase 1 when processing a batch,
2615  * and back to phase 0 after the batch is done.
2616  */
2617  Assert(aggstate->current_phase == 0);
2618  if (aggstate->phase->aggstrategy == AGG_MIXED)
2619  {
2620  aggstate->current_phase = 1;
2621  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2622  }
2623 
2624  select_current_set(aggstate, batch->setno, true);
2625 
2626  perhash = &aggstate->perhash[aggstate->current_set];
2627 
2628  /*
2629  * Spilled tuples are always read back as MinimalTuples, which may be
2630  * different from the outer plan, so recompile the aggregate expressions.
2631  *
2632  * We still need the NULL check, because we are only processing one
2633  * grouping set at a time and the rest will be NULL.
2634  */
2635  hashagg_recompile_expressions(aggstate, true, true);
2636 
2637  for (;;)
2638  {
2639  TupleTableSlot *spillslot = aggstate->hash_spill_rslot;
2640  TupleTableSlot *hashslot = perhash->hashslot;
2641  TupleHashEntry entry;
2642  MinimalTuple tuple;
2643  uint32 hash;
2644  bool isnew = false;
2645  bool *p_isnew = aggstate->hash_spill_mode ? NULL : &isnew;
2646 
2648 
2649  tuple = hashagg_batch_read(batch, &hash);
2650  if (tuple == NULL)
2651  break;
2652 
2653  ExecStoreMinimalTuple(tuple, spillslot, true);
2654  aggstate->tmpcontext->ecxt_outertuple = spillslot;
2655 
2656  prepare_hash_slot(perhash,
2657  aggstate->tmpcontext->ecxt_outertuple,
2658  hashslot);
2659  entry = LookupTupleHashEntryHash(perhash->hashtable, hashslot,
2660  p_isnew, hash);
2661 
2662  if (entry != NULL)
2663  {
2664  if (isnew)
2665  initialize_hash_entry(aggstate, perhash->hashtable, entry);
2666  aggstate->hash_pergroup[batch->setno] = entry->additional;
2667  advance_aggregates(aggstate);
2668  }
2669  else
2670  {
2671  if (!spill_initialized)
2672  {
2673  /*
2674  * Avoid initializing the spill until we actually need it so
2675  * that we don't assign tapes that will never be used.
2676  */
2677  spill_initialized = true;
2678  hashagg_spill_init(&spill, tapeset, batch->used_bits,
2679  batch->input_card, aggstate->hashentrysize);
2680  }
2681  /* no memory for a new group, spill */
2682  hashagg_spill_tuple(aggstate, &spill, spillslot, hash);
2683 
2684  aggstate->hash_pergroup[batch->setno] = NULL;
2685  }
2686 
2687  /*
2688  * Reset per-input-tuple context after each tuple, but note that the
2689  * hash lookups do this too
2690  */
2691  ResetExprContext(aggstate->tmpcontext);
2692  }
2693 
2694  LogicalTapeClose(batch->input_tape);
2695 
2696  /* change back to phase 0 */
2697  aggstate->current_phase = 0;
2698  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2699 
2700  if (spill_initialized)
2701  {
2702  hashagg_spill_finish(aggstate, &spill, batch->setno);
2703  hash_agg_update_metrics(aggstate, true, spill.npartitions);
2704  }
2705  else
2706  hash_agg_update_metrics(aggstate, true, 0);
2707 
2708  aggstate->hash_spill_mode = false;
2709 
2710  /* prepare to walk the first hash table */
2711  select_current_set(aggstate, batch->setno, true);
2712  ResetTupleHashIterator(aggstate->perhash[batch->setno].hashtable,
2713  &aggstate->perhash[batch->setno].hashiter);
2714 
2715  pfree(batch);
2716 
2717  return true;
2718 }
unsigned int uint32
Definition: c.h:441
#define MemSet(start, val, len)
Definition: c.h:1008
TupleHashEntry LookupTupleHashEntryHash(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 hash)
Definition: execGrouping.c:361
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:285
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1446
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:438
Assert(fmt[strlen(fmt) - 1] !='\n')
List * list_delete_last(List *list)
Definition: list.c:916
void LogicalTapeClose(LogicalTape *lt)
Definition: logtape.c:734
void pfree(void *pointer)
Definition: mcxt.c:1175
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
static void initialize_hash_entry(AggState *aggstate, TupleHashTable hashtable, TupleHashEntry entry)
Definition: nodeAgg.c:2027
static void hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
Definition: nodeAgg.c:3075
static Size hashagg_spill_tuple(AggState *aggstate, HashAggSpill *spill, TupleTableSlot *slot, uint32 hash)
Definition: nodeAgg.c:2907
static MinimalTuple hashagg_batch_read(HashAggBatch *batch, uint32 *hashp)
Definition: nodeAgg.c:2992
static void hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
Definition: nodeAgg.c:1899
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1723
static void prepare_hash_slot(AggStatePerHash perhash, TupleTableSlot *inputslot, TupleTableSlot *hashslot)
Definition: nodeAgg.c:1201
static void hashagg_spill_init(HashAggSpill *spill, LogicalTapeSet *lts, int used_bits, double input_groups, double hashentrysize)
Definition: nodeAgg.c:2876
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:1780
@ AGG_MIXED
Definition: nodes.h:810
#define llast(l)
Definition: pg_list.h:194
#define NIL
Definition: pg_list.h:65
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715
TupleTableSlot * hashslot
Definition: nodeAgg.h:305
AggStrategy aggstrategy
Definition: nodeAgg.h:274
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2390
Size hash_mem_limit
Definition: execnodes.h:2378
int current_set
Definition: execnodes.h:2349
struct LogicalTapeSet * hash_tapeset
Definition: execnodes.h:2369
ExprContext * hashcontext
Definition: execnodes.h:2337
uint64 hash_ngroups_limit
Definition: execnodes.h:2379
AggStatePerPhase phases
Definition: execnodes.h:2357
bool hash_spill_mode
Definition: execnodes.h:2376
double hashentrysize
Definition: execnodes.h:2382
uint64 hash_ngroups_current
Definition: execnodes.h:2384
int num_hashes
Definition: execnodes.h:2367
List * hash_batches
Definition: execnodes.h:2374
TupleTableSlot * hash_spill_rslot
Definition: execnodes.h:2372
int current_phase
Definition: execnodes.h:2334
int used_bits
Definition: nodeAgg.c:354
double input_card
Definition: nodeAgg.c:357
LogicalTape * input_tape
Definition: nodeAgg.c:355
int npartitions
Definition: nodeAgg.c:334

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_tapeset, hashagg_batch_read(), hashagg_recompile_expressions(), hashagg_spill_finish(), hashagg_spill_init(), hashagg_spill_tuple(), AggState::hashcontext, AggState::hashentrysize, AggStatePerHashData::hashiter, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, initialize_hash_entry(), HashAggBatch::input_card, HashAggBatch::input_tape, list_delete_last(), llast, LogicalTapeClose(), 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().

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

Definition at line 2176 of file nodeAgg.c.

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

References advance_aggregates(), AggState::agg_done, AGG_MIXED, AGG_PLAIN, agg_retrieve_hash_table(), AggState::aggcontexts, AggStatePerPhaseData::aggnode, AggState::aggstrategy, Agg::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().

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

Definition at line 2728 of file nodeAgg.c.

2729 {
2730  TupleTableSlot *result = NULL;
2731 
2732  while (result == NULL)
2733  {
2734  result = agg_retrieve_hash_table_in_memory(aggstate);
2735  if (result == NULL)
2736  {
2737  if (!agg_refill_hash_table(aggstate))
2738  {
2739  aggstate->agg_done = true;
2740  break;
2741  }
2742  }
2743  }
2744 
2745  return result;
2746 }
static bool agg_refill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2576
static TupleTableSlot * agg_retrieve_hash_table_in_memory(AggState *aggstate)
Definition: nodeAgg.c:2753

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

Referenced by agg_retrieve_direct(), and ExecAgg().

◆ agg_retrieve_hash_table_in_memory()

static TupleTableSlot * agg_retrieve_hash_table_in_memory ( AggState aggstate)
static

Definition at line 2753 of file nodeAgg.c.

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

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

◆ AggCheckCallContext()

int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

Definition at line 4487 of file nodeAgg.c.

4488 {
4489  if (fcinfo->context && IsA(fcinfo->context, AggState))
4490  {
4491  if (aggcontext)
4492  {
4493  AggState *aggstate = ((AggState *) fcinfo->context);
4494  ExprContext *cxt = aggstate->curaggcontext;
4495 
4496  *aggcontext = cxt->ecxt_per_tuple_memory;
4497  }
4498  return AGG_CONTEXT_AGGREGATE;
4499  }
4500  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4501  {
4502  if (aggcontext)
4503  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4504  return AGG_CONTEXT_WINDOW;
4505  }
4506 
4507  /* this is just to prevent "uninitialized variable" warnings */
4508  if (aggcontext)
4509  *aggcontext = NULL;
4510  return 0;
4511 }
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:743
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:742
#define IsA(nodeptr, _type_)
Definition: nodes.h:624
fmNodePtr context
Definition: fmgr.h:88

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_worker(), json_object_agg_finalfn(), json_object_agg_transfn_worker(), jsonb_agg_finalfn(), jsonb_agg_transfn_worker(), jsonb_object_agg_finalfn(), jsonb_object_agg_transfn_worker(), makeBoolAggState(), makeNumericAggState(), makeStringAggState(), mode_final(), multirange_agg_transfn(), multirange_intersect_agg_transfn(), numeric_avg_combine(), numeric_avg_deserialize(), numeric_avg_serialize(), numeric_combine(), numeric_deserialize(), numeric_poly_combine(), numeric_poly_deserialize(), numeric_poly_serialize(), numeric_serialize(), ordered_set_startup(), percentile_cont_final_common(), percentile_cont_multi_final_common(), percentile_disc_final(), percentile_disc_multi_final(), range_agg_finalfn(), range_agg_transfn(), range_intersect_agg_transfn(), and string_agg_finalfn().

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4531 of file nodeAgg.c.

4532 {
4533  if (fcinfo->context && IsA(fcinfo->context, AggState))
4534  {
4535  AggState *aggstate = (AggState *) fcinfo->context;
4536  AggStatePerAgg curperagg;
4537  AggStatePerTrans curpertrans;
4538 
4539  /* check curperagg (valid when in a final function) */
4540  curperagg = aggstate->curperagg;
4541 
4542  if (curperagg)
4543  return curperagg->aggref;
4544 
4545  /* check curpertrans (valid when in a transition function) */
4546  curpertrans = aggstate->curpertrans;
4547 
4548  if (curpertrans)
4549  return curpertrans->aggref;
4550  }
4551  return NULL;
4552 }
Aggref * aggref
Definition: nodeAgg.h:44
AggStatePerAgg curperagg
Definition: execnodes.h:2342

References AggStatePerTransData::aggref, FunctionCallInfoBaseData::context, AggState::curperagg, AggState::curpertrans, if(), and IsA.

Referenced by ordered_set_startup().

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4565 of file nodeAgg.c.

4566 {
4567  if (fcinfo->context && IsA(fcinfo->context, AggState))
4568  {
4569  AggState *aggstate = (AggState *) fcinfo->context;
4570 
4571  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4572  }
4573  return NULL;
4574 }

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

◆ AggRegisterCallback()

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

Definition at line 4630 of file nodeAgg.c.

4633 {
4634  if (fcinfo->context && IsA(fcinfo->context, AggState))
4635  {
4636  AggState *aggstate = (AggState *) fcinfo->context;
4637  ExprContext *cxt = aggstate->curaggcontext;
4638 
4639  RegisterExprContextCallback(cxt, func, arg);
4640 
4641  return;
4642  }
4643  elog(ERROR, "aggregate function cannot register a callback in this context");
4644 }
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:925
void * arg

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

Referenced by ordered_set_startup().

◆ AggStateIsShared()

bool AggStateIsShared ( FunctionCallInfo  fcinfo)

Definition at line 4591 of file nodeAgg.c.

4592 {
4593  if (fcinfo->context && IsA(fcinfo->context, AggState))
4594  {
4595  AggState *aggstate = (AggState *) fcinfo->context;
4596  AggStatePerAgg curperagg;
4597  AggStatePerTrans curpertrans;
4598 
4599  /* check curperagg (valid when in a final function) */
4600  curperagg = aggstate->curperagg;
4601 
4602  if (curperagg)
4603  return aggstate->pertrans[curperagg->transno].aggshared;
4604 
4605  /* check curpertrans (valid when in a transition function) */
4606  curpertrans = aggstate->curpertrans;
4607 
4608  if (curpertrans)
4609  return curpertrans->aggshared;
4610  }
4611  return true;
4612 }
AggStatePerTrans pertrans
Definition: execnodes.h:2336

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

Referenced by ordered_set_startup().

◆ build_hash_table()

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

Definition at line 1486 of file nodeAgg.c.

1487 {
1488  AggStatePerHash perhash = &aggstate->perhash[setno];
1489  MemoryContext metacxt = aggstate->hash_metacxt;
1490  MemoryContext hashcxt = aggstate->hashcontext->ecxt_per_tuple_memory;
1491  MemoryContext tmpcxt = aggstate->tmpcontext->ecxt_per_tuple_memory;
1492  Size additionalsize;
1493 
1494  Assert(aggstate->aggstrategy == AGG_HASHED ||
1495  aggstate->aggstrategy == AGG_MIXED);
1496 
1497  /*
1498  * Used to make sure initial hash table allocation does not exceed
1499  * hash_mem. Note that the estimate does not include space for
1500  * pass-by-reference transition data values, nor for the representative
1501  * tuple of each group.
1502  */
1503  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1504 
1505  perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
1506  perhash->hashslot->tts_tupleDescriptor,
1507  perhash->numCols,
1508  perhash->hashGrpColIdxHash,
1509  perhash->eqfuncoids,
1510  perhash->hashfunctions,
1511  perhash->aggnode->grpCollations,
1512  nbuckets,
1513  additionalsize,
1514  metacxt,
1515  hashcxt,
1516  tmpcxt,
1517  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1518 }
size_t Size
Definition: c.h:540
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
struct AggStatePerGroupData AggStatePerGroupData
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:839
@ AGG_HASHED
Definition: nodes.h:809
FmgrInfo * hashfunctions
Definition: nodeAgg.h:306
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:312
MemoryContext hash_metacxt
Definition: execnodes.h:2368
int numtrans
Definition: execnodes.h:2329
AggSplit aggsplit
Definition: execnodes.h:2331
Oid * grpCollations
Definition: plannodes.h:902

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

◆ build_hash_tables()

static void build_hash_tables ( AggState aggstate)
static

Definition at line 1451 of file nodeAgg.c.

1452 {
1453  int setno;
1454 
1455  for (setno = 0; setno < aggstate->num_hashes; ++setno)
1456  {
1457  AggStatePerHash perhash = &aggstate->perhash[setno];
1458  long nbuckets;
1459  Size memory;
1460 
1461  if (perhash->hashtable != NULL)
1462  {
1463  ResetTupleHashTable(perhash->hashtable);
1464  continue;
1465  }
1466 
1467  Assert(perhash->aggnode->numGroups > 0);
1468 
1469  memory = aggstate->hash_mem_limit / aggstate->num_hashes;
1470 
1471  /* choose reasonable number of buckets per hashtable */
1472  nbuckets = hash_choose_num_buckets(aggstate->hashentrysize,
1473  perhash->aggnode->numGroups,
1474  memory);
1475 
1476  build_hash_table(aggstate, setno, nbuckets);
1477  }
1478 
1479  aggstate->hash_ngroups_current = 0;
1480 }
static void build_hash_table(AggState *aggstate, int setno, long nbuckets)
Definition: nodeAgg.c:1486
static long hash_choose_num_buckets(double hashentrysize, long estimated_nbuckets, Size memory)
Definition: nodeAgg.c:1948
long numGroups
Definition: plannodes.h:903

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

◆ build_pertrans_for_aggref()

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

Definition at line 4019 of file nodeAgg.c.

4026 {
4027  int numGroupingSets = Max(aggstate->maxsets, 1);
4028  Expr *transfnexpr;
4029  int numTransArgs;
4030  Expr *serialfnexpr = NULL;
4031  Expr *deserialfnexpr = NULL;
4032  ListCell *lc;
4033  int numInputs;
4034  int numDirectArgs;
4035  List *sortlist;
4036  int numSortCols;
4037  int numDistinctCols;
4038  int i;
4039 
4040  /* Begin filling in the pertrans data */
4041  pertrans->aggref = aggref;
4042  pertrans->aggshared = false;
4043  pertrans->aggCollation = aggref->inputcollid;
4044  pertrans->transfn_oid = transfn_oid;
4045  pertrans->serialfn_oid = aggserialfn;
4046  pertrans->deserialfn_oid = aggdeserialfn;
4047  pertrans->initValue = initValue;
4048  pertrans->initValueIsNull = initValueIsNull;
4049 
4050  /* Count the "direct" arguments, if any */
4051  numDirectArgs = list_length(aggref->aggdirectargs);
4052 
4053  /* Count the number of aggregated input columns */
4054  pertrans->numInputs = numInputs = list_length(aggref->args);
4055 
4056  pertrans->aggtranstype = aggtranstype;
4057 
4058  /* account for the current transition state */
4059  numTransArgs = pertrans->numTransInputs + 1;
4060 
4061  /*
4062  * Set up infrastructure for calling the transfn. Note that invtrans is
4063  * not needed here.
4064  */
4065  build_aggregate_transfn_expr(inputTypes,
4066  numArguments,
4067  numDirectArgs,
4068  aggref->aggvariadic,
4069  aggtranstype,
4070  aggref->inputcollid,
4071  transfn_oid,
4072  InvalidOid,
4073  &transfnexpr,
4074  NULL);
4075 
4076  fmgr_info(transfn_oid, &pertrans->transfn);
4077  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
4078 
4079  pertrans->transfn_fcinfo =
4082  &pertrans->transfn,
4083  numTransArgs,
4084  pertrans->aggCollation,
4085  (void *) aggstate, NULL);
4086 
4087  /* get info about the state value's datatype */
4088  get_typlenbyval(aggtranstype,
4089  &pertrans->transtypeLen,
4090  &pertrans->transtypeByVal);
4091 
4092  if (OidIsValid(aggserialfn))
4093  {
4094  build_aggregate_serialfn_expr(aggserialfn,
4095  &serialfnexpr);
4096  fmgr_info(aggserialfn, &pertrans->serialfn);
4097  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
4098 
4099  pertrans->serialfn_fcinfo =
4102  &pertrans->serialfn,
4103  1,
4104  InvalidOid,
4105  (void *) aggstate, NULL);
4106  }
4107 
4108  if (OidIsValid(aggdeserialfn))
4109  {
4110  build_aggregate_deserialfn_expr(aggdeserialfn,
4111  &deserialfnexpr);
4112  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
4113  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
4114 
4115  pertrans->deserialfn_fcinfo =
4118  &pertrans->deserialfn,
4119  2,
4120  InvalidOid,
4121  (void *) aggstate, NULL);
4122  }
4123 
4124  /*
4125  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
4126  * have a list of SortGroupClause nodes; fish out the data in them and
4127  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
4128  * however; the agg's transfn and finalfn are responsible for that.
4129  *
4130  * Note that by construction, if there is a DISTINCT clause then the ORDER
4131  * BY clause is a prefix of it (see transformDistinctClause).
4132  */
4133  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4134  {
4135  sortlist = NIL;
4136  numSortCols = numDistinctCols = 0;
4137  }
4138  else if (aggref->aggdistinct)
4139  {
4140  sortlist = aggref->aggdistinct;
4141  numSortCols = numDistinctCols = list_length(sortlist);
4142  Assert(numSortCols >= list_length(aggref->aggorder));
4143  }
4144  else
4145  {
4146  sortlist = aggref->aggorder;
4147  numSortCols = list_length(sortlist);
4148  numDistinctCols = 0;
4149  }
4150 
4151  pertrans->numSortCols = numSortCols;
4152  pertrans->numDistinctCols = numDistinctCols;
4153 
4154  /*
4155  * If we have either sorting or filtering to do, create a tupledesc and
4156  * slot corresponding to the aggregated inputs (including sort
4157  * expressions) of the agg.
4158  */
4159  if (numSortCols > 0 || aggref->aggfilter)
4160  {
4161  pertrans->sortdesc = ExecTypeFromTL(aggref->args);
4162  pertrans->sortslot =
4163  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4165  }
4166 
4167  if (numSortCols > 0)
4168  {
4169  /*
4170  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
4171  * (yet)
4172  */
4173  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
4174 
4175  /* ORDER BY aggregates are not supported with partial aggregation */
4176  Assert(!DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
4177 
4178  /* If we have only one input, we need its len/byval info. */
4179  if (numInputs == 1)
4180  {
4181  get_typlenbyval(inputTypes[numDirectArgs],
4182  &pertrans->inputtypeLen,
4183  &pertrans->inputtypeByVal);
4184  }
4185  else if (numDistinctCols > 0)
4186  {
4187  /* we will need an extra slot to store prior values */
4188  pertrans->uniqslot =
4189  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4191  }
4192 
4193  /* Extract the sort information for use later */
4194  pertrans->sortColIdx =
4195  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
4196  pertrans->sortOperators =
4197  (Oid *) palloc(numSortCols * sizeof(Oid));
4198  pertrans->sortCollations =
4199  (Oid *) palloc(numSortCols * sizeof(Oid));
4200  pertrans->sortNullsFirst =
4201  (bool *) palloc(numSortCols * sizeof(bool));
4202 
4203  i = 0;
4204  foreach(lc, sortlist)
4205  {
4206  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
4207  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
4208 
4209  /* the parser should have made sure of this */
4210  Assert(OidIsValid(sortcl->sortop));
4211 
4212  pertrans->sortColIdx[i] = tle->resno;
4213  pertrans->sortOperators[i] = sortcl->sortop;
4214  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
4215  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
4216  i++;
4217  }
4218  Assert(i == numSortCols);
4219  }
4220 
4221  if (aggref->aggdistinct)
4222  {
4223  Oid *ops;
4224 
4225  Assert(numArguments > 0);
4226  Assert(list_length(aggref->aggdistinct) == numDistinctCols);
4227 
4228  ops = palloc(numDistinctCols * sizeof(Oid));
4229 
4230  i = 0;
4231  foreach(lc, aggref->aggdistinct)
4232  ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
4233 
4234  /* lookup / build the necessary comparators */
4235  if (numDistinctCols == 1)
4236  fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
4237  else
4238  pertrans->equalfnMulti =
4239  execTuplesMatchPrepare(pertrans->sortdesc,
4240  numDistinctCols,
4241  pertrans->sortColIdx,
4242  ops,
4243  pertrans->sortCollations,
4244  &aggstate->ss.ps);
4245  pfree(ops);
4246  }
4247 
4248  pertrans->sortstates = (Tuplesortstate **)
4249  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
4250 }
int16 AttrNumber
Definition: attnum.h:21
#define OidIsValid(objectId)
Definition: c.h:710
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1831
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1938
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
struct FunctionCallInfoBaseData * FunctionCallInfo
Definition: fmgr.h:38
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
static int initValue(long lng_val)
Definition: informix.c:677
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2208
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1266
void * palloc0(Size size)
Definition: mcxt.c:1099
void * palloc(Size size)
Definition: mcxt.c:1068
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:788
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:838
void build_aggregate_deserialfn_expr(Oid deserialfn_oid, Expr **deserialfnexpr)
Definition: parse_agg.c:2060
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:1976
void build_aggregate_serialfn_expr(Oid serialfn_oid, Expr **serialfnexpr)
Definition: parse_agg.c:2037
#define lfirst(lc)
Definition: pg_list.h:169
static int list_length(const List *l)
Definition: pg_list.h:149
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
bool * sortNullsFirst
Definition: nodeAgg.h:103
FmgrInfo serialfn
Definition: nodeAgg.h:84
FmgrInfo equalfnOne
Definition: nodeAgg.h:110
TupleDesc sortdesc
Definition: nodeAgg.h:138
TupleTableSlot * sortslot
Definition: nodeAgg.h:136
ExprState * equalfnMulti
Definition: nodeAgg.h:111
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
TupleTableSlot * uniqslot
Definition: nodeAgg.h:137
FmgrInfo deserialfn
Definition: nodeAgg.h:87
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:167
AttrNumber * sortColIdx
Definition: nodeAgg.h:100
FunctionCallInfo serialfn_fcinfo
Definition: nodeAgg.h:165
int maxsets
Definition: execnodes.h:2356
List * aggdistinct
Definition: primnodes.h:341
List * aggdirectargs
Definition: primnodes.h:338
bool aggvariadic
Definition: primnodes.h:344
char aggkind
Definition: primnodes.h:346
List * args
Definition: primnodes.h:339
Expr * aggfilter
Definition: primnodes.h:342
Oid inputcollid
Definition: primnodes.h:335
List * aggorder
Definition: primnodes.h:340
Definition: pg_list.h:51
Definition: nodes.h:574
Expr * expr
Definition: primnodes.h:1716
AttrNumber resno
Definition: primnodes.h:1717
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:356

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

◆ ExecAgg()

static TupleTableSlot* ExecAgg ( PlanState pstate)
static

Definition at line 2140 of file nodeAgg.c.

2141 {
2142  AggState *node = castNode(AggState, pstate);
2143  TupleTableSlot *result = NULL;
2144 
2146 
2147  if (!node->agg_done)
2148  {
2149  /* Dispatch based on strategy */
2150  switch (node->phase->aggstrategy)
2151  {
2152  case AGG_HASHED:
2153  if (!node->table_filled)
2154  agg_fill_hash_table(node);
2155  /* FALLTHROUGH */
2156  case AGG_MIXED:
2157  result = agg_retrieve_hash_table(node);
2158  break;
2159  case AGG_PLAIN:
2160  case AGG_SORTED:
2161  result = agg_retrieve_direct(node);
2162  break;
2163  }
2164 
2165  if (!TupIsNull(result))
2166  return result;
2167  }
2168 
2169  return NULL;
2170 }
static void agg_fill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2522
static TupleTableSlot * agg_retrieve_direct(AggState *aggstate)
Definition: nodeAgg.c:2176
@ AGG_SORTED
Definition: nodes.h:808
#define castNode(_type_, nodeptr)
Definition: nodes.h:642

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

◆ ExecAggEstimate()

void ExecAggEstimate ( AggState node,
ParallelContext pcxt 
)

Definition at line 4659 of file nodeAgg.c.

4660 {
4661  Size size;
4662 
4663  /* don't need this if not instrumenting or no workers */
4664  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4665  return;
4666 
4667  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4668  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4669  shm_toc_estimate_chunk(&pcxt->estimator, size);
4670  shm_toc_estimate_keys(&pcxt->estimator, 1);
4671 }
#define offsetof(type, field)
Definition: c.h:727
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
shm_toc_estimator estimator
Definition: parallel.h:42
Instrumentation * instrument
Definition: execnodes.h:1008

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

◆ ExecAggInitializeDSM()

void ExecAggInitializeDSM ( AggState node,
ParallelContext pcxt 
)

Definition at line 4680 of file nodeAgg.c.

4681 {
4682  Size size;
4683 
4684  /* don't need this if not instrumenting or no workers */
4685  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4686  return;
4687 
4688  size = offsetof(SharedAggInfo, sinstrument)
4689  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4690  node->shared_info = shm_toc_allocate(pcxt->toc, size);
4691  /* ensure any unfilled slots will contain zeroes */
4692  memset(node->shared_info, 0, size);
4693  node->shared_info->num_workers = pcxt->nworkers;
4694  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4695  node->shared_info);
4696 }
struct AggregateInstrumentation AggregateInstrumentation
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
SharedAggInfo * shared_info
Definition: execnodes.h:2398
shm_toc * toc
Definition: parallel.h:45
Plan * plan
Definition: execnodes.h:998
int plan_node_id
Definition: plannodes.h:141

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

◆ ExecAggInitializeWorker()

void ExecAggInitializeWorker ( AggState node,
ParallelWorkerContext pwcxt 
)

Definition at line 4705 of file nodeAgg.c.

4706 {
4707  node->shared_info =
4708  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4709 }
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

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

Referenced by ExecParallelInitializeWorker().

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 4718 of file nodeAgg.c.

4719 {
4720  Size size;
4721  SharedAggInfo *si;
4722 
4723  if (node->shared_info == NULL)
4724  return;
4725 
4726  size = offsetof(SharedAggInfo, sinstrument)
4728  si = palloc(size);
4729  memcpy(si, node->shared_info, size);
4730  node->shared_info = si;
4731 }

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

Referenced by ExecParallelRetrieveInstrumentation().

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 4270 of file nodeAgg.c.

4271 {
4273  int transno;
4274  int numGroupingSets = Max(node->maxsets, 1);
4275  int setno;
4276 
4277  /*
4278  * When ending a parallel worker, copy the statistics gathered by the
4279  * worker back into shared memory so that it can be picked up by the main
4280  * process to report in EXPLAIN ANALYZE.
4281  */
4282  if (node->shared_info && IsParallelWorker())
4283  {
4285 
4286  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4289  si->hash_disk_used = node->hash_disk_used;
4290  si->hash_mem_peak = node->hash_mem_peak;
4291  }
4292 
4293  /* Make sure we have closed any open tuplesorts */
4294 
4295  if (node->sort_in)
4296  tuplesort_end(node->sort_in);
4297  if (node->sort_out)
4298  tuplesort_end(node->sort_out);
4299 
4301 
4302  if (node->hash_metacxt != NULL)
4303  {
4305  node->hash_metacxt = NULL;
4306  }
4307 
4308  for (transno = 0; transno < node->numtrans; transno++)
4309  {
4310  AggStatePerTrans pertrans = &node->pertrans[transno];
4311 
4312  for (setno = 0; setno < numGroupingSets; setno++)
4313  {
4314  if (pertrans->sortstates[setno])
4315  tuplesort_end(pertrans->sortstates[setno]);
4316  }
4317  }
4318 
4319  /* And ensure any agg shutdown callbacks have been called */
4320  for (setno = 0; setno < numGroupingSets; setno++)
4321  ReScanExprContext(node->aggcontexts[setno]);
4322  if (node->hashcontext)
4324 
4325  /*
4326  * We don't actually free any ExprContexts here (see comment in
4327  * ExecFreeExprContext), just unlinking the output one from the plan node
4328  * suffices.
4329  */
4330  ExecFreeExprContext(&node->ss.ps);
4331 
4332  /* clean up tuple table */
4334 
4335  outerPlan = outerPlanState(node);
4337 }
int ParallelWorkerNumber
Definition: parallel.c:112
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:556
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
#define outerPlanState(node)
Definition: execnodes.h:1094
#define IsParallelWorker()
Definition: parallel.h:61
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3115
#define outerPlan(node)
Definition: plannodes.h:172
Tuplesortstate * sort_out
Definition: execnodes.h:2359
uint64 hash_disk_used
Definition: execnodes.h:2386
Size hash_mem_peak
Definition: execnodes.h:2383
int hash_batches_used
Definition: execnodes.h:2387
Tuplesortstate * sort_in
Definition: execnodes.h:2358
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2302
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1620

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

◆ ExecInitAgg()

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

Definition at line 3155 of file nodeAgg.c.

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

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, AggState::agg_done, AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, AggState::aggcontexts, AggStatePerAggData::aggdirectargs, Aggref::aggdirectargs, Aggref::aggfnoid, AGGFNOID, Aggref::aggkind, Aggref::agglevelsup, Aggref::aggno, AggStatePerPhaseData::aggnode, AggStatePerHashData::aggnode, AggStatePerTransData::aggref, AggStatePerAggData::aggref, AggState::aggs, AggStatePerTransData::aggshared, AggState::aggsplit, Agg::aggsplit, Aggref::aggsplit, AggStatePerPhaseData::aggstrategy, AggState::aggstrategy, Agg::aggstrategy, Aggref::aggtransno, Aggref::aggtranstype, Aggref::aggtype, AggState::all_grouped_cols, AggState::all_pergroups, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Aggref::args, Assert(), bms_add_member(), bms_add_members(), bms_next_member(), build_aggregate_finalfn_expr(), build_hash_tables(), build_pertrans_for_aggref(), castNode, Agg::chain, CreateWorkExprContext(), AggState::curperagg, AggState::curpertrans, AggState::current_phase, AggState::current_set, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_DESERIALIZE, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, elog, AggStatePerPhaseData::eqfunctions, ereport, errcode(), errmsg(), ERROR, EState::es_query_cxt, AggStatePerPhaseData::evaltrans, AggStatePerPhaseData::evaltrans_cache, EXEC_FLAG_BACKWARD, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_MARK, EXEC_FLAG_REWIND, ExecAgg(), ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecBuildAggTrans(), ExecCreateScanSlotFromOuterPlan(), ExecGetResultSlotOps(), ExecInitExprList(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), PlanState::ExecProcNode, execTuplesMatchPrepare(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, find_hash_columns(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_strict, format_type_be(), FUNC_MAX_ARGS, get_aggregate_argtypes(), get_func_name(), get_typlenbyval(), GetAggInitVal(), GETSTRUCT, GetUserId(), AggStatePerPhaseData::grouped_cols, Agg::groupingSets, AggState::grp_firstTuple, Agg::grpColIdx, Agg::grpCollations, Agg::grpOperators, AggStatePerPhaseData::gset_lengths, hash_agg_entry_size(), hash_agg_set_limits(), AggState::hash_batches_used, AggState::hash_mem_limit, AggState::hash_metacxt, AggState::hash_ngroups_limit, AggState::hash_pergroup, AggState::hash_planned_partitions, AggState::hash_spill_rslot, AggState::hash_spill_wslot, AggState::hashcontext, AggState::hashentrysize, HeapTupleIsValid, i, initialize_phase(), initValue(), AggStatePerTransData::initValueIsNull, AggState::input_done, Aggref::inputcollid, InvalidOid, InvokeFunctionExecuteHook, IsBinaryCoercible(), j, lcons_int(), Plan::lefttree, lfirst, list_length(), list_nth_node, makeNode, Max, AggState::maxsets, NIL, AggState::num_hashes, AggState::numaggs, AggStatePerHashData::numCols, Agg::numCols, AggStatePerAggData::numFinalArgs, Agg::numGroups, AggState::numphases, AggStatePerPhaseData::numsets, AggState::numtrans, AggStatePerTransData::numTransInputs, OBJECT_AGGREGATE, OBJECT_FUNCTION, ObjectIdGetDatum, OidIsValid, PlanState::outerops, PlanState::outeropsfixed, PlanState::outeropsset, outerPlan, outerPlanState, palloc(), palloc0(), AggState::peragg, AggState::pergroups, AggState::perhash, AggState::pertrans, pg_proc_aclcheck(), AggState::phases, PlanState::plan, Agg::plan, Plan::plan_width, PROCOID, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, PlanState::qual, Plan::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::table_filled, AggState::tmpcontext, AggStatePerTransData::transfn, Agg::transitionSpace, AggStatePerAggData::transno, TupleTableSlot::tts_tupleDescriptor, TTSOpsMinimalTuple, and TTSOpsVirtual.

Referenced by ExecInitNode().

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 4340 of file nodeAgg.c.

4341 {
4342  ExprContext *econtext = node->ss.ps.ps_ExprContext;
4344  Agg *aggnode = (Agg *) node->ss.ps.plan;
4345  int transno;
4346  int numGroupingSets = Max(node->maxsets, 1);
4347  int setno;
4348 
4349  node->agg_done = false;
4350 
4351  if (node->aggstrategy == AGG_HASHED)
4352  {
4353  /*
4354  * In the hashed case, if we haven't yet built the hash table then we
4355  * can just return; nothing done yet, so nothing to undo. If subnode's
4356  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4357  * else no reason to re-scan it at all.
4358  */
4359  if (!node->table_filled)
4360  return;
4361 
4362  /*
4363  * If we do have the hash table, and it never spilled, and the subplan
4364  * does not have any parameter changes, and none of our own parameter
4365  * changes affect input expressions of the aggregated functions, then
4366  * we can just rescan the existing hash table; no need to build it
4367  * again.
4368  */
4369  if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4370  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4371  {
4373  &node->perhash[0].hashiter);
4374  select_current_set(node, 0, true);
4375  return;
4376  }
4377  }
4378 
4379  /* Make sure we have closed any open tuplesorts */
4380  for (transno = 0; transno < node->numtrans; transno++)
4381  {
4382  for (setno = 0; setno < numGroupingSets; setno++)
4383  {
4384  AggStatePerTrans pertrans = &node->pertrans[transno];
4385 
4386  if (pertrans->sortstates[setno])
4387  {
4388  tuplesort_end(pertrans->sortstates[setno]);
4389  pertrans->sortstates[setno] = NULL;
4390  }
4391  }
4392  }
4393 
4394  /*
4395  * We don't need to ReScanExprContext the output tuple context here;
4396  * ExecReScan already did it. But we do need to reset our per-grouping-set
4397  * contexts, which may have transvalues stored in them. (We use rescan
4398  * rather than just reset because transfns may have registered callbacks
4399  * that need to be run now.) For the AGG_HASHED case, see below.
4400  */
4401 
4402  for (setno = 0; setno < numGroupingSets; setno++)
4403  {
4404  ReScanExprContext(node->aggcontexts[setno]);
4405  }
4406 
4407  /* Release first tuple of group, if we have made a copy */
4408  if (node->grp_firstTuple != NULL)
4409  {
4411  node->grp_firstTuple = NULL;
4412  }
4414 
4415  /* Forget current agg values */
4416  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4417  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4418 
4419  /*
4420  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4421  * the hashcontext. This used to be an issue, but now, resetting a context
4422  * automatically deletes sub-contexts too.
4423  */
4424  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4425  {
4427 
4428  node->hash_ever_spilled = false;
4429  node->hash_spill_mode = false;
4430  node->hash_ngroups_current = 0;
4431 
4433  /* Rebuild an empty hash table */
4434  build_hash_tables(node);
4435  node->table_filled = false;
4436  /* iterator will be reset when the table is filled */
4437 
4438  hashagg_recompile_expressions(node, false, false);
4439  }
4440 
4441  if (node->aggstrategy != AGG_HASHED)
4442  {
4443  /*
4444  * Reset the per-group state (in particular, mark transvalues null)
4445  */
4446  for (setno = 0; setno < numGroupingSets; setno++)
4447  {
4448  MemSet(node->pergroups[setno], 0,
4449  sizeof(AggStatePerGroupData) * node->numaggs);
4450  }
4451 
4452  /* reset to phase 1 */
4453  initialize_phase(node, 1);
4454 
4455  node->input_done = false;
4456  node->projected_set = -1;
4457  }
4458 
4459  if (outerPlan->chgParam == NULL)
4461 }
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
bool hash_ever_spilled
Definition: execnodes.h:2375
Bitmapset * aggParams
Definition: plannodes.h:905
Bitmapset * chgParam
Definition: execnodes.h:1030

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

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

Definition at line 549 of file nodeAgg.c.

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

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

◆ finalize_aggregate()

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

Definition at line 1038 of file nodeAgg.c.

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

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

◆ finalize_aggregates()

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

Definition at line 1291 of file nodeAgg.c.

1294 {
1295  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1296  Datum *aggvalues = econtext->ecxt_aggvalues;
1297  bool *aggnulls = econtext->ecxt_aggnulls;
1298  int aggno;
1299  int transno;
1300 
1301  /*
1302  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1303  * inputs and run the transition functions.
1304  */
1305  for (transno = 0; transno < aggstate->numtrans; transno++)
1306  {
1307  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1308  AggStatePerGroup pergroupstate;
1309 
1310  pergroupstate = &pergroup[transno];
1311 
1312  if (pertrans->numSortCols > 0)
1313  {
1314  Assert(aggstate->aggstrategy != AGG_HASHED &&
1315  aggstate->aggstrategy != AGG_MIXED);
1316 
1317  if (pertrans->numInputs == 1)
1319  pertrans,
1320  pergroupstate);
1321  else
1323  pertrans,
1324  pergroupstate);
1325  }
1326  }
1327 
1328  /*
1329  * Run the final functions.
1330  */
1331  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1332  {
1333  AggStatePerAgg peragg = &peraggs[aggno];
1334  int transno = peragg->transno;
1335  AggStatePerGroup pergroupstate;
1336 
1337  pergroupstate = &pergroup[transno];
1338 
1339  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1340  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1341  &aggvalues[aggno], &aggnulls[aggno]);
1342  else
1343  finalize_aggregate(aggstate, peragg, pergroupstate,
1344  &aggvalues[aggno], &aggnulls[aggno]);
1345  }
1346 }
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:944
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1038
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:852
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1141

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

◆ finalize_partialaggregate()

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

Definition at line 1141 of file nodeAgg.c.

1145 {
1146  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1147  MemoryContext oldContext;
1148 
1150 
1151  /*
1152  * serialfn_oid will be set if we must serialize the transvalue before
1153  * returning it
1154  */
1155  if (OidIsValid(pertrans->serialfn_oid))
1156  {
1157  /* Don't call a strict serialization function with NULL input. */
1158  if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
1159  {
1160  *resultVal = (Datum) 0;
1161  *resultIsNull = true;
1162  }
1163  else
1164  {
1165  FunctionCallInfo fcinfo = pertrans->serialfn_fcinfo;
1166 
1167  fcinfo->args[0].value =
1168  MakeExpandedObjectReadOnly(pergroupstate->transValue,
1169  pergroupstate->transValueIsNull,
1170  pertrans->transtypeLen);
1171  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
1172  fcinfo->isnull = false;
1173 
1174  *resultVal = FunctionCallInvoke(fcinfo);
1175  *resultIsNull = fcinfo->isnull;
1176  }
1177  }
1178  else
1179  {
1180  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1181  *resultVal = pergroupstate->transValue;
1182  *resultIsNull = pergroupstate->transValueIsNull;
1183  }
1184 
1185  /* If result is pass-by-ref, make sure it is in the right context. */
1186  if (!peragg->resulttypeByVal && !*resultIsNull &&
1188  DatumGetPointer(*resultVal)))
1189  *resultVal = datumCopy(*resultVal,
1190  peragg->resulttypeByVal,
1191  peragg->resulttypeLen);
1192 
1193  MemoryContextSwitchTo(oldContext);
1194 }

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

◆ find_cols()

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

Definition at line 1380 of file nodeAgg.c.

1381 {
1382  Agg *agg = (Agg *) aggstate->ss.ps.plan;
1383  FindColsContext context;
1384 
1385  context.is_aggref = false;
1386  context.aggregated = NULL;
1387  context.unaggregated = NULL;
1388 
1389  /* Examine tlist and quals */
1390  (void) find_cols_walker((Node *) agg->plan.targetlist, &context);
1391  (void) find_cols_walker((Node *) agg->plan.qual, &context);
1392 
1393  /* In some cases, grouping columns will not appear in the tlist */
1394  for (int i = 0; i < agg->numCols; i++)
1395  context.unaggregated = bms_add_member(context.unaggregated,
1396  agg->grpColIdx[i]);
1397 
1398  *aggregated = context.aggregated;
1399  *unaggregated = context.unaggregated;
1400 }
static bool find_cols_walker(Node *node, FindColsContext *context)
Definition: nodeAgg.c:1403
bool is_aggref
Definition: nodeAgg.c:363
List * targetlist
Definition: plannodes.h:142

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

Referenced by find_hash_columns().

◆ find_cols_walker()

static bool find_cols_walker ( Node node,
FindColsContext context 
)
static

Definition at line 1403 of file nodeAgg.c.

1404 {
1405  if (node == NULL)
1406  return false;
1407  if (IsA(node, Var))
1408  {
1409  Var *var = (Var *) node;
1410 
1411  /* setrefs.c should have set the varno to OUTER_VAR */
1412  Assert(var->varno == OUTER_VAR);
1413  Assert(var->varlevelsup == 0);
1414  if (context->is_aggref)
1415  context->aggregated = bms_add_member(context->aggregated,
1416  var->varattno);
1417  else
1418  context->unaggregated = bms_add_member(context->unaggregated,
1419  var->varattno);
1420  return false;
1421  }
1422  if (IsA(node, Aggref))
1423  {
1424  Assert(!context->is_aggref);
1425  context->is_aggref = true;
1426  expression_tree_walker(node, find_cols_walker, (void *) context);
1427  context->is_aggref = false;
1428  return false;
1429  }
1431  (void *) context);
1432 }
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:2015
#define OUTER_VAR
Definition: primnodes.h:185
Bitmapset * aggregated
Definition: nodeAgg.c:364
Bitmapset * unaggregated
Definition: nodeAgg.c:365
Definition: primnodes.h:196
AttrNumber varattno
Definition: primnodes.h:200
int varno
Definition: primnodes.h:198
Index varlevelsup
Definition: primnodes.h:205

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

◆ find_hash_columns()

static void find_hash_columns ( AggState aggstate)
static

Definition at line 1546 of file nodeAgg.c.

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

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

◆ GetAggInitVal()

static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 4254 of file nodeAgg.c.

4255 {
4256  Oid typinput,
4257  typioparam;
4258  char *strInitVal;
4259  Datum initVal;
4260 
4261  getTypeInputInfo(transtype, &typinput, &typioparam);
4262  strInitVal = TextDatumGetCString(textInitVal);
4263  initVal = OidInputFunctionCall(typinput, strInitVal,
4264  typioparam, -1);
4265  pfree(strInitVal);
4266  return initVal;
4267 }
#define TextDatumGetCString(d)
Definition: builtins.h:86
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1630
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2831

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

Referenced by ExecInitAgg().

◆ hash_agg_check_limits()

static void hash_agg_check_limits ( AggState aggstate)
static

Definition at line 1838 of file nodeAgg.c.

1839 {
1840  uint64 ngroups = aggstate->hash_ngroups_current;
1841  Size meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt,
1842  true);
1844  true);
1845 
1846  /*
1847  * Don't spill unless there's at least one group in the hash table so we
1848  * can be sure to make progress even in edge cases.
1849  */
1850  if (aggstate->hash_ngroups_current > 0 &&
1851  (meta_mem + hashkey_mem > aggstate->hash_mem_limit ||
1852  ngroups > aggstate->hash_ngroups_limit))
1853  {
1854  hash_agg_enter_spill_mode(aggstate);
1855  }
1856 }
Size MemoryContextMemAllocated(MemoryContext context, bool recurse)
Definition: mcxt.c:477
static void hash_agg_enter_spill_mode(AggState *aggstate)
Definition: nodeAgg.c:1864

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

◆ hash_agg_enter_spill_mode()

static void hash_agg_enter_spill_mode ( AggState aggstate)
static

Definition at line 1864 of file nodeAgg.c.

1865 {
1866  aggstate->hash_spill_mode = true;
1867  hashagg_recompile_expressions(aggstate, aggstate->table_filled, true);
1868 
1869  if (!aggstate->hash_ever_spilled)
1870  {
1871  Assert(aggstate->hash_tapeset == NULL);
1872  Assert(aggstate->hash_spills == NULL);
1873 
1874  aggstate->hash_ever_spilled = true;
1875 
1876  aggstate->hash_tapeset = LogicalTapeSetCreate(true, NULL, -1);
1877 
1878  aggstate->hash_spills = palloc(sizeof(HashAggSpill) * aggstate->num_hashes);
1879 
1880  for (int setno = 0; setno < aggstate->num_hashes; setno++)
1881  {
1882  AggStatePerHash perhash = &aggstate->perhash[setno];
1883  HashAggSpill *spill = &aggstate->hash_spills[setno];
1884 
1885  hashagg_spill_init(spill, aggstate->hash_tapeset, 0,
1886  perhash->aggnode->numGroups,
1887  aggstate->hashentrysize);
1888  }
1889  }
1890 }
LogicalTapeSet * LogicalTapeSetCreate(bool preallocate, SharedFileSet *fileset, int worker)
Definition: logtape.c:557
struct HashAggSpill * hash_spills
Definition: execnodes.h:2370

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

Referenced by hash_agg_check_limits().

◆ hash_agg_entry_size()

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

Definition at line 1676 of file nodeAgg.c.

1677 {
1678  Size tupleChunkSize;
1679  Size pergroupChunkSize;
1680  Size transitionChunkSize;
1681  Size tupleSize = (MAXALIGN(SizeofMinimalTupleHeader) +
1682  tupleWidth);
1683  Size pergroupSize = numTrans * sizeof(AggStatePerGroupData);
1684 
1685  tupleChunkSize = CHUNKHDRSZ + tupleSize;
1686 
1687  if (pergroupSize > 0)
1688  pergroupChunkSize = CHUNKHDRSZ + pergroupSize;
1689  else
1690  pergroupChunkSize = 0;
1691 
1692  if (transitionSpace > 0)
1693  transitionChunkSize = CHUNKHDRSZ + transitionSpace;
1694  else
1695  transitionChunkSize = 0;
1696 
1697  return
1698  sizeof(TupleHashEntryData) +
1699  tupleChunkSize +
1700  pergroupChunkSize +
1701  transitionChunkSize;
1702 }
#define MAXALIGN(LEN)
Definition: c.h:757
struct TupleHashEntryData TupleHashEntryData
#define SizeofMinimalTupleHeader
Definition: htup_details.h:643
#define CHUNKHDRSZ
Definition: nodeAgg.c:321

References CHUNKHDRSZ, MAXALIGN, and SizeofMinimalTupleHeader.

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

◆ hash_agg_set_limits()

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

Definition at line 1780 of file nodeAgg.c.

1783 {
1784  int npartitions;
1785  Size partition_mem;
1786  Size hash_mem_limit = get_hash_memory_limit();
1787 
1788  /* if not expected to spill, use all of hash_mem */
1789  if (input_groups * hashentrysize <= hash_mem_limit)
1790  {
1791  if (num_partitions != NULL)
1792  *num_partitions = 0;
1793  *mem_limit = hash_mem_limit;
1794  *ngroups_limit = hash_mem_limit / hashentrysize;
1795  return;
1796  }
1797 
1798  /*
1799  * Calculate expected memory requirements for spilling, which is the size
1800  * of the buffers needed for all the tapes that need to be open at once.
1801  * Then, subtract that from the memory available for holding hash tables.
1802  */
1803  npartitions = hash_choose_num_partitions(input_groups,
1804  hashentrysize,
1805  used_bits,
1806  NULL);
1807  if (num_partitions != NULL)
1808  *num_partitions = npartitions;
1809 
1810  partition_mem =
1812  HASHAGG_WRITE_BUFFER_SIZE * npartitions;
1813 
1814  /*
1815  * Don't set the limit below 3/4 of hash_mem. In that case, we are at the
1816  * minimum number of partitions, so we aren't going to dramatically exceed
1817  * work mem anyway.
1818  */
1819  if (hash_mem_limit > 4 * partition_mem)
1820  *mem_limit = hash_mem_limit - partition_mem;
1821  else
1822  *mem_limit = hash_mem_limit * 0.75;
1823 
1824  if (*mem_limit > hashentrysize)
1825  *ngroups_limit = *mem_limit / hashentrysize;
1826  else
1827  *ngroups_limit = 1;
1828 }
static int hash_choose_num_partitions(double input_groups, double hashentrysize, int used_bits, int *log2_npartittions)
Definition: nodeAgg.c:1973
#define HASHAGG_READ_BUFFER_SIZE
Definition: nodeAgg.c:306
#define HASHAGG_WRITE_BUFFER_SIZE
Definition: nodeAgg.c:307
size_t get_hash_memory_limit(void)
Definition: nodeHash.c:3401

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

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

◆ hash_agg_update_metrics()

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

Definition at line 1899 of file nodeAgg.c.

1900 {
1901  Size meta_mem;
1902  Size hashkey_mem;
1903  Size buffer_mem;
1904  Size total_mem;
1905 
1906  if (aggstate->aggstrategy != AGG_MIXED &&
1907  aggstate->aggstrategy != AGG_HASHED)
1908  return;
1909 
1910  /* memory for the hash table itself */
1911  meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt, true);
1912 
1913  /* memory for the group keys and transition states */
1914  hashkey_mem = MemoryContextMemAllocated(aggstate->hashcontext->ecxt_per_tuple_memory, true);
1915 
1916  /* memory for read/write tape buffers, if spilled */
1917  buffer_mem = npartitions * HASHAGG_WRITE_BUFFER_SIZE;
1918  if (from_tape)
1919  buffer_mem += HASHAGG_READ_BUFFER_SIZE;
1920 
1921  /* update peak mem */
1922  total_mem = meta_mem + hashkey_mem + buffer_mem;
1923  if (total_mem > aggstate->hash_mem_peak)
1924  aggstate->hash_mem_peak = total_mem;
1925 
1926  /* update disk usage */
1927  if (aggstate->hash_tapeset != NULL)
1928  {
1929  uint64 disk_used = LogicalTapeSetBlocks(aggstate->hash_tapeset) * (BLCKSZ / 1024);
1930 
1931  if (aggstate->hash_disk_used < disk_used)
1932  aggstate->hash_disk_used = disk_used;
1933  }
1934 
1935  /* update hashentrysize estimate based on contents */
1936  if (aggstate->hash_ngroups_current > 0)
1937  {
1938  aggstate->hashentrysize =
1939  sizeof(TupleHashEntryData) +
1940  (hashkey_mem / (double) aggstate->hash_ngroups_current);
1941  }
1942 }
long LogicalTapeSetBlocks(LogicalTapeSet *lts)
Definition: logtape.c:1184

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_tapeset, HASHAGG_READ_BUFFER_SIZE, HASHAGG_WRITE_BUFFER_SIZE, AggState::hashcontext, AggState::hashentrysize, LogicalTapeSetBlocks(), and MemoryContextMemAllocated().

Referenced by agg_refill_hash_table(), and hashagg_finish_initial_spills().

◆ hash_choose_num_buckets()

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

Definition at line 1948 of file nodeAgg.c.

1949 {
1950  long max_nbuckets;
1951  long nbuckets = ngroups;
1952 
1953  max_nbuckets = memory / hashentrysize;
1954 
1955  /*
1956  * Underestimating is better than overestimating. Too many buckets crowd
1957  * out space for group keys and transition state values.
1958  */
1959  max_nbuckets >>= 1;
1960 
1961  if (nbuckets > max_nbuckets)
1962  nbuckets = max_nbuckets;
1963 
1964  return Max(nbuckets, 1);
1965 }

References Max.

Referenced by build_hash_tables().

◆ hash_choose_num_partitions()

static int hash_choose_num_partitions ( double  input_groups,
double  hashentrysize,
int  used_bits,
int *  log2_npartittions 
)
static

Definition at line 1973 of file nodeAgg.c.

1975 {
1976  Size hash_mem_limit = get_hash_memory_limit();
1977  double partition_limit;
1978  double mem_wanted;
1979  double dpartitions;
1980  int npartitions;
1981  int partition_bits;
1982 
1983  /*
1984  * Avoid creating so many partitions that the memory requirements of the
1985  * open partition files are greater than 1/4 of hash_mem.
1986  */
1987  partition_limit =
1988  (hash_mem_limit * 0.25 - HASHAGG_READ_BUFFER_SIZE) /
1990 
1991  mem_wanted = HASHAGG_PARTITION_FACTOR * input_groups * hashentrysize;
1992 
1993  /* make enough partitions so that each one is likely to fit in memory */
1994  dpartitions = 1 + (mem_wanted / hash_mem_limit);
1995 
1996  if (dpartitions > partition_limit)
1997  dpartitions = partition_limit;
1998 
1999  if (dpartitions < HASHAGG_MIN_PARTITIONS)
2000  dpartitions = HASHAGG_MIN_PARTITIONS;
2001  if (dpartitions > HASHAGG_MAX_PARTITIONS)
2002  dpartitions = HASHAGG_MAX_PARTITIONS;
2003 
2004  /* HASHAGG_MAX_PARTITIONS limit makes this safe */
2005  npartitions = (int) dpartitions;
2006 
2007  /* ceil(log2(npartitions)) */
2008  partition_bits = my_log2(npartitions);
2009 
2010  /* make sure that we don't exhaust the hash bits */
2011  if (partition_bits + used_bits >= 32)
2012  partition_bits = 32 - used_bits;
2013 
2014  if (log2_npartitions != NULL)
2015  *log2_npartitions = partition_bits;
2016 
2017  /* number of partitions will be a power of two */
2018  npartitions = 1 << partition_bits;
2019 
2020  return npartitions;
2021 }
int my_log2(long num)
Definition: dynahash.c:1765
#define HASHAGG_MAX_PARTITIONS
Definition: nodeAgg.c:298
#define HASHAGG_MIN_PARTITIONS
Definition: nodeAgg.c:297
#define HASHAGG_PARTITION_FACTOR
Definition: nodeAgg.c:296

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

Referenced by hash_agg_set_limits(), and hashagg_spill_init().

◆ hashagg_batch_new()

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

Definition at line 2973 of file nodeAgg.c.

2975 {
2976  HashAggBatch *batch = palloc0(sizeof(HashAggBatch));
2977 
2978  batch->setno = setno;
2979  batch->used_bits = used_bits;
2980  batch->input_tape = input_tape;
2981  batch->input_tuples = input_tuples;
2982  batch->input_card = input_card;
2983 
2984  return batch;
2985 }
int64 input_tuples
Definition: nodeAgg.c:356

References HashAggBatch::input_card, HashAggBatch::input_tape, HashAggBatch::input_tuples, palloc0(), HashAggBatch::setno, and HashAggBatch::used_bits.

Referenced by hashagg_spill_finish().

◆ hashagg_batch_read()

static MinimalTuple hashagg_batch_read ( HashAggBatch batch,
uint32 hashp 
)
static

Definition at line 2992 of file nodeAgg.c.

2993 {
2994  LogicalTape *tape = batch->input_tape;
2995  MinimalTuple tuple;
2996  uint32 t_len;
2997  size_t nread;
2998  uint32 hash;
2999 
3000  nread = LogicalTapeRead(tape, &hash, sizeof(uint32));
3001  if (nread == 0)
3002  return NULL;
3003  if (nread != sizeof(uint32))
3004  ereport(ERROR,
3006  errmsg("unexpected EOF for tape %p: requested %zu bytes, read %zu bytes",
3007  tape, sizeof(uint32), nread)));
3008  if (hashp != NULL)
3009  *hashp = hash;
3010 
3011  nread = LogicalTapeRead(tape, &t_len, sizeof(t_len));
3012  if (nread != sizeof(uint32))
3013  ereport(ERROR,
3015  errmsg("unexpected EOF for tape %p: requested %zu bytes, read %zu bytes",
3016  tape, sizeof(uint32), nread)));
3017 
3018  tuple = (MinimalTuple) palloc(t_len);
3019  tuple->t_len = t_len;
3020 
3021  nread = LogicalTapeRead(tape,
3022  (void *) ((char *) tuple + sizeof(uint32)),
3023  t_len - sizeof(uint32));
3024  if (nread != t_len - sizeof(uint32))
3025  ereport(ERROR,
3027  errmsg("unexpected EOF for tape %p: requested %zu bytes, read %zu bytes",
3028  tape, t_len - sizeof(uint32), nread)));
3029 
3030  return tuple;
3031 }
int errcode_for_file_access(void)
Definition: elog.c:716
MinimalTupleData * MinimalTuple
Definition: htup.h:27
size_t LogicalTapeRead(LogicalTape *lt, void *ptr, size_t size)
Definition: logtape.c:929

References ereport, errcode_for_file_access(), errmsg(), ERROR, hash(), HashAggBatch::input_tape, LogicalTapeRead(), palloc(), and MinimalTupleData::t_len.

Referenced by agg_refill_hash_table().

◆ hashagg_finish_initial_spills()

static void hashagg_finish_initial_spills ( AggState aggstate)
static

Definition at line 3041 of file nodeAgg.c.

3042 {
3043  int setno;
3044  int total_npartitions = 0;
3045 
3046  if (aggstate->hash_spills != NULL)
3047  {
3048  for (setno = 0; setno < aggstate->num_hashes; setno++)
3049  {
3050  HashAggSpill *spill = &aggstate->hash_spills[setno];
3051 
3052  total_npartitions += spill->npartitions;
3053  hashagg_spill_finish(aggstate, spill, setno);
3054  }
3055 
3056  /*
3057  * We're not processing tuples from outer plan any more; only
3058  * processing batches of spilled tuples. The initial spill structures
3059  * are no longer needed.
3060  */
3061  pfree(aggstate->hash_spills);
3062  aggstate->hash_spills = NULL;
3063  }
3064 
3065  hash_agg_update_metrics(aggstate, false, total_npartitions);
3066  aggstate->hash_spill_mode = false;
3067 }

References hash_agg_update_metrics(), AggState::hash_spill_mode, AggState::hash_spills, hashagg_spill_finish(), HashAggSpill::npartitions, AggState::num_hashes, and pfree().

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

◆ hashagg_recompile_expressions()

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

Definition at line 1723 of file nodeAgg.c.

1724 {
1725  AggStatePerPhase phase;
1726  int i = minslot ? 1 : 0;
1727  int j = nullcheck ? 1 : 0;
1728 
1729  Assert(aggstate->aggstrategy == AGG_HASHED ||
1730  aggstate->aggstrategy == AGG_MIXED);
1731 
1732  if (aggstate->aggstrategy == AGG_HASHED)
1733  phase = &aggstate->phases[0];
1734  else /* AGG_MIXED */
1735  phase = &aggstate->phases[1];
1736 
1737  if (phase->evaltrans_cache[i][j] == NULL)
1738  {
1739  const TupleTableSlotOps *outerops = aggstate->ss.ps.outerops;
1740  bool outerfixed = aggstate->ss.ps.outeropsfixed;
1741  bool dohash = true;
1742  bool dosort = false;
1743 
1744  /*
1745  * If minslot is true, that means we are processing a spilled batch
1746  * (inside agg_refill_hash_table()), and we must not advance the
1747  * sorted grouping sets.
1748  */
1749  if (aggstate->aggstrategy == AGG_MIXED && !minslot)
1750  dosort = true;
1751 
1752  /* temporarily change the outerops while compiling the expression */
1753  if (minslot)
1754  {
1755  aggstate->ss.ps.outerops = &TTSOpsMinimalTuple;
1756  aggstate->ss.ps.outeropsfixed = true;
1757  }
1758 
1759  phase->evaltrans_cache[i][j] = ExecBuildAggTrans(aggstate, phase,
1760  dosort, dohash,
1761  nullcheck);
1762 
1763  /* change back */
1764  aggstate->ss.ps.outerops = outerops;
1765  aggstate->ss.ps.outeropsfixed = outerfixed;
1766  }
1767 
1768  phase->evaltrans = phase->evaltrans_cache[i][j];
1769 }

References AGG_HASHED, AGG_MIXED, AggState::aggstrategy, Assert(), AggStatePerPhaseData::evaltrans, AggStatePerPhaseData::evaltrans_cache, ExecBuildAggTrans(), i, j, PlanState::outerops, PlanState::outeropsfixed, AggState::phases, ScanState::ps, AggState::ss, and TTSOpsMinimalTuple.

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

◆ hashagg_reset_spill_state()

static void hashagg_reset_spill_state ( AggState aggstate)
static

Definition at line 3115 of file nodeAgg.c.

3116 {
3117  /* free spills from initial pass */
3118  if (aggstate->hash_spills != NULL)
3119  {
3120  int setno;
3121 
3122  for (setno = 0; setno < aggstate->num_hashes; setno++)
3123  {
3124  HashAggSpill *spill = &aggstate->hash_spills[setno];
3125 
3126  pfree(spill->ntuples);
3127  pfree(spill->partitions);
3128  }
3129  pfree(aggstate->hash_spills);
3130  aggstate->hash_spills = NULL;
3131  }
3132 
3133  /* free batches */
3134  list_free_deep(aggstate->hash_batches);
3135  aggstate->hash_batches = NIL;
3136 
3137  /* close tape set */
3138  if (aggstate->hash_tapeset != NULL)
3139  {
3140  LogicalTapeSetClose(aggstate->hash_tapeset);
3141  aggstate->hash_tapeset = NULL;
3142  }
3143 }
void list_free_deep(List *list)
Definition: list.c:1519
void LogicalTapeSetClose(LogicalTapeSet *lts)
Definition: logtape.c:668
int64 * ntuples
Definition: nodeAgg.c:336
LogicalTape ** partitions
Definition: nodeAgg.c:335

References AggState::hash_batches, AggState::hash_spills, AggState::hash_tapeset, list_free_deep(), LogicalTapeSetClose(), NIL, HashAggSpill::ntuples, AggState::num_hashes, HashAggSpill::partitions, and pfree().

Referenced by ExecEndAgg(), and ExecReScanAgg().

◆ hashagg_spill_finish()

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

Definition at line 3075 of file nodeAgg.c.

3076 {
3077  int i;
3078  int used_bits = 32 - spill->shift;
3079 
3080  if (spill->npartitions == 0)
3081  return; /* didn't spill */
3082 
3083  for (i = 0; i < spill->npartitions; i++)
3084  {
3085  LogicalTape *tape = spill->partitions[i];
3086  HashAggBatch *new_batch;
3087  double cardinality;
3088 
3089  /* if the partition is empty, don't create a new batch of work */
3090  if (spill->ntuples[i] == 0)
3091  continue;
3092 
3093  cardinality = estimateHyperLogLog(&spill->hll_card[i]);
3094  freeHyperLogLog(&spill->hll_card[i]);
3095 
3096  /* rewinding frees the buffer while not in use */
3098 
3099  new_batch = hashagg_batch_new(tape, setno,
3100  spill->ntuples[i], cardinality,
3101  used_bits);
3102  aggstate->hash_batches = lappend(aggstate->hash_batches, new_batch);
3103  aggstate->hash_batches_used++;
3104  }
3105 
3106  pfree(spill->ntuples);
3107  pfree(spill->hll_card);
3108  pfree(spill->partitions);
3109 }
double estimateHyperLogLog(hyperLogLogState *cState)
Definition: hyperloglog.c:186
void freeHyperLogLog(hyperLogLogState *cState)
Definition: hyperloglog.c:151
void LogicalTapeRewindForRead(LogicalTape *lt, size_t buffer_size)
Definition: logtape.c:847
static HashAggBatch * hashagg_batch_new(LogicalTape *input_tape, int setno, int64 input_tuples, double input_card, int used_bits)
Definition: nodeAgg.c:2973
hyperLogLogState * hll_card
Definition: nodeAgg.c:339

References estimateHyperLogLog(), freeHyperLogLog(), AggState::hash_batches, AggState::hash_batches_used, hashagg_batch_new(), HASHAGG_READ_BUFFER_SIZE, HashAggSpill::hll_card, i, lappend(), LogicalTapeRewindForRead(), HashAggSpill::npartitions, HashAggSpill::ntuples, HashAggSpill::partitions, pfree(), and HashAggSpill::shift.

Referenced by agg_refill_hash_table(), and hashagg_finish_initial_spills().

◆ hashagg_spill_init()

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

Definition at line 2876 of file nodeAgg.c.

2878 {
2879  int npartitions;
2880  int partition_bits;
2881 
2882  npartitions = hash_choose_num_partitions(input_groups, hashentrysize,
2883  used_bits, &partition_bits);
2884 
2885  spill->partitions = palloc0(sizeof(LogicalTape *) * npartitions);
2886  spill->ntuples = palloc0(sizeof(int64) * npartitions);
2887  spill->hll_card = palloc0(sizeof(hyperLogLogState) * npartitions);
2888 
2889  for (int i = 0; i < npartitions; i++)
2890  spill->partitions[i] = LogicalTapeCreate(tapeset);
2891 
2892  spill->shift = 32 - used_bits - partition_bits;
2893  spill->mask = (npartitions - 1) << spill->shift;
2894  spill->npartitions = npartitions;
2895 
2896  for (int i = 0; i < npartitions; i++)
2898 }
void initHyperLogLog(hyperLogLogState *cState, uint8 bwidth)
Definition: hyperloglog.c:66
LogicalTape * LogicalTapeCreate(LogicalTapeSet *lts)
Definition: logtape.c:681
#define HASHAGG_HLL_BIT_WIDTH
Definition: nodeAgg.c:315
uint32 mask
Definition: nodeAgg.c:337

References hash_choose_num_partitions(), HASHAGG_HLL_BIT_WIDTH, HashAggSpill::hll_card, i, initHyperLogLog(), LogicalTapeCreate(), HashAggSpill::mask, HashAggSpill::npartitions, HashAggSpill::ntuples, palloc0(), HashAggSpill::partitions, and HashAggSpill::shift.

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

◆ hashagg_spill_tuple()

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

Definition at line 2907 of file nodeAgg.c.

2909 {
2910  TupleTableSlot *spillslot;
2911  int partition;
2912  MinimalTuple tuple;
2913  LogicalTape *tape;
2914  int total_written = 0;
2915  bool shouldFree;
2916 
2917  Assert(spill->partitions != NULL);
2918 
2919  /* spill only attributes that we actually need */
2920  if (!aggstate->all_cols_needed)
2921  {
2922  spillslot = aggstate->hash_spill_wslot;
2923  slot_getsomeattrs(inputslot, aggstate->max_colno_needed);
2924  ExecClearTuple(spillslot);
2925  for (int i = 0; i < spillslot->tts_tupleDescriptor->natts; i++)
2926  {
2927  if (bms_is_member(i + 1, aggstate->colnos_needed))
2928  {
2929  spillslot->tts_values[i] = inputslot->tts_values[i];
2930  spillslot->tts_isnull[i] = inputslot->tts_isnull[i];
2931  }
2932  else
2933  spillslot->tts_isnull[i] = true;
2934  }
2935  ExecStoreVirtualTuple(spillslot);
2936  }
2937  else
2938  spillslot = inputslot;
2939 
2940  tuple = ExecFetchSlotMinimalTuple(spillslot, &shouldFree);
2941 
2942  partition = (hash & spill->mask) >> spill->shift;
2943  spill->ntuples[partition]++;
2944 
2945  /*
2946  * All hash values destined for a given partition have some bits in
2947  * common, which causes bad HLL cardinality estimates. Hash the hash to
2948  * get a more uniform distribution.
2949  */
2950  addHyperLogLog(&spill->hll_card[partition], hash_bytes_uint32(hash));
2951 
2952  tape = spill->partitions[partition];
2953 
2954  LogicalTapeWrite(tape, (void *) &hash, sizeof(uint32));
2955  total_written += sizeof(uint32);
2956 
2957  LogicalTapeWrite(tape, (void *) tuple, tuple->t_len);
2958  total_written += tuple->t_len;
2959 
2960  if (shouldFree)
2961  pfree(tuple);
2962 
2963  return total_written;
2964 }
MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot, bool *shouldFree)
Definition: execTuples.c:1692
uint32 hash_bytes_uint32(uint32 k)
Definition: hashfn.c:610
void addHyperLogLog(hyperLogLogState *cState, uint32 hash)
Definition: hyperloglog.c:167
void LogicalTapeWrite(LogicalTape *lt, void *ptr, size_t size)
Definition: logtape.c:762
static void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:341

References addHyperLogLog(), AggState::all_cols_needed, Assert(), bms_is_member(), AggState::colnos_needed, ExecClearTuple(), ExecFetchSlotMinimalTuple(), ExecStoreVirtualTuple(), hash(), hash_bytes_uint32(), AggState::hash_spill_wslot, HashAggSpill::hll_card, i, LogicalTapeWrite(), HashAggSpill::mask, AggState::max_colno_needed, TupleDescData::natts, HashAggSpill::ntuples, HashAggSpill::partitions, pfree(), HashAggSpill::shift, slot_getsomeattrs(), MinimalTupleData::t_len, TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, and TupleTableSlot::tts_values.

Referenced by agg_refill_hash_table(), and lookup_hash_entries().

◆ initialize_aggregate()

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

Definition at line 580 of file nodeAgg.c.

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

References AggState::curaggcontext, AggState::current_set, datumCopy(), ExprContext::ecxt_per_tuple_memory, AggStatePerTransData::initValue, AggStatePerTransData::initValueIsNull, MemoryContextSwitchTo(), AggStatePerGroupData::noTransValue, AggStatePerTransData::numInputs, AggStatePerTransData::numSortCols, AggStatePerTransData::sortColIdx, AggStatePerTransData::sortCollations, AggStatePerTransData::sortdesc, AggStatePerTransData::sortNullsFirst, AggStatePerTransData::sortOperators, AggStatePerTransData::sortstates, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, AggStatePerGroupData::transValue, AggStatePerGroupData::transValueIsNull, TupleDescAttr, tuplesort_begin_datum(), tuplesort_begin_heap(), tuplesort_end(), TUPLESORT_NONE, and work_mem.

Referenced by initialize_aggregates(), and initialize_hash_entry().

◆ initialize_aggregates()

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

Definition at line 667 of file nodeAgg.c.

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

References initialize_aggregate(), Max, AggStatePerPhaseData::numsets, AggState::numtrans, AggState::pertrans, AggState::phase, and select_current_set().

Referenced by agg_retrieve_direct().

◆ initialize_hash_entry()

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

Definition at line 2027 of file nodeAgg.c.

2029 {
2030  AggStatePerGroup pergroup;
2031  int transno;
2032 
2033  aggstate->hash_ngroups_current++;
2034  hash_agg_check_limits(aggstate);
2035 
2036  /* no need to allocate or initialize per-group state */
2037  if (aggstate->numtrans == 0)
2038  return;
2039 
2040  pergroup = (AggStatePerGroup)
2041  MemoryContextAlloc(hashtable->tablecxt,
2042  sizeof(AggStatePerGroupData) * aggstate->numtrans);
2043 
2044  entry->additional = pergroup;
2045 
2046  /*
2047  * Initialize aggregates for new tuple group, lookup_hash_entries()
2048  * already has selected the relevant grouping set.
2049  */
2050  for (transno = 0; transno < aggstate->numtrans; transno++)
2051  {
2052  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
2053  AggStatePerGroup pergroupstate = &pergroup[transno];
2054 
2055  initialize_aggregate(aggstate, pertrans, pergroupstate);
2056  }
2057 }
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
static void hash_agg_check_limits(AggState *aggstate)
Definition: nodeAgg.c:1838
MemoryContext tablecxt
Definition: execnodes.h:778

References TupleHashEntryData::additional, hash_agg_check_limits(), AggState::hash_ngroups_current, initialize_aggregate(), MemoryContextAlloc(), AggState::numtrans, AggState::pertrans, and TupleHashTableData::tablecxt.

Referenced by agg_refill_hash_table(), and lookup_hash_entries().

◆ initialize_phase()

static void initialize_phase ( AggState aggstate,
int  newphase 
)
static

Definition at line 479 of file nodeAgg.c.

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

References Assert(), Sort::collations, AggState::current_phase, ExecGetResultType(), Sort::nullsFirst, Sort::numCols, outerPlanState, AggState::phase, AggState::phases, AggState::sort_in, AggState::sort_out, Sort::sortColIdx, AggStatePerPhaseData::sortnode, Sort::sortOperators, tuplesort_begin_heap(), tuplesort_end(), TUPLESORT_NONE, tuplesort_performsort(), and work_mem.

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

◆ lookup_hash_entries()

static void lookup_hash_entries ( AggState aggstate)
static

Definition at line 2077 of file nodeAgg.c.

2078 {
2079  AggStatePerGroup *pergroup = aggstate->hash_pergroup;
2080  TupleTableSlot *outerslot = aggstate->tmpcontext->ecxt_outertuple;
2081  int setno;
2082 
2083  for (setno = 0; setno < aggstate->num_hashes; setno++)
2084  {
2085  AggStatePerHash perhash = &aggstate->perhash[setno];
2086  TupleHashTable hashtable = perhash->hashtable;
2087  TupleTableSlot *hashslot = perhash->hashslot;
2088  TupleHashEntry entry;
2089  uint32 hash;
2090  bool isnew = false;
2091  bool *p_isnew;
2092 
2093  /* if hash table already spilled, don't create new entries */
2094  p_isnew = aggstate->hash_spill_mode ? NULL : &isnew;
2095 
2096  select_current_set(aggstate, setno, true);
2097  prepare_hash_slot(perhash,
2098  outerslot,
2099  hashslot);
2100 
2101  entry = LookupTupleHashEntry(hashtable, hashslot,
2102  p_isnew, &hash);
2103 
2104  if (entry != NULL)
2105  {
2106  if (isnew)
2107  initialize_hash_entry(aggstate, hashtable, entry);
2108  pergroup[setno] = entry->additional;
2109  }
2110  else
2111  {
2112  HashAggSpill *spill = &aggstate->hash_spills[setno];
2113  TupleTableSlot *slot = aggstate->tmpcontext->ecxt_outertuple;
2114 
2115  if (spill->partitions == NULL)
2116  hashagg_spill_init(spill, aggstate->hash_tapeset, 0,
2117  perhash->aggnode->numGroups,
2118  aggstate->hashentrysize);
2119 
2120  hashagg_spill_tuple(aggstate, spill, slot, hash);
2121  pergroup[setno] = NULL;
2122  }
2123  }
2124 }
TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 *hash)
Definition: execGrouping.c:306

References TupleHashEntryData::additional, AggStatePerHashData::aggnode, ExprContext::ecxt_outertuple, hash(), AggState::hash_pergroup, AggState::hash_spill_mode, AggState::hash_spills, AggState::hash_tapeset, hashagg_spill_init(), hashagg_spill_tuple(), AggState::hashentrysize, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, initialize_hash_entry(), LookupTupleHashEntry(), AggState::num_hashes, Agg::numGroups, HashAggSpill::partitions, AggState::perhash, prepare_hash_slot(), select_current_set(), and AggState::tmpcontext.

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

◆ prepare_hash_slot()

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

Definition at line 1201 of file nodeAgg.c.

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

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

Referenced by agg_refill_hash_table(), and lookup_hash_entries().

◆ prepare_projection_slot()

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

Definition at line 1246 of file nodeAgg.c.

1247 {
1248  if (aggstate->phase->grouped_cols)
1249  {
1250  Bitmapset *grouped_cols = aggstate->phase->grouped_cols[currentSet];
1251 
1252  aggstate->grouped_cols = grouped_cols;
1253 
1254  if (TTS_EMPTY(slot))
1255  {
1256  /*
1257  * Force all values to be NULL if working on an empty input tuple
1258  * (i.e. an empty grouping set for which no input rows were
1259  * supplied).
1260  */
1261  ExecStoreAllNullTuple(slot);
1262  }
1263  else if (aggstate->all_grouped_cols)
1264  {</