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 peraggs, AggStatePerGroup pergroup)
 
static TupleTableSlotproject_aggregates (AggState *aggstate)
 
static void find_cols (AggState *aggstate, Bitmapset **aggregated, Bitmapset **unaggregated)
 
static bool find_cols_walker (Node *node, FindColsContext *context)
 
static void build_hash_tables (AggState *aggstate)
 
static void build_hash_table (AggState *aggstate, int setno, long nbuckets)
 
static void hashagg_recompile_expressions (AggState *aggstate, bool minslot, bool nullcheck)
 
static long hash_choose_num_buckets (double hashentrysize, long ngroups, Size memory)
 
static int hash_choose_num_partitions (double input_groups, double hashentrysize, int used_bits, int *log2_npartitions)
 
static void initialize_hash_entry (AggState *aggstate, TupleHashTable hashtable, TupleHashEntry entry)
 
static void lookup_hash_entries (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_direct (AggState *aggstate)
 
static void agg_fill_hash_table (AggState *aggstate)
 
static bool agg_refill_hash_table (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_hash_table (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_hash_table_in_memory (AggState *aggstate)
 
static void hash_agg_check_limits (AggState *aggstate)
 
static void hash_agg_enter_spill_mode (AggState *aggstate)
 
static void hash_agg_update_metrics (AggState *aggstate, bool from_tape, int npartitions)
 
static void hashagg_finish_initial_spills (AggState *aggstate)
 
static void hashagg_reset_spill_state (AggState *aggstate)
 
static HashAggBatchhashagg_batch_new (LogicalTape *input_tape, int setno, int64 input_tuples, double input_card, int used_bits)
 
static MinimalTuple hashagg_batch_read (HashAggBatch *batch, uint32 *hashp)
 
static void hashagg_spill_init (HashAggSpill *spill, LogicalTapeSet *tapeset, int used_bits, double input_groups, double hashentrysize)
 
static Size hashagg_spill_tuple (AggState *aggstate, HashAggSpill *spill, TupleTableSlot *inputslot, uint32 hash)
 
static void hashagg_spill_finish (AggState *aggstate, HashAggSpill *spill, int setno)
 
static Datum GetAggInitVal (Datum textInitVal, Oid transtype)
 
static void build_pertrans_for_aggref (AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid transfn_oid, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
 
static void initialize_aggregate (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void find_hash_columns (AggState *aggstate)
 
Size hash_agg_entry_size (int numTrans, Size tupleWidth, Size transitionSpace)
 
void hash_agg_set_limits (double hashentrysize, double input_groups, int used_bits, Size *mem_limit, uint64 *ngroups_limit, int *num_partitions)
 
static TupleTableSlotExecAgg (PlanState *pstate)
 
AggStateExecInitAgg (Agg *node, EState *estate, int eflags)
 
void ExecEndAgg (AggState *node)
 
void ExecReScanAgg (AggState *node)
 
int AggCheckCallContext (FunctionCallInfo fcinfo, MemoryContext *aggcontext)
 
AggrefAggGetAggref (FunctionCallInfo fcinfo)
 
MemoryContext AggGetTempMemoryContext (FunctionCallInfo fcinfo)
 
bool AggStateIsShared (FunctionCallInfo fcinfo)
 
void AggRegisterCallback (FunctionCallInfo fcinfo, ExprContextCallbackFunction func, Datum arg)
 
void ExecAggEstimate (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeDSM (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeWorker (AggState *node, ParallelWorkerContext *pwcxt)
 
void ExecAggRetrieveInstrumentation (AggState *node)
 

Macro Definition Documentation

◆ CHUNKHDRSZ

#define CHUNKHDRSZ   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 819 of file nodeAgg.c.

820 {
821  bool dummynull;
822 
824  aggstate->tmpcontext,
825  &dummynull);
826 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:346
ExprState * evaltrans
Definition: nodeAgg.h:291
AggStatePerPhase phase
Definition: execnodes.h:2371
ExprContext * tmpcontext
Definition: execnodes.h:2378

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

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

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

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

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

2588 {
2589  HashAggBatch *batch;
2590  AggStatePerHash perhash;
2591  HashAggSpill spill;
2592  LogicalTapeSet *tapeset = aggstate->hash_tapeset;
2593  bool spill_initialized = false;
2594 
2595  if (aggstate->hash_batches == NIL)
2596  return false;
2597 
2598  /* hash_batches is a stack, with the top item at the end of the list */
2599  batch = llast(aggstate->hash_batches);
2600  aggstate->hash_batches = list_delete_last(aggstate->hash_batches);
2601 
2602  hash_agg_set_limits(aggstate->hashentrysize, batch->input_card,
2603  batch->used_bits, &aggstate->hash_mem_limit,
2604  &aggstate->hash_ngroups_limit, NULL);
2605 
2606  /*
2607  * Each batch only processes one grouping set; set the rest to NULL so
2608  * that advance_aggregates() knows to ignore them. We don't touch
2609  * pergroups for sorted grouping sets here, because they will be needed if
2610  * we rescan later. The expressions for sorted grouping sets will not be
2611  * evaluated after we recompile anyway.
2612  */
2613  MemSet(aggstate->hash_pergroup, 0,
2614  sizeof(AggStatePerGroup) * aggstate->num_hashes);
2615 
2616  /* free memory and reset hash tables */
2617  ReScanExprContext(aggstate->hashcontext);
2618  for (int setno = 0; setno < aggstate->num_hashes; setno++)
2619  ResetTupleHashTable(aggstate->perhash[setno].hashtable);
2620 
2621  aggstate->hash_ngroups_current = 0;
2622 
2623  /*
2624  * In AGG_MIXED mode, hash aggregation happens in phase 1 and the output
2625  * happens in phase 0. So, we switch to phase 1 when processing a batch,
2626  * and back to phase 0 after the batch is done.
2627  */
2628  Assert(aggstate->current_phase == 0);
2629  if (aggstate->phase->aggstrategy == AGG_MIXED)
2630  {
2631  aggstate->current_phase = 1;
2632  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2633  }
2634 
2635  select_current_set(aggstate, batch->setno, true);
2636 
2637  perhash = &aggstate->perhash[aggstate->current_set];
2638 
2639  /*
2640  * Spilled tuples are always read back as MinimalTuples, which may be
2641  * different from the outer plan, so recompile the aggregate expressions.
2642  *
2643  * We still need the NULL check, because we are only processing one
2644  * grouping set at a time and the rest will be NULL.
2645  */
2646  hashagg_recompile_expressions(aggstate, true, true);
2647 
2648  for (;;)
2649  {
2650  TupleTableSlot *spillslot = aggstate->hash_spill_rslot;
2651  TupleTableSlot *hashslot = perhash->hashslot;
2652  TupleHashEntry entry;
2653  MinimalTuple tuple;
2654  uint32 hash;
2655  bool isnew = false;
2656  bool *p_isnew = aggstate->hash_spill_mode ? NULL : &isnew;
2657 
2659 
2660  tuple = hashagg_batch_read(batch, &hash);
2661  if (tuple == NULL)
2662  break;
2663 
2664  ExecStoreMinimalTuple(tuple, spillslot, true);
2665  aggstate->tmpcontext->ecxt_outertuple = spillslot;
2666 
2667  prepare_hash_slot(perhash,
2668  aggstate->tmpcontext->ecxt_outertuple,
2669  hashslot);
2670  entry = LookupTupleHashEntryHash(perhash->hashtable, hashslot,
2671  p_isnew, hash);
2672 
2673  if (entry != NULL)
2674  {
2675  if (isnew)
2676  initialize_hash_entry(aggstate, perhash->hashtable, entry);
2677  aggstate->hash_pergroup[batch->setno] = entry->additional;
2678  advance_aggregates(aggstate);
2679  }
2680  else
2681  {
2682  if (!spill_initialized)
2683  {
2684  /*
2685  * Avoid initializing the spill until we actually need it so
2686  * that we don't assign tapes that will never be used.
2687  */
2688  spill_initialized = true;
2689  hashagg_spill_init(&spill, tapeset, batch->used_bits,
2690  batch->input_card, aggstate->hashentrysize);
2691  }
2692  /* no memory for a new group, spill */
2693  hashagg_spill_tuple(aggstate, &spill, spillslot, hash);
2694 
2695  aggstate->hash_pergroup[batch->setno] = NULL;
2696  }
2697 
2698  /*
2699  * Reset per-input-tuple context after each tuple, but note that the
2700  * hash lookups do this too
2701  */
2702  ResetExprContext(aggstate->tmpcontext);
2703  }
2704 
2705  LogicalTapeClose(batch->input_tape);
2706 
2707  /* change back to phase 0 */
2708  aggstate->current_phase = 0;
2709  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2710 
2711  if (spill_initialized)
2712  {
2713  hashagg_spill_finish(aggstate, &spill, batch->setno);
2714  hash_agg_update_metrics(aggstate, true, spill.npartitions);
2715  }
2716  else
2717  hash_agg_update_metrics(aggstate, true, 0);
2718 
2719  aggstate->hash_spill_mode = false;
2720 
2721  /* prepare to walk the first hash table */
2722  select_current_set(aggstate, batch->setno, true);
2723  ResetTupleHashIterator(aggstate->perhash[batch->setno].hashtable,
2724  &aggstate->perhash[batch->setno].hashiter);
2725 
2726  pfree(batch);
2727 
2728  return true;
2729 }
unsigned int uint32
Definition: c.h:490
#define MemSet(start, val, len)
Definition: c.h:1004
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:1447
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:446
Assert(fmt[strlen(fmt) - 1] !='\n')
List * list_delete_last(List *list)
Definition: list.c:956
void LogicalTapeClose(LogicalTape *lt)
Definition: logtape.c:733
void pfree(void *pointer)
Definition: mcxt.c:1436
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
static void initialize_hash_entry(AggState *aggstate, TupleHashTable hashtable, TupleHashEntry entry)
Definition: nodeAgg.c:2038
static void hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
Definition: nodeAgg.c:3086
static MinimalTuple hashagg_batch_read(HashAggBatch *batch, uint32 *hashp)
Definition: nodeAgg.c:3003
static void hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
Definition: nodeAgg.c:1910
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1734
static void prepare_hash_slot(AggStatePerHash perhash, TupleTableSlot *inputslot, TupleTableSlot *hashslot)
Definition: nodeAgg.c:1197
static Size hashagg_spill_tuple(AggState *aggstate, HashAggSpill *spill, TupleTableSlot *inputslot, uint32 hash)
Definition: nodeAgg.c:2918
static void hashagg_spill_init(HashAggSpill *spill, LogicalTapeSet *tapeset, int used_bits, double input_groups, double hashentrysize)
Definition: nodeAgg.c:2887
void hash_agg_set_limits(double hashentrysize, double input_groups, int used_bits, Size *mem_limit, uint64 *ngroups_limit, int *num_partitions)
Definition: nodeAgg.c:1791
@ AGG_MIXED
Definition: nodes.h:365
#define llast(l)
Definition: pg_list.h:198
#define NIL
Definition: pg_list.h:68
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715
TupleTableSlot * hashslot
Definition: nodeAgg.h:313
AggStrategy aggstrategy
Definition: nodeAgg.h:282
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2429
Size hash_mem_limit
Definition: execnodes.h:2417
int current_set
Definition: execnodes.h:2388
struct LogicalTapeSet * hash_tapeset
Definition: execnodes.h:2408
ExprContext * hashcontext
Definition: execnodes.h:2376
uint64 hash_ngroups_limit
Definition: execnodes.h:2418
AggStatePerPhase phases
Definition: execnodes.h:2396
bool hash_spill_mode
Definition: execnodes.h:2415
double hashentrysize
Definition: execnodes.h:2421
uint64 hash_ngroups_current
Definition: execnodes.h:2423
int num_hashes
Definition: execnodes.h:2406
List * hash_batches
Definition: execnodes.h:2413
TupleTableSlot * hash_spill_rslot
Definition: execnodes.h:2411
int current_phase
Definition: execnodes.h:2373
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 2187 of file nodeAgg.c.

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

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

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

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

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

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

4515 {
4516  if (fcinfo->context && IsA(fcinfo->context, AggState))
4517  {
4518  if (aggcontext)
4519  {
4520  AggState *aggstate = ((AggState *) fcinfo->context);
4521  ExprContext *cxt = aggstate->curaggcontext;
4522 
4523  *aggcontext = cxt->ecxt_per_tuple_memory;
4524  }
4525  return AGG_CONTEXT_AGGREGATE;
4526  }
4527  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4528  {
4529  if (aggcontext)
4530  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4531  return AGG_CONTEXT_WINDOW;
4532  }
4533 
4534  /* this is just to prevent "uninitialized variable" warnings */
4535  if (aggcontext)
4536  *aggcontext = NULL;
4537  return 0;
4538 }
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:762
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:761
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
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_combine(), array_agg_array_deserialize(), array_agg_array_finalfn(), array_agg_array_serialize(), array_agg_array_transfn(), array_agg_combine(), array_agg_deserialize(), array_agg_finalfn(), array_agg_serialize(), array_agg_transfn(), bytea_string_agg_finalfn(), 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(), string_agg_combine(), string_agg_deserialize(), string_agg_finalfn(), and string_agg_serialize().

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4558 of file nodeAgg.c.

4559 {
4560  if (fcinfo->context && IsA(fcinfo->context, AggState))
4561  {
4562  AggState *aggstate = (AggState *) fcinfo->context;
4563  AggStatePerAgg curperagg;
4564  AggStatePerTrans curpertrans;
4565 
4566  /* check curperagg (valid when in a final function) */
4567  curperagg = aggstate->curperagg;
4568 
4569  if (curperagg)
4570  return curperagg->aggref;
4571 
4572  /* check curpertrans (valid when in a transition function) */
4573  curpertrans = aggstate->curpertrans;
4574 
4575  if (curpertrans)
4576  return curpertrans->aggref;
4577  }
4578  return NULL;
4579 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Aggref * aggref
Definition: nodeAgg.h:44
AggStatePerAgg curperagg
Definition: execnodes.h:2381

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

4593 {
4594  if (fcinfo->context && IsA(fcinfo->context, AggState))
4595  {
4596  AggState *aggstate = (AggState *) fcinfo->context;
4597 
4598  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4599  }
4600  return NULL;
4601 }

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

◆ AggRegisterCallback()

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

Definition at line 4657 of file nodeAgg.c.

4660 {
4661  if (fcinfo->context && IsA(fcinfo->context, AggState))
4662  {
4663  AggState *aggstate = (AggState *) fcinfo->context;
4664  ExprContext *cxt = aggstate->curaggcontext;
4665 
4666  RegisterExprContextCallback(cxt, func, arg);
4667 
4668  return;
4669  }
4670  elog(ERROR, "aggregate function cannot register a callback in this context");
4671 }
#define ERROR
Definition: elog.h:39
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:928
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 4618 of file nodeAgg.c.

4619 {
4620  if (fcinfo->context && IsA(fcinfo->context, AggState))
4621  {
4622  AggState *aggstate = (AggState *) fcinfo->context;
4623  AggStatePerAgg curperagg;
4624  AggStatePerTrans curpertrans;
4625 
4626  /* check curperagg (valid when in a final function) */
4627  curperagg = aggstate->curperagg;
4628 
4629  if (curperagg)
4630  return aggstate->pertrans[curperagg->transno].aggshared;
4631 
4632  /* check curpertrans (valid when in a transition function) */
4633  curpertrans = aggstate->curpertrans;
4634 
4635  if (curpertrans)
4636  return curpertrans->aggshared;
4637  }
4638  return true;
4639 }
AggStatePerTrans pertrans
Definition: execnodes.h:2375

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

1497 {
1498  AggStatePerHash perhash = &aggstate->perhash[setno];
1499  MemoryContext metacxt = aggstate->hash_metacxt;
1500  MemoryContext hashcxt = aggstate->hashcontext->ecxt_per_tuple_memory;
1501  MemoryContext tmpcxt = aggstate->tmpcontext->ecxt_per_tuple_memory;
1502  Size additionalsize;
1503 
1504  Assert(aggstate->aggstrategy == AGG_HASHED ||
1505  aggstate->aggstrategy == AGG_MIXED);
1506 
1507  /*
1508  * Used to make sure initial hash table allocation does not exceed
1509  * hash_mem. Note that the estimate does not include space for
1510  * pass-by-reference transition data values, nor for the representative
1511  * tuple of each group.
1512  */
1513  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1514 
1515  perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
1516  perhash->hashslot->tts_tupleDescriptor,
1517  perhash->numCols,
1518  perhash->hashGrpColIdxHash,
1519  perhash->eqfuncoids,
1520  perhash->hashfunctions,
1521  perhash->aggnode->grpCollations,
1522  nbuckets,
1523  additionalsize,
1524  metacxt,
1525  hashcxt,
1526  tmpcxt,
1527  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1528 }
size_t Size
Definition: c.h:589
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:394
@ AGG_HASHED
Definition: nodes.h:364
FmgrInfo * hashfunctions
Definition: nodeAgg.h:314
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:320
MemoryContext hash_metacxt
Definition: execnodes.h:2407
int numtrans
Definition: execnodes.h:2368
AggSplit aggsplit
Definition: execnodes.h:2370

References AGG_HASHED, AGG_MIXED, AggStatePerHashData::aggnode, AggState::aggsplit, AggState::aggstrategy, Assert(), BuildTupleHashTableExt(), DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_per_tuple_memory, AggStatePerHashData::eqfuncoids, 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 1461 of file nodeAgg.c.

1462 {
1463  int setno;
1464 
1465  for (setno = 0; setno < aggstate->num_hashes; ++setno)
1466  {
1467  AggStatePerHash perhash = &aggstate->perhash[setno];
1468  long nbuckets;
1469  Size memory;
1470 
1471  if (perhash->hashtable != NULL)
1472  {
1473  ResetTupleHashTable(perhash->hashtable);
1474  continue;
1475  }
1476 
1477  Assert(perhash->aggnode->numGroups > 0);
1478 
1479  memory = aggstate->hash_mem_limit / aggstate->num_hashes;
1480 
1481  /* choose reasonable number of buckets per hashtable */
1482  nbuckets = hash_choose_num_buckets(aggstate->hashentrysize,
1483  perhash->aggnode->numGroups,
1484  memory);
1485 
1486  build_hash_table(aggstate, setno, nbuckets);
1487  }
1488 
1489  aggstate->hash_ngroups_current = 0;
1490 }
static long hash_choose_num_buckets(double hashentrysize, long ngroups, Size memory)
Definition: nodeAgg.c:1959
static void build_hash_table(AggState *aggstate, int setno, long nbuckets)
Definition: nodeAgg.c:1496
long numGroups
Definition: plannodes.h:1018

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

4038 {
4039  int numGroupingSets = Max(aggstate->maxsets, 1);
4040  Expr *transfnexpr;
4041  int numTransArgs;
4042  Expr *serialfnexpr = NULL;
4043  Expr *deserialfnexpr = NULL;
4044  ListCell *lc;
4045  int numInputs;
4046  int numDirectArgs;
4047  List *sortlist;
4048  int numSortCols;
4049  int numDistinctCols;
4050  int i;
4051 
4052  /* Begin filling in the pertrans data */
4053  pertrans->aggref = aggref;
4054  pertrans->aggshared = false;
4055  pertrans->aggCollation = aggref->inputcollid;
4056  pertrans->transfn_oid = transfn_oid;
4057  pertrans->serialfn_oid = aggserialfn;
4058  pertrans->deserialfn_oid = aggdeserialfn;
4059  pertrans->initValue = initValue;
4060  pertrans->initValueIsNull = initValueIsNull;
4061 
4062  /* Count the "direct" arguments, if any */
4063  numDirectArgs = list_length(aggref->aggdirectargs);
4064 
4065  /* Count the number of aggregated input columns */
4066  pertrans->numInputs = numInputs = list_length(aggref->args);
4067 
4068  pertrans->aggtranstype = aggtranstype;
4069 
4070  /* account for the current transition state */
4071  numTransArgs = pertrans->numTransInputs + 1;
4072 
4073  /*
4074  * Set up infrastructure for calling the transfn. Note that invtrans is
4075  * not needed here.
4076  */
4077  build_aggregate_transfn_expr(inputTypes,
4078  numArguments,
4079  numDirectArgs,
4080  aggref->aggvariadic,
4081  aggtranstype,
4082  aggref->inputcollid,
4083  transfn_oid,
4084  InvalidOid,
4085  &transfnexpr,
4086  NULL);
4087 
4088  fmgr_info(transfn_oid, &pertrans->transfn);
4089  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
4090 
4091  pertrans->transfn_fcinfo =
4094  &pertrans->transfn,
4095  numTransArgs,
4096  pertrans->aggCollation,
4097  (void *) aggstate, NULL);
4098 
4099  /* get info about the state value's datatype */
4100  get_typlenbyval(aggtranstype,
4101  &pertrans->transtypeLen,
4102  &pertrans->transtypeByVal);
4103 
4104  if (OidIsValid(aggserialfn))
4105  {
4106  build_aggregate_serialfn_expr(aggserialfn,
4107  &serialfnexpr);
4108  fmgr_info(aggserialfn, &pertrans->serialfn);
4109  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
4110 
4111  pertrans->serialfn_fcinfo =
4114  &pertrans->serialfn,
4115  1,
4116  InvalidOid,
4117  (void *) aggstate, NULL);
4118  }
4119 
4120  if (OidIsValid(aggdeserialfn))
4121  {
4122  build_aggregate_deserialfn_expr(aggdeserialfn,
4123  &deserialfnexpr);
4124  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
4125  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
4126 
4127  pertrans->deserialfn_fcinfo =
4130  &pertrans->deserialfn,
4131  2,
4132  InvalidOid,
4133  (void *) aggstate, NULL);
4134  }
4135 
4136  /*
4137  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
4138  * have a list of SortGroupClause nodes; fish out the data in them and
4139  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
4140  * however; the agg's transfn and finalfn are responsible for that.
4141  *
4142  * When the planner has set the aggpresorted flag, the input to the
4143  * aggregate is already correctly sorted. For ORDER BY aggregates we can
4144  * simply treat these as normal aggregates. For presorted DISTINCT
4145  * aggregates an extra step must be added to remove duplicate consecutive
4146  * inputs.
4147  *
4148  * Note that by construction, if there is a DISTINCT clause then the ORDER
4149  * BY clause is a prefix of it (see transformDistinctClause).
4150  */
4151  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4152  {
4153  sortlist = NIL;
4154  numSortCols = numDistinctCols = 0;
4155  pertrans->aggsortrequired = false;
4156  }
4157  else if (aggref->aggpresorted && aggref->aggdistinct == NIL)
4158  {
4159  sortlist = NIL;
4160  numSortCols = numDistinctCols = 0;
4161  pertrans->aggsortrequired = false;
4162  }
4163  else if (aggref->aggdistinct)
4164  {
4165  sortlist = aggref->aggdistinct;
4166  numSortCols = numDistinctCols = list_length(sortlist);
4167  Assert(numSortCols >= list_length(aggref->aggorder));
4168  pertrans->aggsortrequired = !aggref->aggpresorted;
4169  }
4170  else
4171  {
4172  sortlist = aggref->aggorder;
4173  numSortCols = list_length(sortlist);
4174  numDistinctCols = 0;
4175  pertrans->aggsortrequired = (numSortCols > 0);
4176  }
4177 
4178  pertrans->numSortCols = numSortCols;
4179  pertrans->numDistinctCols = numDistinctCols;
4180 
4181  /*
4182  * If we have either sorting or filtering to do, create a tupledesc and
4183  * slot corresponding to the aggregated inputs (including sort
4184  * expressions) of the agg.
4185  */
4186  if (numSortCols > 0 || aggref->aggfilter)
4187  {
4188  pertrans->sortdesc = ExecTypeFromTL(aggref->args);
4189  pertrans->sortslot =
4190  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4192  }
4193 
4194  if (numSortCols > 0)
4195  {
4196  /*
4197  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
4198  * (yet)
4199  */
4200  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
4201 
4202  /* ORDER BY aggregates are not supported with partial aggregation */
4203  Assert(!DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
4204 
4205  /* If we have only one input, we need its len/byval info. */
4206  if (numInputs == 1)
4207  {
4208  get_typlenbyval(inputTypes[numDirectArgs],
4209  &pertrans->inputtypeLen,
4210  &pertrans->inputtypeByVal);
4211  }
4212  else if (numDistinctCols > 0)
4213  {
4214  /* we will need an extra slot to store prior values */
4215  pertrans->uniqslot =
4216  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4218  }
4219 
4220  /* Extract the sort information for use later */
4221  pertrans->sortColIdx =
4222  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
4223  pertrans->sortOperators =
4224  (Oid *) palloc(numSortCols * sizeof(Oid));
4225  pertrans->sortCollations =
4226  (Oid *) palloc(numSortCols * sizeof(Oid));
4227  pertrans->sortNullsFirst =
4228  (bool *) palloc(numSortCols * sizeof(bool));
4229 
4230  i = 0;
4231  foreach(lc, sortlist)
4232  {
4233  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
4234  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
4235 
4236  /* the parser should have made sure of this */
4237  Assert(OidIsValid(sortcl->sortop));
4238 
4239  pertrans->sortColIdx[i] = tle->resno;
4240  pertrans->sortOperators[i] = sortcl->sortop;
4241  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
4242  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
4243  i++;
4244  }
4245  Assert(i == numSortCols);
4246  }
4247 
4248  if (aggref->aggdistinct)
4249  {
4250  Oid *ops;
4251 
4252  Assert(numArguments > 0);
4253  Assert(list_length(aggref->aggdistinct) == numDistinctCols);
4254 
4255  ops = palloc(numDistinctCols * sizeof(Oid));
4256 
4257  i = 0;
4258  foreach(lc, aggref->aggdistinct)
4259  ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
4260 
4261  /* lookup / build the necessary comparators */
4262  if (numDistinctCols == 1)
4263  fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
4264  else
4265  pertrans->equalfnMulti =
4266  execTuplesMatchPrepare(pertrans->sortdesc,
4267  numDistinctCols,
4268  pertrans->sortColIdx,
4269  ops,
4270  pertrans->sortCollations,
4271  &aggstate->ss.ps);
4272  pfree(ops);
4273  }
4274 
4275  pertrans->sortstates = (Tuplesortstate **)
4276  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
4277 }
int16 AttrNumber
Definition: attnum.h:21
#define OidIsValid(objectId)
Definition: c.h:759
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:1832
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1939
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#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:2209
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1267
void * palloc0(Size size)
Definition: mcxt.c:1241
void * palloc(Size size)
Definition: mcxt.c:1210
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:783
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:393
void build_aggregate_deserialfn_expr(Oid deserialfn_oid, Expr **deserialfnexpr)
Definition: parse_agg.c:2098
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:2014
void build_aggregate_serialfn_expr(Oid serialfn_oid, Expr **serialfnexpr)
Definition: parse_agg.c:2075
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
bool * sortNullsFirst
Definition: nodeAgg.h:108
FmgrInfo serialfn
Definition: nodeAgg.h:89
FmgrInfo equalfnOne
Definition: nodeAgg.h:115
TupleDesc sortdesc
Definition: nodeAgg.h:143
TupleTableSlot * sortslot
Definition: nodeAgg.h:141
ExprState * equalfnMulti
Definition: nodeAgg.h:116
Tuplesortstate ** sortstates
Definition: nodeAgg.h:162
TupleTableSlot * uniqslot
Definition: nodeAgg.h:142
FmgrInfo deserialfn
Definition: nodeAgg.h:92
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:175
AttrNumber * sortColIdx
Definition: nodeAgg.h:105
FunctionCallInfo serialfn_fcinfo
Definition: nodeAgg.h:173
int maxsets
Definition: execnodes.h:2395
List * aggdistinct
Definition: primnodes.h:452
List * aggdirectargs
Definition: primnodes.h:443
List * args
Definition: primnodes.h:446
Expr * aggfilter
Definition: primnodes.h:455
List * aggorder
Definition: primnodes.h:449
Definition: pg_list.h:54
Definition: nodes.h:129
Expr * expr
Definition: primnodes.h:1842
AttrNumber resno
Definition: primnodes.h:1844
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:367

References AGG_HASHED, AGG_MIXED, AggStatePerTransData::aggCollation, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggorder, AggStatePerTransData::aggref, AggStatePerTransData::aggshared, AggStatePerTransData::aggsortrequired, AggState::aggsplit, AggState::aggstrategy, AggStatePerTransData::aggtranstype, Aggref::args, Assert(), build_aggregate_deserialfn_expr(), build_aggregate_serialfn_expr(), build_aggregate_transfn_expr(), AggStatePerTransData::deserialfn, AggStatePerTransData::deserialfn_fcinfo, AggStatePerTransData::deserialfn_oid, DO_AGGSPLIT_COMBINE, AggStatePerTransData::equalfnMulti, AggStatePerTransData::equalfnOne, ExecInitExtraTupleSlot(), execTuplesMatchPrepare(), ExecTypeFromTL(), TargetEntry::expr, exprCollation(), fmgr_info(), fmgr_info_set_expr, get_opcode(), get_sortgroupclause_tle(), get_typlenbyval(), i, InitFunctionCallInfoData, AggStatePerTransData::initValue, initValue(), AggStatePerTransData::initValueIsNull, AggStatePerTransData::inputtypeByVal, AggStatePerTransData::inputtypeLen, InvalidOid, lfirst, list_length(), Max, 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 2151 of file nodeAgg.c.

2152 {
2153  AggState *node = castNode(AggState, pstate);
2154  TupleTableSlot *result = NULL;
2155 
2157 
2158  if (!node->agg_done)
2159  {
2160  /* Dispatch based on strategy */
2161  switch (node->phase->aggstrategy)
2162  {
2163  case AGG_HASHED:
2164  if (!node->table_filled)
2165  agg_fill_hash_table(node);
2166  /* FALLTHROUGH */
2167  case AGG_MIXED:
2168  result = agg_retrieve_hash_table(node);
2169  break;
2170  case AGG_PLAIN:
2171  case AGG_SORTED:
2172  result = agg_retrieve_direct(node);
2173  break;
2174  }
2175 
2176  if (!TupIsNull(result))
2177  return result;
2178  }
2179 
2180  return NULL;
2181 }
static void agg_fill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2533
static TupleTableSlot * agg_retrieve_direct(AggState *aggstate)
Definition: nodeAgg.c:2187
@ AGG_SORTED
Definition: nodes.h:363
#define castNode(_type_, nodeptr)
Definition: nodes.h:197

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

4687 {
4688  Size size;
4689 
4690  /* don't need this if not instrumenting or no workers */
4691  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4692  return;
4693 
4694  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4695  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4696  shm_toc_estimate_chunk(&pcxt->estimator, size);
4697  shm_toc_estimate_keys(&pcxt->estimator, 1);
4698 }
#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:1045

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

Referenced by ExecParallelEstimate().

◆ ExecAggInitializeDSM()

void ExecAggInitializeDSM ( AggState node,
ParallelContext pcxt 
)

Definition at line 4707 of file nodeAgg.c.

4708 {
4709  Size size;
4710 
4711  /* don't need this if not instrumenting or no workers */
4712  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4713  return;
4714 
4715  size = offsetof(SharedAggInfo, sinstrument)
4716  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4717  node->shared_info = shm_toc_allocate(pcxt->toc, size);
4718  /* ensure any unfilled slots will contain zeroes */
4719  memset(node->shared_info, 0, size);
4720  node->shared_info->num_workers = pcxt->nworkers;
4721  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4722  node->shared_info);
4723 }
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:2437
shm_toc * toc
Definition: parallel.h:45
Plan * plan
Definition: execnodes.h:1035
int plan_node_id
Definition: plannodes.h:155

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

Referenced by ExecParallelInitializeDSM().

◆ ExecAggInitializeWorker()

void ExecAggInitializeWorker ( AggState node,
ParallelWorkerContext pwcxt 
)

Definition at line 4732 of file nodeAgg.c.

4733 {
4734  node->shared_info =
4735  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4736 }
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 4745 of file nodeAgg.c.

4746 {
4747  Size size;
4748  SharedAggInfo *si;
4749 
4750  if (node->shared_info == NULL)
4751  return;
4752 
4753  size = offsetof(SharedAggInfo, sinstrument)
4755  si = palloc(size);
4756  memcpy(si, node->shared_info, size);
4757  node->shared_info = si;
4758 }

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

Referenced by ExecParallelRetrieveInstrumentation().

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 4297 of file nodeAgg.c.

4298 {
4300  int transno;
4301  int numGroupingSets = Max(node->maxsets, 1);
4302  int setno;
4303 
4304  /*
4305  * When ending a parallel worker, copy the statistics gathered by the
4306  * worker back into shared memory so that it can be picked up by the main
4307  * process to report in EXPLAIN ANALYZE.
4308  */
4309  if (node->shared_info && IsParallelWorker())
4310  {
4312 
4313  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4316  si->hash_disk_used = node->hash_disk_used;
4317  si->hash_mem_peak = node->hash_mem_peak;
4318  }
4319 
4320  /* Make sure we have closed any open tuplesorts */
4321 
4322  if (node->sort_in)
4323  tuplesort_end(node->sort_in);
4324  if (node->sort_out)
4325  tuplesort_end(node->sort_out);
4326 
4328 
4329  if (node->hash_metacxt != NULL)
4330  {
4332  node->hash_metacxt = NULL;
4333  }
4334 
4335  for (transno = 0; transno < node->numtrans; transno++)
4336  {
4337  AggStatePerTrans pertrans = &node->pertrans[transno];
4338 
4339  for (setno = 0; setno < numGroupingSets; setno++)
4340  {
4341  if (pertrans->sortstates[setno])
4342  tuplesort_end(pertrans->sortstates[setno]);
4343  }
4344  }
4345 
4346  /* And ensure any agg shutdown callbacks have been called */
4347  for (setno = 0; setno < numGroupingSets; setno++)
4348  ReScanExprContext(node->aggcontexts[setno]);
4349  if (node->hashcontext)
4351 
4352  /*
4353  * We don't actually free any ExprContexts here (see comment in
4354  * ExecFreeExprContext), just unlinking the output one from the plan node
4355  * suffices.
4356  */
4357  ExecFreeExprContext(&node->ss.ps);
4358 
4359  /* clean up tuple table */
4361 
4362  outerPlan = outerPlanState(node);
4364 }
int ParallelWorkerNumber
Definition: parallel.c:113
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:557
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:658
#define outerPlanState(node)
Definition: execnodes.h:1131
#define IsParallelWorker()
Definition: parallel.h:61
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:387
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3126
#define outerPlan(node)
Definition: plannodes.h:186
Tuplesortstate * sort_out
Definition: execnodes.h:2398
uint64 hash_disk_used
Definition: execnodes.h:2425
Size hash_mem_peak
Definition: execnodes.h:2422
int hash_batches_used
Definition: execnodes.h:2426
Tuplesortstate * sort_in
Definition: execnodes.h:2397
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2341
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:972

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

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

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

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

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

References CHECK_FOR_INTERRUPTS, ExecProcNode(), 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 1048 of file nodeAgg.c.

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

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

Referenced by finalize_aggregates().

◆ finalize_aggregates()

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

Definition at line 1287 of file nodeAgg.c.

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

References AGG_HASHED, AGG_MIXED, AggStatePerTransData::aggsortrequired, AggState::aggsplit, AggState::aggstrategy, Assert(), DatumGetPointer(), DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecClearTuple(), finalize_aggregate(), finalize_partialaggregate(), AggStatePerTransData::haslast, AggStatePerTransData::inputtypeByVal, AggStatePerTransData::lastdatum, AggStatePerTransData::lastisnull, AggState::numaggs, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numInputs, AggState::numtrans, AggState::pertrans, pfree(), process_ordered_aggregate_multi(), process_ordered_aggregate_single(), ScanState::ps, PlanState::ps_ExprContext, AggState::ss, AggStatePerAggData::transno, and AggStatePerTransData::uniqslot.

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table_in_memory().

◆ finalize_partialaggregate()

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

Definition at line 1143 of file nodeAgg.c.

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

References FunctionCallInfoBaseData::args, ExprContext::ecxt_per_tuple_memory, FmgrInfo::fn_strict, FunctionCallInvoke, FunctionCallInfoBaseData::isnull, NullableDatum::isnull, MakeExpandedObjectReadOnly, MemoryContextSwitchTo(), OidIsValid, AggState::pertrans, ScanState::ps, PlanState::ps_ExprContext, 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 1390 of file nodeAgg.c.

1391 {
1392  Agg *agg = (Agg *) aggstate->ss.ps.plan;
1393  FindColsContext context;
1394 
1395  context.is_aggref = false;
1396  context.aggregated = NULL;
1397  context.unaggregated = NULL;
1398 
1399  /* Examine tlist and quals */
1400  (void) find_cols_walker((Node *) agg->plan.targetlist, &context);
1401  (void) find_cols_walker((Node *) agg->plan.qual, &context);
1402 
1403  /* In some cases, grouping columns will not appear in the tlist */
1404  for (int i = 0; i < agg->numCols; i++)
1405  context.unaggregated = bms_add_member(context.unaggregated,
1406  agg->grpColIdx[i]);
1407 
1408  *aggregated = context.aggregated;
1409  *unaggregated = context.unaggregated;
1410 }
static bool find_cols_walker(Node *node, FindColsContext *context)
Definition: nodeAgg.c:1413
bool is_aggref
Definition: nodeAgg.c:363
List * targetlist
Definition: plannodes.h:156

References bms_add_member(), find_cols_walker(), 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 1413 of file nodeAgg.c.

1414 {
1415  if (node == NULL)
1416  return false;
1417  if (IsA(node, Var))
1418  {
1419  Var *var = (Var *) node;
1420 
1421  /* setrefs.c should have set the varno to OUTER_VAR */
1422  Assert(var->varno == OUTER_VAR);
1423  Assert(var->varlevelsup == 0);
1424  if (context->is_aggref)
1425  context->aggregated = bms_add_member(context->aggregated,
1426  var->varattno);
1427  else
1428  context->unaggregated = bms_add_member(context->unaggregated,
1429  var->varattno);
1430  return false;
1431  }
1432  if (IsA(node, Aggref))
1433  {
1434  Assert(!context->is_aggref);
1435  context->is_aggref = true;
1436  expression_tree_walker(node, find_cols_walker, (void *) context);
1437  context->is_aggref = false;
1438  return false;
1439  }
1441  (void *) context);
1442 }
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151
#define OUTER_VAR
Definition: primnodes.h:215
Bitmapset * aggregated
Definition: nodeAgg.c:364
Bitmapset * unaggregated
Definition: nodeAgg.c:365
Definition: primnodes.h:226
AttrNumber varattno
Definition: primnodes.h:238
int varno
Definition: primnodes.h:233
Index varlevelsup
Definition: primnodes.h:258

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

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

References AggStatePerHashData::aggnode, AggState::all_cols_needed, AggState::all_grouped_cols, attnum, bms_add_member(), bms_copy(), bms_del_member(), bms_free(), bms_is_member(), bms_next_member(), bms_num_members(), bms_union(), AggState::colnos_needed, AggStatePerHashData::eqfuncoids, EState::es_tupleTable, ExecAllocTableSlot(), execTuplesHashPrepare(), ExecTypeFromTL(), find_cols(), AggStatePerPhaseData::grouped_cols, 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 4281 of file nodeAgg.c.

4282 {
4283  Oid typinput,
4284  typioparam;
4285  char *strInitVal;
4286  Datum initVal;
4287 
4288  getTypeInputInfo(transtype, &typinput, &typioparam);
4289  strInitVal = TextDatumGetCString(textInitVal);
4290  initVal = OidInputFunctionCall(typinput, strInitVal,
4291  typioparam, -1);
4292  pfree(strInitVal);
4293  return initVal;
4294 }
#define TextDatumGetCString(d)
Definition: builtins.h:95
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1726
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2832

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

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

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

1876 {
1877  aggstate->hash_spill_mode = true;
1878  hashagg_recompile_expressions(aggstate, aggstate->table_filled, true);
1879 
1880  if (!aggstate->hash_ever_spilled)
1881  {
1882  Assert(aggstate->hash_tapeset == NULL);
1883  Assert(aggstate->hash_spills == NULL);
1884 
1885  aggstate->hash_ever_spilled = true;
1886 
1887  aggstate->hash_tapeset = LogicalTapeSetCreate(true, NULL, -1);
1888 
1889  aggstate->hash_spills = palloc(sizeof(HashAggSpill) * aggstate->num_hashes);
1890 
1891  for (int setno = 0; setno < aggstate->num_hashes; setno++)
1892  {
1893  AggStatePerHash perhash = &aggstate->perhash[setno];
1894  HashAggSpill *spill = &aggstate->hash_spills[setno];
1895 
1896  hashagg_spill_init(spill, aggstate->hash_tapeset, 0,
1897  perhash->aggnode->numGroups,
1898  aggstate->hashentrysize);
1899  }
1900  }
1901 }
LogicalTapeSet * LogicalTapeSetCreate(bool preallocate, SharedFileSet *fileset, int worker)
Definition: logtape.c:556
struct HashAggSpill * hash_spills
Definition: execnodes.h:2409

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

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

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

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

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

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  ngroups,
Size  memory 
)
static

Definition at line 1959 of file nodeAgg.c.

1960 {
1961  long max_nbuckets;
1962  long nbuckets = ngroups;
1963 
1964  max_nbuckets = memory / hashentrysize;
1965 
1966  /*
1967  * Underestimating is better than overestimating. Too many buckets crowd
1968  * out space for group keys and transition state values.
1969  */
1970  max_nbuckets >>= 1;
1971 
1972  if (nbuckets > max_nbuckets)
1973  nbuckets = max_nbuckets;
1974 
1975  return Max(nbuckets, 1);
1976 }

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_npartitions 
)
static

Definition at line 1984 of file nodeAgg.c.

1986 {
1987  Size hash_mem_limit = get_hash_memory_limit();
1988  double partition_limit;
1989  double mem_wanted;
1990  double dpartitions;
1991  int npartitions;
1992  int partition_bits;
1993 
1994  /*
1995  * Avoid creating so many partitions that the memory requirements of the
1996  * open partition files are greater than 1/4 of hash_mem.
1997  */
1998  partition_limit =
1999  (hash_mem_limit * 0.25 - HASHAGG_READ_BUFFER_SIZE) /
2001 
2002  mem_wanted = HASHAGG_PARTITION_FACTOR * input_groups * hashentrysize;
2003 
2004  /* make enough partitions so that each one is likely to fit in memory */
2005  dpartitions = 1 + (mem_wanted / hash_mem_limit);
2006 
2007  if (dpartitions > partition_limit)
2008  dpartitions = partition_limit;
2009 
2010  if (dpartitions < HASHAGG_MIN_PARTITIONS)
2011  dpartitions = HASHAGG_MIN_PARTITIONS;
2012  if (dpartitions > HASHAGG_MAX_PARTITIONS)
2013  dpartitions = HASHAGG_MAX_PARTITIONS;
2014 
2015  /* HASHAGG_MAX_PARTITIONS limit makes this safe */
2016  npartitions = (int) dpartitions;
2017 
2018  /* ceil(log2(npartitions)) */
2019  partition_bits = my_log2(npartitions);
2020 
2021  /* make sure that we don't exhaust the hash bits */
2022  if (partition_bits + used_bits >= 32)
2023  partition_bits = 32 - used_bits;
2024 
2025  if (log2_npartitions != NULL)
2026  *log2_npartitions = partition_bits;
2027 
2028  /* number of partitions will be a power of two */
2029  npartitions = 1 << partition_bits;
2030 
2031  return npartitions;
2032 }
int my_log2(long num)
Definition: dynahash.c:1760
#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 2984 of file nodeAgg.c.

2986 {
2987  HashAggBatch *batch = palloc0(sizeof(HashAggBatch));
2988 
2989  batch->setno = setno;
2990  batch->used_bits = used_bits;
2991  batch->input_tape = input_tape;
2992  batch->input_tuples = input_tuples;
2993  batch->input_card = input_card;
2994 
2995  return batch;
2996 }
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 3003 of file nodeAgg.c.

3004 {
3005  LogicalTape *tape = batch->input_tape;
3006  MinimalTuple tuple;
3007  uint32 t_len;
3008  size_t nread;
3009  uint32 hash;
3010 
3011  nread = LogicalTapeRead(tape, &hash, sizeof(uint32));
3012  if (nread == 0)
3013  return NULL;
3014  if (nread != sizeof(uint32))
3015  ereport(ERROR,
3017  errmsg("unexpected EOF for tape %p: requested %zu bytes, read %zu bytes",
3018  tape, sizeof(uint32), nread)));
3019  if (hashp != NULL)
3020  *hashp = hash;
3021 
3022  nread = LogicalTapeRead(tape, &t_len, sizeof(t_len));
3023  if (nread != sizeof(uint32))
3024  ereport(ERROR,
3026  errmsg("unexpected EOF for tape %p: requested %zu bytes, read %zu bytes",
3027  tape, sizeof(uint32), nread)));
3028 
3029  tuple = (MinimalTuple) palloc(t_len);
3030  tuple->t_len = t_len;
3031 
3032  nread = LogicalTapeRead(tape,
3033  (char *) tuple + sizeof(uint32),
3034  t_len - sizeof(uint32));
3035  if (nread != t_len - sizeof(uint32))
3036  ereport(ERROR,
3038  errmsg("unexpected EOF for tape %p: requested %zu bytes, read %zu bytes",
3039  tape, t_len - sizeof(uint32), nread)));
3040 
3041  return tuple;
3042 }
int errcode_for_file_access(void)
Definition: elog.c:881
MinimalTupleData * MinimalTuple
Definition: htup.h:27
size_t LogicalTapeRead(LogicalTape *lt, void *ptr, size_t size)
Definition: logtape.c:928

References ereport, errcode_for_file_access(), errmsg(), 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 3052 of file nodeAgg.c.

3053 {
3054  int setno;
3055  int total_npartitions = 0;
3056 
3057  if (aggstate->hash_spills != NULL)
3058  {
3059  for (setno = 0; setno < aggstate->num_hashes; setno++)
3060  {
3061  HashAggSpill *spill = &aggstate->hash_spills[setno];
3062 
3063  total_npartitions += spill->npartitions;
3064  hashagg_spill_finish(aggstate, spill, setno);
3065  }
3066 
3067  /*
3068  * We're not processing tuples from outer plan any more; only
3069  * processing batches of spilled tuples. The initial spill structures
3070  * are no longer needed.
3071  */
3072  pfree(aggstate->hash_spills);
3073  aggstate->hash_spills = NULL;
3074  }
3075 
3076  hash_agg_update_metrics(aggstate, false, total_npartitions);
3077  aggstate->hash_spill_mode = false;
3078 }

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

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

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

3127 {
3128  /* free spills from initial pass */
3129  if (aggstate->hash_spills != NULL)
3130  {
3131  int setno;
3132 
3133  for (setno = 0; setno < aggstate->num_hashes; setno++)
3134  {
3135  HashAggSpill *spill = &aggstate->hash_spills[setno];
3136 
3137  pfree(spill->ntuples);
3138  pfree(spill->partitions);
3139  }
3140  pfree(aggstate->hash_spills);
3141  aggstate->hash_spills = NULL;
3142  }
3143 
3144  /* free batches */
3145  list_free_deep(aggstate->hash_batches);
3146  aggstate->hash_batches = NIL;
3147 
3148  /* close tape set */
3149  if (aggstate->hash_tapeset != NULL)
3150  {
3151  LogicalTapeSetClose(aggstate->hash_tapeset);
3152  aggstate->hash_tapeset = NULL;
3153  }
3154 }
void list_free_deep(List *list)
Definition: list.c:1559
void LogicalTapeSetClose(LogicalTapeSet *lts)
Definition: logtape.c:667
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 3086 of file nodeAgg.c.

3087 {
3088  int i;
3089  int used_bits = 32 - spill->shift;
3090 
3091  if (spill->npartitions == 0)
3092  return; /* didn't spill */
3093 
3094  for (i = 0; i < spill->npartitions; i++)
3095  {
3096  LogicalTape *tape = spill->partitions[i];
3097  HashAggBatch *new_batch;
3098  double cardinality;
3099 
3100  /* if the partition is empty, don't create a new batch of work */
3101  if (spill->ntuples[i] == 0)
3102  continue;
3103 
3104  cardinality = estimateHyperLogLog(&spill->hll_card[i]);
3105  freeHyperLogLog(&spill->hll_card[i]);
3106 
3107  /* rewinding frees the buffer while not in use */
3109 
3110  new_batch = hashagg_batch_new(tape, setno,
3111  spill->ntuples[i], cardinality,
3112  used_bits);
3113  aggstate->hash_batches = lappend(aggstate->hash_batches, new_batch);
3114  aggstate->hash_batches_used++;
3115  }
3116 
3117  pfree(spill->ntuples);
3118  pfree(spill->hll_card);
3119  pfree(spill->partitions);
3120 }
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:846
static HashAggBatch * hashagg_batch_new(LogicalTape *input_tape, int setno, int64 input_tuples, double input_card, int used_bits)
Definition: nodeAgg.c:2984
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 tapeset,
int  used_bits,
double  input_groups,
double  hashentrysize 
)
static

Definition at line 2887 of file nodeAgg.c.

2889 {
2890  int npartitions;
2891  int partition_bits;
2892 
2893  npartitions = hash_choose_num_partitions(input_groups, hashentrysize,
2894  used_bits, &partition_bits);
2895 
2896  spill->partitions = palloc0(sizeof(LogicalTape *) * npartitions);
2897  spill->ntuples = palloc0(sizeof(int64) * npartitions);
2898  spill->hll_card = palloc0(sizeof(hyperLogLogState) * npartitions);
2899 
2900  for (int i = 0; i < npartitions; i++)
2901  spill->partitions[i] = LogicalTapeCreate(tapeset);
2902 
2903  spill->shift = 32 - used_bits - partition_bits;
2904  spill->mask = (npartitions - 1) << spill->shift;
2905  spill->npartitions = npartitions;
2906 
2907  for (int i = 0; i < npartitions; i++)
2909 }
void initHyperLogLog(hyperLogLogState *cState, uint8 bwidth)
Definition: hyperloglog.c:66
LogicalTape * LogicalTapeCreate(LogicalTapeSet *lts)
Definition: logtape.c:680
#define HASHAGG_HLL_BIT_WIDTH
Definition: nodeAgg.c: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 inputslot,
uint32  hash 
)
static

Definition at line 2918 of file nodeAgg.c.

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

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

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

References AggStatePerTransData::aggsortrequired, 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 666 of file nodeAgg.c.

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

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

2040 {
2041  AggStatePerGroup pergroup;
2042  int transno;
2043 
2044  aggstate->hash_ngroups_current++;
2045  hash_agg_check_limits(aggstate);
2046 
2047  /* no need to allocate or initialize per-group state */
2048  if (aggstate->numtrans == 0)
2049  return;
2050 
2051  pergroup = (AggStatePerGroup)
2052  MemoryContextAlloc(hashtable->tablecxt,
2053  sizeof(AggStatePerGroupData) * aggstate->numtrans);
2054 
2055  entry->additional = pergroup;
2056 
2057  /*
2058  * Initialize aggregates for new tuple group, lookup_hash_entries()
2059  * already has selected the relevant grouping set.
2060  */
2061  for (transno = 0; transno < aggstate->numtrans; transno++)
2062  {
2063  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
2064  AggStatePerGroup pergroupstate = &pergroup[transno];
2065 
2066  initialize_aggregate(aggstate, pertrans, pergroupstate);
2067  }
2068 }
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1005
static void hash_agg_check_limits(AggState *aggstate)
Definition: nodeAgg.c:1849
MemoryContext tablecxt
Definition: execnodes.h:813

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

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

References Assert(), AggState::current_phase, ExecGetResultType(), Sort::numCols, outerPlanState, AggState::phase, AggState::phases, AggState::sort_in, AggState::sort_out, AggStatePerPhaseData::sortnode, 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 2088 of file nodeAgg.c.

2089 {
2090  AggStatePerGroup *pergroup = aggstate->hash_pergroup;
2091  TupleTableSlot *outerslot = aggstate->tmpcontext->ecxt_outertuple;
2092  int setno;
2093 
2094  for (setno = 0; setno < aggstate->num_hashes; setno++)
2095  {
2096  AggStatePerHash perhash = &aggstate->perhash[setno];
2097  TupleHashTable hashtable = perhash->hashtable;
2098  TupleTableSlot *hashslot = perhash->hashslot;
2099  TupleHashEntry entry;
2100  uint32 hash;
2101  bool isnew = false;
2102  bool *p_isnew;
2103 
2104  /* if hash table already spilled, don't create new entries */
2105  p_isnew = aggstate->hash_spill_mode ? NULL : &isnew;
2106 
2107  select_current_set(aggstate, setno, true);
2108  prepare_hash_slot(perhash,
2109  outerslot,
2110  hashslot);
2111 
2112  entry = LookupTupleHashEntry(hashtable, hashslot,
2113  p_isnew, &hash);
2114 
2115  if (entry != NULL)
2116  {
2117  if (isnew)
2118  initialize_hash_entry(aggstate, hashtable, entry);
2119  pergroup[setno] = entry->additional;
2120  }
2121  else
2122  {
2123  HashAggSpill *spill = &aggstate->hash_spills[setno];
2124  TupleTableSlot *slot = aggstate->tmpcontext->ecxt_outertuple;
2125 
2126  if (spill->partitions == NULL)
2127  hashagg_spill_init(spill, aggstate->hash_tapeset, 0,
2128  perhash->aggnode->numGroups,
2129  aggstate->hashentrysize);
2130 
2131  hashagg_spill_tuple(aggstate, spill, slot, hash);
2132  pergroup[setno] = NULL;
2133  }
2134  }
2135 }
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 1197 of file nodeAgg.c.

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

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

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

References AggState::all_grouped_cols, attnum, bms_is_member(), ExecStoreAllNullTuple(), AggStatePerPhaseData::grouped_cols, AggState::grouped_cols, lfirst_int, linitial_int, AggState::phase, slot_getsomeattrs(), TTS_EMPTY, and TupleTableSlot::tts_isnull.

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table_in_memory().

◆ process_ordered_aggregate_multi()