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

Go to the source code of this file.

Data Structures

struct  HashTapeInfo
 
struct  HashAggSpill
 
struct  HashAggBatch
 
struct  FindColsContext
 

Macros

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

Typedefs

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

Functions

static void select_current_set (AggState *aggstate, int setno, bool is_hash)
 
static void initialize_phase (AggState *aggstate, int newphase)
 
static TupleTableSlotfetch_input_tuple (AggState *aggstate)
 
static void initialize_aggregates (AggState *aggstate, AggStatePerGroup *pergroups, int numReset)
 
static void advance_transition_function (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void advance_aggregates (AggState *aggstate)
 
static void process_ordered_aggregate_single (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void process_ordered_aggregate_multi (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void finalize_aggregate (AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
 
static void finalize_partialaggregate (AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
 
static void prepare_hash_slot (AggStatePerHash perhash, TupleTableSlot *inputslot, TupleTableSlot *hashslot)
 
static void prepare_projection_slot (AggState *aggstate, TupleTableSlot *slot, int currentSet)
 
static void finalize_aggregates (AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroup)
 
static TupleTableSlotproject_aggregates (AggState *aggstate)
 
static void find_cols (AggState *aggstate, Bitmapset **aggregated, Bitmapset **unaggregated)
 
static bool find_cols_walker (Node *node, FindColsContext *context)
 
static void build_hash_tables (AggState *aggstate)
 
static void build_hash_table (AggState *aggstate, int setno, long nbuckets)
 
static void hashagg_recompile_expressions (AggState *aggstate, bool minslot, bool nullcheck)
 
static long hash_choose_num_buckets (double hashentrysize, long estimated_nbuckets, Size memory)
 
static int hash_choose_num_partitions (double input_groups, double hashentrysize, int used_bits, int *log2_npartittions)
 
static void initialize_hash_entry (AggState *aggstate, TupleHashTable hashtable, TupleHashEntry entry)
 
static void lookup_hash_entries (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_direct (AggState *aggstate)
 
static void agg_fill_hash_table (AggState *aggstate)
 
static bool agg_refill_hash_table (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_hash_table (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_hash_table_in_memory (AggState *aggstate)
 
static void hash_agg_check_limits (AggState *aggstate)
 
static void hash_agg_enter_spill_mode (AggState *aggstate)
 
static void hash_agg_update_metrics (AggState *aggstate, bool from_tape, int npartitions)
 
static void hashagg_finish_initial_spills (AggState *aggstate)
 
static void hashagg_reset_spill_state (AggState *aggstate)
 
static HashAggBatchhashagg_batch_new (LogicalTapeSet *tapeset, int input_tapenum, int setno, int64 input_tuples, double input_card, int used_bits)
 
static MinimalTuple hashagg_batch_read (HashAggBatch *batch, uint32 *hashp)
 
static void hashagg_spill_init (HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits, double input_groups, double hashentrysize)
 
static Size hashagg_spill_tuple (AggState *aggstate, HashAggSpill *spill, TupleTableSlot *slot, uint32 hash)
 
static void hashagg_spill_finish (AggState *aggstate, HashAggSpill *spill, int setno)
 
static void hashagg_tapeinfo_init (AggState *aggstate)
 
static void hashagg_tapeinfo_assign (HashTapeInfo *tapeinfo, int *dest, int ndest)
 
static void hashagg_tapeinfo_release (HashTapeInfo *tapeinfo, int tapenum)
 
static Datum GetAggInitVal (Datum textInitVal, Oid transtype)
 
static void build_pertrans_for_aggref (AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
 
static int find_compatible_peragg (Aggref *newagg, AggState *aggstate, int lastaggno, List **same_input_transnos)
 
static int find_compatible_pertrans (AggState *aggstate, Aggref *newagg, bool shareable, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, List *transnos)
 
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)
 
Datum aggregate_dummy (PG_FUNCTION_ARGS)
 
void ExecAggEstimate (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeDSM (AggState *node, ParallelContext *pcxt)
 
void ExecAggInitializeWorker (AggState *node, ParallelWorkerContext *pwcxt)
 
void ExecAggRetrieveInstrumentation (AggState *node)
 

Macro Definition Documentation

◆ CHUNKHDRSZ

#define CHUNKHDRSZ   16

Definition at line 312 of file nodeAgg.c.

Referenced by hash_agg_entry_size().

◆ HASHAGG_HLL_BIT_WIDTH

#define HASHAGG_HLL_BIT_WIDTH   5

Definition at line 306 of file nodeAgg.c.

Referenced by hashagg_spill_init().

◆ HASHAGG_MAX_PARTITIONS

#define HASHAGG_MAX_PARTITIONS   1024

Definition at line 289 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_MIN_PARTITIONS

#define HASHAGG_MIN_PARTITIONS   4

Definition at line 288 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_PARTITION_FACTOR

#define HASHAGG_PARTITION_FACTOR   1.50

Definition at line 287 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_READ_BUFFER_SIZE

#define HASHAGG_READ_BUFFER_SIZE   BLCKSZ

◆ HASHAGG_WRITE_BUFFER_SIZE

#define HASHAGG_WRITE_BUFFER_SIZE   BLCKSZ

Typedef Documentation

◆ FindColsContext

◆ HashAggBatch

typedef struct HashAggBatch HashAggBatch

◆ HashAggSpill

typedef struct HashAggSpill HashAggSpill

◆ HashTapeInfo

typedef struct HashTapeInfo HashTapeInfo

Function Documentation

◆ advance_aggregates()

static void advance_aggregates ( AggState aggstate)
static

Definition at line 846 of file nodeAgg.c.

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

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

847 {
848  bool dummynull;
849 
851  aggstate->tmpcontext,
852  &dummynull);
853 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:305
ExprState * evaltrans
Definition: nodeAgg.h:283
ExprContext * tmpcontext
Definition: execnodes.h:2146
AggStatePerPhase phase
Definition: execnodes.h:2139

◆ advance_transition_function()

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

Definition at line 734 of file nodeAgg.c.

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

Referenced by process_ordered_aggregate_multi(), and process_ordered_aggregate_single().

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

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

Definition at line 2532 of file nodeAgg.c.

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

Referenced by ExecAgg().

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

◆ agg_refill_hash_table()

static bool agg_refill_hash_table ( AggState aggstate)
static

Definition at line 2586 of file nodeAgg.c.

References TupleHashEntryData::additional, advance_aggregates(), AGG_MIXED, AggStatePerPhaseData::aggstrategy, AggState::all_pergroups, Assert, CHECK_FOR_INTERRUPTS, AggState::current_phase, AggState::current_set, ExprContext::ecxt_outertuple, ExecStoreMinimalTuple(), hash(), hash_agg_set_limits(), hash_agg_update_metrics(), AggState::hash_batches, AggState::hash_mem_limit, AggState::hash_ngroups_current, AggState::hash_ngroups_limit, AggState::hash_pergroup, AggState::hash_spill_mode, AggState::hash_spill_rslot, AggState::hash_tapeinfo, hashagg_batch_read(), hashagg_recompile_expressions(), hashagg_spill_finish(), hashagg_spill_init(), hashagg_spill_tuple(), hashagg_tapeinfo_release(), AggState::hashcontext, AggState::hashentrysize, AggStatePerHashData::hashiter, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, initialize_hash_entry(), HashAggBatch::input_card, HashAggBatch::input_tapenum, linitial, list_delete_first(), LookupTupleHashEntryHash(), AggState::maxsets, 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().

2587 {
2588  HashAggBatch *batch;
2589  AggStatePerHash perhash;
2590  HashAggSpill spill;
2591  HashTapeInfo *tapeinfo = aggstate->hash_tapeinfo;
2592  bool spill_initialized = false;
2593 
2594  if (aggstate->hash_batches == NIL)
2595  return false;
2596 
2597  batch = linitial(aggstate->hash_batches);
2598  aggstate->hash_batches = list_delete_first(aggstate->hash_batches);
2599 
2600  hash_agg_set_limits(aggstate->hashentrysize, batch->input_card,
2601  batch->used_bits, &aggstate->hash_mem_limit,
2602  &aggstate->hash_ngroups_limit, NULL);
2603 
2604  /* there could be residual pergroup pointers; clear them */
2605  for (int setoff = 0;
2606  setoff < aggstate->maxsets + aggstate->num_hashes;
2607  setoff++)
2608  aggstate->all_pergroups[setoff] = NULL;
2609 
2610  /* free memory and reset hash tables */
2611  ReScanExprContext(aggstate->hashcontext);
2612  for (int setno = 0; setno < aggstate->num_hashes; setno++)
2613  ResetTupleHashTable(aggstate->perhash[setno].hashtable);
2614 
2615  aggstate->hash_ngroups_current = 0;
2616 
2617  /*
2618  * In AGG_MIXED mode, hash aggregation happens in phase 1 and the output
2619  * happens in phase 0. So, we switch to phase 1 when processing a batch,
2620  * and back to phase 0 after the batch is done.
2621  */
2622  Assert(aggstate->current_phase == 0);
2623  if (aggstate->phase->aggstrategy == AGG_MIXED)
2624  {
2625  aggstate->current_phase = 1;
2626  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2627  }
2628 
2629  select_current_set(aggstate, batch->setno, true);
2630 
2631  perhash = &aggstate->perhash[aggstate->current_set];
2632 
2633  /*
2634  * Spilled tuples are always read back as MinimalTuples, which may be
2635  * different from the outer plan, so recompile the aggregate expressions.
2636  *
2637  * We still need the NULL check, because we are only processing one
2638  * grouping set at a time and the rest will be NULL.
2639  */
2640  hashagg_recompile_expressions(aggstate, true, true);
2641 
2642  for (;;)
2643  {
2644  TupleTableSlot *spillslot = aggstate->hash_spill_rslot;
2645  TupleTableSlot *hashslot = perhash->hashslot;
2646  TupleHashEntry entry;
2647  MinimalTuple tuple;
2648  uint32 hash;
2649  bool isnew = false;
2650  bool *p_isnew = aggstate->hash_spill_mode ? NULL : &isnew;
2651 
2653 
2654  tuple = hashagg_batch_read(batch, &hash);
2655  if (tuple == NULL)
2656  break;
2657 
2658  ExecStoreMinimalTuple(tuple, spillslot, true);
2659  aggstate->tmpcontext->ecxt_outertuple = spillslot;
2660 
2661  prepare_hash_slot(perhash,
2662  aggstate->tmpcontext->ecxt_outertuple,
2663  hashslot);
2664  entry = LookupTupleHashEntryHash(
2665  perhash->hashtable, hashslot, p_isnew, hash);
2666 
2667  if (entry != NULL)
2668  {
2669  if (isnew)
2670  initialize_hash_entry(aggstate, perhash->hashtable, entry);
2671  aggstate->hash_pergroup[batch->setno] = entry->additional;
2672  advance_aggregates(aggstate);
2673  }
2674  else
2675  {
2676  if (!spill_initialized)
2677  {
2678  /*
2679  * Avoid initializing the spill until we actually need it so
2680  * that we don't assign tapes that will never be used.
2681  */
2682  spill_initialized = true;
2683  hashagg_spill_init(&spill, tapeinfo, batch->used_bits,
2684  batch->input_card, aggstate->hashentrysize);
2685  }
2686  /* no memory for a new group, spill */
2687  hashagg_spill_tuple(aggstate, &spill, spillslot, hash);
2688 
2689  aggstate->hash_pergroup[batch->setno] = NULL;
2690  }
2691 
2692  /*
2693  * Reset per-input-tuple context after each tuple, but note that the
2694  * hash lookups do this too
2695  */
2696  ResetExprContext(aggstate->tmpcontext);
2697  }
2698 
2699  hashagg_tapeinfo_release(tapeinfo, batch->input_tapenum);
2700 
2701  /* change back to phase 0 */
2702  aggstate->current_phase = 0;
2703  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2704 
2705  if (spill_initialized)
2706  {
2707  hashagg_spill_finish(aggstate, &spill, batch->setno);
2708  hash_agg_update_metrics(aggstate, true, spill.npartitions);
2709  }
2710  else
2711  hash_agg_update_metrics(aggstate, true, 0);
2712 
2713  aggstate->hash_spill_mode = false;
2714 
2715  /* prepare to walk the first hash table */
2716  select_current_set(aggstate, batch->setno, true);
2717  ResetTupleHashIterator(aggstate->perhash[batch->setno].hashtable,
2718  &aggstate->perhash[batch->setno].hashiter);
2719 
2720  pfree(batch);
2721 
2722  return true;
2723 }
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2197
#define NIL
Definition: pg_list.h:65
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:483
AggStatePerPhase phases
Definition: execnodes.h:2164
double hashentrysize
Definition: execnodes.h:2189
static void hashagg_tapeinfo_release(HashTapeInfo *tapeinfo, int tapenum)
Definition: nodeAgg.c:2922
static void hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
Definition: nodeAgg.c:1912
TupleHashEntry LookupTupleHashEntryHash(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 hash)
Definition: execGrouping.c:359
uint64 hash_ngroups_limit
Definition: execnodes.h:2186
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1416
static void hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
Definition: nodeAgg.c:3144
int current_phase
Definition: execnodes.h:2141
TupleTableSlot * hash_spill_rslot
Definition: execnodes.h:2179
static void advance_aggregates(AggState *aggstate)
Definition: nodeAgg.c:846
int current_set
Definition: execnodes.h:2156
static void hashagg_spill_init(HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits, double input_groups, double hashentrysize)
Definition: nodeAgg.c:2942
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:283
ExprContext * tmpcontext
Definition: execnodes.h:2146
bool hash_spill_mode
Definition: execnodes.h:2183
List * hash_batches
Definition: execnodes.h:2181
int maxsets
Definition: execnodes.h:2163
void pfree(void *pointer)
Definition: mcxt.c:1057
#define linitial(l)
Definition: pg_list.h:194
int npartitions
Definition: nodeAgg.c:347
static Size hashagg_spill_tuple(AggState *aggstate, HashAggSpill *spill, TupleTableSlot *slot, uint32 hash)
Definition: nodeAgg.c:2973
int used_bits
Definition: nodeAgg.c:367
unsigned int uint32
Definition: c.h:374
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2176
AggStatePerHash perhash
Definition: execnodes.h:2196
AggStrategy aggstrategy
Definition: nodeAgg.h:274
double input_card
Definition: nodeAgg.c:371
TupleHashIterator hashiter
Definition: nodeAgg.h:304
int num_hashes
Definition: execnodes.h:2174
ExprContext * hashcontext
Definition: execnodes.h:2144
AggStatePerPhase phase
Definition: execnodes.h:2139
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:724
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1742
static void prepare_hash_slot(AggStatePerHash perhash, TupleTableSlot *inputslot, TupleTableSlot *hashslot)
Definition: nodeAgg.c:1227
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:230
#define Assert(condition)
Definition: c.h:745
int input_tapenum
Definition: nodeAgg.c:369
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:443
Size hash_mem_limit
Definition: execnodes.h:2185
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:1793
static MinimalTuple hashagg_batch_read(HashAggBatch *batch, uint32 *hashp)
Definition: nodeAgg.c:3060
uint64 hash_ngroups_current
Definition: execnodes.h:2191
static void initialize_hash_entry(AggState *aggstate, TupleHashTable hashtable, TupleHashEntry entry)
Definition: nodeAgg.c:2036
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
TupleTableSlot * hashslot
Definition: nodeAgg.h:305
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:541
TupleHashTable hashtable
Definition: nodeAgg.h:303
#define ResetExprContext(econtext)
Definition: executor.h:501
List * list_delete_first(List *list)
Definition: list.c:860
AggStatePerGroup * all_pergroups
Definition: execnodes.h:2202

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

Definition at line 2186 of file nodeAgg.c.

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

Referenced by ExecAgg().

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

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

Definition at line 2733 of file nodeAgg.c.

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

Referenced by agg_retrieve_direct(), and ExecAgg().

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

◆ agg_retrieve_hash_table_in_memory()

static TupleTableSlot * agg_retrieve_hash_table_in_memory ( AggState aggstate)
static

Definition at line 2758 of file nodeAgg.c.

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

Referenced by agg_retrieve_hash_table().

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

◆ AggCheckCallContext()

int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

Definition at line 4778 of file nodeAgg.c.

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

Referenced by array_agg_array_finalfn(), array_agg_array_transfn(), array_agg_finalfn(), array_agg_transfn(), bytea_string_agg_finalfn(), fetch_array_arg_replace_nulls(), float4_accum(), float8_accum(), float8_combine(), float8_regr_accum(), float8_regr_combine(), hypothetical_dense_rank_final(), hypothetical_rank_common(), int2_avg_accum(), int2_avg_accum_inv(), int2_sum(), int4_avg_accum(), int4_avg_accum_inv(), int4_avg_combine(), int4_sum(), int8_avg_combine(), int8_avg_deserialize(), int8_avg_serialize(), int8dec(), int8inc(), json_agg_finalfn(), json_agg_transfn(), json_object_agg_finalfn(), json_object_agg_transfn(), jsonb_agg_finalfn(), jsonb_agg_transfn(), jsonb_object_agg_finalfn(), jsonb_object_agg_transfn(), makeBoolAggState(), makeNumericAggState(), makeStringAggState(), mode_final(), numeric_accum_inv(), numeric_avg_combine(), numeric_avg_deserialize(), numeric_avg_serialize(), numeric_combine(), numeric_deserialize(), numeric_poly_combine(), numeric_poly_deserialize(), numeric_poly_serialize(), numeric_serialize(), ordered_set_startup(), percentile_cont_final_common(), percentile_cont_multi_final_common(), percentile_disc_final(), percentile_disc_multi_final(), and string_agg_finalfn().

4779 {
4780  if (fcinfo->context && IsA(fcinfo->context, AggState))
4781  {
4782  if (aggcontext)
4783  {
4784  AggState *aggstate = ((AggState *) fcinfo->context);
4785  ExprContext *cxt = aggstate->curaggcontext;
4786 
4787  *aggcontext = cxt->ecxt_per_tuple_memory;
4788  }
4789  return AGG_CONTEXT_AGGREGATE;
4790  }
4791  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4792  {
4793  if (aggcontext)
4794  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4795  return AGG_CONTEXT_WINDOW;
4796  }
4797 
4798  /* this is just to prevent "uninitialized variable" warnings */
4799  if (aggcontext)
4800  *aggcontext = NULL;
4801  return 0;
4802 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
fmNodePtr context
Definition: fmgr.h:88
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:736
ExprContext * curaggcontext
Definition: execnodes.h:2148
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:737

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4822 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4823 {
4824  if (fcinfo->context && IsA(fcinfo->context, AggState))
4825  {
4826  AggState *aggstate = (AggState *) fcinfo->context;
4827  AggStatePerAgg curperagg;
4828  AggStatePerTrans curpertrans;
4829 
4830  /* check curperagg (valid when in a final function) */
4831  curperagg = aggstate->curperagg;
4832 
4833  if (curperagg)
4834  return curperagg->aggref;
4835 
4836  /* check curpertrans (valid when in a transition function) */
4837  curpertrans = aggstate->curpertrans;
4838 
4839  if (curpertrans)
4840  return curpertrans->aggref;
4841  }
4842  return NULL;
4843 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
fmNodePtr context
Definition: fmgr.h:88
Aggref * aggref
Definition: nodeAgg.h:187
Aggref * aggref
Definition: nodeAgg.h:44
AggStatePerAgg curperagg
Definition: execnodes.h:2149
AggStatePerTrans curpertrans
Definition: execnodes.h:2151

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4856 of file nodeAgg.c.

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

4857 {
4858  if (fcinfo->context && IsA(fcinfo->context, AggState))
4859  {
4860  AggState *aggstate = (AggState *) fcinfo->context;
4861 
4862  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4863  }
4864  return NULL;
4865 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
fmNodePtr context
Definition: fmgr.h:88
ExprContext * tmpcontext
Definition: execnodes.h:2146

◆ aggregate_dummy()

Datum aggregate_dummy ( PG_FUNCTION_ARGS  )

Definition at line 4949 of file nodeAgg.c.

References elog, and ERROR.

4950 {
4951  elog(ERROR, "aggregate function %u called as normal function",
4952  fcinfo->flinfo->fn_oid);
4953  return (Datum) 0; /* keep compiler quiet */
4954 }
#define ERROR
Definition: elog.h:43
uintptr_t Datum
Definition: postgres.h:367
#define elog(elevel,...)
Definition: elog.h:214

◆ AggRegisterCallback()

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

Definition at line 4921 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4924 {
4925  if (fcinfo->context && IsA(fcinfo->context, AggState))
4926  {
4927  AggState *aggstate = (AggState *) fcinfo->context;
4928  ExprContext *cxt = aggstate->curaggcontext;
4929 
4930  RegisterExprContextCallback(cxt, func, arg);
4931 
4932  return;
4933  }
4934  elog(ERROR, "aggregate function cannot register a callback in this context");
4935 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
fmNodePtr context
Definition: fmgr.h:88
#define ERROR
Definition: elog.h:43
ExprContext * curaggcontext
Definition: execnodes.h:2148
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:904
#define elog(elevel,...)
Definition: elog.h:214
void * arg

◆ AggStateIsShared()

bool AggStateIsShared ( FunctionCallInfo  fcinfo)

Definition at line 4882 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4883 {
4884  if (fcinfo->context && IsA(fcinfo->context, AggState))
4885  {
4886  AggState *aggstate = (AggState *) fcinfo->context;
4887  AggStatePerAgg curperagg;
4888  AggStatePerTrans curpertrans;
4889 
4890  /* check curperagg (valid when in a final function) */
4891  curperagg = aggstate->curperagg;
4892 
4893  if (curperagg)
4894  return aggstate->pertrans[curperagg->transno].aggshared;
4895 
4896  /* check curpertrans (valid when in a transition function) */
4897  curpertrans = aggstate->curpertrans;
4898 
4899  if (curpertrans)
4900  return curpertrans->aggshared;
4901  }
4902  return true;
4903 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
fmNodePtr context
Definition: fmgr.h:88
AggStatePerTrans pertrans
Definition: execnodes.h:2143
AggStatePerAgg curperagg
Definition: execnodes.h:2149
AggStatePerTrans curpertrans
Definition: execnodes.h:2151

◆ build_hash_table()

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

Definition at line 1506 of file nodeAgg.c.

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

Referenced by build_hash_tables().

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

◆ build_hash_tables()

static void build_hash_tables ( AggState aggstate)
static

Definition at line 1471 of file nodeAgg.c.

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

Referenced by ExecInitAgg(), and ExecReScanAgg().

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

◆ build_pertrans_for_aggref()

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

Definition at line 4096 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

4103 {
4104  int numGroupingSets = Max(aggstate->maxsets, 1);
4105  Expr *serialfnexpr = NULL;
4106  Expr *deserialfnexpr = NULL;
4107  ListCell *lc;
4108  int numInputs;
4109  int numDirectArgs;
4110  List *sortlist;
4111  int numSortCols;
4112  int numDistinctCols;
4113  int i;
4114 
4115  /* Begin filling in the pertrans data */
4116  pertrans->aggref = aggref;
4117  pertrans->aggshared = false;
4118  pertrans->aggCollation = aggref->inputcollid;
4119  pertrans->transfn_oid = aggtransfn;
4120  pertrans->serialfn_oid = aggserialfn;
4121  pertrans->deserialfn_oid = aggdeserialfn;
4122  pertrans->initValue = initValue;
4123  pertrans->initValueIsNull = initValueIsNull;
4124 
4125  /* Count the "direct" arguments, if any */
4126  numDirectArgs = list_length(aggref->aggdirectargs);
4127 
4128  /* Count the number of aggregated input columns */
4129  pertrans->numInputs = numInputs = list_length(aggref->args);
4130 
4131  pertrans->aggtranstype = aggtranstype;
4132 
4133  /*
4134  * When combining states, we have no use at all for the aggregate
4135  * function's transfn. Instead we use the combinefn. In this case, the
4136  * transfn and transfn_oid fields of pertrans refer to the combine
4137  * function rather than the transition function.
4138  */
4139  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
4140  {
4141  Expr *combinefnexpr;
4142  size_t numTransArgs;
4143 
4144  /*
4145  * When combining there's only one input, the to-be-combined added
4146  * transition value from below (this node's transition value is
4147  * counted separately).
4148  */
4149  pertrans->numTransInputs = 1;
4150 
4151  /* account for the current transition state */
4152  numTransArgs = pertrans->numTransInputs + 1;
4153 
4154  build_aggregate_combinefn_expr(aggtranstype,
4155  aggref->inputcollid,
4156  aggtransfn,
4157  &combinefnexpr);
4158  fmgr_info(aggtransfn, &pertrans->transfn);
4159  fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
4160 
4161  pertrans->transfn_fcinfo =
4164  &pertrans->transfn,
4165  numTransArgs,
4166  pertrans->aggCollation,
4167  (void *) aggstate, NULL);
4168 
4169  /*
4170  * Ensure that a combine function to combine INTERNAL states is not
4171  * strict. This should have been checked during CREATE AGGREGATE, but
4172  * the strict property could have been changed since then.
4173  */
4174  if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
4175  ereport(ERROR,
4176  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4177  errmsg("combine function with transition type %s must not be declared STRICT",
4178  format_type_be(aggtranstype))));
4179  }
4180  else
4181  {
4182  Expr *transfnexpr;
4183  size_t numTransArgs;
4184 
4185  /* Detect how many arguments to pass to the transfn */
4186  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4187  pertrans->numTransInputs = numInputs;
4188  else
4189  pertrans->numTransInputs = numArguments;
4190 
4191  /* account for the current transition state */
4192  numTransArgs = pertrans->numTransInputs + 1;
4193 
4194  /*
4195  * Set up infrastructure for calling the transfn. Note that
4196  * invtransfn is not needed here.
4197  */
4198  build_aggregate_transfn_expr(inputTypes,
4199  numArguments,
4200  numDirectArgs,
4201  aggref->aggvariadic,
4202  aggtranstype,
4203  aggref->inputcollid,
4204  aggtransfn,
4205  InvalidOid,
4206  &transfnexpr,
4207  NULL);
4208  fmgr_info(aggtransfn, &pertrans->transfn);
4209  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
4210 
4211  pertrans->transfn_fcinfo =
4214  &pertrans->transfn,
4215  numTransArgs,
4216  pertrans->aggCollation,
4217  (void *) aggstate, NULL);
4218 
4219  /*
4220  * If the transfn is strict and the initval is NULL, make sure input
4221  * type and transtype are the same (or at least binary-compatible), so
4222  * that it's OK to use the first aggregated input value as the initial
4223  * transValue. This should have been checked at agg definition time,
4224  * but we must check again in case the transfn's strictness property
4225  * has been changed.
4226  */
4227  if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
4228  {
4229  if (numArguments <= numDirectArgs ||
4230  !IsBinaryCoercible(inputTypes[numDirectArgs],
4231  aggtranstype))
4232  ereport(ERROR,
4233  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4234  errmsg("aggregate %u needs to have compatible input type and transition type",
4235  aggref->aggfnoid)));
4236  }
4237  }
4238 
4239  /* get info about the state value's datatype */
4240  get_typlenbyval(aggtranstype,
4241  &pertrans->transtypeLen,
4242  &pertrans->transtypeByVal);
4243 
4244  if (OidIsValid(aggserialfn))
4245  {
4246  build_aggregate_serialfn_expr(aggserialfn,
4247  &serialfnexpr);
4248  fmgr_info(aggserialfn, &pertrans->serialfn);
4249  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
4250 
4251  pertrans->serialfn_fcinfo =
4254  &pertrans->serialfn,
4255  1,
4256  InvalidOid,
4257  (void *) aggstate, NULL);
4258  }
4259 
4260  if (OidIsValid(aggdeserialfn))
4261  {
4262  build_aggregate_deserialfn_expr(aggdeserialfn,
4263  &deserialfnexpr);
4264  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
4265  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
4266 
4267  pertrans->deserialfn_fcinfo =
4270  &pertrans->deserialfn,
4271  2,
4272  InvalidOid,
4273  (void *) aggstate, NULL);
4274 
4275  }
4276 
4277  /*
4278  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
4279  * have a list of SortGroupClause nodes; fish out the data in them and
4280  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
4281  * however; the agg's transfn and finalfn are responsible for that.
4282  *
4283  * Note that by construction, if there is a DISTINCT clause then the ORDER
4284  * BY clause is a prefix of it (see transformDistinctClause).
4285  */
4286  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4287  {
4288  sortlist = NIL;
4289  numSortCols = numDistinctCols = 0;
4290  }
4291  else if (aggref->aggdistinct)
4292  {
4293  sortlist = aggref->aggdistinct;
4294  numSortCols = numDistinctCols = list_length(sortlist);
4295  Assert(numSortCols >= list_length(aggref->aggorder));
4296  }
4297  else
4298  {
4299  sortlist = aggref->aggorder;
4300  numSortCols = list_length(sortlist);
4301  numDistinctCols = 0;
4302  }
4303 
4304  pertrans->numSortCols = numSortCols;
4305  pertrans->numDistinctCols = numDistinctCols;
4306 
4307  /*
4308  * If we have either sorting or filtering to do, create a tupledesc and
4309  * slot corresponding to the aggregated inputs (including sort
4310  * expressions) of the agg.
4311  */
4312  if (numSortCols > 0 || aggref->aggfilter)
4313  {
4314  pertrans->sortdesc = ExecTypeFromTL(aggref->args);
4315  pertrans->sortslot =
4316  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4318  }
4319 
4320  if (numSortCols > 0)
4321  {
4322  /*
4323  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
4324  * (yet)
4325  */
4326  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
4327 
4328  /* If we have only one input, we need its len/byval info. */
4329  if (numInputs == 1)
4330  {
4331  get_typlenbyval(inputTypes[numDirectArgs],
4332  &pertrans->inputtypeLen,
4333  &pertrans->inputtypeByVal);
4334  }
4335  else if (numDistinctCols > 0)
4336  {
4337  /* we will need an extra slot to store prior values */
4338  pertrans->uniqslot =
4339  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4341  }
4342 
4343  /* Extract the sort information for use later */
4344  pertrans->sortColIdx =
4345  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
4346  pertrans->sortOperators =
4347  (Oid *) palloc(numSortCols * sizeof(Oid));
4348  pertrans->sortCollations =
4349  (Oid *) palloc(numSortCols * sizeof(Oid));
4350  pertrans->sortNullsFirst =
4351  (bool *) palloc(numSortCols * sizeof(bool));
4352 
4353  i = 0;
4354  foreach(lc, sortlist)
4355  {
4356  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
4357  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
4358 
4359  /* the parser should have made sure of this */
4360  Assert(OidIsValid(sortcl->sortop));
4361 
4362  pertrans->sortColIdx[i] = tle->resno;
4363  pertrans->sortOperators[i] = sortcl->sortop;
4364  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
4365  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
4366  i++;
4367  }
4368  Assert(i == numSortCols);
4369  }
4370 
4371  if (aggref->aggdistinct)
4372  {
4373  Oid *ops;
4374 
4375  Assert(numArguments > 0);
4376  Assert(list_length(aggref->aggdistinct) == numDistinctCols);
4377 
4378  ops = palloc(numDistinctCols * sizeof(Oid));
4379 
4380  i = 0;
4381  foreach(lc, aggref->aggdistinct)
4382  ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
4383 
4384  /* lookup / build the necessary comparators */
4385  if (numDistinctCols == 1)
4386  fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
4387  else
4388  pertrans->equalfnMulti =
4389  execTuplesMatchPrepare(pertrans->sortdesc,
4390  numDistinctCols,
4391  pertrans->sortColIdx,
4392  ops,
4393  pertrans->sortCollations,
4394  &aggstate->ss.ps);
4395  pfree(ops);
4396  }
4397 
4398  pertrans->sortstates = (Tuplesortstate **)
4399  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
4400 }
List * aggdistinct
Definition: primnodes.h:321
#define NIL
Definition: pg_list.h:65
bool aggvariadic
Definition: primnodes.h:324
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:389
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
ScanState ss
Definition: execnodes.h:2133
FmgrInfo equalfnOne
Definition: nodeAgg.h:110
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
Oid inputcollid
Definition: primnodes.h:315
Definition: nodes.h:528
AggSplit aggsplit
Definition: execnodes.h:2138
int errcode(int sqlerrcode)
Definition: elog.c:610
List * args
Definition: primnodes.h:319
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
void build_aggregate_deserialfn_expr(Oid deserialfn_oid, Expr **deserialfnexpr)
Definition: parse_agg.c:2013
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:790
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:162
TupleDesc sortdesc
Definition: nodeAgg.h:138
FmgrInfo transfn
Definition: nodeAgg.h:81
Aggref * aggref
Definition: nodeAgg.h:44
PlanState ps
Definition: execnodes.h:1319
int maxsets
Definition: execnodes.h:2163
void pfree(void *pointer)
Definition: mcxt.c:1057
AggStrategy aggstrategy
Definition: execnodes.h:2137
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
ExprState * equalfnMulti
Definition: nodeAgg.h:111
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
static int initValue(long lng_val)
Definition: informix.c:677
List * aggorder
Definition: primnodes.h:320
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
AttrNumber resno
Definition: primnodes.h:1411
List * aggdirectargs
Definition: primnodes.h:318
AttrNumber * sortColIdx
Definition: nodeAgg.h:100
void build_aggregate_combinefn_expr(Oid agg_state_type, Oid agg_input_collation, Oid combinefn_oid, Expr **combinefnexpr)
Definition: parse_agg.c:1961
bool IsBinaryCoercible(Oid srctype, Oid targettype)
void * palloc0(Size size)
Definition: mcxt.c:981
struct FunctionCallInfoBaseData * FunctionCallInfo
Definition: fmgr.h:38
FmgrInfo deserialfn
Definition: nodeAgg.h:87
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1202
Oid aggfnoid
Definition: primnodes.h:312
#define ereport(elevel,...)
Definition: elog.h:144
#define Max(x, y)
Definition: c.h:921
#define Assert(condition)
Definition: c.h:745
#define lfirst(lc)
Definition: pg_list.h:189
FmgrInfo serialfn
Definition: nodeAgg.h:84
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:167
void build_aggregate_serialfn_expr(Oid serialfn_oid, Expr **serialfnexpr)
Definition: parse_agg.c:1990
Expr * expr
Definition: primnodes.h:1410
void build_aggregate_transfn_expr(Oid *agg_input_types, int agg_num_inputs, int agg_num_direct_inputs, bool agg_variadic, Oid agg_state_type, Oid agg_input_collation, Oid transfn_oid, Oid invtransfn_oid, Expr **transfnexpr, Expr **invtransfnexpr)
Definition: parse_agg.c:1900
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
FunctionCallInfo serialfn_fcinfo
Definition: nodeAgg.h:165
static int list_length(const List *l)
Definition: pg_list.h:169
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:768
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2139
Expr * aggfilter
Definition: primnodes.h:322
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1908
TupleTableSlot * uniqslot
Definition: nodeAgg.h:137
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:824
int i
char aggkind
Definition: primnodes.h:326
TupleTableSlot * sortslot
Definition: nodeAgg.h:136
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
bool * sortNullsFirst
Definition: nodeAgg.h:103

◆ ExecAgg()

static TupleTableSlot* ExecAgg ( PlanState pstate)
static

Definition at line 2150 of file nodeAgg.c.

References AggState::agg_done, agg_fill_hash_table(), AGG_HASHED, AGG_MIXED, AGG_PLAIN, agg_retrieve_direct(), agg_retrieve_hash_table(), AGG_SORTED, AggStatePerPhaseData::aggstrategy, castNode, CHECK_FOR_INTERRUPTS, AggState::phase, AggState::table_filled, and TupIsNull.

Referenced by ExecInitAgg().

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

◆ ExecAggEstimate()

void ExecAggEstimate ( AggState node,
ParallelContext pcxt 
)

Definition at line 4968 of file nodeAgg.c.

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

Referenced by ExecParallelEstimate().

4969 {
4970  Size size;
4971 
4972  /* don't need this if not instrumenting or no workers */
4973  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4974  return;
4975 
4976  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4977  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4978  shm_toc_estimate_chunk(&pcxt->estimator, size);
4979  shm_toc_estimate_keys(&pcxt->estimator, 1);
4980 }
Instrumentation * instrument
Definition: execnodes.h:942
ScanState ss
Definition: execnodes.h:2133
shm_toc_estimator estimator
Definition: parallel.h:42
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
PlanState ps
Definition: execnodes.h:1319
Size mul_size(Size s1, Size s2)
Definition: shmem.c:515
Size add_size(Size s1, Size s2)
Definition: shmem.c:498
size_t Size
Definition: c.h:473
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
#define offsetof(type, field)
Definition: c.h:668

◆ ExecAggInitializeDSM()

void ExecAggInitializeDSM ( AggState node,
ParallelContext pcxt 
)

Definition at line 4989 of file nodeAgg.c.

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

Referenced by ExecParallelInitializeDSM().

4990 {
4991  Size size;
4992 
4993  /* don't need this if not instrumenting or no workers */
4994  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4995  return;
4996 
4997  size = offsetof(SharedAggInfo, sinstrument)
4998  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4999  node->shared_info = shm_toc_allocate(pcxt->toc, size);
5000  /* ensure any unfilled slots will contain zeroes */
5001  memset(node->shared_info, 0, size);
5002  node->shared_info->num_workers = pcxt->nworkers;
5003  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
5004  node->shared_info);
5005 }
Instrumentation * instrument
Definition: execnodes.h:942
ScanState ss
Definition: execnodes.h:2133
int plan_node_id
Definition: plannodes.h:141
PlanState ps
Definition: execnodes.h:1319
struct AggregateInstrumentation AggregateInstrumentation
Plan * plan
Definition: execnodes.h:932
size_t Size
Definition: c.h:473
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
SharedAggInfo * shared_info
Definition: execnodes.h:2205
#define offsetof(type, field)
Definition: c.h:668
shm_toc * toc
Definition: parallel.h:45

◆ ExecAggInitializeWorker()

void ExecAggInitializeWorker ( AggState node,
ParallelWorkerContext pwcxt 
)

Definition at line 5014 of file nodeAgg.c.

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

Referenced by ExecParallelInitializeWorker().

5015 {
5016  node->shared_info =
5017  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
5018 }
ScanState ss
Definition: execnodes.h:2133
int plan_node_id
Definition: plannodes.h:141
PlanState ps
Definition: execnodes.h:1319
Plan * plan
Definition: execnodes.h:932
SharedAggInfo * shared_info
Definition: execnodes.h:2205
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 5027 of file nodeAgg.c.

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

Referenced by ExecParallelRetrieveInstrumentation().

5028 {
5029  Size size;
5030  SharedAggInfo *si;
5031 
5032  if (node->shared_info == NULL)
5033  return;
5034 
5035  size = offsetof(SharedAggInfo, sinstrument)
5037  si = palloc(size);
5038  memcpy(si, node->shared_info, size);
5039  node->shared_info = si;
5040 }
struct AggregateInstrumentation AggregateInstrumentation
size_t Size
Definition: c.h:473
void * palloc(Size size)
Definition: mcxt.c:950
SharedAggInfo * shared_info
Definition: execnodes.h:2205
#define offsetof(type, field)
Definition: c.h:668

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 4561 of file nodeAgg.c.

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

Referenced by ExecEndNode().

4562 {
4564  int transno;
4565  int numGroupingSets = Max(node->maxsets, 1);
4566  int setno;
4567 
4568  /*
4569  * When ending a parallel worker, copy the statistics gathered by the
4570  * worker back into shared memory so that it can be picked up by the main
4571  * process to report in EXPLAIN ANALYZE.
4572  */
4573  if (node->shared_info && IsParallelWorker())
4574  {
4576 
4577  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4580  si->hash_disk_used = node->hash_disk_used;
4581  si->hash_mem_peak = node->hash_mem_peak;
4582  }
4583 
4584  /* Make sure we have closed any open tuplesorts */
4585 
4586  if (node->sort_in)
4587  tuplesort_end(node->sort_in);
4588  if (node->sort_out)
4589  tuplesort_end(node->sort_out);
4590 
4592 
4593  if (node->hash_metacxt != NULL)
4594  {
4596  node->hash_metacxt = NULL;
4597  }
4598 
4599  for (transno = 0; transno < node->numtrans; transno++)
4600  {
4601  AggStatePerTrans pertrans = &node->pertrans[transno];
4602 
4603  for (setno = 0; setno < numGroupingSets; setno++)
4604  {
4605  if (pertrans->sortstates[setno])
4606  tuplesort_end(pertrans->sortstates[setno]);
4607  }
4608  }
4609 
4610  /* And ensure any agg shutdown callbacks have been called */
4611  for (setno = 0; setno < numGroupingSets; setno++)
4612  ReScanExprContext(node->aggcontexts[setno]);
4613  if (node->hashcontext)
4615 
4616  /*
4617  * We don't actually free any ExprContexts here (see comment in
4618  * ExecFreeExprContext), just unlinking the output one from the plan node
4619  * suffices.
4620  */
4621  ExecFreeExprContext(&node->ss.ps);
4622 
4623  /* clean up tuple table */
4625 
4626  outerPlan = outerPlanState(node);
4627  ExecEndNode(outerPlan);
4628 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3186
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:212
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:543
Tuplesortstate * sort_out
Definition: execnodes.h:2166
ScanState ss
Definition: execnodes.h:2133
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1322
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2109
AggStatePerTrans pertrans
Definition: execnodes.h:2143
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:655
int numtrans
Definition: execnodes.h:2136
PlanState ps
Definition: execnodes.h:1319
int maxsets
Definition: execnodes.h:2163
MemoryContext hash_metacxt
Definition: execnodes.h:2175
Tuplesortstate * sort_in
Definition: execnodes.h:2165
#define outerPlanState(node)
Definition: execnodes.h:1026
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
int ParallelWorkerNumber
Definition: parallel.c:112
#define IsParallelWorker()
Definition: parallel.h:61
int hash_batches_used
Definition: execnodes.h:2194
#define outerPlan(node)
Definition: plannodes.h:172
ExprContext * hashcontext
Definition: execnodes.h:2144
uint64 hash_disk_used
Definition: execnodes.h:2193
#define Max(x, y)
Definition: c.h:921
ExprContext ** aggcontexts
Definition: execnodes.h:2145
#define Assert(condition)
Definition: c.h:745
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:443
Size hash_mem_peak
Definition: execnodes.h:2190
SharedAggInfo * shared_info
Definition: execnodes.h:2205
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1445

◆ ExecInitAgg()

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

Definition at line 3238 of file nodeAgg.c.

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

Referenced by ExecInitNode().

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

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 4631 of file nodeAgg.c.

References AggState::agg_done, AGG_HASHED, AGG_MIXED, AggState::aggcontexts, Agg::aggParams, AggState::aggstrategy, bms_overlap(), build_hash_tables(), PlanState::chgParam, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecClearTuple(), ExecReScan(), AggState::grp_firstTuple, AggState::hash_ever_spilled, AggState::hash_ngroups_current, AggState::hash_spill_mode, hashagg_recompile_expressions(), hashagg_reset_spill_state(), AggState::hashcontext, AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, heap_freetuple(), initialize_phase(), AggState::input_done, Max, AggState::maxsets, MemSet, AggState::numaggs, AggState::numtrans, outerPlan, outerPlanState, AggState::pergroups, AggState::perhash, AggState::pertrans, PlanState::plan, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, ReScanExprContext(), ResetTupleHashIterator, select_current_set(), AggStatePerTransData::sortstates, AggState::ss, ScanState::ss_ScanTupleSlot, AggState::table_filled, and tuplesort_end().

Referenced by ExecReScan().

4632 {
4633  ExprContext *econtext = node->ss.ps.ps_ExprContext;
4635  Agg *aggnode = (Agg *) node->ss.ps.plan;
4636  int transno;
4637  int numGroupingSets = Max(node->maxsets, 1);
4638  int setno;
4639 
4640  node->agg_done = false;
4641 
4642  if (node->aggstrategy == AGG_HASHED)
4643  {
4644  /*
4645  * In the hashed case, if we haven't yet built the hash table then we
4646  * can just return; nothing done yet, so nothing to undo. If subnode's
4647  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4648  * else no reason to re-scan it at all.
4649  */
4650  if (!node->table_filled)
4651  return;
4652 
4653  /*
4654  * If we do have the hash table, and it never spilled, and the subplan
4655  * does not have any parameter changes, and none of our own parameter
4656  * changes affect input expressions of the aggregated functions, then
4657  * we can just rescan the existing hash table; no need to build it
4658  * again.
4659  */
4660  if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4661  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4662  {
4664  &node->perhash[0].hashiter);
4665  select_current_set(node, 0, true);
4666  return;
4667  }
4668  }
4669 
4670  /* Make sure we have closed any open tuplesorts */
4671  for (transno = 0; transno < node->numtrans; transno++)
4672  {
4673  for (setno = 0; setno < numGroupingSets; setno++)
4674  {
4675  AggStatePerTrans pertrans = &node->pertrans[transno];
4676 
4677  if (pertrans->sortstates[setno])
4678  {
4679  tuplesort_end(pertrans->sortstates[setno]);
4680  pertrans->sortstates[setno] = NULL;
4681  }
4682  }
4683  }
4684 
4685  /*
4686  * We don't need to ReScanExprContext the output tuple context here;
4687  * ExecReScan already did it. But we do need to reset our per-grouping-set
4688  * contexts, which may have transvalues stored in them. (We use rescan
4689  * rather than just reset because transfns may have registered callbacks
4690  * that need to be run now.) For the AGG_HASHED case, see below.
4691  */
4692 
4693  for (setno = 0; setno < numGroupingSets; setno++)
4694  {
4695  ReScanExprContext(node->aggcontexts[setno]);
4696  }
4697 
4698  /* Release first tuple of group, if we have made a copy */
4699  if (node->grp_firstTuple != NULL)
4700  {
4702  node->grp_firstTuple = NULL;
4703  }
4705 
4706  /* Forget current agg values */
4707  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4708  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4709 
4710  /*
4711  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4712  * the hashcontext. This used to be an issue, but now, resetting a context
4713  * automatically deletes sub-contexts too.
4714  */
4715  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4716  {
4718 
4719  node->hash_ever_spilled = false;
4720  node->hash_spill_mode = false;
4721  node->hash_ngroups_current = 0;
4722 
4724  /* Rebuild an empty hash table */
4725  build_hash_tables(node);
4726  node->table_filled = false;
4727  /* iterator will be reset when the table is filled */
4728 
4729  hashagg_recompile_expressions(node, false, false);
4730  }
4731 
4732  if (node->aggstrategy != AGG_HASHED)
4733  {
4734  /*
4735  * Reset the per-group state (in particular, mark transvalues null)
4736  */
4737  for (setno = 0; setno < numGroupingSets; setno++)
4738  {
4739  MemSet(node->pergroups[setno], 0,
4740  sizeof(AggStatePerGroupData) * node->numaggs);
4741  }
4742 
4743  /* reset to phase 1 */
4744  initialize_phase(node, 1);
4745 
4746  node->input_done = false;
4747  node->projected_set = -1;
4748  }
4749 
4750  if (outerPlan->chgParam == NULL)
4751  ExecReScan(outerPlan);
4752 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3186
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:483
Datum * ecxt_aggvalues
Definition: execnodes.h:245
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2135
bool agg_done
Definition: execnodes.h:2153
ScanState ss
Definition: execnodes.h:2133
ExprContext * ps_ExprContext
Definition: execnodes.h:971
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
#define MemSet(start, val, len)
Definition: c.h:949
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1322
AggStatePerTrans pertrans
Definition: execnodes.h:2143
int projected_set
Definition: execnodes.h:2154
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2171
int numtrans
Definition: execnodes.h:2136
bool hash_spill_mode
Definition: execnodes.h:2183
PlanState ps
Definition: execnodes.h:1319
int maxsets
Definition: execnodes.h:2163
bool table_filled
Definition: execnodes.h:2173
AggStrategy aggstrategy
Definition: execnodes.h:2137
#define outerPlanState(node)
Definition: execnodes.h:1026
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
Bitmapset * aggParams
Definition: plannodes.h:827
AggStatePerHash perhash
Definition: execnodes.h:2196
Bitmapset * chgParam
Definition: execnodes.h:964
#define outerPlan(node)
Definition: plannodes.h:172
TupleHashIterator hashiter
Definition: nodeAgg.h:304
bool input_done
Definition: execnodes.h:2152
ExprContext * hashcontext
Definition: execnodes.h:2144
bool * ecxt_aggnulls
Definition: execnodes.h:247
uintptr_t Datum
Definition: postgres.h:367
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:505
Plan * plan
Definition: execnodes.h:932
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:724
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1742
#define Max(x, y)
Definition: c.h:921
ExprContext ** aggcontexts
Definition: execnodes.h:2145
bool hash_ever_spilled
Definition: execnodes.h:2182
AggStatePerGroup * pergroups
Definition: execnodes.h:2169
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:443
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
uint64 hash_ngroups_current
Definition: execnodes.h:2191
Definition: plannodes.h:816
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1445
TupleHashTable hashtable
Definition: nodeAgg.h:303
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1471

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

Definition at line 575 of file nodeAgg.c.

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

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

576 {
577  TupleTableSlot *slot;
578 
579  if (aggstate->sort_in)
580  {
581  /* make sure we check for interrupts in either path through here */
583  if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
584  aggstate->sort_slot, NULL))
585  return NULL;
586  slot = aggstate->sort_slot;
587  }
588  else
589  slot = ExecProcNode(outerPlanState(aggstate));
590 
591  if (!TupIsNull(slot) && aggstate->sort_out)
592  tuplesort_puttupleslot(aggstate->sort_out, slot);
593 
594  return slot;
595 }
TupleTableSlot * sort_slot
Definition: execnodes.h:2167
Tuplesortstate * sort_out
Definition: execnodes.h:2166
Tuplesortstate * sort_in
Definition: execnodes.h:2165
#define outerPlanState(node)
Definition: execnodes.h:1026
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2389
#define TupIsNull(slot)
Definition: tuptable.h:292
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:240
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1665

◆ finalize_aggregate()

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

Definition at line 1064 of file nodeAgg.c.

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

Referenced by finalize_aggregates().

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

◆ finalize_aggregates()

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

Definition at line 1317 of file nodeAgg.c.

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

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table_in_memory().

1320 {
1321  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1322  Datum *aggvalues = econtext->ecxt_aggvalues;
1323  bool *aggnulls = econtext->ecxt_aggnulls;
1324  int aggno;
1325  int transno;
1326 
1327  /*
1328  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1329  * inputs and run the transition functions.
1330  */
1331  for (transno = 0; transno < aggstate->numtrans; transno++)
1332  {
1333  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1334  AggStatePerGroup pergroupstate;
1335 
1336  pergroupstate = &pergroup[transno];
1337 
1338  if (pertrans->numSortCols > 0)
1339  {
1340  Assert(aggstate->aggstrategy != AGG_HASHED &&
1341  aggstate->aggstrategy != AGG_MIXED);
1342 
1343  if (pertrans->numInputs == 1)
1345  pertrans,
1346  pergroupstate);
1347  else
1349  pertrans,
1350  pergroupstate);
1351  }
1352  }
1353 
1354  /*
1355  * Run the final functions.
1356  */
1357  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1358  {
1359  AggStatePerAgg peragg = &peraggs[aggno];
1360  int transno = peragg->transno;
1361  AggStatePerGroup pergroupstate;
1362 
1363  pergroupstate = &pergroup[transno];
1364 
1365  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1366  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1367  &aggvalues[aggno], &aggnulls[aggno]);
1368  else
1369  finalize_aggregate(aggstate, peragg, pergroupstate,
1370  &aggvalues[aggno], &aggnulls[aggno]);
1371  }
1372 }
Datum * ecxt_aggvalues
Definition: execnodes.h:245
int numaggs
Definition: execnodes.h:2135
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1167
ScanState ss
Definition: execnodes.h:2133
ExprContext * ps_ExprContext
Definition: execnodes.h:971
AggSplit aggsplit
Definition: execnodes.h:2138
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1064
AggStatePerTrans pertrans
Definition: execnodes.h:2143
int numtrans
Definition: execnodes.h:2136
PlanState ps
Definition: execnodes.h:1319
AggStrategy aggstrategy
Definition: execnodes.h:2137
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:970
bool * ecxt_aggnulls
Definition: execnodes.h:247
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:745
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:791
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:878

◆ finalize_partialaggregate()

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

Definition at line 1167 of file nodeAgg.c.

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

Referenced by finalize_aggregates().

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

◆ find_cols()

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

Definition at line 1406 of file nodeAgg.c.

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

Referenced by find_hash_columns().

1407 {
1408  Agg *agg = (Agg *) aggstate->ss.ps.plan;
1409  FindColsContext context;
1410 
1411  context.is_aggref = false;
1412  context.aggregated = NULL;
1413  context.unaggregated = NULL;
1414 
1415  (void) find_cols_walker((Node *) agg->plan.targetlist, &context);
1416  (void) find_cols_walker((Node *) agg->plan.qual, &context);
1417 
1418  *aggregated = context.aggregated;
1419  *unaggregated = context.unaggregated;
1420 }
List * qual
Definition: plannodes.h:143
ScanState ss
Definition: execnodes.h:2133
Definition: nodes.h:528
PlanState ps
Definition: execnodes.h:1319
static bool find_cols_walker(Node *node, FindColsContext *context)
Definition: nodeAgg.c:1423
Plan plan
Definition: plannodes.h:818
Plan * plan
Definition: execnodes.h:932
List * targetlist
Definition: plannodes.h:142
Definition: plannodes.h:816
bool is_aggref
Definition: nodeAgg.c:377

◆ find_cols_walker()

static bool find_cols_walker ( Node node,
FindColsContext context 
)
static

Definition at line 1423 of file nodeAgg.c.

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

Referenced by find_cols().

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

◆ find_compatible_peragg()

static int find_compatible_peragg ( Aggref newagg,
AggState aggstate,
int  lastaggno,
List **  same_input_transnos 
)
static

Definition at line 4432 of file nodeAgg.c.

References Aggref::aggcollid, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggkind, Aggref::aggorder, AggStatePerAggData::aggref, Aggref::aggstar, Aggref::aggtranstype, Aggref::aggtype, Aggref::aggvariadic, Aggref::args, contain_volatile_functions(), equal(), Aggref::inputcollid, lappend_int(), list_free(), NIL, AggState::peragg, AggStatePerAggData::shareable, and AggStatePerAggData::transno.

Referenced by ExecInitAgg().

4434 {
4435  int aggno;
4436  AggStatePerAgg peraggs;
4437 
4438  *same_input_transnos = NIL;
4439 
4440  /* we mustn't reuse the aggref if it contains volatile function calls */
4441  if (contain_volatile_functions((Node *) newagg))
4442  return -1;
4443 
4444  peraggs = aggstate->peragg;
4445 
4446  /*
4447  * Search through the list of already seen aggregates. If we find an
4448  * existing identical aggregate call, then we can re-use that one. While
4449  * searching, we'll also collect a list of Aggrefs with the same input
4450  * parameters. If no matching Aggref is found, the caller can potentially
4451  * still re-use the transition state of one of them. (At this stage we
4452  * just compare the parsetrees; whether different aggregates share the
4453  * same transition function will be checked later.)
4454  */
4455  for (aggno = 0; aggno <= lastaggno; aggno++)
4456  {
4457  AggStatePerAgg peragg;
4458  Aggref *existingRef;
4459 
4460  peragg = &peraggs[aggno];
4461  existingRef = peragg->aggref;
4462 
4463  /* all of the following must be the same or it's no match */
4464  if (newagg->inputcollid != existingRef->inputcollid ||
4465  newagg->aggtranstype != existingRef->aggtranstype ||
4466  newagg->aggstar != existingRef->aggstar ||
4467  newagg->aggvariadic != existingRef->aggvariadic ||
4468  newagg->aggkind != existingRef->aggkind ||
4469  !equal(newagg->args, existingRef->args) ||
4470  !equal(newagg->aggorder, existingRef->aggorder) ||
4471  !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
4472  !equal(newagg->aggfilter, existingRef->aggfilter))
4473  continue;
4474 
4475  /* if it's the same aggregate function then report exact match */
4476  if (newagg->aggfnoid == existingRef->aggfnoid &&
4477  newagg->aggtype == existingRef->aggtype &&
4478  newagg->aggcollid == existingRef->aggcollid &&
4479  equal(newagg->aggdirectargs, existingRef->aggdirectargs))
4480  {
4481  list_free(*same_input_transnos);
4482  *same_input_transnos = NIL;
4483  return aggno;
4484  }
4485 
4486  /*
4487  * Not identical, but it had the same inputs. If the final function
4488  * permits sharing, return its transno to the caller, in case we can
4489  * re-use its per-trans state. (If there's already sharing going on,
4490  * we might report a transno more than once. find_compatible_pertrans
4491  * is cheap enough that it's not worth spending cycles to avoid that.)
4492  */
4493  if (peragg->shareable)
4494  *same_input_transnos = lappend_int(*same_input_transnos,
4495  peragg->transno);
4496  }
4497 
4498  return -1;
4499 }
List * aggdistinct
Definition: primnodes.h:321
#define NIL
Definition: pg_list.h:65
bool aggvariadic
Definition: primnodes.h:324
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3032
Oid inputcollid
Definition: primnodes.h:315
Definition: nodes.h:528
List * args
Definition: primnodes.h:319
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:724
bool aggstar
Definition: primnodes.h:323
Aggref * aggref
Definition: nodeAgg.h:187
List * aggorder
Definition: primnodes.h:320
List * aggdirectargs
Definition: primnodes.h:318
List * lappend_int(List *list, int datum)
Definition: list.c:339
Oid aggfnoid
Definition: primnodes.h:312
Expr * aggfilter
Definition: primnodes.h:322
Oid aggcollid
Definition: primnodes.h:314
AggStatePerAgg peragg
Definition: execnodes.h:2142
void list_free(List *list)
Definition: list.c:1376
Oid aggtranstype
Definition: primnodes.h:316
Oid aggtype
Definition: primnodes.h:313
char aggkind
Definition: primnodes.h:326

◆ find_compatible_pertrans()

static int find_compatible_pertrans ( AggState aggstate,
Aggref newagg,
bool  shareable,
Oid  aggtransfn,
Oid  aggtranstype,
Oid  aggserialfn,
Oid  aggdeserialfn,
Datum  initValue,
bool  initValueIsNull,
List transnos 
)
static

Definition at line 4510 of file nodeAgg.c.

References AggStatePerTransData::aggtranstype, datumIsEqual(), AggStatePerTransData::deserialfn_oid, AggStatePerTransData::initValue, AggStatePerTransData::initValueIsNull, lfirst_int, AggState::pertrans, AggStatePerTransData::serialfn_oid, AggStatePerTransData::transfn_oid, AggStatePerTransData::transtypeByVal, and AggStatePerTransData::transtypeLen.

Referenced by ExecInitAgg().

4515 {
4516  ListCell *lc;
4517 
4518  /* If this aggregate can't share transition states, give up */
4519  if (!shareable)
4520  return -1;
4521 
4522  foreach(lc, transnos)
4523  {
4524  int transno = lfirst_int(lc);
4525  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
4526 
4527  /*
4528  * if the transfns or transition state types are not the same then the
4529  * state can't be shared.
4530  */
4531  if (aggtransfn != pertrans->transfn_oid ||
4532  aggtranstype != pertrans->aggtranstype)
4533  continue;
4534 
4535  /*
4536  * The serialization and deserialization functions must match, if
4537  * present, as we're unable to share the trans state for aggregates
4538  * which will serialize or deserialize into different formats.
4539  * Remember that these will be InvalidOid if they're not required for
4540  * this agg node.
4541  */
4542  if (aggserialfn != pertrans->serialfn_oid ||
4543  aggdeserialfn != pertrans->deserialfn_oid)
4544  continue;
4545 
4546  /*
4547  * Check that the initial condition matches, too.
4548  */
4549  if (initValueIsNull && pertrans->initValueIsNull)
4550  return transno;
4551 
4552  if (!initValueIsNull && !pertrans->initValueIsNull &&
4553  datumIsEqual(initValue, pertrans->initValue,
4554  pertrans->transtypeByVal, pertrans->transtypeLen))
4555  return transno;
4556  }
4557  return -1;
4558 }
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:222
AggStatePerTrans pertrans
Definition: execnodes.h:2143
#define lfirst_int(lc)
Definition: pg_list.h:190
static int initValue(long lng_val)
Definition: informix.c:677

◆ find_hash_columns()

static void find_hash_columns ( AggState aggstate)
static

Definition at line 1566 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

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

◆ GetAggInitVal()

static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 4404 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

4405 {
4406  Oid typinput,
4407  typioparam;
4408  char *strInitVal;
4409  Datum initVal;
4410 
4411  getTypeInputInfo(transtype, &typinput, &typioparam);
4412  strInitVal = TextDatumGetCString(textInitVal);
4413  initVal = OidInputFunctionCall(typinput, strInitVal,
4414  typioparam, -1);
4415  pfree(strInitVal);
4416  return initVal;
4417 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:1057
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2751
#define TextDatumGetCString(d)
Definition: builtins.h:87
uintptr_t Datum
Definition: postgres.h:367
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1648

◆ hash_agg_check_limits()

static void hash_agg_check_limits ( AggState aggstate)
static

Definition at line 1851 of file nodeAgg.c.

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

Referenced by initialize_hash_entry().

1852 {
1853  uint64 ngroups = aggstate->hash_ngroups_current;
1854  Size meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt,
1855  true);
1857  true);
1858 
1859  /*
1860  * Don't spill unless there's at least one group in the hash table so we
1861  * can be sure to make progress even in edge cases.
1862  */
1863  if (aggstate->hash_ngroups_current > 0 &&
1864  (meta_mem + hashkey_mem > aggstate->hash_mem_limit ||
1865  ngroups > aggstate->hash_ngroups_limit))
1866  {
1867  hash_agg_enter_spill_mode(aggstate);
1868  }
1869 }
uint64 hash_ngroups_limit
Definition: execnodes.h:2186