PostgreSQL Source Code  git master
nodeAgg.c File Reference
#include "postgres.h"
#include "access/htup_details.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
 

Macros

#define HASHAGG_PARTITION_FACTOR   1.50
 
#define HASHAGG_MIN_PARTITIONS   4
 
#define HASHAGG_MAX_PARTITIONS   1024
 
#define HASHAGG_READ_BUFFER_SIZE   BLCKSZ
 
#define HASHAGG_WRITE_BUFFER_SIZE   BLCKSZ
 
#define HASHAGG_MIN_BUCKETS   256
 

Typedefs

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

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 Bitmapsetfind_unaggregated_cols (AggState *aggstate)
 
static bool find_unaggregated_cols_walker (Node *node, Bitmapset **colnos)
 
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 (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 numAggs, 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)
 

Macro Definition Documentation

◆ HASHAGG_MAX_PARTITIONS

#define HASHAGG_MAX_PARTITIONS   1024

Definition at line 286 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_MIN_BUCKETS

#define HASHAGG_MIN_BUCKETS   256

Definition at line 298 of file nodeAgg.c.

Referenced by hash_choose_num_buckets().

◆ HASHAGG_MIN_PARTITIONS

#define HASHAGG_MIN_PARTITIONS   4

Definition at line 285 of file nodeAgg.c.

Referenced by hash_choose_num_partitions().

◆ HASHAGG_PARTITION_FACTOR

#define HASHAGG_PARTITION_FACTOR   1.50

Definition at line 284 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

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

818 {
819  bool dummynull;
820 
822  aggstate->tmpcontext,
823  &dummynull);
824 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:305
ExprState * evaltrans
Definition: nodeAgg.h:282
ExprContext * tmpcontext
Definition: execnodes.h:2056
AggStatePerPhase phase
Definition: execnodes.h:2049

◆ advance_transition_function()

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

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

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

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

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

2483 {
2484  TupleTableSlot *outerslot;
2485  ExprContext *tmpcontext = aggstate->tmpcontext;
2486 
2487  /*
2488  * Process each outer-plan tuple, and then fetch the next one, until we
2489  * exhaust the outer plan.
2490  */
2491  for (;;)
2492  {
2493  outerslot = fetch_input_tuple(aggstate);
2494  if (TupIsNull(outerslot))
2495  break;
2496 
2497  /* set up for lookup_hash_entries and advance_aggregates */
2498  tmpcontext->ecxt_outertuple = outerslot;
2499 
2500  /* Find or build hashtable entries */
2501  lookup_hash_entries(aggstate);
2502 
2503  /* Advance the aggregates (or combine functions) */
2504  advance_aggregates(aggstate);
2505 
2506  /*
2507  * Reset per-input-tuple context after each tuple, but note that the
2508  * hash lookups do this too
2509  */
2510  ResetExprContext(aggstate->tmpcontext);
2511  }
2512 
2513  /* finalize spills, if any */
2515 
2516  aggstate->table_filled = true;
2517  /* Initialize to walk the first hash table */
2518  select_current_set(aggstate, 0, true);
2520  &aggstate->perhash[0].hashiter);
2521 }
static TupleTableSlot * fetch_input_tuple(AggState *aggstate)
Definition: nodeAgg.c:546
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:454
static void hashagg_finish_initial_spills(AggState *aggstate)
Definition: nodeAgg.c:3024
static void advance_aggregates(AggState *aggstate)
Definition: nodeAgg.c:817
ExprContext * tmpcontext
Definition: execnodes.h:2056
bool table_filled
Definition: execnodes.h:2080
#define TupIsNull(slot)
Definition: tuptable.h:292
AggStatePerHash perhash
Definition: execnodes.h:2102
TupleHashIterator hashiter
Definition: nodeAgg.h:300
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:725
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:228
TupleHashTable hashtable
Definition: nodeAgg.h:299
static void lookup_hash_entries(AggState *aggstate)
Definition: nodeAgg.c:2054
#define ResetExprContext(econtext)
Definition: executor.h:500

◆ agg_refill_hash_table()

static bool agg_refill_hash_table ( AggState aggstate)
static

Definition at line 2536 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_slot, 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().

2537 {
2538  HashAggBatch *batch;
2539  HashAggSpill spill;
2540  HashTapeInfo *tapeinfo = aggstate->hash_tapeinfo;
2541  uint64 ngroups_estimate;
2542  bool spill_initialized = false;
2543 
2544  if (aggstate->hash_batches == NIL)
2545  return false;
2546 
2547  batch = linitial(aggstate->hash_batches);
2548  aggstate->hash_batches = list_delete_first(aggstate->hash_batches);
2549 
2550  /*
2551  * Estimate the number of groups for this batch as the total number of
2552  * tuples in its input file. Although that's a worst case, it's not bad
2553  * here for two reasons: (1) overestimating is better than
2554  * underestimating; and (2) we've already scanned the relation once, so
2555  * it's likely that we've already finalized many of the common values.
2556  */
2557  ngroups_estimate = batch->input_tuples;
2558 
2559  hash_agg_set_limits(aggstate->hashentrysize, ngroups_estimate,
2560  batch->used_bits, &aggstate->hash_mem_limit,
2561  &aggstate->hash_ngroups_limit, NULL);
2562 
2563  /* there could be residual pergroup pointers; clear them */
2564  for (int setoff = 0;
2565  setoff < aggstate->maxsets + aggstate->num_hashes;
2566  setoff++)
2567  aggstate->all_pergroups[setoff] = NULL;
2568 
2569  /* free memory and reset hash tables */
2570  ReScanExprContext(aggstate->hashcontext);
2571  for (int setno = 0; setno < aggstate->num_hashes; setno++)
2572  ResetTupleHashTable(aggstate->perhash[setno].hashtable);
2573 
2574  aggstate->hash_ngroups_current = 0;
2575 
2576  /*
2577  * In AGG_MIXED mode, hash aggregation happens in phase 1 and the output
2578  * happens in phase 0. So, we switch to phase 1 when processing a batch,
2579  * and back to phase 0 after the batch is done.
2580  */
2581  Assert(aggstate->current_phase == 0);
2582  if (aggstate->phase->aggstrategy == AGG_MIXED)
2583  {
2584  aggstate->current_phase = 1;
2585  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2586  }
2587 
2588  select_current_set(aggstate, batch->setno, true);
2589 
2590  /*
2591  * Spilled tuples are always read back as MinimalTuples, which may be
2592  * different from the outer plan, so recompile the aggregate expressions.
2593  *
2594  * We still need the NULL check, because we are only processing one
2595  * grouping set at a time and the rest will be NULL.
2596  */
2597  hashagg_recompile_expressions(aggstate, true, true);
2598 
2601  for (;;) {
2602  TupleTableSlot *slot = aggstate->hash_spill_slot;
2603  MinimalTuple tuple;
2604  uint32 hash;
2605  bool in_hash_table;
2606 
2608 
2609  tuple = hashagg_batch_read(batch, &hash);
2610  if (tuple == NULL)
2611  break;
2612 
2613  ExecStoreMinimalTuple(tuple, slot, true);
2614  aggstate->tmpcontext->ecxt_outertuple = slot;
2615 
2616  prepare_hash_slot(aggstate);
2617  aggstate->hash_pergroup[batch->setno] = lookup_hash_entry(
2618  aggstate, hash, &in_hash_table);
2619 
2620  if (in_hash_table)
2621  {
2622  /* Advance the aggregates (or combine functions) */
2623  advance_aggregates(aggstate);
2624  }
2625  else
2626  {
2627  if (!spill_initialized)
2628  {
2629  /*
2630  * Avoid initializing the spill until we actually need it so
2631  * that we don't assign tapes that will never be used.
2632  */
2633  spill_initialized = true;
2634  hashagg_spill_init(&spill, tapeinfo, batch->used_bits,
2635  ngroups_estimate, aggstate->hashentrysize);
2636  }
2637  /* no memory for a new group, spill */
2638  hashagg_spill_tuple(&spill, slot, hash);
2639  }
2640 
2641  /*
2642  * Reset per-input-tuple context after each tuple, but note that the
2643  * hash lookups do this too
2644  */
2645  ResetExprContext(aggstate->tmpcontext);
2646  }
2647 
2648  hashagg_tapeinfo_release(tapeinfo, batch->input_tapenum);
2649 
2650  /* change back to phase 0 */
2651  aggstate->current_phase = 0;
2652  aggstate->phase = &aggstate->phases[aggstate->current_phase];
2653 
2654  if (spill_initialized)
2655  {
2656  hash_agg_update_metrics(aggstate, true, spill.npartitions);
2657  hashagg_spill_finish(aggstate, &spill, batch->setno);
2658  }
2659  else
2660  hash_agg_update_metrics(aggstate, true, 0);
2661 
2662  aggstate->hash_spill_mode = false;
2663 
2664  /* prepare to walk the first hash table */
2665  select_current_set(aggstate, batch->setno, true);
2666  ResetTupleHashIterator(aggstate->perhash[batch->setno].hashtable,
2667  &aggstate->perhash[batch->setno].hashiter);
2668 
2669  pfree(batch);
2670 
2671  return true;
2672 }
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2103
#define NIL
Definition: pg_list.h:65
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:454
AggStatePerPhase phases
Definition: execnodes.h:2071
double hashentrysize
Definition: execnodes.h:2095
static void hashagg_tapeinfo_release(HashTapeInfo *tapeinfo, int tapenum)
Definition: nodeAgg.c:2871
static void hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
Definition: nodeAgg.c:1841
uint64 hash_ngroups_limit
Definition: execnodes.h:2092
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:1978
static void hashagg_spill_finish(AggState *aggstate, HashAggSpill *spill, int setno)
Definition: nodeAgg.c:3057
int64 input_tuples
Definition: nodeAgg.c:355
int current_phase
Definition: execnodes.h:2051
static void advance_aggregates(AggState *aggstate)
Definition: nodeAgg.c:817
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:282
ExprContext * tmpcontext
Definition: execnodes.h:2056
bool hash_spill_mode
Definition: execnodes.h:2089
List * hash_batches
Definition: execnodes.h:2087
int maxsets
Definition: execnodes.h:2070
TupleTableSlot * hash_spill_slot
Definition: execnodes.h:2086
void pfree(void *pointer)
Definition: mcxt.c:1056
#define linitial(l)
Definition: pg_list.h:195
int npartitions
Definition: nodeAgg.c:333
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:1721
int used_bits
Definition: nodeAgg.c:352
unsigned int uint32
Definition: c.h:367
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2083
AggStatePerHash perhash
Definition: execnodes.h:2102
AggStrategy aggstrategy
Definition: nodeAgg.h:273
static Size hashagg_spill_tuple(HashAggSpill *spill, TupleTableSlot *slot, uint32 hash)
Definition: nodeAgg.c:2917
TupleHashIterator hashiter
Definition: nodeAgg.h:300
int num_hashes
Definition: execnodes.h:2081
ExprContext * hashcontext
Definition: execnodes.h:2054
#define HASHAGG_READ_BUFFER_SIZE
Definition: nodeAgg.c:294
AggStatePerPhase phase
Definition: execnodes.h:2049
LogicalTapeSet * tapeset
Definition: nodeAgg.c:314
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:725
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1671
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:228
#define Assert(condition)
Definition: c.h:738
int input_tapenum
Definition: nodeAgg.c:354
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:402
Size hash_mem_limit
Definition: execnodes.h:2091
void LogicalTapeRewindForRead(LogicalTapeSet *lts, int tapenum, size_t buffer_size)
Definition: logtape.c:776
static MinimalTuple hashagg_batch_read(HashAggBatch *batch, uint32 *hashp)
Definition: nodeAgg.c:2974
uint64 hash_ngroups_current
Definition: execnodes.h:2097
#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:299
static void prepare_hash_slot(AggState *aggstate)
Definition: nodeAgg.c:1197
static void hashagg_spill_init(HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits, uint64 input_tuples, double hashentrysize)
Definition: nodeAgg.c:2890
#define ResetExprContext(econtext)
Definition: executor.h:500
List * list_delete_first(List *list)
Definition: list.c:861
AggStatePerGroup * all_pergroups
Definition: execnodes.h:2108

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

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

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

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

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

2683 {
2684  TupleTableSlot *result = NULL;
2685 
2686  while (result == NULL)
2687  {
2688  result = agg_retrieve_hash_table_in_memory(aggstate);
2689  if (result == NULL)
2690  {
2691  if (!agg_refill_hash_table(aggstate))
2692  {
2693  aggstate->agg_done = true;
2694  break;
2695  }
2696  }
2697  }
2698 
2699  return result;
2700 }
bool agg_done
Definition: execnodes.h:2063
static bool agg_refill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2536
static TupleTableSlot * agg_retrieve_hash_table_in_memory(AggState *aggstate)
Definition: nodeAgg.c:2707

◆ agg_retrieve_hash_table_in_memory()

static TupleTableSlot * agg_retrieve_hash_table_in_memory ( AggState aggstate)
static

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

2708 {
2709  ExprContext *econtext;
2710  AggStatePerAgg peragg;
2711  AggStatePerGroup pergroup;
2712  TupleHashEntryData *entry;
2713  TupleTableSlot *firstSlot;
2714  TupleTableSlot *result;
2715  AggStatePerHash perhash;
2716 
2717  /*
2718  * get state info from node.
2719  *
2720  * econtext is the per-output-tuple expression context.
2721  */
2722  econtext = aggstate->ss.ps.ps_ExprContext;
2723  peragg = aggstate->peragg;
2724  firstSlot = aggstate->ss.ss_ScanTupleSlot;
2725 
2726  /*
2727  * Note that perhash (and therefore anything accessed through it) can
2728  * change inside the loop, as we change between grouping sets.
2729  */
2730  perhash = &aggstate->perhash[aggstate->current_set];
2731 
2732  /*
2733  * We loop retrieving groups until we find one satisfying
2734  * aggstate->ss.ps.qual
2735  */
2736  for (;;)
2737  {
2738  TupleTableSlot *hashslot = perhash->hashslot;
2739  int i;
2740 
2742 
2743  /*
2744  * Find the next entry in the hash table
2745  */
2746  entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);
2747  if (entry == NULL)
2748  {
2749  int nextset = aggstate->current_set + 1;
2750 
2751  if (nextset < aggstate->num_hashes)
2752  {
2753  /*
2754  * Switch to next grouping set, reinitialize, and restart the
2755  * loop.
2756  */
2757  select_current_set(aggstate, nextset, true);
2758 
2759  perhash = &aggstate->perhash[aggstate->current_set];
2760 
2761  ResetTupleHashIterator(perhash->hashtable, &perhash->hashiter);
2762 
2763  continue;
2764  }
2765  else
2766  {
2767  return NULL;
2768  }
2769  }
2770 
2771  /*
2772  * Clear the per-output-tuple context for each group
2773  *
2774  * We intentionally don't use ReScanExprContext here; if any aggs have
2775  * registered shutdown callbacks, they mustn't be called yet, since we
2776  * might not be done with that agg.
2777  */
2778  ResetExprContext(econtext);
2779 
2780  /*
2781  * Transform representative tuple back into one with the right
2782  * columns.
2783  */
2784  ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);
2785  slot_getallattrs(hashslot);
2786 
2787  ExecClearTuple(firstSlot);
2788  memset(firstSlot->tts_isnull, true,
2789  firstSlot->tts_tupleDescriptor->natts * sizeof(bool));
2790 
2791  for (i = 0; i < perhash->numhashGrpCols; i++)
2792  {
2793  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
2794 
2795  firstSlot->tts_values[varNumber] = hashslot->tts_values[i];
2796  firstSlot->tts_isnull[varNumber] = hashslot->tts_isnull[i];
2797  }
2798  ExecStoreVirtualTuple(firstSlot);
2799 
2800  pergroup = (AggStatePerGroup) entry->additional;
2801 
2802  /*
2803  * Use the representative input tuple for any references to
2804  * non-aggregated input columns in the qual and tlist.
2805  */
2806  econtext->ecxt_outertuple = firstSlot;
2807 
2808  prepare_projection_slot(aggstate,
2809  econtext->ecxt_outertuple,
2810  aggstate->current_set);
2811 
2812  finalize_aggregates(aggstate, peragg, pergroup);
2813 
2814  result = project_aggregates(aggstate);
2815  if (result)
2816  return result;
2817  }
2818 
2819  /* No more groups */
2820  return NULL;
2821 }
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2037
#define ScanTupleHashTable(htable, iter)
Definition: execnodes.h:727
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:454
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.h:307
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:2043
ExprContext * ps_ExprContext
Definition: execnodes.h:982
MinimalTuple firstTuple
Definition: execnodes.h:680
Datum * tts_values
Definition: tuptable.h:126
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1333
static TupleTableSlot * project_aggregates(AggState *aggstate)
Definition: nodeAgg.c:1351
int current_set
Definition: execnodes.h:2066
static void prepare_projection_slot(AggState *aggstate, TupleTableSlot *slot, int currentSet)
Definition: nodeAgg.c:1243
PlanState ps
Definition: execnodes.h:1330
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:354
static void finalize_aggregates(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1288
bool * tts_isnull
Definition: tuptable.h:128
AggStatePerHash perhash
Definition: execnodes.h:2102
TupleHashIterator hashiter
Definition: nodeAgg.h:300
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:725
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:228
AggStatePerAgg peragg
Definition: execnodes.h:2052
int i
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
TupleTableSlot * hashslot
Definition: nodeAgg.h:301
TupleHashTable hashtable
Definition: nodeAgg.h:299
#define ResetExprContext(econtext)
Definition: executor.h:500
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522

◆ AggCheckCallContext()

int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

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

4662 {
4663  if (fcinfo->context && IsA(fcinfo->context, AggState))
4664  {
4665  if (aggcontext)
4666  {
4667  AggState *aggstate = ((AggState *) fcinfo->context);
4668  ExprContext *cxt = aggstate->curaggcontext;
4669 
4670  *aggcontext = cxt->ecxt_per_tuple_memory;
4671  }
4672  return AGG_CONTEXT_AGGREGATE;
4673  }
4674  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4675  {
4676  if (aggcontext)
4677  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4678  return AGG_CONTEXT_WINDOW;
4679  }
4680 
4681  /* this is just to prevent "uninitialized variable" warnings */
4682  if (aggcontext)
4683  *aggcontext = NULL;
4684  return 0;
4685 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:577
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
fmNodePtr context
Definition: fmgr.h:88
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:724
ExprContext * curaggcontext
Definition: execnodes.h:2058
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:725

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4705 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4706 {
4707  if (fcinfo->context && IsA(fcinfo->context, AggState))
4708  {
4709  AggState *aggstate = (AggState *) fcinfo->context;
4710  AggStatePerAgg curperagg;
4711  AggStatePerTrans curpertrans;
4712 
4713  /* check curperagg (valid when in a final function) */
4714  curperagg = aggstate->curperagg;
4715 
4716  if (curperagg)
4717  return curperagg->aggref;
4718 
4719  /* check curpertrans (valid when in a transition function) */
4720  curpertrans = aggstate->curpertrans;
4721 
4722  if (curpertrans)
4723  return curpertrans->aggref;
4724  }
4725  return NULL;
4726 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:577
fmNodePtr context
Definition: fmgr.h:88
Aggref * aggref
Definition: nodeAgg.h:186
Aggref * aggref
Definition: nodeAgg.h:43
AggStatePerAgg curperagg
Definition: execnodes.h:2059
AggStatePerTrans curpertrans
Definition: execnodes.h:2061

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4739 of file nodeAgg.c.

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

4740 {
4741  if (fcinfo->context && IsA(fcinfo->context, AggState))
4742  {
4743  AggState *aggstate = (AggState *) fcinfo->context;
4744 
4745  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4746  }
4747  return NULL;
4748 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:577
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
fmNodePtr context
Definition: fmgr.h:88
ExprContext * tmpcontext
Definition: execnodes.h:2056

◆ aggregate_dummy()

Datum aggregate_dummy ( PG_FUNCTION_ARGS  )

Definition at line 4832 of file nodeAgg.c.

References elog, and ERROR.

4833 {
4834  elog(ERROR, "aggregate function %u called as normal function",
4835  fcinfo->flinfo->fn_oid);
4836  return (Datum) 0; /* keep compiler quiet */
4837 }
#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 4804 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4807 {
4808  if (fcinfo->context && IsA(fcinfo->context, AggState))
4809  {
4810  AggState *aggstate = (AggState *) fcinfo->context;
4811  ExprContext *cxt = aggstate->curaggcontext;
4812 
4813  RegisterExprContextCallback(cxt, func, arg);
4814 
4815  return;
4816  }
4817  elog(ERROR, "aggregate function cannot register a callback in this context");
4818 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:577
fmNodePtr context
Definition: fmgr.h:88
#define ERROR
Definition: elog.h:43
ExprContext * curaggcontext
Definition: execnodes.h:2058
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:863
#define elog(elevel,...)
Definition: elog.h:214
void * arg

◆ AggStateIsShared()

bool AggStateIsShared ( FunctionCallInfo  fcinfo)

Definition at line 4765 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4766 {
4767  if (fcinfo->context && IsA(fcinfo->context, AggState))
4768  {
4769  AggState *aggstate = (AggState *) fcinfo->context;
4770  AggStatePerAgg curperagg;
4771  AggStatePerTrans curpertrans;
4772 
4773  /* check curperagg (valid when in a final function) */
4774  curperagg = aggstate->curperagg;
4775 
4776  if (curperagg)
4777  return aggstate->pertrans[curperagg->transno].aggshared;
4778 
4779  /* check curpertrans (valid when in a transition function) */
4780  curpertrans = aggstate->curpertrans;
4781 
4782  if (curpertrans)
4783  return curpertrans->aggshared;
4784  }
4785  return true;
4786 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:577
fmNodePtr context
Definition: fmgr.h:88
AggStatePerTrans pertrans
Definition: execnodes.h:2053
AggStatePerAgg curperagg
Definition: execnodes.h:2059
AggStatePerTrans curpertrans
Definition: execnodes.h:2061

◆ build_hash_table()

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

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

1467 {
1468  AggStatePerHash perhash = &aggstate->perhash[setno];
1469  MemoryContext metacxt = aggstate->hash_metacxt;
1470  MemoryContext hashcxt = aggstate->hashcontext->ecxt_per_tuple_memory;
1471  MemoryContext tmpcxt = aggstate->tmpcontext->ecxt_per_tuple_memory;
1472  Size additionalsize;
1473 
1474  Assert(aggstate->aggstrategy == AGG_HASHED ||
1475  aggstate->aggstrategy == AGG_MIXED);
1476 
1477  /*
1478  * Used to make sure initial hash table allocation does not exceed
1479  * work_mem. Note that the estimate does not include space for
1480  * pass-by-reference transition data values, nor for the representative
1481  * tuple of each group.
1482  */
1483  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1484 
1485  perhash->hashtable = BuildTupleHashTableExt(
1486  &aggstate->ss.ps,
1487  perhash->hashslot->tts_tupleDescriptor,
1488  perhash->numCols,
1489  perhash->hashGrpColIdxHash,
1490  perhash->eqfuncoids,
1491  perhash->hashfunctions,
1492  perhash->aggnode->grpCollations,
1493  nbuckets,
1494  additionalsize,
1495  metacxt,
1496  hashcxt,
1497  tmpcxt,
1498  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1499 }
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:814
ScanState ss
Definition: execnodes.h:2043
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
AggSplit aggsplit
Definition: execnodes.h:2048
int numtrans
Definition: execnodes.h:2046
ExprContext * tmpcontext
Definition: execnodes.h:2056
PlanState ps
Definition: execnodes.h:1330
AggStrategy aggstrategy
Definition: execnodes.h:2047
MemoryContext hash_metacxt
Definition: execnodes.h:2082
struct AggStatePerGroupData AggStatePerGroupData
AggStatePerHash perhash
Definition: execnodes.h:2102
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:308
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2054
FmgrInfo * hashfunctions
Definition: nodeAgg.h:302
#define Assert(condition)
Definition: c.h:738
size_t Size
Definition: c.h:466
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:789
TupleTableSlot * hashslot
Definition: nodeAgg.h:301
TupleHashTable hashtable
Definition: nodeAgg.h:299

◆ build_hash_tables()

static void build_hash_tables ( AggState aggstate)
static

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

1433 {
1434  int setno;
1435 
1436  for (setno = 0; setno < aggstate->num_hashes; ++setno)
1437  {
1438  AggStatePerHash perhash = &aggstate->perhash[setno];
1439  long nbuckets;
1440  Size memory;
1441 
1442  if (perhash->hashtable != NULL)
1443  {
1444  ResetTupleHashTable(perhash->hashtable);
1445  continue;
1446  }
1447 
1448  Assert(perhash->aggnode->numGroups > 0);
1449 
1450  memory = aggstate->hash_mem_limit / aggstate->num_hashes;
1451 
1452  /* choose reasonable number of buckets per hashtable */
1453  nbuckets = hash_choose_num_buckets(
1454  aggstate->hashentrysize, perhash->aggnode->numGroups, memory);
1455 
1456  build_hash_table(aggstate, setno, nbuckets);
1457  }
1458 
1459  aggstate->hash_ngroups_current = 0;
1460 }
double hashentrysize
Definition: execnodes.h:2095
static long hash_choose_num_buckets(double hashentrysize, long estimated_nbuckets, Size memory)
Definition: nodeAgg.c:1892
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:282
static void build_hash_table(AggState *aggstate, int setno, long nbuckets)
Definition: nodeAgg.c:1466
AggStatePerHash perhash
Definition: execnodes.h:2102
int num_hashes
Definition: execnodes.h:2081
#define Assert(condition)
Definition: c.h:738
size_t Size
Definition: c.h:466
long numGroups
Definition: plannodes.h:815
Size hash_mem_limit
Definition: execnodes.h:2091
uint64 hash_ngroups_current
Definition: execnodes.h:2097
TupleHashTable hashtable
Definition: nodeAgg.h:299

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

4002 {
4003  int numGroupingSets = Max(aggstate->maxsets, 1);
4004  Expr *serialfnexpr = NULL;
4005  Expr *deserialfnexpr = NULL;
4006  ListCell *lc;
4007  int numInputs;
4008  int numDirectArgs;
4009  List *sortlist;
4010  int numSortCols;
4011  int numDistinctCols;
4012  int i;
4013 
4014  /* Begin filling in the pertrans data */
4015  pertrans->aggref = aggref;
4016  pertrans->aggshared = false;
4017  pertrans->aggCollation = aggref->inputcollid;
4018  pertrans->transfn_oid = aggtransfn;
4019  pertrans->serialfn_oid = aggserialfn;
4020  pertrans->deserialfn_oid = aggdeserialfn;
4021  pertrans->initValue = initValue;
4022  pertrans->initValueIsNull = initValueIsNull;
4023 
4024  /* Count the "direct" arguments, if any */
4025  numDirectArgs = list_length(aggref->aggdirectargs);
4026 
4027  /* Count the number of aggregated input columns */
4028  pertrans->numInputs = numInputs = list_length(aggref->args);
4029 
4030  pertrans->aggtranstype = aggtranstype;
4031 
4032  /*
4033  * When combining states, we have no use at all for the aggregate
4034  * function's transfn. Instead we use the combinefn. In this case, the
4035  * transfn and transfn_oid fields of pertrans refer to the combine
4036  * function rather than the transition function.
4037  */
4038  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
4039  {
4040  Expr *combinefnexpr;
4041  size_t numTransArgs;
4042 
4043  /*
4044  * When combining there's only one input, the to-be-combined added
4045  * transition value from below (this node's transition value is
4046  * counted separately).
4047  */
4048  pertrans->numTransInputs = 1;
4049 
4050  /* account for the current transition state */
4051  numTransArgs = pertrans->numTransInputs + 1;
4052 
4053  build_aggregate_combinefn_expr(aggtranstype,
4054  aggref->inputcollid,
4055  aggtransfn,
4056  &combinefnexpr);
4057  fmgr_info(aggtransfn, &pertrans->transfn);
4058  fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
4059 
4060  pertrans->transfn_fcinfo =
4063  &pertrans->transfn,
4064  numTransArgs,
4065  pertrans->aggCollation,
4066  (void *) aggstate, NULL);
4067 
4068  /*
4069  * Ensure that a combine function to combine INTERNAL states is not
4070  * strict. This should have been checked during CREATE AGGREGATE, but
4071  * the strict property could have been changed since then.
4072  */
4073  if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
4074  ereport(ERROR,
4075  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4076  errmsg("combine function with transition type %s must not be declared STRICT",
4077  format_type_be(aggtranstype))));
4078  }
4079  else
4080  {
4081  Expr *transfnexpr;
4082  size_t numTransArgs;
4083 
4084  /* Detect how many arguments to pass to the transfn */
4085  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4086  pertrans->numTransInputs = numInputs;
4087  else
4088  pertrans->numTransInputs = numArguments;
4089 
4090  /* account for the current transition state */
4091  numTransArgs = pertrans->numTransInputs + 1;
4092 
4093  /*
4094  * Set up infrastructure for calling the transfn. Note that
4095  * invtransfn is not needed here.
4096  */
4097  build_aggregate_transfn_expr(inputTypes,
4098  numArguments,
4099  numDirectArgs,
4100  aggref->aggvariadic,
4101  aggtranstype,
4102  aggref->inputcollid,
4103  aggtransfn,
4104  InvalidOid,
4105  &transfnexpr,
4106  NULL);
4107  fmgr_info(aggtransfn, &pertrans->transfn);
4108  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
4109 
4110  pertrans->transfn_fcinfo =
4113  &pertrans->transfn,
4114  numTransArgs,
4115  pertrans->aggCollation,
4116  (void *) aggstate, NULL);
4117 
4118  /*
4119  * If the transfn is strict and the initval is NULL, make sure input
4120  * type and transtype are the same (or at least binary-compatible), so
4121  * that it's OK to use the first aggregated input value as the initial
4122  * transValue. This should have been checked at agg definition time,
4123  * but we must check again in case the transfn's strictness property
4124  * has been changed.
4125  */
4126  if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
4127  {
4128  if (numArguments <= numDirectArgs ||
4129  !IsBinaryCoercible(inputTypes[numDirectArgs],
4130  aggtranstype))
4131  ereport(ERROR,
4132  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
4133  errmsg("aggregate %u needs to have compatible input type and transition type",
4134  aggref->aggfnoid)));
4135  }
4136  }
4137 
4138  /* get info about the state value's datatype */
4139  get_typlenbyval(aggtranstype,
4140  &pertrans->transtypeLen,
4141  &pertrans->transtypeByVal);
4142 
4143  if (OidIsValid(aggserialfn))
4144  {
4145  build_aggregate_serialfn_expr(aggserialfn,
4146  &serialfnexpr);
4147  fmgr_info(aggserialfn, &pertrans->serialfn);
4148  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
4149 
4150  pertrans->serialfn_fcinfo =
4153  &pertrans->serialfn,
4154  1,
4155  InvalidOid,
4156  (void *) aggstate, NULL);
4157  }
4158 
4159  if (OidIsValid(aggdeserialfn))
4160  {
4161  build_aggregate_deserialfn_expr(aggdeserialfn,
4162  &deserialfnexpr);
4163  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
4164  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
4165 
4166  pertrans->deserialfn_fcinfo =
4169  &pertrans->deserialfn,
4170  2,
4171  InvalidOid,
4172  (void *) aggstate, NULL);
4173 
4174  }
4175 
4176  /*
4177  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
4178  * have a list of SortGroupClause nodes; fish out the data in them and
4179  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
4180  * however; the agg's transfn and finalfn are responsible for that.
4181  *
4182  * Note that by construction, if there is a DISTINCT clause then the ORDER
4183  * BY clause is a prefix of it (see transformDistinctClause).
4184  */
4185  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
4186  {
4187  sortlist = NIL;
4188  numSortCols = numDistinctCols = 0;
4189  }
4190  else if (aggref->aggdistinct)
4191  {
4192  sortlist = aggref->aggdistinct;
4193  numSortCols = numDistinctCols = list_length(sortlist);
4194  Assert(numSortCols >= list_length(aggref->aggorder));
4195  }
4196  else
4197  {
4198  sortlist = aggref->aggorder;
4199  numSortCols = list_length(sortlist);
4200  numDistinctCols = 0;
4201  }
4202 
4203  pertrans->numSortCols = numSortCols;
4204  pertrans->numDistinctCols = numDistinctCols;
4205 
4206  /*
4207  * If we have either sorting or filtering to do, create a tupledesc and
4208  * slot corresponding to the aggregated inputs (including sort
4209  * expressions) of the agg.
4210  */
4211  if (numSortCols > 0 || aggref->aggfilter)
4212  {
4213  pertrans->sortdesc = ExecTypeFromTL(aggref->args);
4214  pertrans->sortslot =
4215  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4217  }
4218 
4219  if (numSortCols > 0)
4220  {
4221  /*
4222  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
4223  * (yet)
4224  */
4225  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
4226 
4227  /* If we have only one input, we need its len/byval info. */
4228  if (numInputs == 1)
4229  {
4230  get_typlenbyval(inputTypes[numDirectArgs],
4231  &pertrans->inputtypeLen,
4232  &pertrans->inputtypeByVal);
4233  }
4234  else if (numDistinctCols > 0)
4235  {
4236  /* we will need an extra slot to store prior values */
4237  pertrans->uniqslot =
4238  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
4240  }
4241 
4242  /* Extract the sort information for use later */
4243  pertrans->sortColIdx =
4244  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
4245  pertrans->sortOperators =
4246  (Oid *) palloc(numSortCols * sizeof(Oid));
4247  pertrans->sortCollations =
4248  (Oid *) palloc(numSortCols * sizeof(Oid));
4249  pertrans->sortNullsFirst =
4250  (bool *) palloc(numSortCols * sizeof(bool));
4251 
4252  i = 0;
4253  foreach(lc, sortlist)
4254  {
4255  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
4256  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
4257 
4258  /* the parser should have made sure of this */
4259  Assert(OidIsValid(sortcl->sortop));
4260 
4261  pertrans->sortColIdx[i] = tle->resno;
4262  pertrans->sortOperators[i] = sortcl->sortop;
4263  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
4264  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
4265  i++;
4266  }
4267  Assert(i == numSortCols);
4268  }
4269 
4270  if (aggref->aggdistinct)
4271  {
4272  Oid *ops;
4273 
4274  Assert(numArguments > 0);
4275  Assert(list_length(aggref->aggdistinct) == numDistinctCols);
4276 
4277  ops = palloc(numDistinctCols * sizeof(Oid));
4278 
4279  i = 0;
4280  foreach(lc, aggref->aggdistinct)
4281  ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
4282 
4283  /* lookup / build the necessary comparators */
4284  if (numDistinctCols == 1)
4285  fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
4286  else
4287  pertrans->equalfnMulti =
4288  execTuplesMatchPrepare(pertrans->sortdesc,
4289  numDistinctCols,
4290  pertrans->sortColIdx,
4291  ops,
4292  pertrans->sortCollations,
4293  &aggstate->ss.ps);
4294  pfree(ops);
4295  }
4296 
4297  pertrans->sortstates = (Tuplesortstate **)
4298  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
4299 }
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:2043
FmgrInfo equalfnOne
Definition: nodeAgg.h:109
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
Oid inputcollid
Definition: primnodes.h:315
Definition: nodes.h:526
AggSplit aggsplit
Definition: execnodes.h:2048
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:327
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:644
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:788
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:161
TupleDesc sortdesc
Definition: nodeAgg.h:137
FmgrInfo transfn
Definition: nodeAgg.h:80
Aggref * aggref
Definition: nodeAgg.h:43
PlanState ps
Definition: execnodes.h:1330
int maxsets
Definition: execnodes.h:2070
void pfree(void *pointer)
Definition: mcxt.c:1056
AggStrategy aggstrategy
Definition: execnodes.h:2047
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:124
ExprState * equalfnMulti
Definition: nodeAgg.h:110
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
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:99
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:86
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1118
Oid aggfnoid
Definition: primnodes.h:312
#define ereport(elevel,...)
Definition: elog.h:144
#define Max(x, y)
Definition: c.h:914
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
FmgrInfo serialfn
Definition: nodeAgg.h:83
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:166
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:164
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:2055
Expr * aggfilter
Definition: primnodes.h:322
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1908
TupleTableSlot * uniqslot
Definition: nodeAgg.h:136
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:135
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
bool * sortNullsFirst
Definition: nodeAgg.h:102

◆ ExecAgg()

static TupleTableSlot* ExecAgg ( PlanState pstate)
static

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

2101 {
2102  AggState *node = castNode(AggState, pstate);
2103  TupleTableSlot *result = NULL;
2104 
2106 
2107  if (!node->agg_done)
2108  {
2109  /* Dispatch based on strategy */
2110  switch (node->phase->aggstrategy)
2111  {
2112  case AGG_HASHED:
2113  if (!node->table_filled)
2114  agg_fill_hash_table(node);
2115  /* FALLTHROUGH */
2116  case AGG_MIXED:
2117  result = agg_retrieve_hash_table(node);
2118  break;
2119  case AGG_PLAIN:
2120  case AGG_SORTED:
2121  result = agg_retrieve_direct(node);
2122  break;
2123  }
2124 
2125  if (!TupIsNull(result))
2126  return result;
2127  }
2128 
2129  return NULL;
2130 }
static void agg_fill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2482
bool agg_done
Definition: execnodes.h:2063
#define castNode(_type_, nodeptr)
Definition: nodes.h:595
bool table_filled
Definition: execnodes.h:2080
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2682
static TupleTableSlot * agg_retrieve_direct(AggState *aggstate)
Definition: nodeAgg.c:2136
#define TupIsNull(slot)
Definition: tuptable.h:292
AggStrategy aggstrategy
Definition: nodeAgg.h:273
AggStatePerPhase phase
Definition: execnodes.h:2049
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 4460 of file nodeAgg.c.

References AggState::aggcontexts, ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), AggState::hash_metacxt, hashagg_reset_spill_state(), AggState::hashcontext, Max, AggState::maxsets, MemoryContextDelete(), AggState::numtrans, outerPlan, outerPlanState, AggState::pertrans, ScanState::ps, ReScanExprContext(), AggState::sort_in, AggState::sort_out, AggStatePerTransData::sortstates, AggState::ss, ScanState::ss_ScanTupleSlot, and tuplesort_end().

Referenced by ExecEndNode().

4461 {
4463  int transno;
4464  int numGroupingSets = Max(node->maxsets, 1);
4465  int setno;
4466 
4467  /* Make sure we have closed any open tuplesorts */
4468 
4469  if (node->sort_in)
4470  tuplesort_end(node->sort_in);
4471  if (node->sort_out)
4472  tuplesort_end(node->sort_out);
4473 
4475 
4476  if (node->hash_metacxt != NULL)
4477  {
4479  node->hash_metacxt = NULL;
4480  }
4481 
4482  for (transno = 0; transno < node->numtrans; transno++)
4483  {
4484  AggStatePerTrans pertrans = &node->pertrans[transno];
4485 
4486  for (setno = 0; setno < numGroupingSets; setno++)
4487  {
4488  if (pertrans->sortstates[setno])
4489  tuplesort_end(pertrans->sortstates[setno]);
4490  }
4491  }
4492 
4493  /* And ensure any agg shutdown callbacks have been called */
4494  for (setno = 0; setno < numGroupingSets; setno++)
4495  ReScanExprContext(node->aggcontexts[setno]);
4496  if (node->hashcontext)
4498 
4499  /*
4500  * We don't actually free any ExprContexts here (see comment in
4501  * ExecFreeExprContext), just unlinking the output one from the plan node
4502  * suffices.
4503  */
4504  ExecFreeExprContext(&node->ss.ps);
4505 
4506  /* clean up tuple table */
4508 
4509  outerPlan = outerPlanState(node);
4510  ExecEndNode(outerPlan);
4511 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3089
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:537
Tuplesortstate * sort_out
Definition: execnodes.h:2073
ScanState ss
Definition: execnodes.h:2043
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1333
AggStatePerTrans pertrans
Definition: execnodes.h:2053
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:614
int numtrans
Definition: execnodes.h:2046
PlanState ps
Definition: execnodes.h:1330
int maxsets
Definition: execnodes.h:2070
MemoryContext hash_metacxt
Definition: execnodes.h:2082
Tuplesortstate * sort_in
Definition: execnodes.h:2072
#define outerPlanState(node)
Definition: execnodes.h:1037
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
#define outerPlan(node)
Definition: plannodes.h:172
ExprContext * hashcontext
Definition: execnodes.h:2054
#define Max(x, y)
Definition: c.h:914
ExprContext ** aggcontexts
Definition: execnodes.h:2055
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:402
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236

◆ ExecInitAgg()

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

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

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

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

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

4515 {
4516  ExprContext *econtext = node->ss.ps.ps_ExprContext;
4518  Agg *aggnode = (Agg *) node->ss.ps.plan;
4519  int transno;
4520  int numGroupingSets = Max(node->maxsets, 1);
4521  int setno;
4522 
4523  node->agg_done = false;
4524 
4525  if (node->aggstrategy == AGG_HASHED)
4526  {
4527  /*
4528  * In the hashed case, if we haven't yet built the hash table then we
4529  * can just return; nothing done yet, so nothing to undo. If subnode's
4530  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
4531  * else no reason to re-scan it at all.
4532  */
4533  if (!node->table_filled)
4534  return;
4535 
4536  /*
4537  * If we do have the hash table, and it never spilled, and the subplan
4538  * does not have any parameter changes, and none of our own parameter
4539  * changes affect input expressions of the aggregated functions, then
4540  * we can just rescan the existing hash table; no need to build it
4541  * again.
4542  */
4543  if (outerPlan->chgParam == NULL && !node->hash_ever_spilled &&
4544  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4545  {
4547  &node->perhash[0].hashiter);
4548  select_current_set(node, 0, true);
4549  return;
4550  }
4551  }
4552 
4553  /* Make sure we have closed any open tuplesorts */
4554  for (transno = 0; transno < node->numtrans; transno++)
4555  {
4556  for (setno = 0; setno < numGroupingSets; setno++)
4557  {
4558  AggStatePerTrans pertrans = &node->pertrans[transno];
4559 
4560  if (pertrans->sortstates[setno])
4561  {
4562  tuplesort_end(pertrans->sortstates[setno]);
4563  pertrans->sortstates[setno] = NULL;
4564  }
4565  }
4566  }
4567 
4568  /*
4569  * We don't need to ReScanExprContext the output tuple context here;
4570  * ExecReScan already did it. But we do need to reset our per-grouping-set
4571  * contexts, which may have transvalues stored in them. (We use rescan
4572  * rather than just reset because transfns may have registered callbacks
4573  * that need to be run now.) For the AGG_HASHED case, see below.
4574  */
4575 
4576  for (setno = 0; setno < numGroupingSets; setno++)
4577  {
4578  ReScanExprContext(node->aggcontexts[setno]);
4579  }
4580 
4581  /* Release first tuple of group, if we have made a copy */
4582  if (node->grp_firstTuple != NULL)
4583  {
4585  node->grp_firstTuple = NULL;
4586  }
4588 
4589  /* Forget current agg values */
4590  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4591  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4592 
4593  /*
4594  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4595  * the hashcontext. This used to be an issue, but now, resetting a context
4596  * automatically deletes sub-contexts too.
4597  */
4598  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4599  {
4601 
4602  node->hash_ever_spilled = false;
4603  node->hash_spill_mode = false;
4604  node->hash_ngroups_current = 0;
4605 
4607  /* Rebuild an empty hash table */
4608  build_hash_tables(node);
4609  node->table_filled = false;
4610  /* iterator will be reset when the table is filled */
4611 
4612  hashagg_recompile_expressions(node, false, false);
4613  }
4614 
4615  if (node->aggstrategy != AGG_HASHED)
4616  {
4617  /*
4618  * Reset the per-group state (in particular, mark transvalues null)
4619  */
4620  for (setno = 0; setno < numGroupingSets; setno++)
4621  {
4622  MemSet(node->pergroups[setno], 0,
4623  sizeof(AggStatePerGroupData) * node->numaggs);
4624  }
4625 
4626  /* reset to phase 1 */
4627  initialize_phase(node, 1);
4628 
4629  node->input_done = false;
4630  node->projected_set = -1;
4631  }
4632 
4633  if (outerPlan->chgParam == NULL)
4634  ExecReScan(outerPlan);
4635 }
static void hashagg_reset_spill_state(AggState *aggstate)
Definition: nodeAgg.c:3089
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:454
Datum * ecxt_aggvalues
Definition: execnodes.h:243
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2045
bool agg_done
Definition: execnodes.h:2063
ScanState ss
Definition: execnodes.h:2043
ExprContext * ps_ExprContext
Definition: execnodes.h:982
void ExecReScan(PlanState *node)
Definition: execAmi.c:75
#define MemSet(start, val, len)
Definition: c.h:971
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1333
AggStatePerTrans pertrans
Definition: execnodes.h:2053
int projected_set
Definition: execnodes.h:2064
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2078
int numtrans
Definition: execnodes.h:2046
bool hash_spill_mode
Definition: execnodes.h:2089
PlanState ps
Definition: execnodes.h:1330
int maxsets
Definition: execnodes.h:2070
bool table_filled
Definition: execnodes.h:2080
AggStrategy aggstrategy
Definition: execnodes.h:2047
#define outerPlanState(node)
Definition: execnodes.h:1037
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
Bitmapset * aggParams
Definition: plannodes.h:817
AggStatePerHash perhash
Definition: execnodes.h:2102
Bitmapset * chgParam
Definition: execnodes.h:975
#define outerPlan(node)
Definition: plannodes.h:172
TupleHashIterator hashiter
Definition: nodeAgg.h:300
bool input_done
Definition: execnodes.h:2062
ExprContext * hashcontext
Definition: execnodes.h:2054
bool * ecxt_aggnulls
Definition: execnodes.h:245
uintptr_t Datum
Definition: postgres.h:367
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:476
Plan * plan
Definition: execnodes.h:943
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:725
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1671
#define Max(x, y)
Definition: c.h:914
ExprContext ** aggcontexts
Definition: execnodes.h:2055
bool hash_ever_spilled
Definition: execnodes.h:2088
AggStatePerGroup * pergroups
Definition: execnodes.h:2076
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:402
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
uint64 hash_ngroups_current
Definition: execnodes.h:2097
Definition: plannodes.h:806
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236
TupleHashTable hashtable
Definition: nodeAgg.h:299
static void build_hash_tables(AggState *aggstate)
Definition: nodeAgg.c:1432

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

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

547 {
548  TupleTableSlot *slot;
549 
550  if (aggstate->sort_in)
551  {
552  /* make sure we check for interrupts in either path through here */
554  if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
555  aggstate->sort_slot, NULL))
556  return NULL;
557  slot = aggstate->sort_slot;
558  }
559  else
560  slot = ExecProcNode(outerPlanState(aggstate));
561 
562  if (!TupIsNull(slot) && aggstate->sort_out)
563  tuplesort_puttupleslot(aggstate->sort_out, slot);
564 
565  return slot;
566 }
TupleTableSlot * sort_slot
Definition: execnodes.h:2074
Tuplesortstate * sort_out
Definition: execnodes.h:2073
Tuplesortstate * sort_in
Definition: execnodes.h:2072
#define outerPlanState(node)
Definition: execnodes.h:1037
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2159
#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:1435

◆ finalize_aggregate()

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

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

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

◆ finalize_aggregates()

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

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

1291 {
1292  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1293  Datum *aggvalues = econtext->ecxt_aggvalues;
1294  bool *aggnulls = econtext->ecxt_aggnulls;
1295  int aggno;
1296  int transno;
1297 
1298  /*
1299  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1300  * inputs and run the transition functions.
1301  */
1302  for (transno = 0; transno < aggstate->numtrans; transno++)
1303  {
1304  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1305  AggStatePerGroup pergroupstate;
1306 
1307  pergroupstate = &pergroup[transno];
1308 
1309  if (pertrans->numSortCols > 0)
1310  {
1311  Assert(aggstate->aggstrategy != AGG_HASHED &&
1312  aggstate->aggstrategy != AGG_MIXED);
1313 
1314  if (pertrans->numInputs == 1)
1316  pertrans,
1317  pergroupstate);
1318  else
1320  pertrans,
1321  pergroupstate);
1322  }
1323  }
1324 
1325  /*
1326  * Run the final functions.
1327  */
1328  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1329  {
1330  AggStatePerAgg peragg = &peraggs[aggno];
1331  int transno = peragg->transno;
1332  AggStatePerGroup pergroupstate;
1333 
1334  pergroupstate = &pergroup[transno];
1335 
1336  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1337  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1338  &aggvalues[aggno], &aggnulls[aggno]);
1339  else
1340  finalize_aggregate(aggstate, peragg, pergroupstate,
1341  &aggvalues[aggno], &aggnulls[aggno]);
1342  }
1343 }
Datum * ecxt_aggvalues
Definition: execnodes.h:243
int numaggs
Definition: execnodes.h:2045
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1138
ScanState ss
Definition: execnodes.h:2043
ExprContext * ps_ExprContext
Definition: execnodes.h:982
AggSplit aggsplit
Definition: execnodes.h:2048
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1035
AggStatePerTrans pertrans
Definition: execnodes.h:2053
int numtrans
Definition: execnodes.h:2046
PlanState ps
Definition: execnodes.h:1330
AggStrategy aggstrategy
Definition: execnodes.h:2047
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:941
bool * ecxt_aggnulls
Definition: execnodes.h:245
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:738
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:789
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:849

◆ finalize_partialaggregate()

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

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

1142 {
1143  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1144  MemoryContext oldContext;
1145 
1147 
1148  /*
1149  * serialfn_oid will be set if we must serialize the transvalue before
1150  * returning it
1151  */
1152  if (OidIsValid(pertrans->serialfn_oid))
1153  {
1154  /* Don't call a strict serialization function with NULL input. */
1155  if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
1156  {
1157  *resultVal = (Datum) 0;
1158  *resultIsNull = true;
1159  }
1160  else
1161  {
1162  FunctionCallInfo fcinfo = pertrans->serialfn_fcinfo;
1163 
1164  fcinfo->args[0].value =
1165  MakeExpandedObjectReadOnly(pergroupstate->transValue,
1166  pergroupstate->transValueIsNull,
1167  pertrans->transtypeLen);
1168  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
1169 
1170  *resultVal = FunctionCallInvoke(fcinfo);
1171  *resultIsNull = fcinfo->isnull;
1172  }
1173  }
1174  else
1175  {
1176  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1177  *resultVal = pergroupstate->transValue;
1178  *resultIsNull = pergroupstate->transValueIsNull;
1179  }
1180 
1181  /* If result is pass-by-ref, make sure it is in the right context. */
1182  if (!peragg->resulttypeByVal && !*resultIsNull &&
1184  DatumGetPointer(*resultVal)))
1185  *resultVal = datumCopy(*resultVal,
1186  peragg->resulttypeByVal,
1187  peragg->resulttypeLen);
1188 
1189  MemoryContextSwitchTo(oldContext);
1190 }
ScanState ss
Definition: execnodes.h:2043
ExprContext * ps_ExprContext
Definition: execnodes.h:982
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:2053
#define OidIsValid(objectId)
Definition: c.h:644
PlanState ps
Definition: execnodes.h:1330
bool fn_strict
Definition: fmgr.h:61
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:167
#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:215
FmgrInfo serialfn
Definition: nodeAgg.h:83
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:691
FunctionCallInfo serialfn_fcinfo
Definition: nodeAgg.h:164
#define DatumGetPointer(X)
Definition: postgres.h:549
bool resulttypeByVal
Definition: nodeAgg.h:216

◆ find_compatible_peragg()

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

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

4333 {
4334  int aggno;
4335  AggStatePerAgg peraggs;
4336 
4337  *same_input_transnos = NIL;
4338 
4339  /* we mustn't reuse the aggref if it contains volatile function calls */
4340  if (contain_volatile_functions((Node *) newagg))
4341  return -1;
4342 
4343  peraggs = aggstate->peragg;
4344 
4345  /*
4346  * Search through the list of already seen aggregates. If we find an
4347  * existing identical aggregate call, then we can re-use that one. While
4348  * searching, we'll also collect a list of Aggrefs with the same input
4349  * parameters. If no matching Aggref is found, the caller can potentially
4350  * still re-use the transition state of one of them. (At this stage we
4351  * just compare the parsetrees; whether different aggregates share the
4352  * same transition function will be checked later.)
4353  */
4354  for (aggno = 0; aggno <= lastaggno; aggno++)
4355  {
4356  AggStatePerAgg peragg;
4357  Aggref *existingRef;
4358 
4359  peragg = &peraggs[aggno];
4360  existingRef = peragg->aggref;
4361 
4362  /* all of the following must be the same or it's no match */
4363  if (newagg->inputcollid != existingRef->inputcollid ||
4364  newagg->aggtranstype != existingRef->aggtranstype ||
4365  newagg->aggstar != existingRef->aggstar ||
4366  newagg->aggvariadic != existingRef->aggvariadic ||
4367  newagg->aggkind != existingRef->aggkind ||
4368  !equal(newagg->args, existingRef->args) ||
4369  !equal(newagg->aggorder, existingRef->aggorder) ||
4370  !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
4371  !equal(newagg->aggfilter, existingRef->aggfilter))
4372  continue;
4373 
4374  /* if it's the same aggregate function then report exact match */
4375  if (newagg->aggfnoid == existingRef->aggfnoid &&
4376  newagg->aggtype == existingRef->aggtype &&
4377  newagg->aggcollid == existingRef->aggcollid &&
4378  equal(newagg->aggdirectargs, existingRef->aggdirectargs))
4379  {
4380  list_free(*same_input_transnos);
4381  *same_input_transnos = NIL;
4382  return aggno;
4383  }
4384 
4385  /*
4386  * Not identical, but it had the same inputs. If the final function
4387  * permits sharing, return its transno to the caller, in case we can
4388  * re-use its per-trans state. (If there's already sharing going on,
4389  * we might report a transno more than once. find_compatible_pertrans
4390  * is cheap enough that it's not worth spending cycles to avoid that.)
4391  */
4392  if (peragg->shareable)
4393  *same_input_transnos = lappend_int(*same_input_transnos,
4394  peragg->transno);
4395  }
4396 
4397  return -1;
4398 }
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:3027
Oid inputcollid
Definition: primnodes.h:315
Definition: nodes.h:526
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:186
List * aggorder
Definition: primnodes.h:320
List * aggdirectargs
Definition: primnodes.h:318
List * lappend_int(List *list, int datum)
Definition: list.c:340
Oid aggfnoid
Definition: primnodes.h:312
Expr * aggfilter
Definition: primnodes.h:322
Oid aggcollid
Definition: primnodes.h:314
AggStatePerAgg peragg
Definition: execnodes.h:2052
void list_free(List *list)
Definition: list.c:1377
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 4409 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().

4414 {
4415  ListCell *lc;
4416 
4417  /* If this aggregate can't share transition states, give up */
4418  if (!shareable)
4419  return -1;
4420 
4421  foreach(lc, transnos)
4422  {
4423  int transno = lfirst_int(lc);
4424  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
4425 
4426  /*
4427  * if the transfns or transition state types are not the same then the
4428  * state can't be shared.
4429  */
4430  if (aggtransfn != pertrans->transfn_oid ||
4431  aggtranstype != pertrans->aggtranstype)
4432  continue;
4433 
4434  /*
4435  * The serialization and deserialization functions must match, if
4436  * present, as we're unable to share the trans state for aggregates
4437  * which will serialize or deserialize into different formats.
4438  * Remember that these will be InvalidOid if they're not required for
4439  * this agg node.
4440  */
4441  if (aggserialfn != pertrans->serialfn_oid ||
4442  aggdeserialfn != pertrans->deserialfn_oid)
4443  continue;
4444 
4445  /*
4446  * Check that the initial condition matches, too.
4447  */
4448  if (initValueIsNull && pertrans->initValueIsNull)
4449  return transno;
4450 
4451  if (!initValueIsNull && !pertrans->initValueIsNull &&
4452  datumIsEqual(initValue, pertrans->initValue,
4453  pertrans->transtypeByVal, pertrans->transtypeLen))
4454  return transno;
4455  }
4456  return -1;
4457 }
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:222
AggStatePerTrans pertrans
Definition: execnodes.h:2053
#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 1527 of file nodeAgg.c.

References AggStatePerHashData::aggnode, AggState::all_grouped_cols, attnum, bms_add_member(), bms_copy(), bms_del_member(), bms_first_member(), bms_free(), bms_is_member(), bms_num_members(), AggStatePerHashData::eqfuncoids, EState::es_tupleTable, ExecAllocTableSlot(), execTuplesHashPrepare(), ExecTypeFromTL(), find_unaggregated_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, NIL, AggState::num_hashes, AggStatePerHashData::numCols, AggStatePerHashData::numhashGrpCols, outerPlanState, palloc(), AggState::perhash, AggState::phases, ScanState::ps, AggState::ss, PlanState::state, and TTSOpsMinimalTuple.

Referenced by ExecInitAgg().

1528 {
1529  Bitmapset *base_colnos;
1530  List *outerTlist = outerPlanState(aggstate)->plan->targetlist;
1531  int numHashes = aggstate->num_hashes;
1532  EState *estate = aggstate->ss.ps.state;
1533  int j;
1534 
1535  /* Find Vars that will be needed in tlist and qual */
1536  base_colnos = find_unaggregated_cols(aggstate);
1537 
1538  for (j = 0; j < numHashes; ++j)
1539  {
1540  AggStatePerHash perhash = &aggstate->perhash[j];
1541  Bitmapset *colnos = bms_copy(base_colnos);
1542  AttrNumber *grpColIdx = perhash->aggnode->grpColIdx;
1543  List *hashTlist = NIL;
1544  TupleDesc hashDesc;
1545  int maxCols;
1546  int i;
1547 
1548  perhash->largestGrpColIdx = 0;
1549 
1550  /*
1551  * If we're doing grouping sets, then some Vars might be referenced in
1552  * tlist/qual for the benefit of other grouping sets, but not needed
1553  * when hashing; i.e. prepare_projection_slot will null them out, so
1554  * there'd be no point storing them. Use prepare_projection_slot's
1555  * logic to determine which.
1556  */
1557  if (aggstate->phases[0].grouped_cols)
1558  {
1559  Bitmapset *grouped_cols = aggstate->phases[0].grouped_cols[j];
1560  ListCell *lc;
1561 
1562  foreach(lc, aggstate->all_grouped_cols)
1563  {
1564  int attnum = lfirst_int(lc);
1565 
1566  if (!bms_is_member(attnum, grouped_cols))
1567  colnos = bms_del_member(colnos, attnum);
1568  }
1569  }
1570 
1571  /*
1572  * Compute maximum number of input columns accounting for possible
1573  * duplications in the grpColIdx array, which can happen in some edge
1574  * cases where HashAggregate was generated as part of a semijoin or a
1575  * DISTINCT.
1576  */
1577  maxCols = bms_num_members(colnos) + perhash->numCols;
1578 
1579  perhash->hashGrpColIdxInput =
1580  palloc(maxCols * sizeof(AttrNumber));
1581  perhash->hashGrpColIdxHash =
1582  palloc(perhash->numCols * sizeof(AttrNumber));
1583 
1584  /* Add all the grouping columns to colnos */
1585  for (i = 0; i < perhash->numCols; i++)
1586  colnos = bms_add_member(colnos, grpColIdx[i]);
1587 
1588  /*
1589  * First build mapping for columns directly hashed. These are the
1590  * first, because they'll be accessed when computing hash values and
1591  * comparing tuples for exact matches. We also build simple mapping
1592  * for execGrouping, so it knows where to find the to-be-hashed /
1593  * compared columns in the input.
1594  */
1595  for (i = 0; i < perhash->numCols; i++)
1596  {
1597  perhash->hashGrpColIdxInput[i] = grpColIdx[i];
1598  perhash->hashGrpColIdxHash[i] = i + 1;
1599  perhash->numhashGrpCols++;
1600  /* delete already mapped columns */
1601  bms_del_member(colnos, grpColIdx[i]);
1602  }
1603 
1604  /* and add the remaining columns */
1605  while ((i = bms_first_member(colnos)) >= 0)
1606  {
1607  perhash->hashGrpColIdxInput[perhash->numhashGrpCols] = i;
1608  perhash->numhashGrpCols++;
1609  }
1610 
1611  /* and build a tuple descriptor for the hashtable */
1612  for (i = 0; i < perhash->numhashGrpCols; i++)
1613  {
1614  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
1615 
1616  hashTlist = lappend(hashTlist, list_nth(outerTlist, varNumber));
1617  perhash->largestGrpColIdx =
1618  Max(varNumber + 1, perhash->largestGrpColIdx);
1619  }
1620 
1621  hashDesc = ExecTypeFromTL(hashTlist);
1622 
1623  execTuplesHashPrepare(perhash->numCols,
1624  perhash->aggnode->grpOperators,
1625  &perhash->eqfuncoids,
1626  &perhash->hashfunctions);
1627  perhash->hashslot =
1628  ExecAllocTableSlot(&estate->es_tupleTable, hashDesc,
1630 
1631  list_free(hashTlist);
1632  bms_free(colnos);
1633  }
1634 
1635  bms_free(base_colnos);
1636 }
#define NIL
Definition: pg_list.h:65
int bms_first_member(Bitmapset *a)
Definition: bitmapset.c:996
AggStatePerPhase phases
Definition: execnodes.h:2071
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.h:307
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
AttrNumber * grpColIdx
Definition: plannodes.h:812
List * all_grouped_cols
Definition: execnodes.h:2068
ScanState ss
Definition: execnodes.h:2043
EState * state
Definition: execnodes.h:945
void execTuplesHashPrepare(int numCols, const Oid *eqOperators, Oid **eqFuncOids, FmgrInfo **hashFunctions)
Definition: execGrouping.c:96
Bitmapset ** grouped_cols
Definition: nodeAgg.h:276
PlanState ps
Definition: execnodes.h:1330
#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:1037
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
AggStatePerHash perhash
Definition: execnodes.h:2102
TupleTableSlot * ExecAllocTableSlot(List **tupleTable, TupleDesc desc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1141
List * lappend(List *list, void *datum)
Definition: list.c:322
int num_hashes
Definition: execnodes.h:2081
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:308
List * es_tupleTable
Definition: execnodes.h:555
int16 attnum
Definition: pg_attribute.h:79
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define Max(x, y)
Definition: c.h:914
FmgrInfo * hashfunctions
Definition: nodeAgg.h:302
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1908
static Bitmapset * find_unaggregated_cols(AggState *aggstate)
Definition: nodeAgg.c:1378
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
Oid * grpOperators
Definition: plannodes.h:813
void * palloc(Size size)
Definition: mcxt.c:949
void list_free(List *list)
Definition: list.c:1377
int i
TupleTableSlot * hashslot
Definition: nodeAgg.h:301
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

◆ find_unaggregated_cols()

static Bitmapset * find_unaggregated_cols ( AggState aggstate)
static

Definition at line 1378 of file nodeAgg.c.

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

Referenced by find_hash_columns().

1379 {
1380  Agg *node = (Agg *) aggstate->ss.ps.plan;
1381  Bitmapset *colnos;
1382 
1383  colnos = NULL;
1385  &colnos);
1386  (void) find_unaggregated_cols_walker((Node *) node->plan.qual,
1387  &colnos);
1388  return colnos;
1389 }
List * qual
Definition: plannodes.h:143
ScanState ss
Definition: execnodes.h:2043
Definition: nodes.h:526
PlanState ps
Definition: execnodes.h:1330
static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
Definition: nodeAgg.c:1392
Plan plan
Definition: plannodes.h:808
Plan * plan
Definition: execnodes.h:943
List * targetlist
Definition: plannodes.h:142
Definition: plannodes.h:806

◆ find_unaggregated_cols_walker()

static bool find_unaggregated_cols_walker ( Node node,
Bitmapset **  colnos 
)
static

Definition at line 1392 of file nodeAgg.c.

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

Referenced by find_unaggregated_cols().

1393 {
1394  if (node == NULL)
1395  return false;
1396  if (IsA(node, Var))
1397  {
1398  Var *var = (Var *) node;
1399 
1400  /* setrefs.c should have set the varno to OUTER_VAR */
1401  Assert(var->varno == OUTER_VAR);
1402  Assert(var->varlevelsup == 0);
1403  *colnos = bms_add_member(*colnos, var->varattno);
1404  return false;
1405  }
1406  if (IsA(node, Aggref) ||IsA(node, GroupingFunc))
1407  {
1408  /* do not descend into aggregate exprs */
1409  return false;
1410  }
1412  (void *) colnos);
1413 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:577
Index varlevelsup
Definition: primnodes.h:191
AttrNumber varattno
Definition: primnodes.h:186
Definition: primnodes.h:181
static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
Definition: nodeAgg.c:1392
Index varno
Definition: primnodes.h:184
#define Assert(condition)
Definition: c.h:738
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
#define OUTER_VAR
Definition: primnodes.h:172

◆ GetAggInitVal()

static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 4303 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

4304 {
4305  Oid typinput,
4306  typioparam;
4307  char *strInitVal;
4308  Datum initVal;
4309 
4310  getTypeInputInfo(transtype, &typinput, &typioparam);
4311  strInitVal = TextDatumGetCString(textInitVal);
4312  initVal = OidInputFunctionCall(typinput, strInitVal,
4313  typioparam, -1);
4314  pfree(strInitVal);
4315  return initVal;
4316 }
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:2667
#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:1646

◆ hash_agg_check_limits()

static void hash_agg_check_limits ( AggState aggstate)
static

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

1780 {
1781  uint64 ngroups = aggstate->hash_ngroups_current;
1782  Size meta_mem = MemoryContextMemAllocated(
1783  aggstate->hash_metacxt, true);
1784  Size hash_mem = MemoryContextMemAllocated(
1785  aggstate->hashcontext->ecxt_per_tuple_memory, true);
1786 
1787  /*
1788  * Don't spill unless there's at least one group in the hash table so we
1789  * can be sure to make progress even in edge cases.
1790  */
1791  if (aggstate->hash_ngroups_current > 0 &&
1792  (meta_mem + hash_mem > aggstate->hash_mem_limit ||
1793  ngroups > aggstate->hash_ngroups_limit))
1794  {
1795  hash_agg_enter_spill_mode(aggstate);
1796  }
1797 }
uint64 hash_ngroups_limit
Definition: execnodes.h:2092
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
static void hash_agg_enter_spill_mode(AggState *aggstate)
Definition: nodeAgg.c:1805
MemoryContext hash_metacxt
Definition: execnodes.h:2082
ExprContext * hashcontext
Definition: execnodes.h:2054
Size MemoryContextMemAllocated(MemoryContext context, bool recurse)
Definition: mcxt.c:470
size_t Size
Definition: c.h:466
Size hash_mem_limit
Definition: execnodes.h:2091
uint64 hash_ngroups_current
Definition: execnodes.h:2097

◆ hash_agg_enter_spill_mode()

static void hash_agg_enter_spill_mode ( AggState aggstate)
static

Definition at line 1805 of file nodeAgg.c.

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

Referenced by hash_agg_check_limits().

1806 {
1807  aggstate->hash_spill_mode = true;
1808  hashagg_recompile_expressions(aggstate, aggstate->table_filled, true);
1809 
1810  if (!aggstate->hash_ever_spilled)
1811  {
1812  Assert(aggstate->hash_tapeinfo == NULL);
1813  Assert(aggstate->hash_spills == NULL);
1814 
1815  aggstate->hash_ever_spilled = true;
1816 
1817  hashagg_tapeinfo_init(aggstate);
1818 
1819  aggstate->hash_spills = palloc(
1820  sizeof(HashAggSpill) * aggstate->num_hashes);
1821 
1822  for (int setno = 0; setno < aggstate->num_hashes; setno++)
1823  {
1824  AggStatePerHash perhash = &aggstate->perhash[setno];
1825  HashAggSpill *spill = &aggstate->hash_spills[setno];
1826 
1827  hashagg_spill_init(spill, aggstate->hash_tapeinfo, 0,
1828  perhash->aggnode->numGroups,
1829  aggstate->hashentrysize);
1830  }
1831  }
1832 }
struct HashAggSpill * hash_spills
Definition: execnodes.h:2084
double hashentrysize
Definition: execnodes.h:2095
bool hash_spill_mode
Definition: execnodes.h:2089
static void hashagg_tapeinfo_init(AggState *aggstate)
Definition: nodeAgg.c:2827
bool table_filled
Definition: execnodes.h:2080
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2083
AggStatePerHash perhash
Definition: execnodes.h:2102
int num_hashes
Definition: execnodes.h:2081
static void hashagg_recompile_expressions(AggState *aggstate, bool minslot, bool nullcheck)
Definition: nodeAgg.c:1671
#define Assert(condition)
Definition: c.h:738
bool hash_ever_spilled
Definition: execnodes.h:2088
long numGroups
Definition: plannodes.h:815
void * palloc(Size size)
Definition: mcxt.c:949
static void hashagg_spill_init(HashAggSpill *spill, HashTapeInfo *tapeinfo, int used_bits, uint64 input_tuples, double hashentrysize)
Definition: nodeAgg.c:2890

◆ hash_agg_entry_size()

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

Definition at line 1642 of file nodeAgg.c.

References MAXALIGN, and SizeofMinimalTupleHeader.

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

1643 {
1644  return
1646  MAXALIGN(tupleWidth) +
1647  MAXALIGN(sizeof(TupleHashEntryData) +
1648  numAggs * sizeof(AggStatePerGroupData)) +
1649  transitionSpace;
1650 }
#define SizeofMinimalTupleHeader
Definition: htup_details.h:649
#define MAXALIGN(LEN)
Definition: c.h:691

◆ hash_agg_set_limits()

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

Definition at line 1721 of file nodeAgg.c.

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

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

1724 {
1725  int npartitions;
1726  Size partition_mem;
1727 
1728  /* if not expected to spill, use all of work_mem */
1729  if (input_groups * hashentrysize < work_mem * 1024L)
1730  {
1731  if (num_partitions != NULL)
1732  *num_partitions = 0;
1733  *mem_limit = work_mem * 1024L;
1734  *ngroups_limit = *mem_limit / hashentrysize;
1735  return;
1736  }
1737 
1738  /*
1739  * Calculate expected memory requirements for spilling, which is the size
1740  * of the buffers needed for all the tapes that need to be open at
1741  * once. Then, subtract that from the memory available for holding hash
1742  * tables.
1743  */
1744  npartitions = hash_choose_num_partitions(input_groups,
1745  hashentrysize,
1746  used_bits,
1747  NULL);
1748  if (num_partitions != NULL)
1749  *num_partitions = npartitions;
1750 
1751  partition_mem =
1753  HASHAGG_WRITE_BUFFER_SIZE * npartitions;
1754 
1755  /*
1756  * Don't set the limit below 3/4 of work_mem. In that case, we are at the
1757  * minimum number of partitions, so we aren't going to dramatically exceed
1758  * work mem anyway.
1759  */
1760  if (work_mem * 1024L > 4 * partition_mem)
1761  *mem_limit = work_mem * 1024L - partition_mem;
1762  else
1763  *mem_limit = work_mem * 1024L * 0.75;
1764 
1765  if (*mem_limit > hashentrysize)
1766  *ngroups_limit = *mem_limit / hashentrysize;
1767  else
1768  *ngroups_limit = 1;
1769 }
static int hash_choose_num_partitions(uint64 input_groups, double hashentrysize, int used_bits, int *log2_npartittions)
Definition: nodeAgg.c:1918
#define HASHAGG_READ_BUFFER_SIZE
Definition: nodeAgg.c:294
int work_mem
Definition: globals.c:121
size_t Size
Definition: c.h:466
#define HASHAGG_WRITE_BUFFER_SIZE
Definition: nodeAgg.c:295

◆ hash_agg_update_metrics()

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

Definition at line 1841 of file nodeAgg.c.

References AGG_HASHED, AGG_MIXED, AggState::aggstrategy, ExprContext::ecxt_per_tuple_memory, AggState::hash_disk_used, AggState::hash_mem_peak, AggState::hash_metacxt, AggState::hash_ngroups_current, AggState::hash_tapeinfo, HASHAGG_READ_BUFFER_SIZE, HASHAGG_WRITE_BUFFER_SIZE, AggState::hashcontext, AggState::hashentrysize, LogicalTapeSetBlocks(), MemoryContextMemAllocated(), and HashTapeInfo::tapeset.

Referenced by agg_refill_hash_table(), and hashagg_finish_initial_spills().

1842 {
1843  Size meta_mem;
1844  Size hash_mem;
1845  Size buffer_mem;
1846  Size total_mem;
1847 
1848  if (aggstate->aggstrategy != AGG_MIXED &&
1849  aggstate->aggstrategy != AGG_HASHED)
1850  return;
1851 
1852  /* memory for the hash table itself */
1853  meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt, true);
1854 
1855  /* memory for the group keys and transition states */
1856  hash_mem = MemoryContextMemAllocated(
1857  aggstate->hashcontext->ecxt_per_tuple_memory, true);
1858 
1859  /* memory for read/write tape buffers, if spilled */
1860  buffer_mem = npartitions * HASHAGG_WRITE_BUFFER_SIZE;
1861  if (from_tape)
1862  buffer_mem += HASHAGG_READ_BUFFER_SIZE;
1863 
1864  /* update peak mem */
1865  total_mem = meta_mem + hash_mem + buffer_mem;
1866  if (total_mem > aggstate->hash_mem_peak)
1867  aggstate->hash_mem_peak = total_mem;
1868 
1869  /* update disk usage */
1870  if (aggstate->hash_tapeinfo != NULL)
1871  {
1872  uint64 disk_used = LogicalTapeSetBlocks(
1873  aggstate->hash_tapeinfo->tapeset) * (BLCKSZ / 1024);
1874 
1875  if (aggstate->hash_disk_used < disk_used)
1876  aggstate->hash_disk_used = disk_used;
1877  }
1878 
1879  /* update hashentrysize estimate based on contents */
1880  if (aggstate->hash_ngroups_current > 0)
1881  {
1882  aggstate->hashentrysize =
1883  sizeof(TupleHashEntryData) +
1884  (hash_mem / (double)aggstate->hash_ngroups_current);
1885  }
1886 }
double hashentrysize
Definition: execnodes.h:2095
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
AggStrategy aggstrategy
Definition: execnodes.h:2047
MemoryContext hash_metacxt
Definition: execnodes.h:2082
struct TupleHashEntryData TupleHashEntryData
struct HashTapeInfo * hash_tapeinfo
Definition: execnodes.h:2083
ExprContext * hashcontext
Definition: execnodes.h:2054
#define HASHAGG_READ_BUFFER_SIZE
Definition: nodeAgg.c:294
LogicalTapeSet * tapeset
Definition: nodeAgg.c:314
uint64 hash_disk_used
Definition: execnodes.h:2099
Size MemoryContextMemAllocated(MemoryContext context, bool recurse)
Definition: mcxt.c:470
size_t Size
Definition: c.h:466
#define HASHAGG_WRITE_BUFFER_SIZE
Definition: nodeAgg.c:295
Size hash_mem_peak
Definition: execnodes.h:2096
uint64 hash_ngroups_current
Definition: execnodes.h:2097
long LogicalTapeSetBlocks(LogicalTapeSet *lts)
Definition: logtape.c:1172

◆ hash_choose_num_buckets()

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

Definition at line 1892 of file nodeAgg.c.

References HASHAGG_MIN_BUCKETS.

Referenced by build_hash_tables().

1893 {
1894  long max_nbuckets;
1895  long nbuckets = ngroups;
1896 
1897  max_nbuckets = memory / hashentrysize;
1898 
1899  /*
1900  * Underestimating is better than overestimating. Too many buckets crowd
1901  * out space for group keys and transition state values.
1902  */
1903  max_nbuckets >>= 1;
1904 
1905  if (nbuckets > max_nbuckets)
1906  nbuckets = max_nbuckets;
1907  if (nbuckets < HASHAGG_MIN_BUCKETS)
1908  nbuckets = HASHAGG_MIN_BUCKETS;
1909  return nbuckets;
1910 }
#define HASHAGG_MIN_BUCKETS
Definition: nodeAgg.c:298

◆ hash_choose_num_partitions()

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

Definition at line 1918 of file nodeAgg.c.

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

Referenced by hash_agg_set_limits(), and hashagg_spill_init().

1920 {
1921  Size mem_wanted;
1922  int partition_limit;
1923  int npartitions;
1924  int partition_bits;
1925 
1926  /*
1927  * Avoid creating so many partitions that the memory requirements of the
1928  * open partition files are greater than 1/4 of work_mem.
1929  */
1930  partition_limit =
1931  (work_mem * 1024L * 0.25 - HASHAGG_READ_BUFFER_SIZE) /
1933 
1934  mem_wanted = HASHAGG_PARTITION_FACTOR * input_groups * hashentrysize;
1935 
1936  /* make enough partitions so that each one is likely to fit in memory */
1937  npartitions = 1 + (mem_wanted / (work_mem * 1024L));
1938 
1939  if (npartitions > partition_limit)
1940  npartitions = partition_limit;
1941 
1942  if (npartitions < HASHAGG_MIN_PARTITIONS)
1943  npartitions = HASHAGG_MIN_PARTITIONS;
1944  if (npartitions > HASHAGG_MAX_PARTITIONS)
1945  npartitions = HASHAGG_MAX_PARTITIONS;
1946 
1947  /* ceil(log2(npartitions)) */
1948  partition_bits = my_log2(npartitions);
1949 
1950  /* make sure that we don't exhaust the hash bits */
1951  if (partition_bits + used_bits >= 32)
1952  partition_bits = 32 - used_bits;
1953 
1954  if (log2_npartitions != NULL)
1955  *log2_npartitions = partition_bits;
1956 
1957  /* number of partitions will be a power of two */
1958  npartitions = 1L << partition_bits;
1959 
1960  return npartitions;</