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 "executor/execExpr.h"
#include "executor/executor.h"
#include "executor/nodeAgg.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 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 (AggState *aggstate)
 
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 (uint64 input_groups, double hashentrysize, int used_bits, int *log2_npartittions)
 
static AggStatePerGroup lookup_hash_entry (AggState *aggstate, uint32 hash, bool *in_hash_table)
 
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, int used_bits)
 
static MinimalTuple hashagg_batch_read (HashAggBatch *batch, uint32 *hashp)
 
static void hashagg_spill_init (HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits, uint64 input_tuples, 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, uint64 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 302 of file nodeAgg.c.

Referenced by hash_agg_entry_size().

◆ HASHAGG_MAX_PARTITIONS

#define HASHAGG_MAX_PARTITIONS   1024

Definition at line 287 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_MIN_PARTITIONS

#define HASHAGG_MIN_PARTITIONS   4

Definition at line 286 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_PARTITION_FACTOR

#define HASHAGG_PARTITION_FACTOR   1.50

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

831 {
832  bool dummynull;
833 
835  aggstate->tmpcontext,
836  &dummynull);
837 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:305
ExprState * evaltrans
Definition: nodeAgg.h:283
ExprContext * tmpcontext
Definition: execnodes.h:2159
AggStatePerPhase phase
Definition: execnodes.h:2152

◆ advance_transition_function()

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

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

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

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

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

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

◆ agg_refill_hash_table()

static bool agg_refill_hash_table ( AggState aggstate)
static

Definition at line 2588 of file nodeAgg.c.

References advance_aggregates(), AGG_MIXED, AggStatePerPhaseData::aggstrategy, AggState::all_pergroups, Assert, CHECK_FOR_INTERRUPTS, AggState::current_phase, 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_READ_BUFFER_SIZE, hashagg_recompile_expressions(), hashagg_spill_finish(), hashagg_spill_init(), hashagg_spill_tuple(), hashagg_tapeinfo_release(), AggState::hashcontext, AggState::hashentrysize, AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, HashAggBatch::input_tapenum, HashAggBatch::input_tuples, linitial, list_delete_first(), LogicalTapeRewindForRead(), lookup_hash_entry(), 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, HashTapeInfo::tapeset, AggState::tmpcontext, and HashAggBatch::used_bits.

Referenced by agg_retrieve_hash_table().

2589 {
2590  HashAggBatch *batch;
2591  HashAggSpill spill;
2592  HashTapeInfo *tapeinfo = aggstate->hash_tapeinfo;
2593  uint64 ngroups_estimate;
2594  bool spill_initialized = false;
2595 
2596  if (aggstate->hash_batches == NIL)
2597  return false;
2598 
2599  batch = linitial(aggstate->hash_batches);
2600  aggstate->hash_batches = list_delete_first(aggstate->hash_batches);
2601 
2602  /*
2603  * Estimate the number of groups for this batch as the total number of
2604  * tuples in its input file. Although that's a worst case, it's not bad
2605  * here for two reasons: (1) overestimating is better than
2606  * underestimating; and (2) we've already scanned the relation once, so
2607  * it's likely that we've already finalized many of the common values.
2608  */
2609  ngroups_estimate = batch->input_tuples;
2610 
2611  hash_agg_set_limits(aggstate->hashentrysize, ngroups_estimate,
2612  batch->used_bits, &aggstate->hash_mem_limit,
2613  &aggstate->hash_ngroups_limit, NULL);
2614 
2615  /* there could be residual pergroup pointers; clear them */
2616  for (int setoff = 0;
2617  setoff < aggstate->maxsets + aggstate->num_hashes;
2618  setoff++)
2619  aggstate->all_pergroups[setoff] = NULL;
2620 
2621  /* free memory and reset hash tables */
2622  ReScanExprContext(aggstate->hashcontext);
2623  for (int setno = 0; setno < aggstate->num_hashes; setno++)
2624  ResetTupleHashTable(aggstate->perhash[setno].hashtable);
2625 
2626  aggstate->hash_ngroups_current = 0;
2627 
2628  /*
2629  * In AGG_MIXED mode, hash aggregation happens in phase 1 and the output
2630  * happens in phase 0. So, we switch to phase 1 when processing a batch,
2631  * and back to phase 0 after the batch is done.
2632  */
2633  Assert(aggstate->current_phase == 0);
2634  if (aggstate->phase->aggstrategy == AGG_MIXED)
2635  {
2636  aggstate->current_phase = 1;
2637  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2638  }
2639 
2640  select_current_set(aggstate, batch->setno, true);
2641 
2642  /*
2643  * Spilled tuples are always read back as MinimalTuples, which may be
2644  * different from the outer plan, so recompile the aggregate expressions.
2645  *
2646  * We still need the NULL check, because we are only processing one
2647  * grouping set at a time and the rest will be NULL.
2648  */
2649  hashagg_recompile_expressions(aggstate, true, true);
2650 
2653  for (;;)
2654  {
2655  TupleTableSlot *slot = aggstate->hash_spill_rslot;
2656  MinimalTuple tuple;
2657  uint32 hash;
2658  bool in_hash_table;
2659 
2661 
2662  tuple = hashagg_batch_read(batch, &hash);
2663  if (tuple == NULL)
2664  break;
2665 
2666  ExecStoreMinimalTuple(tuple, slot, true);
2667  aggstate->tmpcontext->ecxt_outertuple = slot;
2668 
2669  prepare_hash_slot(aggstate);
2670  aggstate->hash_pergroup[batch->setno] =
2671  lookup_hash_entry(aggstate, hash, &in_hash_table);
2672 
2673  if (in_hash_table)
2674  {
2675  /* Advance the aggregates (or combine functions) */
2676  advance_aggregates(aggstate);
2677  }
2678  else
2679  {
2680  if (!spill_initialized)
2681  {
2682  /*
2683  * Avoid initializing the spill until we actually need it so
2684  * that we don't assign tapes that will never be used.
2685  */
2686  spill_initialized = true;
2687  hashagg_spill_init(&spill, tapeinfo, batch->used_bits,
2688  ngroups_estimate, aggstate->hashentrysize);
2689  }
2690  /* no memory for a new group, spill */
2691  hashagg_spill_tuple(aggstate, &spill, slot, hash);
2692  }
2693 
2694  /*
2695  * Reset per-input-tuple context after each tuple, but note that the
2696  * hash lookups do this too
2697  */
2698  ResetExprContext(aggstate->tmpcontext);
2699  }
2700 
2701  hashagg_tapeinfo_release(tapeinfo, batch->input_tapenum);
2702 
2703  /* change back to phase 0 */
2704  aggstate->current_phase = 0;
2705  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2706 
2707  if (spill_initialized)
2708  {
2709  hash_agg_update_metrics(aggstate, true, spill.npartitions);
2710  hashagg_spill_finish(aggstate, &spill, batch->setno);
2711  }
2712  else
2713  hash_agg_update_metrics(aggstate, true, 0);
2714 
2715  aggstate->hash_spill_mode = false;
2716 
2717  /* prepare to walk the first hash table */
2718  select_current_set(aggstate, batch->setno, true);
2719  ResetTupleHashIterator(aggstate->perhash[batch->setno].hashtable,
2720  &aggstate->perhash[batch->setno].hashiter);
2721 
2722  pfree(batch);
2723 
2724  return true;
2725 }
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2210
#define NIL
Definition: pg_list.h:65
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:467
AggStatePerPhase phases
Definition: execnodes.h:2177
double hashentrysize
Definition: execnodes.h:2202
static void hashagg_tapeinfo_release(HashTapeInfo *tapeinfo, int tapenum)
Definition: nodeAgg.c:2924
static void hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
Definition: nodeAgg.c:1896
uint64 hash_ngroups_limit
Definition: execnodes.h:2199
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1416
static AggStatePerGroup lookup_hash_entry(AggState *aggstate, uint32 hash, bool *in_hash_table)
Definition: nodeAgg.c:2030
static void hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
Definition: nodeAgg.c:3133
int64 input_tuples
Definition: nodeAgg.c:359
int current_phase
Definition: execnodes.h:2154
TupleTableSlot * hash_spill_rslot
Definition: execnodes.h:2192
static void advance_aggregates(AggState *aggstate)
Definition: nodeAgg.c:830
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:282
ExprContext * tmpcontext
Definition: execnodes.h:2159
bool hash_spill_mode
Definition: execnodes.h:2196
List * hash_batches
Definition: execnodes.h:2194
int maxsets
Definition: execnodes.h:2176
void pfree(void *pointer)
Definition: mcxt.c:1056
#define linitial(l)
Definition: pg_list.h:195
int npartitions
Definition: nodeAgg.c:337
void hash_agg_set_limits(double hashentrysize, uint64 input_groups, int used_bits, Size *mem_limit, uint64 *ngroups_limit, int *num_partitions)
Definition: nodeAgg.c:1778
static Size hashagg_spill_tuple(AggState *aggstate, HashAggSpill *spill, TupleTableSlot *slot, uint32 hash)
Definition: nodeAgg.c:2970
int used_bits
Definition: nodeAgg.c:356
unsigned int uint32
Definition: c.h:374
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2189
AggStatePerHash perhash
Definition: execnodes.h:2209
AggStrategy aggstrategy
Definition: nodeAgg.h:274
TupleHashIterator hashiter
Definition: nodeAgg.h:304
int num_hashes
Definition: execnodes.h:2187
ExprContext * hashcontext
Definition: execnodes.h:2157
#define HASHAGG_READ_BUFFER_SIZE
Definition: nodeAgg.c:295
AggStatePerPhase phase
Definition: execnodes.h:2152
LogicalTapeSet * tapeset
Definition: nodeAgg.c:318
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:727
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1727
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:230
#define Assert(condition)
Definition: c.h:745
int input_tapenum
Definition: nodeAgg.c:358
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:443
Size hash_mem_limit
Definition: execnodes.h:2198
void LogicalTapeRewindForRead(LogicalTapeSet *lts, int tapenum, size_t buffer_size)
Definition: logtape.c:849
static MinimalTuple hashagg_batch_read(HashAggBatch *batch, uint32 *hashp)
Definition: nodeAgg.c:3049
uint64 hash_ngroups_current
Definition: execnodes.h:2204
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:541
TupleHashTable hashtable
Definition: nodeAgg.h:303
static void prepare_hash_slot(AggState *aggstate)
Definition: nodeAgg.c:1211
static void hashagg_spill_init(HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits, uint64 input_tuples, double hashentrysize)
Definition: nodeAgg.c:2943
#define ResetExprContext(econtext)
Definition: executor.h:501
List * list_delete_first(List *list)
Definition: list.c:860
AggStatePerGroup * all_pergroups
Definition: execnodes.h:2215

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

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

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

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

Definition at line 2735 of file nodeAgg.c.

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

Referenced by agg_retrieve_direct(), and ExecAgg().

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

◆ agg_retrieve_hash_table_in_memory()

static TupleTableSlot * agg_retrieve_hash_table_in_memory ( AggState aggstate)
static

Definition at line 2760 of file nodeAgg.c.

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

Referenced by agg_retrieve_hash_table().

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

4755 {
4756  if (fcinfo->context && IsA(fcinfo->context, AggState))
4757  {
4758  if (aggcontext)
4759  {
4760  AggState *aggstate = ((AggState *) fcinfo->context);
4761  ExprContext *cxt = aggstate->curaggcontext;
4762 
4763  *aggcontext = cxt->ecxt_per_tuple_memory;
4764  }
4765  return AGG_CONTEXT_AGGREGATE;
4766  }
4767  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4768  {
4769  if (aggcontext)
4770  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4771  return AGG_CONTEXT_WINDOW;
4772  }
4773 
4774  /* this is just to prevent "uninitialized variable" warnings */
4775  if (aggcontext)
4776  *aggcontext = NULL;
4777  return 0;
4778 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
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:2161
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:737

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4798 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4799 {
4800  if (fcinfo->context && IsA(fcinfo->context, AggState))
4801  {
4802  AggState *aggstate = (AggState *) fcinfo->context;
4803  AggStatePerAgg curperagg;
4804  AggStatePerTrans curpertrans;
4805 
4806  /* check curperagg (valid when in a final function) */
4807  curperagg = aggstate->curperagg;
4808 
4809  if (curperagg)
4810  return curperagg->aggref;
4811 
4812  /* check curpertrans (valid when in a transition function) */
4813  curpertrans = aggstate->curpertrans;
4814 
4815  if (curpertrans)
4816  return curpertrans->aggref;
4817  }
4818  return NULL;
4819 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
fmNodePtr context
Definition: fmgr.h:88
Aggref * aggref
Definition: nodeAgg.h:187
Aggref * aggref
Definition: nodeAgg.h:44
AggStatePerAgg curperagg
Definition: execnodes.h:2162
AggStatePerTrans curpertrans
Definition: execnodes.h:2164

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4832 of file nodeAgg.c.

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

4833 {
4834  if (fcinfo->context && IsA(fcinfo->context, AggState))
4835  {
4836  AggState *aggstate = (AggState *) fcinfo->context;
4837 
4838  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4839  }
4840  return NULL;
4841 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
fmNodePtr context
Definition: fmgr.h:88
ExprContext * tmpcontext
Definition: execnodes.h:2159

◆ aggregate_dummy()

Datum aggregate_dummy ( PG_FUNCTION_ARGS  )

Definition at line 4925 of file nodeAgg.c.

References elog, and ERROR.

4926 {
4927  elog(ERROR, "aggregate function %u called as normal function",
4928  fcinfo->flinfo->fn_oid);
4929  return (Datum) 0; /* keep compiler quiet */
4930 }
#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 4897 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4900 {
4901  if (fcinfo->context && IsA(fcinfo->context, AggState))
4902  {
4903  AggState *aggstate = (AggState *) fcinfo->context;
4904  ExprContext *cxt = aggstate->curaggcontext;
4905 
4906  RegisterExprContextCallback(cxt, func, arg);
4907 
4908  return;
4909  }
4910  elog(ERROR, "aggregate function cannot register a callback in this context");
4911 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
fmNodePtr context
Definition: fmgr.h:88
#define ERROR
Definition: elog.h:43
ExprContext * curaggcontext
Definition: execnodes.h:2161
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 4858 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4859 {
4860  if (fcinfo->context && IsA(fcinfo->context, AggState))
4861  {
4862  AggState *aggstate = (AggState *) fcinfo->context;
4863  AggStatePerAgg curperagg;
4864  AggStatePerTrans curpertrans;
4865 
4866  /* check curperagg (valid when in a final function) */
4867  curperagg = aggstate->curperagg;
4868 
4869  if (curperagg)
4870  return aggstate->pertrans[curperagg->transno].aggshared;
4871 
4872  /* check curpertrans (valid when in a transition function) */
4873  curpertrans = aggstate->curpertrans;
4874 
4875  if (curpertrans)
4876  return curpertrans->aggshared;
4877  }
4878  return true;
4879 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
fmNodePtr context
Definition: fmgr.h:88
AggStatePerTrans pertrans
Definition: execnodes.h:2156
AggStatePerAgg curperagg
Definition: execnodes.h:2162
AggStatePerTrans curpertrans
Definition: execnodes.h:2164

◆ build_hash_table()

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

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

1492 {
1493  AggStatePerHash perhash = &aggstate->perhash[setno];
1494  MemoryContext metacxt = aggstate->hash_metacxt;
1495  MemoryContext hashcxt = aggstate->hashcontext->ecxt_per_tuple_memory;
1496  MemoryContext tmpcxt = aggstate->tmpcontext->ecxt_per_tuple_memory;
1497  Size additionalsize;
1498 
1499  Assert(aggstate->aggstrategy == AGG_HASHED ||
1500  aggstate->aggstrategy == AGG_MIXED);
1501 
1502  /*
1503  * Used to make sure initial hash table allocation does not exceed
1504  * work_mem. Note that the estimate does not include space for
1505  * pass-by-reference transition data values, nor for the representative
1506  * tuple of each group.
1507  */
1508  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1509 
1510  perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
1511  perhash->hashslot->tts_tupleDescriptor,
1512  perhash->numCols,
1513  perhash->hashGrpColIdxHash,
1514  perhash->eqfuncoids,
1515  perhash->hashfunctions,
1516  perhash->aggnode->grpCollations,
1517  nbuckets,
1518  additionalsize,
1519  metacxt,
1520  hashcxt,
1521  tmpcxt,
1522  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1523 }
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:2146
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
AggSplit aggsplit
Definition: execnodes.h:2151
int numtrans
Definition: execnodes.h:2149
ExprContext * tmpcontext
Definition: execnodes.h:2159
PlanState ps
Definition: execnodes.h:1332
AggStrategy aggstrategy
Definition: execnodes.h:2150
MemoryContext hash_metacxt
Definition: execnodes.h:2188
struct AggStatePerGroupData AggStatePerGroupData
AggStatePerHash perhash
Definition: execnodes.h:2209
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:312
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2157
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:792
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 1456 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().

1457 {
1458  int setno;
1459 
1460  for (setno = 0; setno < aggstate->num_hashes; ++setno)
1461  {
1462  AggStatePerHash perhash = &aggstate->perhash[setno];
1463  long nbuckets;
1464  Size memory;
1465 
1466  if (perhash->hashtable != NULL)
1467  {
1468  ResetTupleHashTable(perhash->hashtable);
1469  continue;
1470  }
1471 
1472  Assert(perhash->aggnode->numGroups > 0);
1473 
1474  memory = aggstate->hash_mem_limit / aggstate->num_hashes;
1475 
1476  /* choose reasonable number of buckets per hashtable */
1477  nbuckets = hash_choose_num_buckets(aggstate->hashentrysize,
1478  perhash->aggnode->numGroups,
1479  memory);
1480 
1481  build_hash_table(aggstate, setno, nbuckets);
1482  }
1483 
1484  aggstate->hash_ngroups_current = 0;
1485 }
double hashentrysize
Definition: execnodes.h:2202
static long hash_choose_num_buckets(double hashentrysize, long estimated_nbuckets, Size memory)
Definition: nodeAgg.c:1945
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:282
static void build_hash_table(AggState *aggstate, int setno, long nbuckets)
Definition: nodeAgg.c:1491
AggStatePerHash perhash
Definition: execnodes.h:2209
int num_hashes
Definition: execnodes.h:2187
#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:2198
uint64 hash_ngroups_current
Definition: execnodes.h:2204
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 4072 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().

4079 {
4080  int numGroupingSets = Max(aggstate->maxsets, 1);
4081  Expr *serialfnexpr = NULL;
4082  Expr *deserialfnexpr = NULL;
4083  ListCell *lc;
4084  int numInputs;
4085  int numDirectArgs;
4086  List *sortlist;
4087  int numSortCols;
4088  int numDistinctCols;
4089  int i;
4090 
4091  /* Begin filling in the pertrans data */
4092  pertrans->aggref = aggref;
4093  pertrans->aggshared = false;
4094  pertrans->aggCollation = aggref->inputcollid;
4095  pertrans->transfn_oid = aggtransfn;
4096  pertrans->serialfn_oid = aggserialfn;
4097  pertrans->deserialfn_oid = aggdeserialfn;
4098  pertrans->initValue = initValue;
4099  pertrans->initValueIsNull = initValueIsNull;
4100 
4101  /* Count the "direct" arguments, if any */
4102  numDirectArgs = list_length(aggref->aggdirectargs);
4103 
4104  /* Count the number of aggregated input columns */
4105  pertrans->numInputs = numInputs = list_length(aggref->args);
4106 
4107  pertrans->aggtranstype = aggtranstype;
4108 
4109  /*
4110  * When combining states, we have no use at all for the aggregate
4111  * function's transfn. Instead we use the combinefn. In this case, the
4112  * transfn and transfn_oid fields of pertrans refer to the combine
4113  * function rather than the transition function.
4114  */
4115  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
4116  {
4117  Expr *combinefnexpr;
4118  size_t numTransArgs;
4119 
4120  /*
4121  * When combining there's only one input, the to-be-combined added
4122  * transition value from below (this node's transition value is
4123  * counted separately).
4124  */
4125  pertrans->numTransInputs = 1;
4126 
4127  /* account for the current transition state */
4128  numTransArgs = pertrans->numTransInputs + 1;
4129 
4130  build_aggregate_combinefn_expr(aggtranstype,
4131  aggref->inputcollid,
4132  aggtransfn,
4133  &combinefnexpr);
4134  fmgr_info(aggtransfn, &pertrans->transfn);
4135  fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
4136 
4137  pertrans->transfn_fcinfo =
4140  &pertrans->transfn,
4141  numTransArgs,
4142  pertrans->aggCollation,
4143  (void *) aggstate, NULL);
4144 
4145  /*
4146  * Ensure that a combine function to combine INTERNAL states is not
4147  * strict. This should have been checked during CREATE AGGREGATE, but
4148  * the strict property could have been changed since then.
4149  */
4150  if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
4151  ereport(ERROR,
4152  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4153  errmsg("combine function with transition type %s must not be declared STRICT",
4154  format_type_be(aggtranstype))));
4155  }
4156  else
4157  {
4158  Expr *transfnexpr;
4159  size_t numTransArgs;
4160 
4161  /* Detect how many arguments to pass to the transfn */
4162  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4163  pertrans->numTransInputs = numInputs;
4164  else
4165  pertrans->numTransInputs = numArguments;
4166 
4167  /* account for the current transition state */
4168  numTransArgs = pertrans->numTransInputs + 1;
4169 
4170  /*
4171  * Set up infrastructure for calling the transfn. Note that
4172  * invtransfn is not needed here.
4173  */
4174  build_aggregate_transfn_expr(inputTypes,
4175  numArguments,
4176  numDirectArgs,
4177  aggref->aggvariadic,
4178  aggtranstype,
4179  aggref->inputcollid,
4180  aggtransfn,
4181  InvalidOid,
4182  &transfnexpr,
4183  NULL);
4184  fmgr_info(aggtransfn, &pertrans->transfn);
4185  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
4186 
4187  pertrans->transfn_fcinfo =
4190  &pertrans->transfn,
4191  numTransArgs,
4192  pertrans->aggCollation,
4193  (void *) aggstate, NULL);
4194 
4195  /*
4196  * If the transfn is strict and the initval is NULL, make sure input
4197  * type and transtype are the same (or at least binary-compatible), so
4198  * that it's OK to use the first aggregated input value as the initial
4199  * transValue. This should have been checked at agg definition time,
4200  * but we must check again in case the transfn's strictness property
4201  * has been changed.
4202  */
4203  if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
4204  {
4205  if (numArguments <= numDirectArgs ||
4206  !IsBinaryCoercible(inputTypes[numDirectArgs],
4207  aggtranstype))
4208  ereport(ERROR,
4209  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4210  errmsg("aggregate %u needs to have compatible input type and transition type",
4211  aggref->aggfnoid)));
4212  }
4213  }
4214 
4215  /* get info about the state value's datatype */
4216  get_typlenbyval(aggtranstype,
4217  &pertrans->transtypeLen,
4218  &pertrans->transtypeByVal);
4219 
4220  if (OidIsValid(aggserialfn))
4221  {
4222  build_aggregate_serialfn_expr(aggserialfn,
4223  &serialfnexpr);
4224  fmgr_info(aggserialfn, &pertrans->serialfn);
4225  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
4226 
4227  pertrans->serialfn_fcinfo =
4230  &pertrans->serialfn,
4231  1,
4232  InvalidOid,
4233  (void *) aggstate, NULL);
4234  }
4235 
4236  if (OidIsValid(aggdeserialfn))
4237  {
4238  build_aggregate_deserialfn_expr(aggdeserialfn,
4239  &deserialfnexpr);
4240  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
4241  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
4242 
4243  pertrans->deserialfn_fcinfo =
4246  &pertrans->deserialfn,
4247  2,
4248  InvalidOid,
4249  (void *) aggstate, NULL);
4250 
4251  }
4252 
4253  /*
4254  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
4255  * have a list of SortGroupClause nodes; fish out the data in them and
4256  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
4257  * however; the agg's transfn and finalfn are responsible for that.
4258  *
4259  * Note that by construction, if there is a DISTINCT clause then the ORDER
4260  * BY clause is a prefix of it (see transformDistinctClause).
4261  */
4262  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4263  {
4264  sortlist = NIL;
4265  numSortCols = numDistinctCols = 0;
4266  }
4267  else if (aggref->aggdistinct)
4268  {
4269  sortlist = aggref->aggdistinct;
4270  numSortCols = numDistinctCols = list_length(sortlist);
4271  Assert(numSortCols >= list_length(aggref->aggorder));
4272  }
4273  else
4274  {
4275  sortlist = aggref->aggorder;
4276  numSortCols = list_length(sortlist);
4277  numDistinctCols = 0;
4278  }
4279 
4280  pertrans->numSortCols = numSortCols;
4281  pertrans->numDistinctCols = numDistinctCols;
4282 
4283  /*
4284  * If we have either sorting or filtering to do, create a tupledesc and
4285  * slot corresponding to the aggregated inputs (including sort
4286  * expressions) of the agg.
4287  */
4288  if (numSortCols > 0 || aggref->aggfilter)
4289  {
4290  pertrans->sortdesc = ExecTypeFromTL(aggref->args);
4291  pertrans->sortslot =
4292  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4294  }
4295 
4296  if (numSortCols > 0)
4297  {
4298  /*
4299  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
4300  * (yet)
4301  */
4302  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
4303 
4304  /* If we have only one input, we need its len/byval info. */
4305  if (numInputs == 1)
4306  {
4307  get_typlenbyval(inputTypes[numDirectArgs],
4308  &pertrans->inputtypeLen,
4309  &pertrans->inputtypeByVal);
4310  }
4311  else if (numDistinctCols > 0)
4312  {
4313  /* we will need an extra slot to store prior values */
4314  pertrans->uniqslot =
4315  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4317  }
4318 
4319  /* Extract the sort information for use later */
4320  pertrans->sortColIdx =
4321  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
4322  pertrans->sortOperators =
4323  (Oid *) palloc(numSortCols * sizeof(Oid));
4324  pertrans->sortCollations =
4325  (Oid *) palloc(numSortCols * sizeof(Oid));
4326  pertrans->sortNullsFirst =
4327  (bool *) palloc(numSortCols * sizeof(bool));
4328 
4329  i = 0;
4330  foreach(lc, sortlist)
4331  {
4332  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
4333  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
4334 
4335  /* the parser should have made sure of this */
4336  Assert(OidIsValid(sortcl->sortop));
4337 
4338  pertrans->sortColIdx[i] = tle->resno;
4339  pertrans->sortOperators[i] = sortcl->sortop;
4340  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
4341  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
4342  i++;
4343  }
4344  Assert(i == numSortCols);
4345  }
4346 
4347  if (aggref->aggdistinct)
4348  {
4349  Oid *ops;
4350 
4351  Assert(numArguments > 0);
4352  Assert(list_length(aggref->aggdistinct) == numDistinctCols);
4353 
4354  ops = palloc(numDistinctCols * sizeof(Oid));
4355 
4356  i = 0;
4357  foreach(lc, aggref->aggdistinct)
4358  ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
4359 
4360  /* lookup / build the necessary comparators */
4361  if (numDistinctCols == 1)
4362  fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
4363  else
4364  pertrans->equalfnMulti =
4365  execTuplesMatchPrepare(pertrans->sortdesc,
4366  numDistinctCols,
4367  pertrans->sortColIdx,
4368  ops,
4369  pertrans->sortCollations,
4370  &aggstate->ss.ps);
4371  pfree(ops);
4372  }
4373 
4374  pertrans->sortstates = (Tuplesortstate **)
4375  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
4376 }
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:2146
FmgrInfo equalfnOne
Definition: nodeAgg.h:110
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
Oid inputcollid
Definition: primnodes.h:315
Definition: nodes.h:529
AggSplit aggsplit
Definition: execnodes.h:2151
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:791
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:1332
int maxsets
Definition: execnodes.h:2176
void pfree(void *pointer)
Definition: mcxt.c:1056
AggStrategy aggstrategy
Definition: execnodes.h:2150
#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:1408
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:980
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:190
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:1407
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:719
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:949
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 2152 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().

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

◆ ExecAggEstimate()

void ExecAggEstimate ( AggState node,
ParallelContext pcxt 
)

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

4945 {
4946  Size size;
4947 
4948  /* don't need this if not instrumenting or no workers */
4949  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4950  return;
4951 
4952  size = mul_size(pcxt->nworkers, sizeof(AggregateInstrumentation));
4953  size = add_size(size, offsetof(SharedAggInfo, sinstrument));
4954  shm_toc_estimate_chunk(&pcxt->estimator, size);
4955  shm_toc_estimate_keys(&pcxt->estimator, 1);
4956 }
Instrumentation * instrument
Definition: execnodes.h:955
ScanState ss
Definition: execnodes.h:2146
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:1332
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 4965 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().

4966 {
4967  Size size;
4968 
4969  /* don't need this if not instrumenting or no workers */
4970  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
4971  return;
4972 
4973  size = offsetof(SharedAggInfo, sinstrument)
4974  + pcxt->nworkers * sizeof(AggregateInstrumentation);
4975  node->shared_info = shm_toc_allocate(pcxt->toc, size);
4976  /* ensure any unfilled slots will contain zeroes */
4977  memset(node->shared_info, 0, size);
4978  node->shared_info->num_workers = pcxt->nworkers;
4979  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
4980  node->shared_info);
4981 }
Instrumentation * instrument
Definition: execnodes.h:955
ScanState ss
Definition: execnodes.h:2146
int plan_node_id
Definition: plannodes.h:141
PlanState ps
Definition: execnodes.h:1332
struct AggregateInstrumentation AggregateInstrumentation
Plan * plan
Definition: execnodes.h:945
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:2218
#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 4990 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().

4991 {
4992  node->shared_info =
4993  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
4994 }
ScanState ss
Definition: execnodes.h:2146
int plan_node_id
Definition: plannodes.h:141
PlanState ps
Definition: execnodes.h:1332
Plan * plan
Definition: execnodes.h:945
SharedAggInfo * shared_info
Definition: execnodes.h:2218
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

◆ ExecAggRetrieveInstrumentation()

void ExecAggRetrieveInstrumentation ( AggState node)

Definition at line 5003 of file nodeAgg.c.

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

Referenced by ExecParallelRetrieveInstrumentation().

5004 {
5005  Size size;
5006  SharedAggInfo *si;
5007 
5008  if (node->shared_info == NULL)
5009  return;
5010 
5011  size = offsetof(SharedAggInfo, sinstrument)
5013  si = palloc(size);
5014  memcpy(si, node->shared_info, size);
5015  node->shared_info = si;
5016 }
struct AggregateInstrumentation AggregateInstrumentation
size_t Size
Definition: c.h:473
void * palloc(Size size)
Definition: mcxt.c:949
SharedAggInfo * shared_info
Definition: execnodes.h:2218
#define offsetof(type, field)
Definition: c.h:668

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

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

4538 {
4540  int transno;
4541  int numGroupingSets = Max(node->maxsets, 1);
4542  int setno;
4543 
4544  /*
4545  * When ending a parallel worker, copy the statistics gathered by the
4546  * worker back into shared memory so that it can be picked up by the main
4547  * process to report in EXPLAIN ANALYZE.
4548  */
4549  if (node->shared_info && IsParallelWorker())
4550  {
4552 
4553  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
4556  si->hash_disk_used = node->hash_disk_used;
4557  si->hash_mem_peak = node->hash_mem_peak;
4558  }
4559 
4560  /* Make sure we have closed any open tuplesorts */
4561 
4562  if (node->sort_in)
4563  tuplesort_end(node->sort_in);
4564  if (node->sort_out)
4565  tuplesort_end(node->sort_out);
4566 
4568 
4569  if (node->hash_metacxt != NULL)
4570  {
4572  node->hash_metacxt = NULL;
4573  }
4574 
4575  for (transno = 0; transno < node->numtrans; transno++)
4576  {
4577  AggStatePerTrans pertrans = &node->pertrans[transno];
4578 
4579  for (setno = 0; setno < numGroupingSets; setno++)
4580  {
4581  if (pertrans->sortstates[setno])
4582  tuplesort_end(pertrans->sortstates[setno]);
4583  }
4584  }
4585 
4586  /* And ensure any agg shutdown callbacks have been called */
4587  for (setno = 0; setno < numGroupingSets; setno++)
4588  ReScanExprContext(node->aggcontexts[setno]);
4589  if (node->hashcontext)
4591 
4592  /*
4593  * We don't actually free any ExprContexts here (see comment in
4594  * ExecFreeExprContext), just unlinking the output one from the plan node
4595  * suffices.
4596  */
4597  ExecFreeExprContext(&node->ss.ps);
4598 
4599  /* clean up tuple table */
4601 
4602  outerPlan = outerPlanState(node);
4603  ExecEndNode(outerPlan);
4604 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3165
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:543
Tuplesortstate * sort_out
Definition: execnodes.h:2179
ScanState ss
Definition: execnodes.h:2146
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1335
AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2122
AggStatePerTrans pertrans
Definition: execnodes.h:2156
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:655
int numtrans
Definition: execnodes.h:2149
PlanState ps
Definition: execnodes.h:1332
int maxsets
Definition: execnodes.h:2176
MemoryContext hash_metacxt
Definition: execnodes.h:2188
Tuplesortstate * sort_in
Definition: execnodes.h:2178
#define outerPlanState(node)
Definition: execnodes.h:1039
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:2207
#define outerPlan(node)
Definition: plannodes.h:172
ExprContext * hashcontext
Definition: execnodes.h:2157
uint64 hash_disk_used
Definition: execnodes.h:2206
#define Max(x, y)
Definition: c.h:921
ExprContext ** aggcontexts
Definition: execnodes.h:2158
#define Assert(condition)
Definition: c.h:745
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:443
Size hash_mem_peak
Definition: execnodes.h:2203
SharedAggInfo * shared_info
Definition: execnodes.h:2218
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1388

◆ ExecInitAgg()

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

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

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

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

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

4608 {
4609  ExprContext *econtext = node->ss.ps.ps_ExprContext;
4611  Agg *aggnode = (Agg *) node->ss.ps.plan;
4612  int transno;
4613  int numGroupingSets = Max(node->maxsets, 1);
4614  int setno;
4615 
4616  node->agg_done = false;
4617 
4618  if (node->aggstrategy == AGG_HASHED)
4619  {
4620  /*
4621  * In the hashed case, if we haven't yet built the hash table then we
4622  * can just return; nothing done yet, so nothing to undo. If subnode's
4623  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4624  * else no reason to re-scan it at all.
4625  */
4626  if (!node->table_filled)
4627  return;
4628 
4629  /*
4630  * If we do have the hash table, and it never spilled, and the subplan
4631  * does not have any parameter changes, and none of our own parameter
4632  * changes affect input expressions of the aggregated functions, then
4633  * we can just rescan the existing hash table; no need to build it
4634  * again.
4635  */
4636  if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4637  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4638  {
4640  &node->perhash[0].hashiter);
4641  select_current_set(node, 0, true);
4642  return;
4643  }
4644  }
4645 
4646  /* Make sure we have closed any open tuplesorts */
4647  for (transno = 0; transno < node->numtrans; transno++)
4648  {
4649  for (setno = 0; setno < numGroupingSets; setno++)
4650  {
4651  AggStatePerTrans pertrans = &node->pertrans[transno];
4652 
4653  if (pertrans->sortstates[setno])
4654  {
4655  tuplesort_end(pertrans->sortstates[setno]);
4656  pertrans->sortstates[setno] = NULL;
4657  }
4658  }
4659  }
4660 
4661  /*
4662  * We don't need to ReScanExprContext the output tuple context here;
4663  * ExecReScan already did it. But we do need to reset our per-grouping-set
4664  * contexts, which may have transvalues stored in them. (We use rescan
4665  * rather than just reset because transfns may have registered callbacks
4666  * that need to be run now.) For the AGG_HASHED case, see below.
4667  */
4668 
4669  for (setno = 0; setno < numGroupingSets; setno++)
4670  {
4671  ReScanExprContext(node->aggcontexts[setno]);
4672  }
4673 
4674  /* Release first tuple of group, if we have made a copy */
4675  if (node->grp_firstTuple != NULL)
4676  {
4678  node->grp_firstTuple = NULL;
4679  }
4681 
4682  /* Forget current agg values */
4683  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4684  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4685 
4686  /*
4687  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4688  * the hashcontext. This used to be an issue, but now, resetting a context
4689  * automatically deletes sub-contexts too.
4690  */
4691  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4692  {
4694 
4695  node->hash_ever_spilled = false;
4696  node->hash_spill_mode = false;
4697  node->hash_ngroups_current = 0;
4698 
4700  /* Rebuild an empty hash table */
4701  build_hash_tables(node);
4702  node->table_filled = false;
4703  /* iterator will be reset when the table is filled */
4704 
4705  hashagg_recompile_expressions(node, false, false);
4706  }
4707 
4708  if (node->aggstrategy != AGG_HASHED)
4709  {
4710  /*
4711  * Reset the per-group state (in particular, mark transvalues null)
4712  */
4713  for (setno = 0; setno < numGroupingSets; setno++)
4714  {
4715  MemSet(node->pergroups[setno], 0,
4716  sizeof(AggStatePerGroupData) * node->numaggs);
4717  }
4718 
4719  /* reset to phase 1 */
4720  initialize_phase(node, 1);
4721 
4722  node->input_done = false;
4723  node->projected_set = -1;
4724  }
4725 
4726  if (outerPlan->chgParam == NULL)
4727  ExecReScan(outerPlan);
4728 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3165
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:467
Datum * ecxt_aggvalues
Definition: execnodes.h:245
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2148
bool agg_done
Definition: execnodes.h:2166
ScanState ss
Definition: execnodes.h:2146
ExprContext * ps_ExprContext
Definition: execnodes.h:984
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
#define MemSet(start, val, len)
Definition: c.h:978
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1335
AggStatePerTrans pertrans
Definition: execnodes.h:2156
int projected_set
Definition: execnodes.h:2167
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2184
int numtrans
Definition: execnodes.h:2149
bool hash_spill_mode
Definition: execnodes.h:2196
PlanState ps
Definition: execnodes.h:1332
int maxsets
Definition: execnodes.h:2176
bool table_filled
Definition: execnodes.h:2186
AggStrategy aggstrategy
Definition: execnodes.h:2150
#define outerPlanState(node)
Definition: execnodes.h:1039
Tuplesortstate ** sortstates
Definition: nodeAgg.h:154
Bitmapset * aggParams
Definition: plannodes.h:827
AggStatePerHash perhash
Definition: execnodes.h:2209
Bitmapset * chgParam
Definition: execnodes.h:977
#define outerPlan(node)
Definition: plannodes.h:172
TupleHashIterator hashiter
Definition: nodeAgg.h:304
bool input_done
Definition: execnodes.h:2165
ExprContext * hashcontext
Definition: execnodes.h:2157
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:489
Plan * plan
Definition: execnodes.h:945
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:727
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1727
#define Max(x, y)
Definition: c.h:921
ExprContext ** aggcontexts
Definition: execnodes.h:2158
bool hash_ever_spilled
Definition: execnodes.h:2195
AggStatePerGroup * pergroups
Definition: execnodes.h:2182
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:2204
Definition: plannodes.h:816
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1388
TupleHashTable hashtable
Definition: nodeAgg.h:303
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1456

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

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

560 {
561  TupleTableSlot *slot;
562 
563  if (aggstate->sort_in)
564  {
565  /* make sure we check for interrupts in either path through here */
567  if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
568  aggstate->sort_slot, NULL))
569  return NULL;
570  slot = aggstate->sort_slot;
571  }
572  else
573  slot = ExecProcNode(outerPlanState(aggstate));
574 
575  if (!TupIsNull(slot) && aggstate->sort_out)
576  tuplesort_puttupleslot(aggstate->sort_out, slot);
577 
578  return slot;
579 }
TupleTableSlot * sort_slot
Definition: execnodes.h:2180
Tuplesortstate * sort_out
Definition: execnodes.h:2179
Tuplesortstate * sort_in
Definition: execnodes.h:2178
#define outerPlanState(node)
Definition: execnodes.h:1039
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2332
#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:1608

◆ finalize_aggregate()

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

Definition at line 1048 of file nodeAgg.c.

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

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

1305 {
1306  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1307  Datum *aggvalues = econtext->ecxt_aggvalues;
1308  bool *aggnulls = econtext->ecxt_aggnulls;
1309  int aggno;
1310  int transno;
1311 
1312  /*
1313  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1314  * inputs and run the transition functions.
1315  */
1316  for (transno = 0; transno < aggstate->numtrans; transno++)
1317  {
1318  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1319  AggStatePerGroup pergroupstate;
1320 
1321  pergroupstate = &pergroup[transno];
1322 
1323  if (pertrans->numSortCols > 0)
1324  {
1325  Assert(aggstate->aggstrategy != AGG_HASHED &&
1326  aggstate->aggstrategy != AGG_MIXED);
1327 
1328  if (pertrans->numInputs == 1)
1330  pertrans,
1331  pergroupstate);
1332  else
1334  pertrans,
1335  pergroupstate);
1336  }
1337  }
1338 
1339  /*
1340  * Run the final functions.
1341  */
1342  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1343  {
1344  AggStatePerAgg peragg = &peraggs[aggno];
1345  int transno = peragg->transno;
1346  AggStatePerGroup pergroupstate;
1347 
1348  pergroupstate = &pergroup[transno];
1349 
1350  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1351  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1352  &aggvalues[aggno], &aggnulls[aggno]);
1353  else
1354  finalize_aggregate(aggstate, peragg, pergroupstate,
1355  &aggvalues[aggno], &aggnulls[aggno]);
1356  }
1357 }
Datum * ecxt_aggvalues
Definition: execnodes.h:245
int numaggs
Definition: execnodes.h:2148
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1151
ScanState ss
Definition: execnodes.h:2146
ExprContext * ps_ExprContext
Definition: execnodes.h:984
AggSplit aggsplit
Definition: execnodes.h:2151
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1048
AggStatePerTrans pertrans
Definition: execnodes.h:2156
int numtrans
Definition: execnodes.h:2149
PlanState ps
Definition: execnodes.h:1332
AggStrategy aggstrategy
Definition: execnodes.h:2150
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:954
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:792
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:862

◆ finalize_partialaggregate()

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

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

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

1392 {
1393  Agg *agg = (Agg *) aggstate->ss.ps.plan;
1394  FindColsContext context;
1395 
1396  context.is_aggref = false;
1397  context.aggregated = NULL;
1398  context.unaggregated = NULL;
1399 
1400  (void) find_cols_walker((Node *) agg->plan.targetlist, &context);
1401  (void) find_cols_walker((Node *) agg->plan.qual, &context);
1402 
1403  *aggregated = context.aggregated;
1404  *unaggregated = context.unaggregated;
1405 }
List * qual
Definition: plannodes.h:143
ScanState ss
Definition: execnodes.h:2146
Definition: nodes.h:529
PlanState ps
Definition: execnodes.h:1332
static bool find_cols_walker(Node *node, FindColsContext *context)
Definition: nodeAgg.c:1408
Plan plan
Definition: plannodes.h:818
Plan * plan
Definition: execnodes.h:945
List * targetlist
Definition: plannodes.h:142
Definition: plannodes.h:816
bool is_aggref
Definition: nodeAgg.c:365

◆ find_cols_walker()

static bool find_cols_walker ( Node node,
FindColsContext context 
)
static

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

1409 {
1410  if (node == NULL)
1411  return false;
1412  if (IsA(node, Var))
1413  {
1414  Var *var = (Var *) node;
1415 
1416  /* setrefs.c should have set the varno to OUTER_VAR */
1417  Assert(var->varno == OUTER_VAR);
1418  Assert(var->varlevelsup == 0);
1419  if (context->is_aggref)
1420  context->aggregated = bms_add_member(context->aggregated,
1421  var->varattno);
1422  else
1423  context->unaggregated = bms_add_member(context->unaggregated,
1424  var->varattno);
1425  return false;
1426  }
1427  if (IsA(node, Aggref))
1428  {
1429  Assert(!context->is_aggref);
1430  context->is_aggref = true;
1431  expression_tree_walker(node, find_cols_walker, (void *) context);
1432  context->is_aggref = false;
1433  return false;
1434  }
1436  (void *) context);
1437 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
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:1408
Bitmapset * unaggregated
Definition: nodeAgg.c:367
Bitmapset * aggregated
Definition: nodeAgg.c:366
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:1839
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
bool is_aggref
Definition: nodeAgg.c:365
#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 4408 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().

4410 {
4411  int aggno;
4412  AggStatePerAgg peraggs;
4413 
4414  *same_input_transnos = NIL;
4415 
4416  /* we mustn't reuse the aggref if it contains volatile function calls */
4417  if (contain_volatile_functions((Node *) newagg))
4418  return -1;
4419 
4420  peraggs = aggstate->peragg;
4421 
4422  /*
4423  * Search through the list of already seen aggregates. If we find an
4424  * existing identical aggregate call, then we can re-use that one. While
4425  * searching, we'll also collect a list of Aggrefs with the same input
4426  * parameters. If no matching Aggref is found, the caller can potentially
4427  * still re-use the transition state of one of them. (At this stage we
4428  * just compare the parsetrees; whether different aggregates share the
4429  * same transition function will be checked later.)
4430  */
4431  for (aggno = 0; aggno <= lastaggno; aggno++)
4432  {
4433  AggStatePerAgg peragg;
4434  Aggref *existingRef;
4435 
4436  peragg = &peraggs[aggno];
4437  existingRef = peragg->aggref;
4438 
4439  /* all of the following must be the same or it's no match */
4440  if (newagg->inputcollid != existingRef->inputcollid ||
4441  newagg->aggtranstype != existingRef->aggtranstype ||
4442  newagg->aggstar != existingRef->aggstar ||
4443  newagg->aggvariadic != existingRef->aggvariadic ||
4444  newagg->aggkind != existingRef->aggkind ||
4445  !equal(newagg->args, existingRef->args) ||
4446  !equal(newagg->aggorder, existingRef->aggorder) ||
4447  !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
4448  !equal(newagg->aggfilter, existingRef->aggfilter))
4449  continue;
4450 
4451  /* if it's the same aggregate function then report exact match */
4452  if (newagg->aggfnoid == existingRef->aggfnoid &&
4453  newagg->aggtype == existingRef->aggtype &&
4454  newagg->aggcollid == existingRef->aggcollid &&
4455  equal(newagg->aggdirectargs, existingRef->aggdirectargs))
4456  {
4457  list_free(*same_input_transnos);
4458  *same_input_transnos = NIL;
4459  return aggno;
4460  }
4461 
4462  /*
4463  * Not identical, but it had the same inputs. If the final function
4464  * permits sharing, return its transno to the caller, in case we can
4465  * re-use its per-trans state. (If there's already sharing going on,
4466  * we might report a transno more than once. find_compatible_pertrans
4467  * is cheap enough that it's not worth spending cycles to avoid that.)
4468  */
4469  if (peragg->shareable)
4470  *same_input_transnos = lappend_int(*same_input_transnos,
4471  peragg->transno);
4472  }
4473 
4474  return -1;
4475 }
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:3033
Oid inputcollid
Definition: primnodes.h:315
Definition: nodes.h:529
List * args
Definition: primnodes.h:319
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:726
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:2155
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 4486 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().

4491 {
4492  ListCell *lc;
4493 
4494  /* If this aggregate can't share transition states, give up */
4495  if (!shareable)
4496  return -1;
4497 
4498  foreach(lc, transnos)
4499  {
4500  int transno = lfirst_int(lc);
4501  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
4502 
4503  /*
4504  * if the transfns or transition state types are not the same then the
4505  * state can't be shared.
4506  */
4507  if (aggtransfn != pertrans->transfn_oid ||
4508  aggtranstype != pertrans->aggtranstype)
4509  continue;
4510 
4511  /*
4512  * The serialization and deserialization functions must match, if
4513  * present, as we're unable to share the trans state for aggregates
4514  * which will serialize or deserialize into different formats.
4515  * Remember that these will be InvalidOid if they're not required for
4516  * this agg node.
4517  */
4518  if (aggserialfn != pertrans->serialfn_oid ||
4519  aggdeserialfn != pertrans->deserialfn_oid)
4520  continue;
4521 
4522  /*
4523  * Check that the initial condition matches, too.
4524  */
4525  if (initValueIsNull && pertrans->initValueIsNull)
4526  return transno;
4527 
4528  if (!initValueIsNull && !pertrans->initValueIsNull &&
4529  datumIsEqual(initValue, pertrans->initValue,
4530  pertrans->transtypeByVal, pertrans->transtypeLen))
4531  return transno;
4532  }
4533  return -1;
4534 }
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:222
AggStatePerTrans pertrans
Definition: execnodes.h:2156
#define lfirst_int(lc)
Definition: pg_list.h:191
static int initValue(long lng_val)
Definition: informix.c:677

◆ find_hash_columns()

static void find_hash_columns ( AggState aggstate)
static

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

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

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

Referenced by ExecInitAgg().

4381 {
4382  Oid typinput,
4383  typioparam;
4384  char *strInitVal;
4385  Datum initVal;
4386 
4387  getTypeInputInfo(transtype, &typinput, &typioparam);
4388  strInitVal = TextDatumGetCString(textInitVal);
4389  initVal = OidInputFunctionCall(typinput, strInitVal,
4390  typioparam, -1);
4391  pfree(strInitVal);
4392  return initVal;
4393 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:1056
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2751
#define TextDatumGetCString(d)
Definition: builtins.h:88
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 1835 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 lookup_hash_entry().

1836 {
1837  uint64 ngroups = aggstate->hash_ngroups_current;
1838  Size meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt,
1839  true);
1841  true);
1842 
1843  /*
1844  * Don't spill unless there's at least one group in the hash table so we
1845  * can be sure to make progress even in edge cases.
1846  */
1847  if (aggstate->hash_ngroups_current > 0 &&
1848  (meta_mem + hash_mem > aggstate->hash_mem_limit ||
1849  ngroups > aggstate->hash_ngroups_limit))
1850  {
1851  hash_agg_enter_spill_mode(aggstate);
1852  }
1853 }
uint64 hash_ngroups_limit
Definition: execnodes.h:2199
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:234
static void hash_agg_enter_spill_mode(AggState *aggstate)
Definition: nodeAgg.c:1861
MemoryContext hash_metacxt
Definition: execnodes.h:2188
ExprContext * hashcontext
Definition: execnodes.h:2157
Size MemoryContextMemAllocated(MemoryContext context, bool recurse)
Definition: mcxt.c:470
size_t Size
Definition: c.h:473
Size hash_mem_limit
Definition: execnodes.h:2198
uint64 hash_ngroups_current
Definition: execnodes.h:2204

◆ hash_agg_enter_spill_mode()