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/executor.h"
#include "executor/nodeAgg.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/tlist.h"
#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/tuplesort.h"
#include "utils/datum.h"
Include dependency graph for nodeAgg.c:

Go to the source code of this file.

Data Structures

struct  AggStatePerTransData
 
struct  AggStatePerAggData
 
struct  AggStatePerGroupData
 
struct  AggStatePerPhaseData
 
struct  AggStatePerHashData
 

Typedefs

typedef struct AggStatePerTransData AggStatePerTransData
 
typedef struct AggStatePerAggData AggStatePerAggData
 
typedef struct AggStatePerGroupData AggStatePerGroupData
 
typedef struct AggStatePerPhaseData AggStatePerPhaseData
 
typedef struct AggStatePerHashData AggStatePerHashData
 

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 pergroup, int numReset)
 
static void advance_transition_function (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void advance_aggregates (AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGroup *pergroups)
 
static void advance_combine_function (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void combine_aggregates (AggState *aggstate, AggStatePerGroup pergroup)
 
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_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_table (AggState *aggstate)
 
static TupleHashEntryDatalookup_hash_entry (AggState *aggstate)
 
static AggStatePerGrouplookup_hash_entries (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_direct (AggState *aggstate)
 
static void agg_fill_hash_table (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_hash_table (AggState *aggstate)
 
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 sharable, 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)
 
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)
 

Typedef Documentation

◆ AggStatePerAggData

◆ AggStatePerGroupData

◆ AggStatePerHashData

◆ AggStatePerPhaseData

◆ AggStatePerTransData

Function Documentation

◆ advance_aggregates()

static void advance_aggregates ( AggState aggstate,
AggStatePerGroup  pergroup,
AggStatePerGroup pergroups 
)
static

Definition at line 979 of file nodeAgg.c.

References advance_transition_function(), Aggref::aggfilter, AggStatePerTransData::aggref, FunctionCallInfoData::arg, FunctionCallInfoData::argnull, Assert, AggState::combinedproj, DatumGetBool, AggStatePerTransData::evalproj, ExecClearTuple(), ExecProject(), ExecStoreVirtualTuple(), FmgrInfo::fn_strict, i, AggStatePerTransData::inputoff, Max, AggState::num_hashes, AggStatePerTransData::numInputs, AggStatePerPhaseData::numsets, AggStatePerTransData::numSortCols, AggState::numtrans, AggStatePerTransData::numTransInputs, AggState::pertrans, AggState::phase, select_current_set(), AggStatePerTransData::sortslot, AggStatePerTransData::sortstates, AggStatePerTransData::transfn, AggStatePerTransData::transfn_fcinfo, TupleTableSlot::tts_isnull, TupleTableSlot::tts_nvalid, TupleTableSlot::tts_values, tuplesort_putdatum(), and tuplesort_puttupleslot().

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

980 {
981  int transno;
982  int setno = 0;
983  int numGroupingSets = Max(aggstate->phase->numsets, 1);
984  int numHashes = aggstate->num_hashes;
985  int numTrans = aggstate->numtrans;
986  TupleTableSlot *combinedslot;
987 
988  /* compute required inputs for all aggregates */
989  combinedslot = ExecProject(aggstate->combinedproj);
990 
991  for (transno = 0; transno < numTrans; transno++)
992  {
993  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
994  int numTransInputs = pertrans->numTransInputs;
995  int inputoff = pertrans->inputoff;
996  TupleTableSlot *slot;
997  int i;
998 
999  /* Skip anything FILTERed out */
1000  if (pertrans->aggref->aggfilter)
1001  {
1002  /* Check the result of the filter expression */
1003  if (combinedslot->tts_isnull[inputoff] ||
1004  !DatumGetBool(combinedslot->tts_values[inputoff]))
1005  continue;
1006 
1007  /* Now it's safe to evaluate this agg's arguments */
1008  slot = ExecProject(pertrans->evalproj);
1009  /* There's no offset needed in this slot, of course */
1010  inputoff = 0;
1011  }
1012  else
1013  {
1014  /* arguments are already evaluated into combinedslot @ inputoff */
1015  slot = combinedslot;
1016  }
1017 
1018  if (pertrans->numSortCols > 0)
1019  {
1020  /* DISTINCT and/or ORDER BY case */
1021  Assert(slot->tts_nvalid >= (pertrans->numInputs + inputoff));
1022  Assert(!pergroups);
1023 
1024  /*
1025  * If the transfn is strict, we want to check for nullity before
1026  * storing the row in the sorter, to save space if there are a lot
1027  * of nulls. Note that we must only check numTransInputs columns,
1028  * not numInputs, since nullity in columns used only for sorting
1029  * is not relevant here.
1030  */
1031  if (pertrans->transfn.fn_strict)
1032  {
1033  for (i = 0; i < numTransInputs; i++)
1034  {
1035  if (slot->tts_isnull[i + inputoff])
1036  break;
1037  }
1038  if (i < numTransInputs)
1039  continue;
1040  }
1041 
1042  for (setno = 0; setno < numGroupingSets; setno++)
1043  {
1044  /* OK, put the tuple into the tuplesort object */
1045  if (pertrans->numInputs == 1)
1046  tuplesort_putdatum(pertrans->sortstates[setno],
1047  slot->tts_values[inputoff],
1048  slot->tts_isnull[inputoff]);
1049  else if (pertrans->aggref->aggfilter)
1050  {
1051  /*
1052  * When filtering and ordering, we already have a slot
1053  * containing just the argument columns.
1054  */
1055  Assert(slot == pertrans->sortslot);
1056  tuplesort_puttupleslot(pertrans->sortstates[setno], slot);
1057  }
1058  else
1059  {
1060  /*
1061  * Copy argument columns from combined slot, starting at
1062  * inputoff, into sortslot, so that we can store just the
1063  * columns we want.
1064  */
1065  ExecClearTuple(pertrans->sortslot);
1066  memcpy(pertrans->sortslot->tts_values,
1067  &slot->tts_values[inputoff],
1068  pertrans->numInputs * sizeof(Datum));
1069  memcpy(pertrans->sortslot->tts_isnull,
1070  &slot->tts_isnull[inputoff],
1071  pertrans->numInputs * sizeof(bool));
1072  ExecStoreVirtualTuple(pertrans->sortslot);
1073  tuplesort_puttupleslot(pertrans->sortstates[setno],
1074  pertrans->sortslot);
1075  }
1076  }
1077  }
1078  else
1079  {
1080  /* We can apply the transition function immediately */
1081  FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
1082 
1083  /* Load values into fcinfo */
1084  /* Start from 1, since the 0th arg will be the transition value */
1085  Assert(slot->tts_nvalid >= (numTransInputs + inputoff));
1086 
1087  for (i = 0; i < numTransInputs; i++)
1088  {
1089  fcinfo->arg[i + 1] = slot->tts_values[i + inputoff];
1090  fcinfo->argnull[i + 1] = slot->tts_isnull[i + inputoff];
1091  }
1092 
1093  if (pergroup)
1094  {
1095  /* advance transition states for ordered grouping */
1096 
1097  for (setno = 0; setno < numGroupingSets; setno++)
1098  {
1099  AggStatePerGroup pergroupstate;
1100 
1101  select_current_set(aggstate, setno, false);
1102 
1103  pergroupstate = &pergroup[transno + (setno * numTrans)];
1104 
1105  advance_transition_function(aggstate, pertrans, pergroupstate);
1106  }
1107  }
1108 
1109  if (pergroups)
1110  {
1111  /* advance transition states for hashed grouping */
1112 
1113  for (setno = 0; setno < numHashes; setno++)
1114  {
1115  AggStatePerGroup pergroupstate;
1116 
1117  select_current_set(aggstate, setno, true);
1118 
1119  pergroupstate = &pergroups[setno][transno];
1120 
1121  advance_transition_function(aggstate, pertrans, pergroupstate);
1122  }
1123  }
1124  }
1125  }
1126 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:597
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
Definition: tuplesort.c:1422
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
Datum * tts_values
Definition: tuptable.h:125
AggStatePerTrans pertrans
Definition: execnodes.h:1816
int numtrans
Definition: execnodes.h:1809
FmgrInfo transfn
Definition: nodeAgg.c:302
FunctionCallInfoData transfn_fcinfo
Definition: nodeAgg.c:390
bool fn_strict
Definition: fmgr.h:61
Tuplesortstate ** sortstates
Definition: nodeAgg.c:382
bool * tts_isnull
Definition: tuptable.h:126
#define DatumGetBool(X)
Definition: postgres.h:399
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
int num_hashes
Definition: execnodes.h:1840
ProjectionInfo * combinedproj
Definition: execnodes.h:1844
AggStatePerPhase phase
Definition: execnodes.h:1812
uintptr_t Datum
Definition: postgres.h:372
static void advance_transition_function(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:855
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define Max(x, y)
Definition: c.h:796
#define Assert(condition)
Definition: c.h:670
ProjectionInfo * evalproj
Definition: nodeAgg.c:357
Expr * aggfilter
Definition: primnodes.h:304
int i
TupleTableSlot * sortslot
Definition: nodeAgg.c:364
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:319
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1301

◆ advance_combine_function()

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

Definition at line 1212 of file nodeAgg.c.

References FunctionCallInfoData::arg, FunctionCallInfoData::argnull, AggState::curaggcontext, AggState::curpertrans, CurrentMemoryContext, datumCopy(), DatumGetEOHP(), DatumGetPointer, DatumIsReadWriteExpandedObject, DeleteExpandedObject(), ExprContext::ecxt_per_tuple_memory, FmgrInfo::fn_strict, FunctionCallInvoke, FunctionCallInfoData::isnull, MemoryContextGetParent(), MemoryContextSwitchTo(), AggStatePerGroupData::noTransValue, pfree(), AggState::tmpcontext, AggStatePerTransData::transfn, AggStatePerTransData::transfn_fcinfo, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, AggStatePerGroupData::transValue, and AggStatePerGroupData::transValueIsNull.

Referenced by combine_aggregates().

1215 {
1216  FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
1217  MemoryContext oldContext;
1218  Datum newVal;
1219 
1220  if (pertrans->transfn.fn_strict)
1221  {
1222  /* if we're asked to merge to a NULL state, then do nothing */
1223  if (fcinfo->argnull[1])
1224  return;
1225 
1226  if (pergroupstate->noTransValue)
1227  {
1228  /*
1229  * transValue has not yet been initialized. If pass-by-ref
1230  * datatype we must copy the combining state value into
1231  * aggcontext.
1232  */
1233  if (!pertrans->transtypeByVal)
1234  {
1235  oldContext = MemoryContextSwitchTo(
1237  pergroupstate->transValue = datumCopy(fcinfo->arg[1],
1238  pertrans->transtypeByVal,
1239  pertrans->transtypeLen);
1240  MemoryContextSwitchTo(oldContext);
1241  }
1242  else
1243  pergroupstate->transValue = fcinfo->arg[1];
1244 
1245  pergroupstate->transValueIsNull = false;
1246  pergroupstate->noTransValue = false;
1247  return;
1248  }
1249  }
1250 
1251  /* We run the combine functions in per-input-tuple memory context */
1252  oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
1253 
1254  /* set up aggstate->curpertrans for AggGetAggref() */
1255  aggstate->curpertrans = pertrans;
1256 
1257  /*
1258  * OK to call the combine function
1259  */
1260  fcinfo->arg[0] = pergroupstate->transValue;
1261  fcinfo->argnull[0] = pergroupstate->transValueIsNull;
1262  fcinfo->isnull = false; /* just in case combine func doesn't set it */
1263 
1264  newVal = FunctionCallInvoke(fcinfo);
1265 
1266  aggstate->curpertrans = NULL;
1267 
1268  /*
1269  * If pass-by-ref datatype, must copy the new value into aggcontext and
1270  * free the prior transValue. But if the combine function returned a
1271  * pointer to its first input, we don't need to do anything. Also, if the
1272  * combine function returned a pointer to a R/W expanded object that is
1273  * already a child of the aggcontext, assume we can adopt that value
1274  * without copying it.
1275  */
1276  if (!pertrans->transtypeByVal &&
1277  DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
1278  {
1279  if (!fcinfo->isnull)
1280  {
1282  if (DatumIsReadWriteExpandedObject(newVal,
1283  false,
1284  pertrans->transtypeLen) &&
1285  MemoryContextGetParent(DatumGetEOHP(newVal)->eoh_context) == CurrentMemoryContext)
1286  /* do nothing */ ;
1287  else
1288  newVal = datumCopy(newVal,
1289  pertrans->transtypeByVal,
1290  pertrans->transtypeLen);
1291  }
1292  if (!pergroupstate->transValueIsNull)
1293  {
1294  if (DatumIsReadWriteExpandedObject(pergroupstate->transValue,
1295  false,
1296  pertrans->transtypeLen))
1297  DeleteExpandedObject(pergroupstate->transValue);
1298  else
1299  pfree(DatumGetPointer(pergroupstate->transValue));
1300  }
1301  }
1302 
1303  pergroupstate->transValue = newVal;
1304  pergroupstate->transValueIsNull = fcinfo->isnull;
1305 
1306  MemoryContextSwitchTo(oldContext);
1307 }
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:402
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExprContext * tmpcontext
Definition: execnodes.h:1819
FmgrInfo transfn
Definition: nodeAgg.c:302
FunctionCallInfoData transfn_fcinfo
Definition: nodeAgg.c:390
void pfree(void *pointer)
Definition: mcxt.c:949
bool fn_strict
Definition: fmgr.h:61
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:137
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
ExprContext * curaggcontext
Definition: execnodes.h:1820
uintptr_t Datum
Definition: postgres.h:372
void DeleteExpandedObject(Datum d)
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define DatumGetPointer(X)
Definition: postgres.h:555
AggStatePerTrans curpertrans
Definition: execnodes.h:1822

◆ advance_transition_function()

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

Definition at line 855 of file nodeAgg.c.

References FunctionCallInfoData::arg, FunctionCallInfoData::argnull, AggState::curaggcontext, AggState::curpertrans, CurrentMemoryContext, datumCopy(), DatumGetEOHP(), DatumGetPointer, DatumIsReadWriteExpandedObject, DeleteExpandedObject(), ExprContext::ecxt_per_tuple_memory, FmgrInfo::fn_strict, FunctionCallInvoke, i, FunctionCallInfoData::isnull, MemoryContextGetParent(), MemoryContextSwitchTo(), AggStatePerGroupData::noTransValue, AggStatePerTransData::numTransInputs, pfree(), AggState::tmpcontext, AggStatePerTransData::transfn, AggStatePerTransData::transfn_fcinfo, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, AggStatePerGroupData::transValue, and AggStatePerGroupData::transValueIsNull.

Referenced by advance_aggregates(), process_ordered_aggregate_multi(), and process_ordered_aggregate_single().

858 {
859  FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
860  MemoryContext oldContext;
861  Datum newVal;
862 
863  if (pertrans->transfn.fn_strict)
864  {
865  /*
866  * For a strict transfn, nothing happens when there's a NULL input; we
867  * just keep the prior transValue.
868  */
869  int numTransInputs = pertrans->numTransInputs;
870  int i;
871 
872  for (i = 1; i <= numTransInputs; i++)
873  {
874  if (fcinfo->argnull[i])
875  return;
876  }
877  if (pergroupstate->noTransValue)
878  {
879  /*
880  * transValue has not been initialized. This is the first non-NULL
881  * input value. We use it as the initial value for transValue. (We
882  * already checked that the agg's input type is binary-compatible
883  * with its transtype, so straight copy here is OK.)
884  *
885  * We must copy the datum into aggcontext if it is pass-by-ref. We
886  * do not need to pfree the old transValue, since it's NULL.
887  */
888  oldContext = MemoryContextSwitchTo(
890  pergroupstate->transValue = datumCopy(fcinfo->arg[1],
891  pertrans->transtypeByVal,
892  pertrans->transtypeLen);
893  pergroupstate->transValueIsNull = false;
894  pergroupstate->noTransValue = false;
895  MemoryContextSwitchTo(oldContext);
896  return;
897  }
898  if (pergroupstate->transValueIsNull)
899  {
900  /*
901  * Don't call a strict function with NULL inputs. Note it is
902  * possible to get here despite the above tests, if the transfn is
903  * strict *and* returned a NULL on a prior cycle. If that happens
904  * we will propagate the NULL all the way to the end.
905  */
906  return;
907  }
908  }
909 
910  /* We run the transition functions in per-input-tuple memory context */
911  oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
912 
913  /* set up aggstate->curpertrans for AggGetAggref() */
914  aggstate->curpertrans = pertrans;
915 
916  /*
917  * OK to call the transition function
918  */
919  fcinfo->arg[0] = pergroupstate->transValue;
920  fcinfo->argnull[0] = pergroupstate->transValueIsNull;
921  fcinfo->isnull = false; /* just in case transfn doesn't set it */
922 
923  newVal = FunctionCallInvoke(fcinfo);
924 
925  aggstate->curpertrans = NULL;
926 
927  /*
928  * If pass-by-ref datatype, must copy the new value into aggcontext and
929  * free the prior transValue. But if transfn returned a pointer to its
930  * first input, we don't need to do anything. Also, if transfn returned a
931  * pointer to a R/W expanded object that is already a child of the
932  * aggcontext, assume we can adopt that value without copying it.
933  */
934  if (!pertrans->transtypeByVal &&
935  DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
936  {
937  if (!fcinfo->isnull)
938  {
941  false,
942  pertrans->transtypeLen) &&
944  /* do nothing */ ;
945  else
946  newVal = datumCopy(newVal,
947  pertrans->transtypeByVal,
948  pertrans->transtypeLen);
949  }
950  if (!pergroupstate->transValueIsNull)
951  {
952  if (DatumIsReadWriteExpandedObject(pergroupstate->transValue,
953  false,
954  pertrans->transtypeLen))
955  DeleteExpandedObject(pergroupstate->transValue);
956  else
957  pfree(DatumGetPointer(pergroupstate->transValue));
958  }
959  }
960 
961  pergroupstate->transValue = newVal;
962  pergroupstate->transValueIsNull = fcinfo->isnull;
963 
964  MemoryContextSwitchTo(oldContext);
965 }
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:402
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ExprContext * tmpcontext
Definition: execnodes.h:1819
FmgrInfo transfn
Definition: nodeAgg.c:302
FunctionCallInfoData transfn_fcinfo
Definition: nodeAgg.c:390
void pfree(void *pointer)
Definition: mcxt.c:949
bool fn_strict
Definition: fmgr.h:61
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:137
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
ExprContext * curaggcontext
Definition: execnodes.h:1820
uintptr_t Datum
Definition: postgres.h:372
void DeleteExpandedObject(Datum d)
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define DatumGetPointer(X)
Definition: postgres.h:555
int i
AggStatePerTrans curpertrans
Definition: execnodes.h:1822

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

Definition at line 2523 of file nodeAgg.c.

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

Referenced by ExecAgg().

2524 {
2525  TupleTableSlot *outerslot;
2526  ExprContext *tmpcontext = aggstate->tmpcontext;
2527 
2528  /*
2529  * Process each outer-plan tuple, and then fetch the next one, until we
2530  * exhaust the outer plan.
2531  */
2532  for (;;)
2533  {
2534  AggStatePerGroup *pergroups;
2535 
2536  outerslot = fetch_input_tuple(aggstate);
2537  if (TupIsNull(outerslot))
2538  break;
2539 
2540  /* set up for lookup_hash_entries and advance_aggregates */
2541  tmpcontext->ecxt_outertuple = outerslot;
2542 
2543  /* Find or build hashtable entries */
2544  pergroups = lookup_hash_entries(aggstate);
2545 
2546  /* Advance the aggregates */
2547  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2548  combine_aggregates(aggstate, pergroups[0]);
2549  else
2550  advance_aggregates(aggstate, NULL, pergroups);
2551 
2552  /*
2553  * Reset per-input-tuple context after each tuple, but note that the
2554  * hash lookups do this too
2555  */
2556  ResetExprContext(aggstate->tmpcontext);
2557  }
2558 
2559  aggstate->table_filled = true;
2560  /* Initialize to walk the first hash table */
2561  select_current_set(aggstate, 0, true);
2563  &aggstate->perhash[0].hashiter);
2564 }
static TupleTableSlot * fetch_input_tuple(AggState *aggstate)
Definition: nodeAgg.c:685
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:597
AggSplit aggsplit
Definition: execnodes.h:1811
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:770
ExprContext * tmpcontext
Definition: execnodes.h:1819
static AggStatePerGroup * lookup_hash_entries(AggState *aggstate)
Definition: nodeAgg.c:2105
bool table_filled
Definition: execnodes.h:1839
#define TupIsNull(slot)
Definition: tuptable.h:138
AggStatePerHash perhash
Definition: execnodes.h:1841
TupleHashIterator hashiter
Definition: nodeAgg.c:518
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:634
static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGroup *pergroups)
Definition: nodeAgg.c:979
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
static void combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1136
TupleHashTable hashtable
Definition: nodeAgg.c:517
#define ResetExprContext(econtext)
Definition: executor.h:461

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

Definition at line 2170 of file nodeAgg.c.

References advance_aggregates(), AggState::agg_done, AGG_MIXED, AGG_PLAIN, agg_retrieve_hash_table(), AggState::aggcontexts, AggStatePerPhaseData::aggnode, AggState::aggsplit, Agg::aggstrategy, AggState::aggstrategy, Assert, combine_aggregates(), AggState::current_phase, DO_AGGSPLIT_COMBINE, ExprContext::ecxt_outertuple, ExprContext::ecxt_per_tuple_memory, AggStatePerPhaseData::eqfunctions, ExecCopySlotTuple(), ExecStoreTuple(), execTuplesMatch(), fetch_input_tuple(), finalize_aggregates(), AggState::grp_firstTuple, Agg::grpColIdx, AggStatePerPhaseData::gset_lengths, AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, i, initialize_aggregates(), initialize_phase(), AggState::input_done, InvalidBuffer, lookup_hash_entries(), Max, Agg::numCols, AggState::numphases, AggStatePerPhaseData::numsets, AggState::numtrans, AggState::peragg, AggState::pergroup, 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().

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

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

Definition at line 2570 of file nodeAgg.c.

References TupleHashEntryData::additional, AggState::agg_done, 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, tupleDesc::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_direct(), and ExecAgg().

2571 {
2572  ExprContext *econtext;
2573  AggStatePerAgg peragg;
2574  AggStatePerGroup pergroup;
2575  TupleHashEntryData *entry;
2576  TupleTableSlot *firstSlot;
2577  TupleTableSlot *result;
2578  AggStatePerHash perhash;
2579 
2580  /*
2581  * get state info from node.
2582  *
2583  * econtext is the per-output-tuple expression context.
2584  */
2585  econtext = aggstate->ss.ps.ps_ExprContext;
2586  peragg = aggstate->peragg;
2587  firstSlot = aggstate->ss.ss_ScanTupleSlot;
2588 
2589  /*
2590  * Note that perhash (and therefore anything accessed through it) can
2591  * change inside the loop, as we change between grouping sets.
2592  */
2593  perhash = &aggstate->perhash[aggstate->current_set];
2594 
2595  /*
2596  * We loop retrieving groups until we find one satisfying
2597  * aggstate->ss.ps.qual
2598  */
2599  while (!aggstate->agg_done)
2600  {
2601  TupleTableSlot *hashslot = perhash->hashslot;
2602  int i;
2603 
2605 
2606  /*
2607  * Find the next entry in the hash table
2608  */
2609  entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);
2610  if (entry == NULL)
2611  {
2612  int nextset = aggstate->current_set + 1;
2613 
2614  if (nextset < aggstate->num_hashes)
2615  {
2616  /*
2617  * Switch to next grouping set, reinitialize, and restart the
2618  * loop.
2619  */
2620  select_current_set(aggstate, nextset, true);
2621 
2622  perhash = &aggstate->perhash[aggstate->current_set];
2623 
2624  ResetTupleHashIterator(perhash->hashtable, &perhash->hashiter);
2625 
2626  continue;
2627  }
2628  else
2629  {
2630  /* No more hashtables, so done */
2631  aggstate->agg_done = true;
2632  return NULL;
2633  }
2634  }
2635 
2636  /*
2637  * Clear the per-output-tuple context for each group
2638  *
2639  * We intentionally don't use ReScanExprContext here; if any aggs have
2640  * registered shutdown callbacks, they mustn't be called yet, since we
2641  * might not be done with that agg.
2642  */
2643  ResetExprContext(econtext);
2644 
2645  /*
2646  * Transform representative tuple back into one with the right
2647  * columns.
2648  */
2649  ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);
2650  slot_getallattrs(hashslot);
2651 
2652  ExecClearTuple(firstSlot);
2653  memset(firstSlot->tts_isnull, true,
2654  firstSlot->tts_tupleDescriptor->natts * sizeof(bool));
2655 
2656  for (i = 0; i < perhash->numhashGrpCols; i++)
2657  {
2658  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
2659 
2660  firstSlot->tts_values[varNumber] = hashslot->tts_values[i];
2661  firstSlot->tts_isnull[varNumber] = hashslot->tts_isnull[i];
2662  }
2663  ExecStoreVirtualTuple(firstSlot);
2664 
2665  pergroup = (AggStatePerGroup) entry->additional;
2666 
2667  /*
2668  * Use the representative input tuple for any references to
2669  * non-aggregated input columns in the qual and tlist.
2670  */
2671  econtext->ecxt_outertuple = firstSlot;
2672 
2673  prepare_projection_slot(aggstate,
2674  econtext->ecxt_outertuple,
2675  aggstate->current_set);
2676 
2677  finalize_aggregates(aggstate, peragg, pergroup);
2678 
2679  result = project_aggregates(aggstate);
2680  if (result)
2681  return result;
2682  }
2683 
2684  /* No more groups */
2685  return NULL;
2686 }
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:1800
#define ScanTupleHashTable(htable, iter)
Definition: execnodes.h:636
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:597
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.c:525
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:384
bool agg_done
Definition: execnodes.h:1824
ScanState ss
Definition: execnodes.h:1806
ExprContext * ps_ExprContext
Definition: execnodes.h:883
MinimalTuple firstTuple
Definition: execnodes.h:591
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
Datum * tts_values
Definition: tuptable.h:125
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1106
static TupleTableSlot * project_aggregates(AggState *aggstate)
Definition: nodeAgg.c:1807
int current_set
Definition: execnodes.h:1826
int natts
Definition: tupdesc.h:79
static void prepare_projection_slot(AggState *aggstate, TupleTableSlot *slot, int currentSet)
Definition: nodeAgg.c:1699
PlanState ps
Definition: execnodes.h:1103
static void finalize_aggregates(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1744
bool * tts_isnull
Definition: tuptable.h:126
AggStatePerHash perhash
Definition: execnodes.h:1841
void slot_getallattrs(TupleTableSlot *slot)
Definition: heaptuple.c:1238
TupleHashIterator hashiter
Definition: nodeAgg.c:518
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:634
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
AggStatePerAgg peragg
Definition: execnodes.h:1815
int i
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
TupleTableSlot * hashslot
Definition: nodeAgg.c:519
TupleHashTable hashtable
Definition: nodeAgg.c:517
#define ResetExprContext(econtext)
Definition: executor.h:461
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488

◆ AggCheckCallContext()

int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

Definition at line 4116 of file nodeAgg.c.

References AGG_CONTEXT_AGGREGATE, AGG_CONTEXT_WINDOW, FunctionCallInfoData::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().

4117 {
4118  if (fcinfo->context && IsA(fcinfo->context, AggState))
4119  {
4120  if (aggcontext)
4121  {
4122  AggState *aggstate = ((AggState *) fcinfo->context);
4123  ExprContext *cxt = aggstate->curaggcontext;
4124 
4125  *aggcontext = cxt->ecxt_per_tuple_memory;
4126  }
4127  return AGG_CONTEXT_AGGREGATE;
4128  }
4129  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4130  {
4131  if (aggcontext)
4132  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4133  return AGG_CONTEXT_WINDOW;
4134  }
4135 
4136  /* this is just to prevent "uninitialized variable" warnings */
4137  if (aggcontext)
4138  *aggcontext = NULL;
4139  return 0;
4140 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:562
fmNodePtr context
Definition: fmgr.h:80
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:694
ExprContext * curaggcontext
Definition: execnodes.h:1820
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:695

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4160 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4161 {
4162  if (fcinfo->context && IsA(fcinfo->context, AggState))
4163  {
4164  AggState *aggstate = (AggState *) fcinfo->context;
4165  AggStatePerAgg curperagg;
4166  AggStatePerTrans curpertrans;
4167 
4168  /* check curperagg (valid when in a final function) */
4169  curperagg = aggstate->curperagg;
4170 
4171  if (curperagg)
4172  return curperagg->aggref;
4173 
4174  /* check curpertrans (valid when in a transition function) */
4175  curpertrans = aggstate->curpertrans;
4176 
4177  if (curpertrans)
4178  return curpertrans->aggref;
4179  }
4180  return NULL;
4181 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:562
fmNodePtr context
Definition: fmgr.h:80
Aggref * aggref
Definition: nodeAgg.c:415
AggStatePerAgg curperagg
Definition: execnodes.h:1821
AggStatePerTrans curpertrans
Definition: execnodes.h:1822

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4194 of file nodeAgg.c.

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

Referenced by hypothetical_dense_rank_final().

4195 {
4196  if (fcinfo->context && IsA(fcinfo->context, AggState))
4197  {
4198  AggState *aggstate = (AggState *) fcinfo->context;
4199 
4200  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4201  }
4202  return NULL;
4203 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:562
fmNodePtr context
Definition: fmgr.h:80
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
ExprContext * tmpcontext
Definition: execnodes.h:1819

◆ aggregate_dummy()

Datum aggregate_dummy ( PG_FUNCTION_ARGS  )

Definition at line 4287 of file nodeAgg.c.

References elog, and ERROR.

4288 {
4289  elog(ERROR, "aggregate function %u called as normal function",
4290  fcinfo->flinfo->fn_oid);
4291  return (Datum) 0; /* keep compiler quiet */
4292 }
#define ERROR
Definition: elog.h:43
uintptr_t Datum
Definition: postgres.h:372
#define elog
Definition: elog.h:219

◆ AggRegisterCallback()

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

Definition at line 4259 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4262 {
4263  if (fcinfo->context && IsA(fcinfo->context, AggState))
4264  {
4265  AggState *aggstate = (AggState *) fcinfo->context;
4266  ExprContext *cxt = aggstate->curaggcontext;
4267 
4268  RegisterExprContextCallback(cxt, func, arg);
4269 
4270  return;
4271  }
4272  elog(ERROR, "aggregate function cannot register a callback in this context");
4273 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:562
fmNodePtr context
Definition: fmgr.h:80
#define ERROR
Definition: elog.h:43
ExprContext * curaggcontext
Definition: execnodes.h:1820
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:739
void * arg
#define elog
Definition: elog.h:219

◆ AggStateIsShared()

bool AggStateIsShared ( FunctionCallInfo  fcinfo)

Definition at line 4220 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4221 {
4222  if (fcinfo->context && IsA(fcinfo->context, AggState))
4223  {
4224  AggState *aggstate = (AggState *) fcinfo->context;
4225  AggStatePerAgg curperagg;
4226  AggStatePerTrans curpertrans;
4227 
4228  /* check curperagg (valid when in a final function) */
4229  curperagg = aggstate->curperagg;
4230 
4231  if (curperagg)
4232  return aggstate->pertrans[curperagg->transno].aggshared;
4233 
4234  /* check curpertrans (valid when in a transition function) */
4235  curpertrans = aggstate->curpertrans;
4236 
4237  if (curpertrans)
4238  return curpertrans->aggshared;
4239  }
4240  return true;
4241 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:562
fmNodePtr context
Definition: fmgr.h:80
AggStatePerTrans pertrans
Definition: execnodes.h:1816
AggStatePerAgg curperagg
Definition: execnodes.h:1821
AggStatePerTrans curpertrans
Definition: execnodes.h:1822

◆ build_hash_table()

static void build_hash_table ( AggState aggstate)
static

Definition at line 1888 of file nodeAgg.c.

References AGG_HASHED, AGG_MIXED, AggStatePerHashData::aggnode, AggState::aggsplit, AggState::aggstrategy, Assert, BuildTupleHashTable(), DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_per_tuple_memory, AggStatePerHashData::eqfunctions, AggState::hashcontext, AggStatePerHashData::hashfunctions, AggStatePerHashData::hashGrpColIdxHash, AggStatePerHashData::hashtable, i, AggState::num_hashes, AggStatePerHashData::numCols, Agg::numGroups, AggState::numtrans, AggState::perhash, and AggState::tmpcontext.

Referenced by ExecInitAgg(), and ExecReScanAgg().

1889 {
1890  MemoryContext tmpmem = aggstate->tmpcontext->ecxt_per_tuple_memory;
1891  Size additionalsize;
1892  int i;
1893 
1894  Assert(aggstate->aggstrategy == AGG_HASHED || aggstate->aggstrategy == AGG_MIXED);
1895 
1896  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1897 
1898  for (i = 0; i < aggstate->num_hashes; ++i)
1899  {
1900  AggStatePerHash perhash = &aggstate->perhash[i];
1901 
1902  Assert(perhash->aggnode->numGroups > 0);
1903 
1904  perhash->hashtable = BuildTupleHashTable(perhash->numCols,
1905  perhash->hashGrpColIdxHash,
1906  perhash->eqfunctions,
1907  perhash->hashfunctions,
1908  perhash->aggnode->numGroups,
1909  additionalsize,
1911  tmpmem,
1912  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1913  }
1914 }
FmgrInfo * eqfunctions
Definition: nodeAgg.c:521
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
AggSplit aggsplit
Definition: execnodes.h:1811
int numtrans
Definition: execnodes.h:1809
ExprContext * tmpcontext
Definition: execnodes.h:1819
AggStrategy aggstrategy
Definition: execnodes.h:1810
AggStatePerHash perhash
Definition: execnodes.h:1841
int num_hashes
Definition: execnodes.h:1840
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.c:526
ExprContext * hashcontext
Definition: execnodes.h:1817
struct AggStatePerGroupData AggStatePerGroupData
FmgrInfo * hashfunctions
Definition: nodeAgg.c:520
#define Assert(condition)
Definition: c.h:670
size_t Size
Definition: c.h:404
long numGroups
Definition: plannodes.h:788
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:771
TupleHashTable BuildTupleHashTable(int numCols, AttrNumber *keyColIdx, FmgrInfo *eqfunctions, FmgrInfo *hashfunctions, long nbuckets, Size additionalsize, MemoryContext tablecxt, MemoryContext tempcxt, bool use_variable_hash_iv)
Definition: execGrouping.c:290
int i
TupleHashTable hashtable
Definition: nodeAgg.c:517

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

References AGG_HASHED, AGG_MIXED, AggStatePerTransData::aggCollation, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggkind, AGGKIND_IS_ORDERED_SET, 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, SortGroupClause::eqop, AggStatePerTransData::equalfns, ereport, errcode(), errmsg(), ERROR, ExecInitExtraTupleSlot(), ExecSetSlotDescriptor(), ExecTypeFromTL(), TargetEntry::expr, exprCollation(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_strict, get_opcode(), get_sortgroupclause_tle(), get_typlenbyval(), i, InitFunctionCallInfoData, AggStatePerTransData::initValue, AggStatePerTransData::initValueIsNull, Aggref::inputcollid, AggStatePerTransData::inputtypeByVal, AggStatePerTransData::inputtypeLen, INTERNALOID, InvalidOid, IsBinaryCoercible(), lfirst, list_length(), Max, AggState::maxsets, NIL, SortGroupClause::nulls_first, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numInputs, AggStatePerTransData::numSortCols, AggStatePerTransData::numTransInputs, OidIsValid, palloc(), palloc0(), TargetEntry::resno, AggStatePerTransData::serialfn, AggStatePerTransData::serialfn_fcinfo, AggStatePerTransData::serialfn_oid, AggStatePerTransData::sortColIdx, AggStatePerTransData::sortCollations, AggStatePerTransData::sortdesc, AggStatePerTransData::sortNullsFirst, SortGroupClause::sortop, AggStatePerTransData::sortOperators, AggStatePerTransData::sortslot, AggStatePerTransData::sortstates, AggStatePerTransData::transfn, AggStatePerTransData::transfn_fcinfo, AggStatePerTransData::transfn_oid, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, and AggStatePerTransData::uniqslot.

Referenced by ExecInitAgg().

3504 {
3505  int numGroupingSets = Max(aggstate->maxsets, 1);
3506  Expr *serialfnexpr = NULL;
3507  Expr *deserialfnexpr = NULL;
3508  ListCell *lc;
3509  int numInputs;
3510  int numDirectArgs;
3511  List *sortlist;
3512  int numSortCols;
3513  int numDistinctCols;
3514  int i;
3515 
3516  /* Begin filling in the pertrans data */
3517  pertrans->aggref = aggref;
3518  pertrans->aggshared = false;
3519  pertrans->aggCollation = aggref->inputcollid;
3520  pertrans->transfn_oid = aggtransfn;
3521  pertrans->serialfn_oid = aggserialfn;
3522  pertrans->deserialfn_oid = aggdeserialfn;
3523  pertrans->initValue = initValue;
3524  pertrans->initValueIsNull = initValueIsNull;
3525 
3526  /* Count the "direct" arguments, if any */
3527  numDirectArgs = list_length(aggref->aggdirectargs);
3528 
3529  /* Count the number of aggregated input columns */
3530  pertrans->numInputs = numInputs = list_length(aggref->args);
3531 
3532  pertrans->aggtranstype = aggtranstype;
3533 
3534  /* Detect how many arguments to pass to the transfn */
3535  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3536  pertrans->numTransInputs = numInputs;
3537  else
3538  pertrans->numTransInputs = numArguments;
3539 
3540  /* inputoff and evalproj will be set up later, in ExecInitAgg */
3541 
3542  /*
3543  * When combining states, we have no use at all for the aggregate
3544  * function's transfn. Instead we use the combinefn. In this case, the
3545  * transfn and transfn_oid fields of pertrans refer to the combine
3546  * function rather than the transition function.
3547  */
3548  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3549  {
3550  Expr *combinefnexpr;
3551 
3552  build_aggregate_combinefn_expr(aggtranstype,
3553  aggref->inputcollid,
3554  aggtransfn,
3555  &combinefnexpr);
3556  fmgr_info(aggtransfn, &pertrans->transfn);
3557  fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
3558 
3560  &pertrans->transfn,
3561  2,
3562  pertrans->aggCollation,
3563  (void *) aggstate, NULL);
3564 
3565  /*
3566  * Ensure that a combine function to combine INTERNAL states is not
3567  * strict. This should have been checked during CREATE AGGREGATE, but
3568  * the strict property could have been changed since then.
3569  */
3570  if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
3571  ereport(ERROR,
3572  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3573  errmsg("combine function for aggregate %u must be declared as STRICT",
3574  aggref->aggfnoid)));
3575  }
3576  else
3577  {
3578  Expr *transfnexpr;
3579 
3580  /*
3581  * Set up infrastructure for calling the transfn. Note that invtrans
3582  * is not needed here.
3583  */
3584  build_aggregate_transfn_expr(inputTypes,
3585  numArguments,
3586  numDirectArgs,
3587  aggref->aggvariadic,
3588  aggtranstype,
3589  aggref->inputcollid,
3590  aggtransfn,
3591  InvalidOid,
3592  &transfnexpr,
3593  NULL);
3594  fmgr_info(aggtransfn, &pertrans->transfn);
3595  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
3596 
3598  &pertrans->transfn,
3599  pertrans->numTransInputs + 1,
3600  pertrans->aggCollation,
3601  (void *) aggstate, NULL);
3602 
3603  /*
3604  * If the transfn is strict and the initval is NULL, make sure input
3605  * type and transtype are the same (or at least binary-compatible), so
3606  * that it's OK to use the first aggregated input value as the initial
3607  * transValue. This should have been checked at agg definition time,
3608  * but we must check again in case the transfn's strictness property
3609  * has been changed.
3610  */
3611  if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
3612  {
3613  if (numArguments <= numDirectArgs ||
3614  !IsBinaryCoercible(inputTypes[numDirectArgs],
3615  aggtranstype))
3616  ereport(ERROR,
3617  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3618  errmsg("aggregate %u needs to have compatible input type and transition type",
3619  aggref->aggfnoid)));
3620  }
3621  }
3622 
3623  /* get info about the state value's datatype */
3624  get_typlenbyval(aggtranstype,
3625  &pertrans->transtypeLen,
3626  &pertrans->transtypeByVal);
3627 
3628  if (OidIsValid(aggserialfn))
3629  {
3630  build_aggregate_serialfn_expr(aggserialfn,
3631  &serialfnexpr);
3632  fmgr_info(aggserialfn, &pertrans->serialfn);
3633  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
3634 
3636  &pertrans->serialfn,
3637  1,
3638  InvalidOid,
3639  (void *) aggstate, NULL);
3640  }
3641 
3642  if (OidIsValid(aggdeserialfn))
3643  {
3644  build_aggregate_deserialfn_expr(aggdeserialfn,
3645  &deserialfnexpr);
3646  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
3647  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
3648 
3650  &pertrans->deserialfn,
3651  2,
3652  InvalidOid,
3653  (void *) aggstate, NULL);
3654 
3655  }
3656 
3657  /*
3658  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
3659  * have a list of SortGroupClause nodes; fish out the data in them and
3660  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
3661  * however; the agg's transfn and finalfn are responsible for that.
3662  *
3663  * Note that by construction, if there is a DISTINCT clause then the ORDER
3664  * BY clause is a prefix of it (see transformDistinctClause).
3665  */
3666  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3667  {
3668  sortlist = NIL;
3669  numSortCols = numDistinctCols = 0;
3670  }
3671  else if (aggref->aggdistinct)
3672  {
3673  sortlist = aggref->aggdistinct;
3674  numSortCols = numDistinctCols = list_length(sortlist);
3675  Assert(numSortCols >= list_length(aggref->aggorder));
3676  }
3677  else
3678  {
3679  sortlist = aggref->aggorder;
3680  numSortCols = list_length(sortlist);
3681  numDistinctCols = 0;
3682  }
3683 
3684  pertrans->numSortCols = numSortCols;
3685  pertrans->numDistinctCols = numDistinctCols;
3686 
3687  /*
3688  * If we have either sorting or filtering to do, create a tupledesc and
3689  * slot corresponding to the aggregated inputs (including sort
3690  * expressions) of the agg.
3691  */
3692  if (numSortCols > 0 || aggref->aggfilter)
3693  {
3694  pertrans->sortdesc = ExecTypeFromTL(aggref->args, false);
3695  pertrans->sortslot = ExecInitExtraTupleSlot(estate);
3696  ExecSetSlotDescriptor(pertrans->sortslot, pertrans->sortdesc);
3697  }
3698 
3699  if (numSortCols > 0)
3700  {
3701  /*
3702  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
3703  * (yet)
3704  */
3705  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
3706 
3707  /* If we have only one input, we need its len/byval info. */
3708  if (numInputs == 1)
3709  {
3710  get_typlenbyval(inputTypes[numDirectArgs],
3711  &pertrans->inputtypeLen,
3712  &pertrans->inputtypeByVal);
3713  }
3714  else if (numDistinctCols > 0)
3715  {
3716  /* we will need an extra slot to store prior values */
3717  pertrans->uniqslot = ExecInitExtraTupleSlot(estate);
3718  ExecSetSlotDescriptor(pertrans->uniqslot,
3719  pertrans->sortdesc);
3720  }
3721 
3722  /* Extract the sort information for use later */
3723  pertrans->sortColIdx =
3724  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
3725  pertrans->sortOperators =
3726  (Oid *) palloc(numSortCols * sizeof(Oid));
3727  pertrans->sortCollations =
3728  (Oid *) palloc(numSortCols * sizeof(Oid));
3729  pertrans->sortNullsFirst =
3730  (bool *) palloc(numSortCols * sizeof(bool));
3731 
3732  i = 0;
3733  foreach(lc, sortlist)
3734  {
3735  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
3736  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
3737 
3738  /* the parser should have made sure of this */
3739  Assert(OidIsValid(sortcl->sortop));
3740 
3741  pertrans->sortColIdx[i] = tle->resno;
3742  pertrans->sortOperators[i] = sortcl->sortop;
3743  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
3744  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
3745  i++;
3746  }
3747  Assert(i == numSortCols);
3748  }
3749 
3750  if (aggref->aggdistinct)
3751  {
3752  Assert(numArguments > 0);
3753 
3754  /*
3755  * We need the equal function for each DISTINCT comparison we will
3756  * make.
3757  */
3758  pertrans->equalfns =
3759  (FmgrInfo *) palloc(numDistinctCols * sizeof(FmgrInfo));
3760 
3761  i = 0;
3762  foreach(lc, aggref->aggdistinct)
3763  {
3764  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
3765 
3766  fmgr_info(get_opcode(sortcl->eqop), &pertrans->equalfns[i]);
3767  i++;
3768  }
3769  Assert(i == numDistinctCols);
3770  }
3771 
3772  pertrans->sortstates = (Tuplesortstate **)
3773  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
3774 }
List * aggdistinct
Definition: primnodes.h:303
#define NIL
Definition: pg_list.h:69
Definition: fmgr.h:56
bool aggvariadic
Definition: primnodes.h:306
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate)
Definition: execTuples.c:852
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:370
Oid inputcollid
Definition: primnodes.h:297
Definition: nodes.h:511
AggSplit aggsplit
Definition: execnodes.h:1811
int errcode(int sqlerrcode)
Definition: elog.c:575
List * args
Definition: primnodes.h:301
void build_aggregate_deserialfn_expr(Oid deserialfn_oid, Expr **deserialfnexpr)
Definition: parse_agg.c:1995
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:576
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:770
TupleDesc sortdesc
Definition: nodeAgg.c:366
FmgrInfo transfn
Definition: nodeAgg.c:302
FunctionCallInfoData transfn_fcinfo
Definition: nodeAgg.c:390
#define AGGKIND_IS_ORDERED_SET(kind)
Definition: pg_aggregate.h:133
int maxsets
Definition: execnodes.h:1830
AggStrategy aggstrategy
Definition: execnodes.h:1810
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:122
Tuplesortstate ** sortstates
Definition: nodeAgg.c:382
static int initValue(long lng_val)
Definition: informix.c:702
List * aggorder
Definition: primnodes.h:302
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:104
AttrNumber resno
Definition: primnodes.h:1376
List * aggdirectargs
Definition: primnodes.h:300
AttrNumber * sortColIdx
Definition: nodeAgg.c:321
#define ereport(elevel, rest)
Definition: elog.h:122
void build_aggregate_combinefn_expr(Oid agg_state_type, Oid agg_input_collation, Oid combinefn_oid, Expr **combinefnexpr)
Definition: parse_agg.c:1943
TupleDesc ExecTypeFromTL(List *targetList, bool hasoid)
Definition: execTuples.c:888
bool IsBinaryCoercible(Oid srctype, Oid targettype)
void * palloc0(Size size)
Definition: mcxt.c:877
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
FunctionCallInfoData serialfn_fcinfo
Definition: nodeAgg.c:393
FmgrInfo deserialfn
Definition: nodeAgg.c:308
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1094
Oid aggfnoid
Definition: primnodes.h:294
#define INTERNALOID
Definition: pg_type.h:698
#define Max(x, y)
Definition: c.h:796
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
FmgrInfo serialfn
Definition: nodeAgg.c:305
void build_aggregate_serialfn_expr(Oid serialfn_oid, Expr **serialfnexpr)
Definition: parse_agg.c:1972
Expr * expr
Definition: primnodes.h:1375
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:1882
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:120
static int list_length(const List *l)
Definition: pg_list.h:89
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:720
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2001
Expr * aggfilter
Definition: primnodes.h:304
TupleTableSlot * uniqslot
Definition: nodeAgg.c:365
void * palloc(Size size)
Definition: mcxt.c:848
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
FmgrInfo * equalfns
Definition: nodeAgg.c:331
char aggkind
Definition: primnodes.h:308
TupleTableSlot * sortslot
Definition: nodeAgg.c:364
FunctionCallInfoData deserialfn_fcinfo
Definition: nodeAgg.c:395
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
bool * sortNullsFirst
Definition: nodeAgg.c:324

◆ combine_aggregates()

static void combine_aggregates ( AggState aggstate,
AggStatePerGroup  pergroup 
)
static

Definition at line 1136 of file nodeAgg.c.

References advance_combine_function(), FunctionCallInfoData::arg, FunctionCallInfoData::argnull, Assert, AggState::combinedproj, AggStatePerTransData::deserialfn, AggStatePerTransData::deserialfn_fcinfo, AggStatePerTransData::deserialfn_oid, ExprContext::ecxt_per_tuple_memory, ExecProject(), FmgrInfo::fn_strict, FunctionCallInvoke, AggStatePerTransData::inputoff, FunctionCallInfoData::isnull, MemoryContextSwitchTo(), AggStatePerPhaseData::numsets, AggState::numtrans, OidIsValid, AggState::pertrans, AggState::phase, PointerGetDatum, AggState::tmpcontext, AggStatePerTransData::transfn_fcinfo, TupleTableSlot::tts_isnull, TupleTableSlot::tts_nvalid, and TupleTableSlot::tts_values.

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

1137 {
1138  int transno;
1139  int numTrans = aggstate->numtrans;
1140  TupleTableSlot *slot;
1141 
1142  /* combine not supported with grouping sets */
1143  Assert(aggstate->phase->numsets <= 1);
1144 
1145  /* compute input for all aggregates */
1146  slot = ExecProject(aggstate->combinedproj);
1147 
1148  for (transno = 0; transno < numTrans; transno++)
1149  {
1150  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1151  AggStatePerGroup pergroupstate = &pergroup[transno];
1152  FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
1153  int inputoff = pertrans->inputoff;
1154 
1155  Assert(slot->tts_nvalid > inputoff);
1156 
1157  /*
1158  * deserialfn_oid will be set if we must deserialize the input state
1159  * before calling the combine function
1160  */
1161  if (OidIsValid(pertrans->deserialfn_oid))
1162  {
1163  /* Don't call a strict deserialization function with NULL input */
1164  if (pertrans->deserialfn.fn_strict && slot->tts_isnull[inputoff])
1165  {
1166  fcinfo->arg[1] = slot->tts_values[inputoff];
1167  fcinfo->argnull[1] = slot->tts_isnull[inputoff];
1168  }
1169  else
1170  {
1171  FunctionCallInfo dsinfo = &pertrans->deserialfn_fcinfo;
1172  MemoryContext oldContext;
1173 
1174  dsinfo->arg[0] = slot->tts_values[inputoff];
1175  dsinfo->argnull[0] = slot->tts_isnull[inputoff];
1176  /* Dummy second argument for type-safety reasons */
1177  dsinfo->arg[1] = PointerGetDatum(NULL);
1178  dsinfo->argnull[1] = false;
1179 
1180  /*
1181  * We run the deserialization functions in per-input-tuple
1182  * memory context.
1183  */
1184  oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
1185 
1186  fcinfo->arg[1] = FunctionCallInvoke(dsinfo);
1187  fcinfo->argnull[1] = dsinfo->isnull;
1188 
1189  MemoryContextSwitchTo(oldContext);
1190  }
1191  }
1192  else
1193  {
1194  fcinfo->arg[1] = slot->tts_values[inputoff];
1195  fcinfo->argnull[1] = slot->tts_isnull[inputoff];
1196  }
1197 
1198  advance_combine_function(aggstate, pertrans, pergroupstate);
1199  }
1200 }
#define PointerGetDatum(X)
Definition: postgres.h:562
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Datum * tts_values
Definition: tuptable.h:125
AggStatePerTrans pertrans
Definition: execnodes.h:1816
#define OidIsValid(objectId)
Definition: c.h:576
int numtrans
Definition: execnodes.h:1809
ExprContext * tmpcontext
Definition: execnodes.h:1819
FunctionCallInfoData transfn_fcinfo
Definition: nodeAgg.c:390
bool fn_strict
Definition: fmgr.h:61
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:137
bool * tts_isnull
Definition: tuptable.h:126
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
ProjectionInfo * combinedproj
Definition: execnodes.h:1844
static void advance_combine_function(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:1212
AggStatePerPhase phase
Definition: execnodes.h:1812
FmgrInfo deserialfn
Definition: nodeAgg.c:308
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define Assert(condition)
Definition: c.h:670
FunctionCallInfoData deserialfn_fcinfo
Definition: nodeAgg.c:395
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:319

◆ ExecAgg()

static TupleTableSlot* ExecAgg ( PlanState pstate)
static

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

2135 {
2136  AggState *node = castNode(AggState, pstate);
2137  TupleTableSlot *result = NULL;
2138 
2140 
2141  if (!node->agg_done)
2142  {
2143  /* Dispatch based on strategy */
2144  switch (node->phase->aggstrategy)
2145  {
2146  case AGG_HASHED:
2147  if (!node->table_filled)
2148  agg_fill_hash_table(node);
2149  /* FALLTHROUGH */
2150  case AGG_MIXED:
2151  result = agg_retrieve_hash_table(node);
2152  break;
2153  case AGG_PLAIN:
2154  case AGG_SORTED:
2155  result = agg_retrieve_direct(node);
2156  break;
2157  }
2158 
2159  if (!TupIsNull(result))
2160  return result;
2161  }
2162 
2163  return NULL;
2164 }
static void agg_fill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2523
bool agg_done
Definition: execnodes.h:1824
#define castNode(_type_, nodeptr)
Definition: nodes.h:580
bool table_filled
Definition: execnodes.h:1839
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2570
static TupleTableSlot * agg_retrieve_direct(AggState *aggstate)
Definition: nodeAgg.c:2170
#define TupIsNull(slot)
Definition: tuptable.h:138
AggStrategy aggstrategy
Definition: nodeAgg.c:499
AggStatePerPhase phase
Definition: execnodes.h:1812
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

Definition at line 3935 of file nodeAgg.c.

References AggState::aggcontexts, ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), AggState::hashcontext, Max, AggState::maxsets, 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().

3936 {
3938  int transno;
3939  int numGroupingSets = Max(node->maxsets, 1);
3940  int setno;
3941 
3942  /* Make sure we have closed any open tuplesorts */
3943 
3944  if (node->sort_in)
3945  tuplesort_end(node->sort_in);
3946  if (node->sort_out)
3947  tuplesort_end(node->sort_out);
3948 
3949  for (transno = 0; transno < node->numtrans; transno++)
3950  {
3951  AggStatePerTrans pertrans = &node->pertrans[transno];
3952 
3953  for (setno = 0; setno < numGroupingSets; setno++)
3954  {
3955  if (pertrans->sortstates[setno])
3956  tuplesort_end(pertrans->sortstates[setno]);
3957  }
3958  }
3959 
3960  /* And ensure any agg shutdown callbacks have been called */
3961  for (setno = 0; setno < numGroupingSets; setno++)
3962  ReScanExprContext(node->aggcontexts[setno]);
3963  if (node->hashcontext)
3965 
3966  /*
3967  * We don't actually free any ExprContexts here (see comment in
3968  * ExecFreeExprContext), just unlinking the output one from the plan node
3969  * suffices.
3970  */
3971  ExecFreeExprContext(&node->ss.ps);
3972 
3973  /* clean up tuple table */
3975 
3976  outerPlan = outerPlanState(node);
3977  ExecEndNode(outerPlan);
3978 }
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:523
Tuplesortstate * sort_out
Definition: execnodes.h:1833
ScanState ss
Definition: execnodes.h:1806
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1106
AggStatePerTrans pertrans
Definition: execnodes.h:1816
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:523
int numtrans
Definition: execnodes.h:1809
PlanState ps
Definition: execnodes.h:1103
int maxsets
Definition: execnodes.h:1830
Tuplesortstate * sort_in
Definition: execnodes.h:1832
#define outerPlanState(node)
Definition: execnodes.h:895
Tuplesortstate ** sortstates
Definition: nodeAgg.c:382
#define outerPlan(node)
Definition: plannodes.h:174
ExprContext * hashcontext
Definition: execnodes.h:1817
#define Max(x, y)
Definition: c.h:796
ExprContext ** aggcontexts
Definition: execnodes.h:1818
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:383
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1104

◆ ExecInitAgg()

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

Definition at line 2697 of file nodeAgg.c.

References ACL_EXECUTE, ACL_KIND_PROC, aclcheck_error(), ACLCHECK_OK, AggState::agg_done, AGG_HASHED, AGG_MIXED, AGG_SORTED, AggState::aggcontexts, Aggref::aggdirectargs, AggStatePerAggData::aggdirectargs, Aggref::aggfilter, AGGFNOID, Aggref::aggfnoid, Aggref::agglevelsup, AGGMODIFY_READ_WRITE, AggrefExprState::aggno, AggStatePerPhaseData::aggnode, AggStatePerHashData::aggnode, AggStatePerTransData::aggref, AggStatePerAggData::aggref, AggrefExprState::aggref, AggState::aggs, AggStatePerTransData::aggshared, Aggref::aggsplit, Agg::aggsplit, AggState::aggsplit, AggStatePerPhaseData::aggstrategy, Agg::aggstrategy, AggState::aggstrategy, AggStatePerTransData::aggtranstype, Aggref::aggtranstype, Aggref::aggtype, Anum_pg_aggregate_agginitval, arg, Aggref::args, Assert, bms_add_member(), bms_add_members(), bms_next_member(), build_aggregate_finalfn_expr(), build_hash_table(), build_pertrans_for_aggref(), castNode, Agg::chain, AggState::curperagg, AggState::curpertrans, AggState::current_set, AggStatePerTransData::deserialfn_oid, 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, AggStatePerTransData::evalproj, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, EXEC_FLAG_REWIND, ExecAgg(), ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecAssignResultTypeFromTL(), ExecAssignScanTypeFromOuterPlan(), ExecBuildProjectionInfo(), ExecInitExprList(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlot(), ExecInitScanTupleSlot(), PlanState::ExecProcNode, ExecSetSlotDescriptor(), execTuplesHashPrepare(), execTuplesMatchPrepare(), ExecTypeFromTL(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, find_compatible_peragg(), find_compatible_pertrans(), find_hash_columns(), flatCopyTargetEntry(), 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::grpOperators, AggStatePerPhaseData::gset_lengths, AggState::hashcontext, HeapTupleIsValid, i, initialize_phase(), AggStatePerTransData::initValue, AggStatePerTransData::initValueIsNull, AggState::input_done, Aggref::inputcollid, AggStatePerTransData::inputoff, INTERNALOID, InvalidOid, InvokeFunctionExecuteHook, lappend(), lcons_int(), Plan::lefttree, lfirst, lfirst_node, list_length(), list_nth_node, makeNode, makeTargetEntry(), Max, AggState::maxsets, NIL, AggState::numaggs, AggStatePerHashData::numCols, Agg::numCols, AggStatePerAggData::numFinalArgs, AggState::numphases, AggStatePerPhaseData::numsets, AggState::numtrans, ObjectIdGetDatum, OidIsValid, outerPlan, outerPlanState, palloc(), palloc0(), AggState::peragg, AggState::pergroup, AggState::pertrans, pg_proc_aclcheck(), Agg::plan, PlanState::plan, PROCOID, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, Plan::qual, PlanState::qual, ReleaseSysCache(), TargetEntry::resno, AggStatePerAggData::resulttypeByVal, AggStatePerAggData::resulttypeLen, SearchSysCache1(), select_current_set(), AggStatePerTransData::serialfn_oid, AggStatePerAggData::sharable, AggState::sort_in, AggState::sort_out, AggState::sort_slot, AggStatePerPhaseData::sortnode, AggStatePerTransData::sortslot, AggState::ss, PlanState::state, SysCacheGetAttr(), AggState::tmpcontext, AggStatePerTransData::transfn_oid, and AggStatePerAggData::transno.

Referenced by ExecInitNode().

2698 {
2699  AggState *aggstate;
2700  AggStatePerAgg peraggs;
2701  AggStatePerTrans pertransstates;
2702  Plan *outerPlan;
2703  ExprContext *econtext;
2704  int numaggs,
2705  transno,
2706  aggno;
2707  int phase;
2708  int phaseidx;
2709  List *combined_inputeval;
2710  TupleDesc combineddesc;
2711  TupleTableSlot *combinedslot;
2712  ListCell *l;
2713  Bitmapset *all_grouped_cols = NULL;
2714  int numGroupingSets = 1;
2715  int numPhases;
2716  int numHashes;
2717  int column_offset;
2718  int i = 0;
2719  int j = 0;
2720  bool use_hashing = (node->aggstrategy == AGG_HASHED ||
2721  node->aggstrategy == AGG_MIXED);
2722 
2723  /* check for unsupported flags */
2724  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2725 
2726  /*
2727  * create state structure
2728  */
2729  aggstate = makeNode(AggState);
2730  aggstate->ss.ps.plan = (Plan *) node;
2731  aggstate->ss.ps.state = estate;
2732  aggstate->ss.ps.ExecProcNode = ExecAgg;
2733 
2734  aggstate->aggs = NIL;
2735  aggstate->numaggs = 0;
2736  aggstate->numtrans = 0;
2737  aggstate->aggstrategy = node->aggstrategy;
2738  aggstate->aggsplit = node->aggsplit;
2739  aggstate->maxsets = 0;
2740  aggstate->projected_set = -1;
2741  aggstate->current_set = 0;
2742  aggstate->peragg = NULL;
2743  aggstate->pertrans = NULL;
2744  aggstate->curperagg = NULL;
2745  aggstate->curpertrans = NULL;
2746  aggstate->input_done = false;
2747  aggstate->agg_done = false;
2748  aggstate->pergroup = NULL;
2749  aggstate->grp_firstTuple = NULL;
2750  aggstate->sort_in = NULL;
2751  aggstate->sort_out = NULL;
2752 
2753  /*
2754  * phases[0] always exists, but is dummy in sorted/plain mode
2755  */
2756  numPhases = (use_hashing ? 1 : 2);
2757  numHashes = (use_hashing ? 1 : 0);
2758 
2759  /*
2760  * Calculate the maximum number of grouping sets in any phase; this
2761  * determines the size of some allocations. Also calculate the number of
2762  * phases, since all hashed/mixed nodes contribute to only a single phase.
2763  */
2764  if (node->groupingSets)
2765  {
2766  numGroupingSets = list_length(node->groupingSets);
2767 
2768  foreach(l, node->chain)
2769  {
2770  Agg *agg = lfirst(l);
2771 
2772  numGroupingSets = Max(numGroupingSets,
2773  list_length(agg->groupingSets));
2774 
2775  /*
2776  * additional AGG_HASHED aggs become part of phase 0, but all
2777  * others add an extra phase.
2778  */
2779  if (agg->aggstrategy != AGG_HASHED)
2780  ++numPhases;
2781  else
2782  ++numHashes;
2783  }
2784  }
2785 
2786  aggstate->maxsets = numGroupingSets;
2787  aggstate->numphases = numPhases;
2788 
2789  aggstate->aggcontexts = (ExprContext **)
2790  palloc0(sizeof(ExprContext *) * numGroupingSets);
2791 
2792  /*
2793  * Create expression contexts. We need three or more, one for
2794  * per-input-tuple processing, one for per-output-tuple processing, one
2795  * for all the hashtables, and one for each grouping set. The per-tuple
2796  * memory context of the per-grouping-set ExprContexts (aggcontexts)
2797  * replaces the standalone memory context formerly used to hold transition
2798  * values. We cheat a little by using ExecAssignExprContext() to build
2799  * all of them.
2800  *
2801  * NOTE: the details of what is stored in aggcontexts and what is stored
2802  * in the regular per-query memory context are driven by a simple
2803  * decision: we want to reset the aggcontext at group boundaries (if not
2804  * hashing) and in ExecReScanAgg to recover no-longer-wanted space.
2805  */
2806  ExecAssignExprContext(estate, &aggstate->ss.ps);
2807  aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
2808 
2809  for (i = 0; i < numGroupingSets; ++i)
2810  {
2811  ExecAssignExprContext(estate, &aggstate->ss.ps);
2812  aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
2813  }
2814 
2815  if (use_hashing)
2816  {
2817  ExecAssignExprContext(estate, &aggstate->ss.ps);
2818  aggstate->hashcontext = aggstate->ss.ps.ps_ExprContext;
2819  }
2820 
2821  ExecAssignExprContext(estate, &aggstate->ss.ps);
2822 
2823  /*
2824  * tuple table initialization.
2825  *
2826  * For hashtables, we create some additional slots below.
2827  */
2828  ExecInitScanTupleSlot(estate, &aggstate->ss);
2829  ExecInitResultTupleSlot(estate, &aggstate->ss.ps);
2830  aggstate->sort_slot = ExecInitExtraTupleSlot(estate);
2831 
2832  /*
2833  * initialize child expressions
2834  *
2835  * We expect the parser to have checked that no aggs contain other agg
2836  * calls in their arguments (and just to be sure, we verify it again while
2837  * initializing the plan node). This would make no sense under SQL
2838  * semantics, and it's forbidden by the spec. Because it is true, we
2839  * don't need to worry about evaluating the aggs in any particular order.
2840  *
2841  * Note: execExpr.c finds Aggrefs for us, and adds their AggrefExprState
2842  * nodes to aggstate->aggs. Aggrefs in the qual are found here; Aggrefs
2843  * in the targetlist are found during ExecAssignProjectionInfo, below.
2844  */
2845  aggstate->ss.ps.qual =
2846  ExecInitQual(node->plan.qual, (PlanState *) aggstate);
2847 
2848  /*
2849  * Initialize child nodes.
2850  *
2851  * If we are doing a hashed aggregation then the child plan does not need
2852  * to handle REWIND efficiently; see ExecReScanAgg.
2853  */
2854  if (node->aggstrategy == AGG_HASHED)
2855  eflags &= ~EXEC_FLAG_REWIND;
2856  outerPlan = outerPlan(node);
2857  outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
2858 
2859  /*
2860  * initialize source tuple type.
2861  */
2862  ExecAssignScanTypeFromOuterPlan(&aggstate->ss);
2863  if (node->chain)
2864  ExecSetSlotDescriptor(aggstate->sort_slot,
2866 
2867  /*
2868  * Initialize result tuple type and projection info.
2869  */
2870  ExecAssignResultTypeFromTL(&aggstate->ss.ps);
2871  ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
2872 
2873  /*
2874  * We should now have found all Aggrefs in the targetlist and quals.
2875  */
2876  numaggs = aggstate->numaggs;
2877  Assert(numaggs == list_length(aggstate->aggs));
2878 
2879  /*
2880  * For each phase, prepare grouping set data and fmgr lookup data for
2881  * compare functions. Accumulate all_grouped_cols in passing.
2882  */
2883  aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
2884 
2885  aggstate->num_hashes = numHashes;
2886  if (numHashes)
2887  {
2888  aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
2889  aggstate->phases[0].numsets = 0;
2890  aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
2891  aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
2892  }
2893 
2894  phase = 0;
2895  for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
2896  {
2897  Agg *aggnode;
2898  Sort *sortnode;
2899 
2900  if (phaseidx > 0)
2901  {
2902  aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
2903  sortnode = castNode(Sort, aggnode->plan.lefttree);
2904  }
2905  else
2906  {
2907  aggnode = node;
2908  sortnode = NULL;
2909  }
2910 
2911  Assert(phase <= 1 || sortnode);
2912 
2913  if (aggnode->aggstrategy == AGG_HASHED
2914  || aggnode->aggstrategy == AGG_MIXED)
2915  {
2916  AggStatePerPhase phasedata = &aggstate->phases[0];
2917  AggStatePerHash perhash;
2918  Bitmapset *cols = NULL;
2919 
2920  Assert(phase == 0);
2921  i = phasedata->numsets++;
2922  perhash = &aggstate->perhash[i];
2923 
2924  /* phase 0 always points to the "real" Agg in the hash case */
2925  phasedata->aggnode = node;
2926  phasedata->aggstrategy = node->aggstrategy;
2927 
2928  /* but the actual Agg node representing this hash is saved here */
2929  perhash->aggnode = aggnode;
2930 
2931  phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
2932 
2933  for (j = 0; j < aggnode->numCols; ++j)
2934  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
2935 
2936  phasedata->grouped_cols[i] = cols;
2937 
2938  all_grouped_cols = bms_add_members(all_grouped_cols, cols);
2939  continue;
2940  }
2941  else
2942  {
2943  AggStatePerPhase phasedata = &aggstate->phases[++phase];
2944  int num_sets;
2945 
2946  phasedata->numsets = num_sets = list_length(aggnode->groupingSets);
2947 
2948  if (num_sets)
2949  {
2950  phasedata->gset_lengths = palloc(num_sets * sizeof(int));
2951  phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
2952 
2953  i = 0;
2954  foreach(l, aggnode->groupingSets)
2955  {
2956  int current_length = list_length(lfirst(l));
2957  Bitmapset *cols = NULL;
2958 
2959  /* planner forces this to be correct */
2960  for (j = 0; j < current_length; ++j)
2961  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
2962 
2963  phasedata->grouped_cols[i] = cols;
2964  phasedata->gset_lengths[i] = current_length;
2965 
2966  ++i;
2967  }
2968 
2969  all_grouped_cols = bms_add_members(all_grouped_cols,
2970  phasedata->grouped_cols[0]);
2971  }
2972  else
2973  {
2974  Assert(phaseidx == 0);
2975 
2976  phasedata->gset_lengths = NULL;
2977  phasedata->grouped_cols = NULL;
2978  }
2979 
2980  /*
2981  * If we are grouping, precompute fmgr lookup data for inner loop.
2982  */
2983  if (aggnode->aggstrategy == AGG_SORTED)
2984  {
2985  Assert(aggnode->numCols > 0);
2986 
2987  phasedata->eqfunctions =
2989  aggnode->grpOperators);
2990  }
2991 
2992  phasedata->aggnode = aggnode;
2993  phasedata->aggstrategy = aggnode->aggstrategy;
2994  phasedata->sortnode = sortnode;
2995  }
2996  }
2997 
2998  /*
2999  * Convert all_grouped_cols to a descending-order list.
3000  */
3001  i = -1;
3002  while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
3003  aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
3004 
3005  /*
3006  * Set up aggregate-result storage in the output expr context, and also
3007  * allocate my private per-agg working storage
3008  */
3009  econtext = aggstate->ss.ps.ps_ExprContext;
3010  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
3011  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
3012 
3013  peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
3014  pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numaggs);
3015 
3016  aggstate->peragg = peraggs;
3017  aggstate->pertrans = pertransstates;
3018 
3019  /*
3020  * Hashing can only appear in the initial phase.
3021  */
3022  if (use_hashing)
3023  {
3024  for (i = 0; i < numHashes; ++i)
3025  {
3026  aggstate->perhash[i].hashslot = ExecInitExtraTupleSlot(estate);
3027 
3028  execTuplesHashPrepare(aggstate->perhash[i].numCols,
3029  aggstate->perhash[i].aggnode->grpOperators,
3030  &aggstate->perhash[i].eqfunctions,
3031  &aggstate->perhash[i].hashfunctions);
3032  }
3033 
3034  /* this is an array of pointers, not structures */
3035  aggstate->hash_pergroup = palloc0(sizeof(AggStatePerGroup) * numHashes);
3036 
3037  find_hash_columns(aggstate);
3038  build_hash_table(aggstate);
3039  aggstate->table_filled = false;
3040  }
3041 
3042  if (node->aggstrategy != AGG_HASHED)
3043  {
3044  AggStatePerGroup pergroup;
3045 
3046  pergroup = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
3047  * numaggs
3048  * numGroupingSets);
3049 
3050  aggstate->pergroup = pergroup;
3051  }
3052 
3053  /*
3054  * Initialize current phase-dependent values to initial phase. The initial
3055  * phase is 1 (first sort pass) for all strategies that use sorting (if
3056  * hashing is being done too, then phase 0 is processed last); but if only
3057  * hashing is being done, then phase 0 is all there is.
3058  */
3059  if (node->aggstrategy == AGG_HASHED)
3060  {
3061  aggstate->current_phase = 0;
3062  initialize_phase(aggstate, 0);
3063  select_current_set(aggstate, 0, true);
3064  }
3065  else
3066  {
3067  aggstate->current_phase = 1;
3068  initialize_phase(aggstate, 1);
3069  select_current_set(aggstate, 0, false);
3070  }
3071 
3072  /* -----------------
3073  * Perform lookups of aggregate function info, and initialize the
3074  * unchanging fields of the per-agg and per-trans data.
3075  *
3076  * We try to optimize by detecting duplicate aggregate functions so that
3077  * their state and final values are re-used, rather than needlessly being
3078  * re-calculated independently. We also detect aggregates that are not
3079  * the same, but which can share the same transition state.
3080  *
3081  * Scenarios:
3082  *
3083  * 1. Identical aggregate function calls appear in the query:
3084  *
3085  * SELECT SUM(x) FROM ... HAVING SUM(x) > 0
3086  *
3087  * Since these aggregates are identical, we only need to calculate
3088  * the value once. Both aggregates will share the same 'aggno' value.
3089  *
3090  * 2. Two different aggregate functions appear in the query, but the
3091  * aggregates have the same arguments, transition functions and
3092  * initial values (and, presumably, different final functions):
3093  *
3094  * SELECT AVG(x), STDDEV(x) FROM ...
3095  *
3096  * In this case we must create a new peragg for the varying aggregate,
3097  * and we need to call the final functions separately, but we need
3098  * only run the transition function once. (This requires that the
3099  * final functions be nondestructive of the transition state, but
3100  * that's required anyway for other reasons.)
3101  *
3102  * For either of these optimizations to be valid, all aggregate properties
3103  * used in the transition phase must be the same, including any modifiers
3104  * such as ORDER BY, DISTINCT and FILTER, and the arguments mustn't
3105  * contain any volatile functions.
3106  * -----------------
3107  */
3108  aggno = -1;
3109  transno = -1;
3110  foreach(l, aggstate->aggs)
3111  {
3112  AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l);
3113  Aggref *aggref = aggrefstate->aggref;
3114  AggStatePerAgg peragg;
3115  AggStatePerTrans pertrans;
3116  int existing_aggno;
3117  int existing_transno;
3118  List *same_input_transnos;
3119  Oid inputTypes[FUNC_MAX_ARGS];
3120  int numArguments;
3121  int numDirectArgs;
3122  HeapTuple aggTuple;
3123  Form_pg_aggregate aggform;
3124  AclResult aclresult;
3125  Oid transfn_oid,
3126  finalfn_oid;
3127  bool sharable;
3128  Oid serialfn_oid,
3129  deserialfn_oid;
3130  Expr *finalfnexpr;
3131  Oid aggtranstype;
3132  Datum textInitVal;
3133  Datum initValue;
3134  bool initValueIsNull;
3135 
3136  /* Planner should have assigned aggregate to correct level */
3137  Assert(aggref->agglevelsup == 0);
3138  /* ... and the split mode should match */
3139  Assert(aggref->aggsplit == aggstate->aggsplit);
3140 
3141  /* 1. Check for already processed aggs which can be re-used */
3142  existing_aggno = find_compatible_peragg(aggref, aggstate, aggno,
3143  &same_input_transnos);
3144  if (existing_aggno != -1)
3145  {
3146  /*
3147  * Existing compatible agg found. so just point the Aggref to the
3148  * same per-agg struct.
3149  */
3150  aggrefstate->aggno = existing_aggno;
3151  continue;
3152  }
3153 
3154  /* Mark Aggref state node with assigned index in the result array */
3155  peragg = &peraggs[++aggno];
3156  peragg->aggref = aggref;
3157  aggrefstate->aggno = aggno;
3158 
3159  /* Fetch the pg_aggregate row */
3160  aggTuple = SearchSysCache1(AGGFNOID,
3161  ObjectIdGetDatum(aggref->aggfnoid));
3162  if (!HeapTupleIsValid(aggTuple))
3163  elog(ERROR, "cache lookup failed for aggregate %u",
3164  aggref->aggfnoid);
3165  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
3166 
3167  /* Check permission to call aggregate function */
3168  aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
3169  ACL_EXECUTE);
3170  if (aclresult != ACLCHECK_OK)
3171  aclcheck_error(aclresult, ACL_KIND_PROC,
3172  get_func_name(aggref->aggfnoid));
3174 
3175  /* planner recorded transition state type in the Aggref itself */
3176  aggtranstype = aggref->aggtranstype;
3177  Assert(OidIsValid(aggtranstype));
3178 
3179  /*
3180  * If this aggregation is performing state combines, then instead of
3181  * using the transition function, we'll use the combine function
3182  */
3183  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3184  {
3185  transfn_oid = aggform->aggcombinefn;
3186 
3187  /* If not set then the planner messed up */
3188  if (!OidIsValid(transfn_oid))
3189  elog(ERROR, "combinefn not set for aggregate function");
3190  }
3191  else
3192  transfn_oid = aggform->aggtransfn;
3193 
3194  /* Final function only required if we're finalizing the aggregates */
3195  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
3196  peragg->finalfn_oid = finalfn_oid = InvalidOid;
3197  else
3198  peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
3199 
3200  /*
3201  * If finalfn is marked read-write, we can't share transition states;
3202  * but it is okay to share states for AGGMODIFY_SHARABLE aggs. Also,
3203  * if we're not executing the finalfn here, we can share regardless.
3204  */
3205  sharable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE) ||
3206  (finalfn_oid == InvalidOid);
3207  peragg->sharable = sharable;
3208 
3209  serialfn_oid = InvalidOid;
3210  deserialfn_oid = InvalidOid;
3211 
3212  /*
3213  * Check if serialization/deserialization is required. We only do it
3214  * for aggregates that have transtype INTERNAL.
3215  */
3216  if (aggtranstype == INTERNALOID)
3217  {
3218  /*
3219  * The planner should only have generated a serialize agg node if
3220  * every aggregate with an INTERNAL state has a serialization
3221  * function. Verify that.
3222  */
3223  if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
3224  {
3225  /* serialization only valid when not running finalfn */
3227 
3228  if (!OidIsValid(aggform->aggserialfn))
3229  elog(ERROR, "serialfunc not provided for serialization aggregation");
3230  serialfn_oid = aggform->aggserialfn;
3231  }
3232 
3233  /* Likewise for deserialization functions */
3234  if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
3235  {
3236  /* deserialization only valid when combining states */
3237  Assert(DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
3238 
3239  if (!OidIsValid(aggform->aggdeserialfn))
3240  elog(ERROR, "deserialfunc not provided for deserialization aggregation");
3241  deserialfn_oid = aggform->aggdeserialfn;
3242  }
3243  }
3244 
3245  /* Check that aggregate owner has permission to call component fns */
3246  {
3247  HeapTuple procTuple;
3248  Oid aggOwner;
3249 
3250  procTuple = SearchSysCache1(PROCOID,
3251  ObjectIdGetDatum(aggref->aggfnoid));
3252  if (!HeapTupleIsValid(procTuple))
3253  elog(ERROR, "cache lookup failed for function %u",
3254  aggref->aggfnoid);
3255  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
3256  ReleaseSysCache(procTuple);
3257 
3258  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
3259  ACL_EXECUTE);
3260  if (aclresult != ACLCHECK_OK)
3261  aclcheck_error(aclresult, ACL_KIND_PROC,
3262  get_func_name(transfn_oid));
3263  InvokeFunctionExecuteHook(transfn_oid);
3264  if (OidIsValid(finalfn_oid))
3265  {
3266  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
3267  ACL_EXECUTE);
3268  if (aclresult != ACLCHECK_OK)
3269  aclcheck_error(aclresult, ACL_KIND_PROC,
3270  get_func_name(finalfn_oid));
3271  InvokeFunctionExecuteHook(finalfn_oid);
3272  }
3273  if (OidIsValid(serialfn_oid))
3274  {
3275  aclresult = pg_proc_aclcheck(serialfn_oid, aggOwner,
3276  ACL_EXECUTE);
3277  if (aclresult != ACLCHECK_OK)
3278  aclcheck_error(aclresult, ACL_KIND_PROC,
3279  get_func_name(serialfn_oid));
3280  InvokeFunctionExecuteHook(serialfn_oid);
3281  }
3282  if (OidIsValid(deserialfn_oid))
3283  {
3284  aclresult = pg_proc_aclcheck(deserialfn_oid, aggOwner,
3285  ACL_EXECUTE);
3286  if (aclresult != ACLCHECK_OK)
3287  aclcheck_error(aclresult, ACL_KIND_PROC,
3288  get_func_name(deserialfn_oid));
3289  InvokeFunctionExecuteHook(deserialfn_oid);
3290  }
3291  }
3292 
3293  /*
3294  * Get actual datatypes of the (nominal) aggregate inputs. These
3295  * could be different from the agg's declared input types, when the
3296  * agg accepts ANY or a polymorphic type.
3297  */
3298  numArguments = get_aggregate_argtypes(aggref, inputTypes);
3299 
3300  /* Count the "direct" arguments, if any */
3301  numDirectArgs = list_length(aggref->aggdirectargs);
3302 
3303  /* Detect how many arguments to pass to the finalfn */
3304  if (aggform->aggfinalextra)
3305  peragg->numFinalArgs = numArguments + 1;
3306  else
3307  peragg->numFinalArgs = numDirectArgs + 1;
3308 
3309  /* Initialize any direct-argument expressions */
3310  peragg->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
3311  (PlanState *) aggstate);
3312 
3313  /*
3314  * build expression trees using actual argument & result types for the
3315  * finalfn, if it exists and is required.
3316  */
3317  if (OidIsValid(finalfn_oid))
3318  {
3319  build_aggregate_finalfn_expr(inputTypes,
3320  peragg->numFinalArgs,
3321  aggtranstype,
3322  aggref->aggtype,
3323  aggref->inputcollid,
3324  finalfn_oid,
3325  &finalfnexpr);
3326  fmgr_info(finalfn_oid, &peragg->finalfn);
3327  fmgr_info_set_expr((Node *) finalfnexpr, &peragg->finalfn);
3328  }
3329 
3330  /* get info about the output value's datatype */
3331  get_typlenbyval(aggref->aggtype,
3332  &peragg->resulttypeLen,
3333  &peragg->resulttypeByVal);
3334 
3335  /*
3336  * initval is potentially null, so don't try to access it as a struct
3337  * field. Must do it the hard way with SysCacheGetAttr.
3338  */
3339  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
3341  &initValueIsNull);
3342  if (initValueIsNull)
3343  initValue = (Datum) 0;
3344  else
3345  initValue = GetAggInitVal(textInitVal, aggtranstype);
3346 
3347  /*
3348  * 2. Build working state for invoking the transition function, or
3349  * look up previously initialized working state, if we can share it.
3350  *
3351  * find_compatible_peragg() already collected a list of sharable
3352  * per-Trans's with the same inputs. Check if any of them have the
3353  * same transition function and initial value.
3354  */
3355  existing_transno = find_compatible_pertrans(aggstate, aggref,
3356  sharable,
3357  transfn_oid, aggtranstype,
3358  serialfn_oid, deserialfn_oid,
3359  initValue, initValueIsNull,
3360  same_input_transnos);
3361  if (existing_transno != -1)
3362  {
3363  /*
3364  * Existing compatible trans found, so just point the 'peragg' to
3365  * the same per-trans struct, and mark the trans state as shared.
3366  */
3367  pertrans = &pertransstates[existing_transno];
3368  pertrans->aggshared = true;
3369  peragg->transno = existing_transno;
3370  }
3371  else
3372  {
3373  pertrans = &pertransstates[++transno];
3374  build_pertrans_for_aggref(pertrans, aggstate, estate,
3375  aggref, transfn_oid, aggtranstype,
3376  serialfn_oid, deserialfn_oid,
3377  initValue, initValueIsNull,
3378  inputTypes, numArguments);
3379  peragg->transno = transno;
3380  }
3381  ReleaseSysCache(aggTuple);
3382  }
3383 
3384  /*
3385  * Update aggstate->numaggs to be the number of unique aggregates found.
3386  * Also set numstates to the number of unique transition states found.
3387  */
3388  aggstate->numaggs = aggno + 1;
3389  aggstate->numtrans = transno + 1;
3390 
3391  /*
3392  * Build a single projection computing the required arguments for all
3393  * aggregates at once; if there's more than one, that's considerably
3394  * faster than doing it separately for each.
3395  *
3396  * First create a targetlist representing the values to compute.
3397  */
3398  combined_inputeval = NIL;
3399  column_offset = 0;
3400  for (transno = 0; transno < aggstate->numtrans; transno++)
3401  {
3402  AggStatePerTrans pertrans = &pertransstates[transno];
3403 
3404  /*
3405  * Mark this per-trans state with its starting column in the combined
3406  * slot.
3407  */
3408  pertrans->inputoff = column_offset;
3409 
3410  /*
3411  * If the aggregate has a FILTER, we can only evaluate the filter
3412  * expression, not the actual input expressions, during the combined
3413  * eval step --- unless we're ignoring the filter because this node is
3414  * running combinefns not transfns.
3415  */
3416  if (pertrans->aggref->aggfilter &&
3417  !DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3418  {
3419  TargetEntry *tle;
3420 
3421  tle = makeTargetEntry(pertrans->aggref->aggfilter,
3422  column_offset + 1, NULL, false);
3423  combined_inputeval = lappend(combined_inputeval, tle);
3424  column_offset++;
3425 
3426  /*
3427  * We'll need separate projection machinery for the real args.
3428  * Arrange to evaluate them into the sortslot previously created.
3429  */
3430  Assert(pertrans->sortslot);
3431  pertrans->evalproj = ExecBuildProjectionInfo(pertrans->aggref->args,
3432  aggstate->tmpcontext,
3433  pertrans->sortslot,
3434  &aggstate->ss.ps,
3435  NULL);
3436  }
3437  else
3438  {
3439  /*
3440  * Add agg's input expressions to combined_inputeval, adjusting
3441  * resnos in the copied target entries to match the combined slot.
3442  */
3443  ListCell *arg;
3444 
3445  foreach(arg, pertrans->aggref->args)
3446  {
3447  TargetEntry *source_tle = lfirst_node(TargetEntry, arg);
3448  TargetEntry *tle;
3449 
3450  tle = flatCopyTargetEntry(source_tle);
3451  tle->resno += column_offset;
3452 
3453  combined_inputeval = lappend(combined_inputeval, tle);
3454  }
3455 
3456  column_offset += list_length(pertrans->aggref->args);
3457  }
3458  }
3459 
3460  /* Now create a projection for the combined targetlist */
3461  combineddesc = ExecTypeFromTL(combined_inputeval, false);
3462  combinedslot = ExecInitExtraTupleSlot(estate);
3463  ExecSetSlotDescriptor(combinedslot, combineddesc);
3464  aggstate->combinedproj = ExecBuildProjectionInfo(combined_inputeval,
3465  aggstate->tmpcontext,
3466  combinedslot,
3467  &aggstate->ss.ps,
3468  NULL);
3469 
3470  /*
3471  * Last, check whether any more aggregates got added onto the node while
3472  * we processed the expressions for the aggregate arguments (including not
3473  * only the regular arguments and FILTER expressions handled immediately
3474  * above, but any direct arguments we might've handled earlier). If so,
3475  * we have nested aggregate functions, which is semantically nonsensical,
3476  * so complain. (This should have been caught by the parser, so we don't
3477  * need to work hard on a helpful error message; but we defend against it
3478  * here anyway, just to be sure.)
3479  */
3480  if (numaggs != list_length(aggstate->aggs))
3481  ereport(ERROR,
3482  (errcode(ERRCODE_GROUPING_ERROR),
3483  errmsg("aggregate function calls cannot be nested")));
3484 
3485  return aggstate;
3486 }
FmgrInfo * eqfunctions
Definition: nodeAgg.c:521
struct AggStatePerTransData * AggStatePerTrans
Definition: execnodes.h:1799
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:1842
#define NIL
Definition: pg_list.h:69
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:1800
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:597
int numCols
Definition: plannodes.h:785
List * qual
Definition: plannodes.h:145
AggStatePerPhase phases
Definition: execnodes.h:1831
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate)
Definition: execTuples.c:852
Datum * ecxt_aggvalues
Definition: execnodes.h:213
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
Definition: execTuples.c:842
#define AGGMODIFY_READ_WRITE
Definition: pg_aggregate.h:145
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
AttrNumber * grpColIdx
Definition: plannodes.h:786
#define Anum_pg_aggregate_agginitval
Definition: pg_aggregate.h:117
List * lcons_int(int datum, List *list)
Definition: list.c:277
int numaggs
Definition: execnodes.h:1808
Oid GetUserId(void)
Definition: miscinit.c:284
bool agg_done
Definition: execnodes.h:1824
#define castNode(_type_, nodeptr)
Definition: nodes.h:580
TupleTableSlot * sort_slot
Definition: execnodes.h:1834
List * all_grouped_cols
Definition: execnodes.h:1828
Tuplesortstate * sort_out
Definition: execnodes.h:1833
ScanState ss
Definition: execnodes.h:1806
ExprContext * ps_ExprContext
Definition: execnodes.h:883
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:937
FmgrInfo * eqfunctions
Definition: nodeAgg.c:503
Oid inputcollid
Definition: primnodes.h:297
int current_phase
Definition: execnodes.h:1814
Definition: nodes.h:511
AggSplit aggsplit
Definition: execnodes.h:1811
static TupleTableSlot * ExecAgg(PlanState *pstate)
Definition: nodeAgg.c:2134
int errcode(int sqlerrcode)
Definition: elog.c:575
List * args
Definition: primnodes.h:301
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1106
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:2019
AggStatePerTrans pertrans
Definition: execnodes.h:1816
EState * state
Definition: execnodes.h:851
int projected_set
Definition: execnodes.h:1825
unsigned int Oid
Definition: postgres_ext.h:31
HeapTuple grp_firstTuple
Definition: execnodes.h:1837
Aggref * aggref
Definition: nodeAgg.c:415
int current_set
Definition: execnodes.h:1826
#define OidIsValid(objectId)
Definition: c.h:576
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:770
int numtrans
Definition: execnodes.h:1809
void execTuplesHashPrepare(int numCols, Oid *eqOperators, FmgrInfo **eqFunctions, FmgrInfo **hashFunctions)
Definition: execGrouping.c:233
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:160
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:447
ExprContext * tmpcontext
Definition: execnodes.h:1819
#define FUNC_MAX_ARGS
Bitmapset ** grouped_cols
Definition: nodeAgg.c:502
PlanState ps
Definition: execnodes.h:1103
int maxsets
Definition: execnodes.h:1830
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:772
AggStrategy aggstrategy
Definition: plannodes.h:783
bool table_filled
Definition: execnodes.h:1839
AggStrategy aggstrategy
Definition: execnodes.h:1810
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1412
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:122
static void find_hash_columns(AggState *aggstate)
Definition: nodeAgg.c:1937
Tuplesortstate * sort_in
Definition: execnodes.h:1832
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define outerPlanState(node)
Definition: execnodes.h:895
Aggref * aggref
Definition: execnodes.h:659
#define list_nth_node(type, list, n)
Definition: pg_list.h:227
static int initValue(long lng_val)
Definition: informix.c:702
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:494
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
static void build_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1888
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:104
AttrNumber resno
Definition: primnodes.h:1376
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:266
Index agglevelsup
Definition: primnodes.h:309
List * aggdirectargs
Definition: primnodes.h:300
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: nodeAgg.c:3778
AggStatePerAgg curperagg
Definition: execnodes.h:1821
AggStatePerHash perhash
Definition: execnodes.h:1841
TargetEntry * flatCopyTargetEntry(TargetEntry *src_tle)
Definition: makefuncs.c:270
AggStrategy aggstrategy
Definition: nodeAgg.c:499
#define EXEC_FLAG_REWIND
Definition: executor.h:59
#define ereport(elevel, rest)
Definition: elog.h:122
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:237
TupleDesc ExecTypeFromTL(List *targetList, bool hasoid)
Definition: execTuples.c:888
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:179
#define outerPlan(node)
Definition: plannodes.h:174
List * lappend(List *list, void *datum)
Definition: list.c:128
int num_hashes
Definition: execnodes.h:1840
Plan plan
Definition: plannodes.h:782
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
bool input_done
Definition: execnodes.h:1823
ProjectionInfo * combinedproj
Definition: execnodes.h:1844
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
ExprContext * hashcontext
Definition: execnodes.h:1817
bool * ecxt_aggnulls
Definition: execnodes.h:214
static int find_compatible_peragg(Aggref *newagg, AggState *aggstate, int lastaggno, List **same_input_transnos)
Definition: nodeAgg.c:3806
void * palloc0(Size size)
Definition: mcxt.c:877
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:855
AclResult
Definition: acl.h:178
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
AggStatePerGroup pergroup
Definition: execnodes.h:1836
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
List * groupingSets
Definition: plannodes.h:791
int16 resulttypeLen
Definition: nodeAgg.c:444
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:615
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
Plan * plan
Definition: execnodes.h:849
#define InvalidOid
Definition: postgres_ext.h:36
Oid aggfnoid
Definition: primnodes.h:294
#define INTERNALOID
Definition: pg_type.h:698
#define Max(x, y)
Definition: c.h:796
ExprContext ** aggcontexts
Definition: execnodes.h:1818
#define makeNode(_type_)
Definition: nodes.h:559
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
FmgrInfo * hashfunctions
Definition: nodeAgg.c:520
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
#define EXEC_FLAG_MARK
Definition: executor.h:61
AggSplit aggsplit
Definition: plannodes.h:784
struct AggStatePerAggData * AggStatePerAgg
Definition: execnodes.h:1798
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:89
AggSplit aggsplit
Definition: primnodes.h:310
ProjectionInfo * evalproj
Definition: nodeAgg.c:357
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:425
static int list_length(const List *l)
Definition: pg_list.h:89
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:771
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2001
Expr * aggfilter
Definition: primnodes.h:304
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:773
struct Plan * lefttree
Definition: plannodes.h:146
int numphases
Definition: execnodes.h:1813
ExprState * qual
Definition: execnodes.h:867
void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
Definition: execUtils.c:559
Oid * grpOperators
Definition: plannodes.h:787
void * palloc(Size size)
Definition: mcxt.c:848
ProjectionInfo * ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
Definition: execExpr.c:301
int errmsg(const char *fmt,...)
Definition: elog.c:797
List * chain
Definition: plannodes.h:792
AggStatePerAgg peragg
Definition: execnodes.h:1815
#define ACL_EXECUTE
Definition: parsenodes.h:79
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4446
int i
List * aggdirectargs
Definition: nodeAgg.c:438
Oid aggtranstype
Definition: primnodes.h:298
static int find_compatible_pertrans(AggState *aggstate, Aggref *newagg, bool sharable, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, List *transnos)
Definition: nodeAgg.c:3884
void * arg
AggStatePerTrans curpertrans
Definition: execnodes.h:1822
Oid aggtype
Definition: primnodes.h:295
bool resulttypeByVal
Definition: nodeAgg.c:445
Definition: plannodes.h:780
#define elog
Definition: elog.h:219
List * aggs
Definition: execnodes.h:1807
TupleTableSlot * sortslot
Definition: nodeAgg.c:364
FmgrInfo * execTuplesMatchPrepare(int numCols, Oid *eqOperators)
Definition: execGrouping.c:204
TupleTableSlot * hashslot
Definition: nodeAgg.c:519
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1801
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:3497
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
Definition: pg_list.h:45
FmgrInfo finalfn
Definition: nodeAgg.c:427
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:755

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 3981 of file nodeAgg.c.

References AggState::agg_done, AGG_HASHED, AGG_MIXED, AggState::aggcontexts, Agg::aggParams, AggState::aggstrategy, bms_overlap(), build_hash_table(), PlanState::chgParam, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecClearTuple(), ExecReScan(), AggState::grp_firstTuple, AggState::hashcontext, AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, heap_freetuple(), initialize_phase(), AggState::input_done, Max, AggState::maxsets, MemSet, AggState::numaggs, AggState::numtrans, outerPlan, outerPlanState, AggState::pergroup, 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().

3982 {
3983  ExprContext *econtext = node->ss.ps.ps_ExprContext;
3985  Agg *aggnode = (Agg *) node->ss.ps.plan;
3986  int transno;
3987  int numGroupingSets = Max(node->maxsets, 1);
3988  int setno;
3989 
3990  node->agg_done = false;
3991 
3992  if (node->aggstrategy == AGG_HASHED)
3993  {
3994  /*
3995  * In the hashed case, if we haven't yet built the hash table then we
3996  * can just return; nothing done yet, so nothing to undo. If subnode's
3997  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
3998  * else no reason to re-scan it at all.
3999  */
4000  if (!node->table_filled)
4001  return;
4002 
4003  /*
4004  * If we do have the hash table, and the subplan does not have any
4005  * parameter changes, and none of our own parameter changes affect
4006  * input expressions of the aggregated functions, then we can just
4007  * rescan the existing hash table; no need to build it again.
4008  */
4009  if (outerPlan->chgParam == NULL &&
4010  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
4011  {
4013  &node->perhash[0].hashiter);
4014  select_current_set(node, 0, true);
4015  return;
4016  }
4017  }
4018 
4019  /* Make sure we have closed any open tuplesorts */
4020  for (transno = 0; transno < node->numtrans; transno++)
4021  {
4022  for (setno = 0; setno < numGroupingSets; setno++)
4023  {
4024  AggStatePerTrans pertrans = &node->pertrans[transno];
4025 
4026  if (pertrans->sortstates[setno])
4027  {
4028  tuplesort_end(pertrans->sortstates[setno]);
4029  pertrans->sortstates[setno] = NULL;
4030  }
4031  }
4032  }
4033 
4034  /*
4035  * We don't need to ReScanExprContext the output tuple context here;
4036  * ExecReScan already did it. But we do need to reset our per-grouping-set
4037  * contexts, which may have transvalues stored in them. (We use rescan
4038  * rather than just reset because transfns may have registered callbacks
4039  * that need to be run now.) For the AGG_HASHED case, see below.
4040  */
4041 
4042  for (setno = 0; setno < numGroupingSets; setno++)
4043  {
4044  ReScanExprContext(node->aggcontexts[setno]);
4045  }
4046 
4047  /* Release first tuple of group, if we have made a copy */
4048  if (node->grp_firstTuple != NULL)
4049  {
4051  node->grp_firstTuple = NULL;
4052  }
4054 
4055  /* Forget current agg values */
4056  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
4057  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
4058 
4059  /*
4060  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
4061  * the hashcontext. This used to be an issue, but now, resetting a context
4062  * automatically deletes sub-contexts too.
4063  */
4064  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
4065  {
4067  /* Rebuild an empty hash table */
4068  build_hash_table(node);
4069  node->table_filled = false;
4070  /* iterator will be reset when the table is filled */
4071  }
4072 
4073  if (node->aggstrategy != AGG_HASHED)
4074  {
4075  /*
4076  * Reset the per-group state (in particular, mark transvalues null)
4077  */
4078  MemSet(node->pergroup, 0,
4079  sizeof(AggStatePerGroupData) * node->numaggs * numGroupingSets);
4080 
4081  /* reset to phase 1 */
4082  initialize_phase(node, 1);
4083 
4084  node->input_done = false;
4085  node->projected_set = -1;
4086  }
4087 
4088  if (outerPlan->chgParam == NULL)
4089  ExecReScan(outerPlan);
4090 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:597
Datum * ecxt_aggvalues
Definition: execnodes.h:213
int numaggs
Definition: execnodes.h:1808
bool agg_done
Definition: execnodes.h:1824
ScanState ss
Definition: execnodes.h:1806
ExprContext * ps_ExprContext
Definition: execnodes.h:883
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define MemSet(start, val, len)
Definition: c.h:853
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1106
AggStatePerTrans pertrans
Definition: execnodes.h:1816
int projected_set
Definition: execnodes.h:1825
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
HeapTuple grp_firstTuple
Definition: execnodes.h:1837
int numtrans
Definition: execnodes.h:1809
PlanState ps
Definition: execnodes.h:1103
int maxsets
Definition: execnodes.h:1830
bool table_filled
Definition: execnodes.h:1839
AggStrategy aggstrategy
Definition: execnodes.h:1810
#define outerPlanState(node)
Definition: execnodes.h:895
Tuplesortstate ** sortstates
Definition: nodeAgg.c:382
Bitmapset * aggParams
Definition: plannodes.h:789
static void build_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1888
AggStatePerHash perhash
Definition: execnodes.h:1841
Bitmapset * chgParam
Definition: execnodes.h:877
#define outerPlan(node)
Definition: plannodes.h:174
TupleHashIterator hashiter
Definition: nodeAgg.c:518
bool input_done
Definition: execnodes.h:1823
ExprContext * hashcontext
Definition: execnodes.h:1817
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
AggStatePerGroup pergroup
Definition: execnodes.h:1836
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:615
Plan * plan
Definition: execnodes.h:849
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:634
#define Max(x, y)
Definition: c.h:796
ExprContext ** aggcontexts
Definition: execnodes.h:1818
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:383
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
Definition: plannodes.h:780
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1104
TupleHashTable hashtable
Definition: nodeAgg.c:517

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

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

686 {
687  TupleTableSlot *slot;
688 
689  if (aggstate->sort_in)
690  {
691  /* make sure we check for interrupts in either path through here */
693  if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
694  aggstate->sort_slot, NULL))
695  return NULL;
696  slot = aggstate->sort_slot;
697  }
698  else
699  slot = ExecProcNode(outerPlanState(aggstate));
700 
701  if (!TupIsNull(slot) && aggstate->sort_out)
702  tuplesort_puttupleslot(aggstate->sort_out, slot);
703 
704  return slot;
705 }
TupleTableSlot * sort_slot
Definition: execnodes.h:1834
Tuplesortstate * sort_out
Definition: execnodes.h:1833
Tuplesortstate * sort_in
Definition: execnodes.h:1832
#define outerPlanState(node)
Definition: execnodes.h:895
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:1996
#define TupIsNull(slot)
Definition: tuptable.h:138
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:236
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1301

◆ finalize_aggregate()

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

Definition at line 1519 of file nodeAgg.c.

References AggStatePerTransData::aggCollation, AggStatePerAggData::aggdirectargs, FunctionCallInfoData::arg, FunctionCallInfoData::argnull, AggState::curperagg, CurrentMemoryContext, datumCopy(), DatumGetPointer, ExprContext::ecxt_per_tuple_memory, ExecEvalExpr(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, FunctionCallInfoData::flinfo, FmgrInfo::fn_strict, FunctionCallInvoke, i, InitFunctionCallInfoData, FunctionCallInfoData::isnull, lfirst, 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().

1523 {
1524  FunctionCallInfoData fcinfo;
1525  bool anynull = false;
1526  MemoryContext oldContext;
1527  int i;
1528  ListCell *lc;
1529  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1530 
1532 
1533  /*
1534  * Evaluate any direct arguments. We do this even if there's no finalfn
1535  * (which is unlikely anyway), so that side-effects happen as expected.
1536  * The direct arguments go into arg positions 1 and up, leaving position 0
1537  * for the transition state value.
1538  */
1539  i = 1;
1540  foreach(lc, peragg->aggdirectargs)
1541  {
1542  ExprState *expr = (ExprState *) lfirst(lc);
1543 
1544  fcinfo.arg[i] = ExecEvalExpr(expr,
1545  aggstate->ss.ps.ps_ExprContext,
1546  &fcinfo.argnull[i]);
1547  anynull |= fcinfo.argnull[i];
1548  i++;
1549  }
1550 
1551  /*
1552  * Apply the agg's finalfn if one is provided, else return transValue.
1553  */
1554  if (OidIsValid(peragg->finalfn_oid))
1555  {
1556  int numFinalArgs = peragg->numFinalArgs;
1557 
1558  /* set up aggstate->curperagg for AggGetAggref() */
1559  aggstate->curperagg = peragg;
1560 
1561  InitFunctionCallInfoData(fcinfo, &peragg->finalfn,
1562  numFinalArgs,
1563  pertrans->aggCollation,
1564  (void *) aggstate, NULL);
1565 
1566  /* Fill in the transition state value */
1567  fcinfo.arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
1568  pergroupstate->transValueIsNull,
1569  pertrans->transtypeLen);
1570  fcinfo.argnull[0] = pergroupstate->transValueIsNull;
1571  anynull |= pergroupstate->transValueIsNull;
1572 
1573  /* Fill any remaining argument positions with nulls */
1574  for (; i < numFinalArgs; i++)
1575  {
1576  fcinfo.arg[i] = (Datum) 0;
1577  fcinfo.argnull[i] = true;
1578  anynull = true;
1579  }
1580 
1581  if (fcinfo.flinfo->fn_strict && anynull)
1582  {
1583  /* don't call a strict function with NULL inputs */
1584  *resultVal = (Datum) 0;
1585  *resultIsNull = true;
1586  }
1587  else
1588  {
1589  *resultVal = FunctionCallInvoke(&fcinfo);
1590  *resultIsNull = fcinfo.isnull;
1591  }
1592  aggstate->curperagg = NULL;
1593  }
1594  else
1595  {
1596  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1597  *resultVal = pergroupstate->transValue;
1598  *resultIsNull = pergroupstate->transValueIsNull;
1599  }
1600 
1601  /*
1602  * If result is pass-by-ref, make sure it is in the right context.
1603  */
1604  if (!peragg->resulttypeByVal && !*resultIsNull &&
1606  DatumGetPointer(*resultVal)))
1607  *resultVal = datumCopy(*resultVal,
1608  peragg->resulttypeByVal,
1609  peragg->resulttypeLen);
1610 
1611  MemoryContextSwitchTo(oldContext);
1612 }
ScanState ss
Definition: execnodes.h:1806
ExprContext * ps_ExprContext
Definition: execnodes.h:883
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:1816
#define OidIsValid(objectId)
Definition: c.h:576
PlanState ps
Definition: execnodes.h:1103
FmgrInfo * flinfo
Definition: fmgr.h:79
bool fn_strict
Definition: fmgr.h:61
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:137
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:276
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
AggStatePerAgg curperagg
Definition: execnodes.h:1821
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
uintptr_t Datum
Definition: postgres.h:372
int16 resulttypeLen
Definition: nodeAgg.c:444
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define lfirst(lc)
Definition: pg_list.h:106
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:566
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:120
#define DatumGetPointer(X)
Definition: postgres.h:555
int i
List * aggdirectargs
Definition: nodeAgg.c:438
bool resulttypeByVal
Definition: nodeAgg.c:445
FmgrInfo finalfn
Definition: nodeAgg.c:427

◆ finalize_aggregates()

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

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

1747 {
1748  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1749  Datum *aggvalues = econtext->ecxt_aggvalues;
1750  bool *aggnulls = econtext->ecxt_aggnulls;
1751  int aggno;
1752  int transno;
1753 
1754  /*
1755  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1756  * inputs and run the transition functions.
1757  */
1758  for (transno = 0; transno < aggstate->numtrans; transno++)
1759  {
1760  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1761  AggStatePerGroup pergroupstate;
1762 
1763  pergroupstate = &pergroup[transno];
1764 
1765  if (pertrans->numSortCols > 0)
1766  {
1767  Assert(aggstate->aggstrategy != AGG_HASHED &&
1768  aggstate->aggstrategy != AGG_MIXED);
1769 
1770  if (pertrans->numInputs == 1)
1772  pertrans,
1773  pergroupstate);
1774  else
1776  pertrans,
1777  pergroupstate);
1778  }
1779  }
1780 
1781  /*
1782  * Run the final functions.
1783  */
1784  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1785  {
1786  AggStatePerAgg peragg = &peraggs[aggno];
1787  int transno = peragg->transno;
1788  AggStatePerGroup pergroupstate;
1789 
1790  pergroupstate = &pergroup[transno];
1791 
1792  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1793  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1794  &aggvalues[aggno], &aggnulls[aggno]);
1795  else
1796  finalize_aggregate(aggstate, peragg, pergroupstate,
1797  &aggvalues[aggno], &aggnulls[aggno]);
1798  }
1799 }
Datum * ecxt_aggvalues
Definition: execnodes.h:213
int numaggs
Definition: execnodes.h:1808
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1621
ScanState ss
Definition: execnodes.h:1806
ExprContext * ps_ExprContext
Definition: execnodes.h:883
AggSplit aggsplit
Definition: execnodes.h:1811
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1519
AggStatePerTrans pertrans
Definition: execnodes.h:1816
int numtrans
Definition: execnodes.h:1809
PlanState ps
Definition: execnodes.h:1103
AggStrategy aggstrategy
Definition: execnodes.h:1810
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:1426
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
#define Assert(condition)
Definition: c.h:670
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:771
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:1333

◆ finalize_partialaggregate()

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

Definition at line 1621 of file nodeAgg.c.

References FunctionCallInfoData::arg, FunctionCallInfoData::argnull, CurrentMemoryContext, datumCopy(), DatumGetPointer, ExprContext::ecxt_per_tuple_memory, FmgrInfo::fn_strict, FunctionCallInvoke, FunctionCallInfoData::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, and AggStatePerGroupData::transValueIsNull.

Referenced by finalize_aggregates().

1625 {
1626  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1627  MemoryContext oldContext;
1628 
1630 
1631  /*
1632  * serialfn_oid will be set if we must serialize the transvalue before
1633  * returning it
1634  */
1635  if (OidIsValid(pertrans->serialfn_oid))
1636  {
1637  /* Don't call a strict serialization function with NULL input. */
1638  if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
1639  {
1640  *resultVal = (Datum) 0;
1641  *resultIsNull = true;
1642  }
1643  else
1644  {
1645  FunctionCallInfo fcinfo = &pertrans->serialfn_fcinfo;
1646 
1647  fcinfo->arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
1648  pergroupstate->transValueIsNull,
1649  pertrans->transtypeLen);
1650  fcinfo->argnull[0] = pergroupstate->transValueIsNull;
1651 
1652  *resultVal = FunctionCallInvoke(fcinfo);
1653  *resultIsNull = fcinfo->isnull;
1654  }
1655  }
1656  else
1657  {
1658  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1659  *resultVal = pergroupstate->transValue;
1660  *resultIsNull = pergroupstate->transValueIsNull;
1661  }
1662 
1663  /* If result is pass-by-ref, make sure it is in the right context. */
1664  if (!peragg->resulttypeByVal && !*resultIsNull &&
1666  DatumGetPointer(*resultVal)))
1667  *resultVal = datumCopy(*resultVal,
1668  peragg->resulttypeByVal,
1669  peragg->resulttypeLen);
1670 
1671  MemoryContextSwitchTo(oldContext);
1672 }
ScanState ss
Definition: execnodes.h:1806
ExprContext * ps_ExprContext
Definition: execnodes.h:883
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:1816
#define OidIsValid(objectId)
Definition: c.h:576
PlanState ps
Definition: execnodes.h:1103
bool fn_strict
Definition: fmgr.h:61
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:137
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
bool argnull[FUNC_MAX_ARGS]
Definition: fmgr.h:86
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
uintptr_t Datum
Definition: postgres.h:372
FunctionCallInfoData serialfn_fcinfo
Definition: nodeAgg.c:393
int16 resulttypeLen
Definition: nodeAgg.c:444
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
FmgrInfo serialfn
Definition: nodeAgg.c:305
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:566
#define DatumGetPointer(X)
Definition: postgres.h:555
bool resulttypeByVal
Definition: nodeAgg.c:445

◆ find_compatible_peragg()

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

Definition at line 3806 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::sharable, and AggStatePerAggData::transno.

Referenced by ExecInitAgg().

3808 {
3809  int aggno;
3810  AggStatePerAgg peraggs;
3811 
3812  *same_input_transnos = NIL;
3813 
3814  /* we mustn't reuse the aggref if it contains volatile function calls */
3815  if (contain_volatile_functions((Node *) newagg))
3816  return -1;
3817 
3818  peraggs = aggstate->peragg;
3819 
3820  /*
3821  * Search through the list of already seen aggregates. If we find an
3822  * existing identical aggregate call, then we can re-use that one. While
3823  * searching, we'll also collect a list of Aggrefs with the same input
3824  * parameters. If no matching Aggref is found, the caller can potentially
3825  * still re-use the transition state of one of them. (At this stage we
3826  * just compare the parsetrees; whether different aggregates share the
3827  * same transition function will be checked later.)
3828  */
3829  for (aggno = 0; aggno <= lastaggno; aggno++)
3830  {
3831  AggStatePerAgg peragg;
3832  Aggref *existingRef;
3833 
3834  peragg = &peraggs[aggno];
3835  existingRef = peragg->aggref;
3836 
3837  /* all of the following must be the same or it's no match */
3838  if (newagg->inputcollid != existingRef->inputcollid ||
3839  newagg->aggtranstype != existingRef->aggtranstype ||
3840  newagg->aggstar != existingRef->aggstar ||
3841  newagg->aggvariadic != existingRef->aggvariadic ||
3842  newagg->aggkind != existingRef->aggkind ||
3843  !equal(newagg->args, existingRef->args) ||
3844  !equal(newagg->aggorder, existingRef->aggorder) ||
3845  !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
3846  !equal(newagg->aggfilter, existingRef->aggfilter))
3847  continue;
3848 
3849  /* if it's the same aggregate function then report exact match */
3850  if (newagg->aggfnoid == existingRef->aggfnoid &&
3851  newagg->aggtype == existingRef->aggtype &&
3852  newagg->aggcollid == existingRef->aggcollid &&
3853  equal(newagg->aggdirectargs, existingRef->aggdirectargs))
3854  {
3855  list_free(*same_input_transnos);
3856  *same_input_transnos = NIL;
3857  return aggno;
3858  }
3859 
3860  /*
3861  * Not identical, but it had the same inputs. If the final function
3862  * permits sharing, return its transno to the caller, in case we can
3863  * re-use its per-trans state. (If there's already sharing going on,
3864  * we might report a transno more than once. find_compatible_pertrans
3865  * is cheap enough that it's not worth spending cycles to avoid that.)
3866  */
3867  if (peragg->sharable)
3868  *same_input_transnos = lappend_int(*same_input_transnos,
3869  peragg->transno);
3870  }
3871 
3872  return -1;
3873 }
List * aggdistinct
Definition: primnodes.h:303
#define NIL
Definition: pg_list.h:69
bool aggvariadic
Definition: primnodes.h:306
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2974
Oid inputcollid
Definition: primnodes.h:297
Definition: nodes.h:511
List * args
Definition: primnodes.h:301
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:957
bool aggstar
Definition: primnodes.h:305
Aggref * aggref
Definition: nodeAgg.c:415
List * aggorder
Definition: primnodes.h:302
List * aggdirectargs
Definition: primnodes.h:300
List * lappend_int(List *list, int datum)
Definition: list.c:146
Oid aggfnoid
Definition: primnodes.h:294
Expr * aggfilter
Definition: primnodes.h:304
Oid aggcollid
Definition: primnodes.h:296
AggStatePerAgg peragg
Definition: execnodes.h:1815
void list_free(List *list)
Definition: list.c:1133
Oid aggtranstype
Definition: primnodes.h:298
Oid aggtype
Definition: primnodes.h:295
char aggkind
Definition: primnodes.h:308

◆ find_compatible_pertrans()

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

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

3889 {
3890  ListCell *lc;
3891 
3892  /* If this aggregate can't share transition states, give up */
3893  if (!sharable)
3894  return -1;
3895 
3896  foreach(lc, transnos)
3897  {
3898  int transno = lfirst_int(lc);
3899  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3900 
3901  /*
3902  * if the transfns or transition state types are not the same then the
3903  * state can't be shared.
3904  */
3905  if (aggtransfn != pertrans->transfn_oid ||
3906  aggtranstype != pertrans->aggtranstype)
3907  continue;
3908 
3909  /*
3910  * The serialization and deserialization functions must match, if
3911  * present, as we're unable to share the trans state for aggregates
3912  * which will serialize or deserialize into different formats.
3913  * Remember that these will be InvalidOid if they're not required for
3914  * this agg node.
3915  */
3916  if (aggserialfn != pertrans->serialfn_oid ||
3917  aggdeserialfn != pertrans->deserialfn_oid)
3918  continue;
3919 
3920  /*
3921  * Check that the initial condition matches, too.
3922  */
3923  if (initValueIsNull && pertrans->initValueIsNull)
3924  return transno;
3925 
3926  if (!initValueIsNull && !pertrans->initValueIsNull &&
3927  datumIsEqual(initValue, pertrans->initValue,
3928  pertrans->transtypeByVal, pertrans->transtypeLen))
3929  return transno;
3930  }
3931  return -1;
3932 }
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:219
AggStatePerTrans pertrans
Definition: execnodes.h:1816
#define lfirst_int(lc)
Definition: pg_list.h:107
static int initValue(long lng_val)
Definition: informix.c:702

◆ find_hash_columns()

static void find_hash_columns ( AggState aggstate)
static

Definition at line 1937 of file nodeAgg.c.

References AggStatePerHashData::aggnode, AggState::all_grouped_cols, bms_add_member(), bms_copy(), bms_del_member(), bms_first_member(), bms_free(), bms_is_member(), bms_num_members(), ExecSetSlotDescriptor(), ExecTypeFromTL(), find_unaggregated_cols(), AggStatePerPhaseData::grouped_cols, Agg::grpColIdx, 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, and AggState::phases.

Referenced by ExecInitAgg().

1938 {
1939  Bitmapset *base_colnos;
1940  List *outerTlist = outerPlanState(aggstate)->plan->targetlist;
1941  int numHashes = aggstate->num_hashes;
1942  int j;
1943 
1944  /* Find Vars that will be needed in tlist and qual */
1945  base_colnos = find_unaggregated_cols(aggstate);
1946 
1947  for (j = 0; j < numHashes; ++j)
1948  {
1949  AggStatePerHash perhash = &aggstate->perhash[j];
1950  Bitmapset *colnos = bms_copy(base_colnos);
1951  AttrNumber *grpColIdx = perhash->aggnode->grpColIdx;
1952  List *hashTlist = NIL;
1953  TupleDesc hashDesc;
1954  int i;
1955 
1956  perhash->largestGrpColIdx = 0;
1957 
1958  /*
1959  * If we're doing grouping sets, then some Vars might be referenced in
1960  * tlist/qual for the benefit of other grouping sets, but not needed
1961  * when hashing; i.e. prepare_projection_slot will null them out, so
1962  * there'd be no point storing them. Use prepare_projection_slot's
1963  * logic to determine which.
1964  */
1965  if (aggstate->phases[0].grouped_cols)
1966  {
1967  Bitmapset *grouped_cols = aggstate->phases[0].grouped_cols[j];
1968  ListCell *lc;
1969 
1970  foreach(lc, aggstate->all_grouped_cols)
1971  {
1972  int attnum = lfirst_int(lc);
1973 
1974  if (!bms_is_member(attnum, grouped_cols))
1975  colnos = bms_del_member(colnos, attnum);
1976  }
1977  }
1978  /* Add in all the grouping columns */
1979  for (i = 0; i < perhash->numCols; i++)
1980  colnos = bms_add_member(colnos, grpColIdx[i]);
1981 
1982  perhash->hashGrpColIdxInput =
1983  palloc(bms_num_members(colnos) * sizeof(AttrNumber));
1984  perhash->hashGrpColIdxHash =
1985  palloc(perhash->numCols * sizeof(AttrNumber));
1986 
1987  /*
1988  * First build mapping for columns directly hashed. These are the
1989  * first, because they'll be accessed when computing hash values and
1990  * comparing tuples for exact matches. We also build simple mapping
1991  * for execGrouping, so it knows where to find the to-be-hashed /
1992  * compared columns in the input.
1993  */
1994  for (i = 0; i < perhash->numCols; i++)
1995  {
1996  perhash->hashGrpColIdxInput[i] = grpColIdx[i];
1997  perhash->hashGrpColIdxHash[i] = i + 1;
1998  perhash->numhashGrpCols++;
1999  /* delete already mapped columns */
2000  bms_del_member(colnos, grpColIdx[i]);
2001  }
2002 
2003  /* and add the remaining columns */
2004  while ((i = bms_first_member(colnos)) >= 0)
2005  {
2006  perhash->hashGrpColIdxInput[perhash->numhashGrpCols] = i;
2007  perhash->numhashGrpCols++;
2008  }
2009 
2010  /* and build a tuple descriptor for the hashtable */
2011  for (i = 0; i < perhash->numhashGrpCols; i++)
2012  {
2013  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
2014 
2015  hashTlist = lappend(hashTlist, list_nth(outerTlist, varNumber));
2016  perhash->largestGrpColIdx =
2017  Max(varNumber + 1, perhash->largestGrpColIdx);
2018  }
2019 
2020  hashDesc = ExecTypeFromTL(hashTlist, false);
2021  ExecSetSlotDescriptor(perhash->hashslot, hashDesc);
2022 
2023  list_free(hashTlist);
2024  bms_free(colnos);
2025  }
2026 
2027  bms_free(base_colnos);
2028 }
#define NIL
Definition: pg_list.h:69
int bms_first_member(Bitmapset *a)
Definition: bitmapset.c:885
AggStatePerPhase phases
Definition: execnodes.h:1831
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.c:525
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:111
AttrNumber * grpColIdx
Definition: plannodes.h:786
List * all_grouped_cols
Definition: execnodes.h:1828
Bitmapset ** grouped_cols
Definition: nodeAgg.c:502
#define lfirst_int(lc)
Definition: pg_list.h:107
#define outerPlanState(node)
Definition: execnodes.h:895
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:605
void * list_nth(const List *list, int n)
Definition: list.c:410
AggStatePerHash perhash
Definition: execnodes.h:1841
TupleDesc ExecTypeFromTL(List *targetList, bool hasoid)
Definition: execTuples.c:888
List * lappend(List *list, void *datum)
Definition: list.c:128
int num_hashes
Definition: execnodes.h:1840
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.c:526
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:247
void bms_free(Bitmapset *a)
Definition: bitmapset.c:201
#define Max(x, y)
Definition: c.h:796
static Bitmapset * find_unaggregated_cols(AggState *aggstate)
Definition: nodeAgg.c:1834
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
void * palloc(Size size)
Definition: mcxt.c:848
void list_free(List *list)
Definition: list.c:1133
int i
TupleTableSlot * hashslot
Definition: nodeAgg.c:519
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:735
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
int16 AttrNumber
Definition: attnum.h:21

◆ find_unaggregated_cols()

static Bitmapset * find_unaggregated_cols ( AggState aggstate)
static

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

1835 {
1836  Agg *node = (Agg *) aggstate->ss.ps.plan;
1837  Bitmapset *colnos;
1838 
1839  colnos = NULL;
1841  &colnos);
1842  (void) find_unaggregated_cols_walker((Node *) node->plan.qual,
1843  &colnos);
1844  return colnos;
1845 }
List * qual
Definition: plannodes.h:145
ScanState ss
Definition: execnodes.h:1806
Definition: nodes.h:511
PlanState ps
Definition: execnodes.h:1103
static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
Definition: nodeAgg.c:1848
Plan plan
Definition: plannodes.h:782
Plan * plan
Definition: execnodes.h:849
List * targetlist
Definition: plannodes.h:144
Definition: plannodes.h:780

◆ find_unaggregated_cols_walker()

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

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

1849 {
1850  if (node == NULL)
1851  return false;
1852  if (IsA(node, Var))
1853  {
1854  Var *var = (Var *) node;
1855 
1856  /* setrefs.c should have set the varno to OUTER_VAR */
1857  Assert(var->varno == OUTER_VAR);
1858  Assert(var->varlevelsup == 0);
1859  *colnos = bms_add_member(*colnos, var->varattno);
1860  return false;
1861  }
1862  if (IsA(node, Aggref) ||IsA(node, GroupingFunc))
1863  {
1864  /* do not descend into aggregate exprs */
1865  return false;
1866  }
1868  (void *) colnos);
1869 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:562
Index varlevelsup
Definition: primnodes.h:173
AttrNumber varattno
Definition: primnodes.h:168
Definition: primnodes.h:163
static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
Definition: nodeAgg.c:1848
Index varno
Definition: primnodes.h:166
#define Assert(condition)
Definition: c.h:670
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1834
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define OUTER_VAR
Definition: primnodes.h:154

◆ GetAggInitVal()

static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 3778 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

3779 {
3780  Oid typinput,
3781  typioparam;
3782  char *strInitVal;
3783  Datum initVal;
3784 
3785  getTypeInputInfo(transtype, &typinput, &typioparam);
3786  strInitVal = TextDatumGetCString(textInitVal);
3787  initVal = OidInputFunctionCall(typinput, strInitVal,
3788  typioparam, -1);
3789  pfree(strInitVal);
3790  return initVal;
3791 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:949
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2613
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:372
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1733

◆ hash_agg_entry_size()

Size hash_agg_entry_size ( int  numAggs)

Definition at line 2039 of file nodeAgg.c.

References MAXALIGN.

Referenced by create_distinct_paths(), and estimate_hashagg_tablesize().

2040 {
2041  Size entrysize;
2042 
2043  /* This must match build_hash_table */
2044  entrysize = sizeof(TupleHashEntryData) +
2045  numAggs * sizeof(AggStatePerGroupData);
2046  entrysize = MAXALIGN(entrysize);
2047 
2048  return entrysize;
2049 }
struct TupleHashEntryData TupleHashEntryData
size_t Size
Definition: c.h:404
#define MAXALIGN(LEN)
Definition: c.h:623

◆ initialize_aggregate()

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

Definition at line 716 of file nodeAgg.c.

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

Referenced by initialize_aggregates().

718 {
719  /*
720  * Start a fresh sort operation for each DISTINCT/ORDER BY aggregate.
721  */
722  if (pertrans->numSortCols > 0)
723  {
724  /*
725  * In case of rescan, maybe there could be an uncompleted sort
726  * operation? Clean it up if so.
727  */
728  if (pertrans->sortstates[aggstate->current_set])
729  tuplesort_end(pertrans->sortstates[aggstate->current_set]);
730 
731 
732  /*
733  * We use a plain Datum sorter when there's a single input column;
734  * otherwise sort the full tuple. (See comments for
735  * process_ordered_aggregate_single.)
736  */
737  if (pertrans->numInputs == 1)
738  {
739  Form_pg_attribute attr = TupleDescAttr(pertrans->sortdesc, 0);
740 
741  pertrans->sortstates[aggstate->current_set] =
742  tuplesort_begin_datum(attr->atttypid,
743  pertrans->sortOperators[0],
744  pertrans->sortCollations[0],
745  pertrans->sortNullsFirst[0],
746  work_mem, false);
747  }
748  else
749  pertrans->sortstates[aggstate->current_set] =
750  tuplesort_begin_heap(pertrans->sortdesc,
751  pertrans->numSortCols,
752  pertrans->sortColIdx,
753  pertrans->sortOperators,
754  pertrans->sortCollations,
755  pertrans->sortNullsFirst,
756  work_mem, false);
757  }
758 
759  /*
760  * (Re)set transValue to the initial value.
761  *
762  * Note that when the initial value is pass-by-ref, we must copy it (into
763  * the aggcontext) since we will pfree the transValue later.
764  */
765  if (pertrans->initValueIsNull)
766  pergroupstate->transValue = pertrans->initValue;
767  else
768  {
769  MemoryContext oldContext;
770 
771  oldContext = MemoryContextSwitchTo(
773  pergroupstate->transValue = datumCopy(pertrans->initValue,
774  pertrans->transtypeByVal,
775  pertrans->transtypeLen);
776  MemoryContextSwitchTo(oldContext);
777  }
778  pergroupstate->transValueIsNull = pertrans->initValueIsNull;
779 
780  /*
781  * If the initial value for the transition state doesn't exist in the
782  * pg_aggregate table then we will let the first non-NULL value returned
783  * from the outer procNode become the initial value. (This is useful for
784  * aggregates like max() and min().) The noTransValue flag signals that we
785  * still need to do this.
786  */
787  pergroupstate->noTransValue = pertrans->initValueIsNull;
788 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int current_set
Definition: execnodes.h:1826
TupleDesc sortdesc
Definition: nodeAgg.c:366
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, bool randomAccess)
Definition: tuplesort.c:975
Tuplesortstate ** sortstates
Definition: nodeAgg.c:382
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
AttrNumber * sortColIdx
Definition: nodeAgg.c:321
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
ExprContext * curaggcontext
Definition: execnodes.h:1820
int work_mem
Definition: globals.c:113
Tuplesortstate * tuplesort_begin_heap(TupleDesc tupDesc, int nkeys, AttrNumber *attNums, Oid *sortOperators, Oid *sortCollations, bool *nullsFirstFlags, int workMem, bool randomAccess)
Definition: tuplesort.c:693
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1104
bool * sortNullsFirst
Definition: nodeAgg.c:324

◆ initialize_aggregates()

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

Definition at line 802 of file nodeAgg.c.

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

Referenced by agg_retrieve_direct(), and lookup_hash_entry().

805 {
806  int transno;
807  int numGroupingSets = Max(aggstate->phase->numsets, 1);
808  int setno = 0;
809  int numTrans = aggstate->numtrans;
810  AggStatePerTrans transstates = aggstate->pertrans;
811 
812  if (numReset == 0)
813  numReset = numGroupingSets;
814 
815  for (transno = 0; transno < numTrans; transno++)
816  {
817  AggStatePerTrans pertrans = &transstates[transno];
818 
819  if (numReset < 0)
820  {
821  AggStatePerGroup pergroupstate;
822 
823  pergroupstate = &pergroup[transno];
824 
825  initialize_aggregate(aggstate, pertrans, pergroupstate);
826  }
827  else
828  {
829  for (setno = 0; setno < numReset; setno++)
830  {
831  AggStatePerGroup pergroupstate;
832 
833  pergroupstate = &pergroup[transno + (setno * numTrans)];
834 
835  select_current_set(aggstate, setno, false);
836 
837  initialize_aggregate(aggstate, pertrans, pergroupstate);
838  }
839  }
840  }
841 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:597
AggStatePerTrans pertrans
Definition: execnodes.h:1816
int numtrans
Definition: execnodes.h:1809
static void initialize_aggregate(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:716
AggStatePerPhase phase
Definition: execnodes.h:1812
#define Max(x, y)
Definition: c.h:796

◆ initialize_phase()

static void initialize_phase ( AggState aggstate,
int  newphase 
)
static

Definition at line 615 of file nodeAgg.c.

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

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

616 {
617  Assert(newphase <= 1 || newphase == aggstate->current_phase + 1);
618 
619  /*
620  * Whatever the previous state, we're now done with whatever input
621  * tuplesort was in use.
622  */
623  if (aggstate->sort_in)
624  {
625  tuplesort_end(aggstate->sort_in);
626  aggstate->sort_in = NULL;
627  }
628 
629  if (newphase <= 1)
630  {
631  /*
632  * Discard any existing output tuplesort.
633  */
634  if (aggstate->sort_out)
635  {
636  tuplesort_end(aggstate->sort_out);
637  aggstate->sort_out = NULL;
638  }
639  }
640  else
641  {
642  /*
643  * The old output tuplesort becomes the new input one, and this is the
644  * right time to actually sort it.
645  */
646  aggstate->sort_in = aggstate->sort_out;
647  aggstate->sort_out = NULL;
648  Assert(aggstate->sort_in);
649  tuplesort_performsort(aggstate->sort_in);
650  }
651 
652  /*
653  * If this isn't the last phase, we need to sort appropriately for the
654  * next phase in sequence.
655  */
656  if (newphase > 0 && newphase < aggstate->numphases - 1)
657  {
658  Sort *sortnode = aggstate->phases[newphase + 1].sortnode;
659  PlanState *outerNode = outerPlanState(aggstate);
660  TupleDesc tupDesc = ExecGetResultType(outerNode);
661 
662  aggstate->sort_out = tuplesort_begin_heap(tupDesc,
663  sortnode->numCols,
664  sortnode->sortColIdx,
665  sortnode->sortOperators,
666  sortnode->collations,
667  sortnode->nullsFirst,
668  work_mem,
669  false);
670  }
671 
672  aggstate->current_phase = newphase;
673  aggstate->phase = &aggstate->phases[newphase];
674 }
AggStatePerPhase phases
Definition: execnodes.h:1831
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1656
Tuplesortstate * sort_out
Definition: execnodes.h:1833
int current_phase
Definition: execnodes.h:1814
bool * nullsFirst
Definition: plannodes.h:749
Oid * sortOperators
Definition: plannodes.h:747
Tuplesortstate * sort_in
Definition: execnodes.h:1832
#define outerPlanState(node)
Definition: execnodes.h:895
int numCols
Definition: plannodes.h:745
AggStatePerPhase phase
Definition: execnodes.h:1812
int work_mem
Definition: globals.c:113
#define Assert(condition)
Definition: c.h:670
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:476
AttrNumber * sortColIdx
Definition: plannodes.h:746
Tuplesortstate * tuplesort_begin_heap(TupleDesc tupDesc, int nkeys, AttrNumber *attNums, Oid *sortOperators, Oid *sortCollations, bool *nullsFirstFlags, int workMem, bool randomAccess)
Definition: tuplesort.c:693
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1104
Oid * collations
Definition: plannodes.h:748

◆ lookup_hash_entries()

static AggStatePerGroup * lookup_hash_entries ( AggState aggstate)
static

Definition at line 2105 of file nodeAgg.c.

References TupleHashEntryData::additional, AggState::hash_pergroup, lookup_hash_entry(), AggState::num_hashes, and select_current_set().

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

2106 {
2107  int numHashes = aggstate->num_hashes;
2108  AggStatePerGroup *pergroup = aggstate->hash_pergroup;
2109  int setno;
2110 
2111  for (setno = 0; setno < numHashes; setno++)
2112  {
2113  select_current_set(aggstate, setno, true);
2114  pergroup[setno] = lookup_hash_entry(aggstate)->additional;
2115  }
2116 
2117  return pergroup;
2118 }
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:1842
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:597
static TupleHashEntryData * lookup_hash_entry(AggState *aggstate)
Definition: nodeAgg.c:2060
int num_hashes
Definition: execnodes.h:1840

◆ lookup_hash_entry()

static TupleHashEntryData * lookup_hash_entry ( AggState aggstate)
static

Definition at line 2060 of file nodeAgg.c.

References TupleHashEntryData::additional, AggState::current_set, ExprContext::ecxt_outertuple, ExecClearTuple(), ExecStoreVirtualTuple(), AggStatePerHashData::hashGrpColIdxInput, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, i, initialize_aggregates(), AggStatePerHashData::largestGrpColIdx, LookupTupleHashEntry(), MemoryContextAlloc(), AggStatePerHashData::numhashGrpCols, AggState::numtrans, AggState::perhash, slot_getsomeattrs(), TupleHashTableData::tablecxt, AggState::tmpcontext, TupleTableSlot::tts_isnull, and TupleTableSlot::tts_values.

Referenced by lookup_hash_entries().

2061 {
2062  TupleTableSlot *inputslot = aggstate->tmpcontext->ecxt_outertuple;
2063  AggStatePerHash perhash = &aggstate->perhash[aggstate->current_set];
2064  TupleTableSlot *hashslot = perhash->hashslot;
2065  TupleHashEntryData *entry;
2066  bool isnew;
2067  int i;
2068 
2069  /* transfer just the needed columns into hashslot */
2070  slot_getsomeattrs(inputslot, perhash->largestGrpColIdx);
2071  ExecClearTuple(hashslot);
2072 
2073  for (i = 0; i < perhash->numhashGrpCols; i++)
2074  {
2075  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
2076 
2077  hashslot->tts_values[i] = inputslot->tts_values[varNumber];
2078  hashslot->tts_isnull[i] = inputslot->tts_isnull[varNumber];
2079  }
2080  ExecStoreVirtualTuple(hashslot);
2081 
2082  /* find or create the hashtable entry using the filtered tuple */
2083  entry = LookupTupleHashEntry(perhash->hashtable, hashslot, &isnew);
2084 
2085  if (isnew)
2086  {
2087  entry->additional = (AggStatePerGroup)
2089  sizeof(AggStatePerGroupData) * aggstate->numtrans);
2090  /* initialize aggregates for new tuple group */