PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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, 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)
 
void AggRegisterCallback (FunctionCallInfo fcinfo, ExprContextCallbackFunction func, Datum arg)
 
Datum aggregate_dummy (PG_FUNCTION_ARGS)
 

Typedef Documentation

Function Documentation

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

Definition at line 968 of file nodeAgg.c.

References advance_transition_function(), AggStatePerTransData::aggfilter, FunctionCallInfoData::arg, FunctionCallInfoData::argnull, Assert, DatumGetBool, AggState::evalproj, AggState::evalslot, ExecClearTuple(), ExecEvalExprSwitchContext(), 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, AggState::tmpcontext, 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().

969 {
970  int transno;
971  int setno = 0;
972  int numGroupingSets = Max(aggstate->phase->numsets, 1);
973  int numHashes = aggstate->num_hashes;
974  int numTrans = aggstate->numtrans;
975  TupleTableSlot *slot = aggstate->evalslot;
976 
977  /* compute input for all aggregates */
978  if (aggstate->evalproj)
979  aggstate->evalslot = ExecProject(aggstate->evalproj);
980 
981  for (transno = 0; transno < numTrans; transno++)
982  {
983  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
984  ExprState *filter = pertrans->aggfilter;
985  int numTransInputs = pertrans->numTransInputs;
986  int i;
987  int inputoff = pertrans->inputoff;
988 
989  /* Skip anything FILTERed out */
990  if (filter)
991  {
992  Datum res;
993  bool isnull;
994 
995  res = ExecEvalExprSwitchContext(filter, aggstate->tmpcontext,
996  &isnull);
997  if (isnull || !DatumGetBool(res))
998  continue;
999  }
1000 
1001  if (pertrans->numSortCols > 0)
1002  {
1003  /* DISTINCT and/or ORDER BY case */
1004  Assert(slot->tts_nvalid >= (pertrans->numInputs + inputoff));
1005  Assert(!pergroups);
1006 
1007  /*
1008  * If the transfn is strict, we want to check for nullity before
1009  * storing the row in the sorter, to save space if there are a lot
1010  * of nulls. Note that we must only check numTransInputs columns,
1011  * not numInputs, since nullity in columns used only for sorting
1012  * is not relevant here.
1013  */
1014  if (pertrans->transfn.fn_strict)
1015  {
1016  for (i = 0; i < numTransInputs; i++)
1017  {
1018  if (slot->tts_isnull[i + inputoff])
1019  break;
1020  }
1021  if (i < numTransInputs)
1022  continue;
1023  }
1024 
1025  for (setno = 0; setno < numGroupingSets; setno++)
1026  {
1027  /* OK, put the tuple into the tuplesort object */
1028  if (pertrans->numInputs == 1)
1029  tuplesort_putdatum(pertrans->sortstates[setno],
1030  slot->tts_values[inputoff],
1031  slot->tts_isnull[inputoff]);
1032  else
1033  {
1034  /*
1035  * Copy slot contents, starting from inputoff, into sort
1036  * slot.
1037  */
1038  ExecClearTuple(pertrans->sortslot);
1039  memcpy(pertrans->sortslot->tts_values,
1040  &slot->tts_values[inputoff],
1041  pertrans->numInputs * sizeof(Datum));
1042  memcpy(pertrans->sortslot->tts_isnull,
1043  &slot->tts_isnull[inputoff],
1044  pertrans->numInputs * sizeof(bool));
1045  pertrans->sortslot->tts_nvalid = pertrans->numInputs;
1046  ExecStoreVirtualTuple(pertrans->sortslot);
1047  tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot);
1048  }
1049  }
1050  }
1051  else
1052  {
1053  /* We can apply the transition function immediately */
1054  FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
1055 
1056  /* Load values into fcinfo */
1057  /* Start from 1, since the 0th arg will be the transition value */
1058  Assert(slot->tts_nvalid >= (numTransInputs + inputoff));
1059 
1060  for (i = 0; i < numTransInputs; i++)
1061  {
1062  fcinfo->arg[i + 1] = slot->tts_values[i + inputoff];
1063  fcinfo->argnull[i + 1] = slot->tts_isnull[i + inputoff];
1064  }
1065 
1066  if (pergroup)
1067  {
1068  /* advance transition states for ordered grouping */
1069 
1070  for (setno = 0; setno < numGroupingSets; setno++)
1071  {
1072  AggStatePerGroup pergroupstate;
1073 
1074  select_current_set(aggstate, setno, false);
1075 
1076  pergroupstate = &pergroup[transno + (setno * numTrans)];
1077 
1078  advance_transition_function(aggstate, pertrans, pergroupstate);
1079  }
1080  }
1081 
1082  if (pergroups)
1083  {
1084  /* advance transition states for hashed grouping */
1085 
1086  for (setno = 0; setno < numHashes; setno++)
1087  {
1088  AggStatePerGroup pergroupstate;
1089 
1090  select_current_set(aggstate, setno, true);
1091 
1092  pergroupstate = &pergroups[setno][transno];
1093 
1094  advance_transition_function(aggstate, pertrans, pergroupstate);
1095  }
1096  }
1097  }
1098  }
1099 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:586
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:301
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
Definition: tuplesort.c:1485
ProjectionInfo * evalproj
Definition: execnodes.h:1833
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
Datum * tts_values
Definition: tuptable.h:125
AggStatePerTrans pertrans
Definition: execnodes.h:1805
int numtrans
Definition: execnodes.h:1798
ExprContext * tmpcontext
Definition: execnodes.h:1808
FmgrInfo transfn
Definition: nodeAgg.c:301
FunctionCallInfoData transfn_fcinfo
Definition: nodeAgg.c:388
bool fn_strict
Definition: fmgr.h:61
Tuplesortstate ** sortstates
Definition: nodeAgg.c:380
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:1828
TupleTableSlot * evalslot
Definition: execnodes.h:1832
AggStatePerPhase phase
Definition: execnodes.h:1801
uintptr_t Datum
Definition: postgres.h:372
static void advance_transition_function(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:844
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define Max(x, y)
Definition: c.h:789
#define Assert(condition)
Definition: c.h:664
ExprState * aggfilter
Definition: nodeAgg.c:294
int i
TupleTableSlot * sortslot
Definition: nodeAgg.c:363
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:329
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1364
static void advance_combine_function ( AggState aggstate,
AggStatePerTrans  pertrans,
AggStatePerGroup  pergroupstate 
)
static

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

1188 {
1189  FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
1190  MemoryContext oldContext;
1191  Datum newVal;
1192 
1193  if (pertrans->transfn.fn_strict)
1194  {
1195  /* if we're asked to merge to a NULL state, then do nothing */
1196  if (fcinfo->argnull[1])
1197  return;
1198 
1199  if (pergroupstate->noTransValue)
1200  {
1201  /*
1202  * transValue has not yet been initialized. If pass-by-ref
1203  * datatype we must copy the combining state value into
1204  * aggcontext.
1205  */
1206  if (!pertrans->transtypeByVal)
1207  {
1208  oldContext = MemoryContextSwitchTo(
1210  pergroupstate->transValue = datumCopy(fcinfo->arg[1],
1211  pertrans->transtypeByVal,
1212  pertrans->transtypeLen);
1213  MemoryContextSwitchTo(oldContext);
1214  }
1215  else
1216  pergroupstate->transValue = fcinfo->arg[1];
1217 
1218  pergroupstate->transValueIsNull = false;
1219  pergroupstate->noTransValue = false;
1220  return;
1221  }
1222  }
1223 
1224  /* We run the combine functions in per-input-tuple memory context */
1225  oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
1226 
1227  /* set up aggstate->curpertrans for AggGetAggref() */
1228  aggstate->curpertrans = pertrans;
1229 
1230  /*
1231  * OK to call the combine function
1232  */
1233  fcinfo->arg[0] = pergroupstate->transValue;
1234  fcinfo->argnull[0] = pergroupstate->transValueIsNull;
1235  fcinfo->isnull = false; /* just in case combine func doesn't set it */
1236 
1237  newVal = FunctionCallInvoke(fcinfo);
1238 
1239  aggstate->curpertrans = NULL;
1240 
1241  /*
1242  * If pass-by-ref datatype, must copy the new value into aggcontext and
1243  * free the prior transValue. But if the combine function returned a
1244  * pointer to its first input, we don't need to do anything. Also, if the
1245  * combine function returned a pointer to a R/W expanded object that is
1246  * already a child of the aggcontext, assume we can adopt that value
1247  * without copying it.
1248  */
1249  if (!pertrans->transtypeByVal &&
1250  DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
1251  {
1252  if (!fcinfo->isnull)
1253  {
1255  if (DatumIsReadWriteExpandedObject(newVal,
1256  false,
1257  pertrans->transtypeLen) &&
1258  MemoryContextGetParent(DatumGetEOHP(newVal)->eoh_context) == CurrentMemoryContext)
1259  /* do nothing */ ;
1260  else
1261  newVal = datumCopy(newVal,
1262  pertrans->transtypeByVal,
1263  pertrans->transtypeLen);
1264  }
1265  if (!pergroupstate->transValueIsNull)
1266  {
1267  if (DatumIsReadWriteExpandedObject(pergroupstate->transValue,
1268  false,
1269  pertrans->transtypeLen))
1270  DeleteExpandedObject(pergroupstate->transValue);
1271  else
1272  pfree(DatumGetPointer(pergroupstate->transValue));
1273  }
1274  }
1275 
1276  pergroupstate->transValue = newVal;
1277  pergroupstate->transValueIsNull = fcinfo->isnull;
1278 
1279  MemoryContextSwitchTo(oldContext);
1280 }
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:1808
FmgrInfo transfn
Definition: nodeAgg.c:301
FunctionCallInfoData transfn_fcinfo
Definition: nodeAgg.c:388
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:1809
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:1810
static void advance_transition_function ( AggState aggstate,
AggStatePerTrans  pertrans,
AggStatePerGroup  pergroupstate 
)
static

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

847 {
848  FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
849  MemoryContext oldContext;
850  Datum newVal;
851 
852  if (pertrans->transfn.fn_strict)
853  {
854  /*
855  * For a strict transfn, nothing happens when there's a NULL input; we
856  * just keep the prior transValue.
857  */
858  int numTransInputs = pertrans->numTransInputs;
859  int i;
860 
861  for (i = 1; i <= numTransInputs; i++)
862  {
863  if (fcinfo->argnull[i])
864  return;
865  }
866  if (pergroupstate->noTransValue)
867  {
868  /*
869  * transValue has not been initialized. This is the first non-NULL
870  * input value. We use it as the initial value for transValue. (We
871  * already checked that the agg's input type is binary-compatible
872  * with its transtype, so straight copy here is OK.)
873  *
874  * We must copy the datum into aggcontext if it is pass-by-ref. We
875  * do not need to pfree the old transValue, since it's NULL.
876  */
877  oldContext = MemoryContextSwitchTo(
879  pergroupstate->transValue = datumCopy(fcinfo->arg[1],
880  pertrans->transtypeByVal,
881  pertrans->transtypeLen);
882  pergroupstate->transValueIsNull = false;
883  pergroupstate->noTransValue = false;
884  MemoryContextSwitchTo(oldContext);
885  return;
886  }
887  if (pergroupstate->transValueIsNull)
888  {
889  /*
890  * Don't call a strict function with NULL inputs. Note it is
891  * possible to get here despite the above tests, if the transfn is
892  * strict *and* returned a NULL on a prior cycle. If that happens
893  * we will propagate the NULL all the way to the end.
894  */
895  return;
896  }
897  }
898 
899  /* We run the transition functions in per-input-tuple memory context */
900  oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
901 
902  /* set up aggstate->curpertrans for AggGetAggref() */
903  aggstate->curpertrans = pertrans;
904 
905  /*
906  * OK to call the transition function
907  */
908  fcinfo->arg[0] = pergroupstate->transValue;
909  fcinfo->argnull[0] = pergroupstate->transValueIsNull;
910  fcinfo->isnull = false; /* just in case transfn doesn't set it */
911 
912  newVal = FunctionCallInvoke(fcinfo);
913 
914  aggstate->curpertrans = NULL;
915 
916  /*
917  * If pass-by-ref datatype, must copy the new value into aggcontext and
918  * free the prior transValue. But if transfn returned a pointer to its
919  * first input, we don't need to do anything. Also, if transfn returned a
920  * pointer to a R/W expanded object that is already a child of the
921  * aggcontext, assume we can adopt that value without copying it.
922  */
923  if (!pertrans->transtypeByVal &&
924  DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
925  {
926  if (!fcinfo->isnull)
927  {
930  false,
931  pertrans->transtypeLen) &&
933  /* do nothing */ ;
934  else
935  newVal = datumCopy(newVal,
936  pertrans->transtypeByVal,
937  pertrans->transtypeLen);
938  }
939  if (!pergroupstate->transValueIsNull)
940  {
941  if (DatumIsReadWriteExpandedObject(pergroupstate->transValue,
942  false,
943  pertrans->transtypeLen))
944  DeleteExpandedObject(pergroupstate->transValue);
945  else
946  pfree(DatumGetPointer(pergroupstate->transValue));
947  }
948  }
949 
950  pergroupstate->transValue = newVal;
951  pergroupstate->transValueIsNull = fcinfo->isnull;
952 
953  MemoryContextSwitchTo(oldContext);
954 }
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:1808
FmgrInfo transfn
Definition: nodeAgg.c:301
FunctionCallInfoData transfn_fcinfo
Definition: nodeAgg.c:388
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:1809
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:1810
static void agg_fill_hash_table ( AggState aggstate)
static

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

2497 {
2498  TupleTableSlot *outerslot;
2499  ExprContext *tmpcontext = aggstate->tmpcontext;
2500 
2501  /*
2502  * Process each outer-plan tuple, and then fetch the next one, until we
2503  * exhaust the outer plan.
2504  */
2505  for (;;)
2506  {
2507  AggStatePerGroup *pergroups;
2508 
2509  outerslot = fetch_input_tuple(aggstate);
2510  if (TupIsNull(outerslot))
2511  break;
2512 
2513  /* set up for lookup_hash_entries and advance_aggregates */
2514  tmpcontext->ecxt_outertuple = outerslot;
2515 
2516  /* Find or build hashtable entries */
2517  pergroups = lookup_hash_entries(aggstate);
2518 
2519  /* Advance the aggregates */
2520  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2521  combine_aggregates(aggstate, pergroups[0]);
2522  else
2523  advance_aggregates(aggstate, NULL, pergroups);
2524 
2525  /*
2526  * Reset per-input-tuple context after each tuple, but note that the
2527  * hash lookups do this too
2528  */
2529  ResetExprContext(aggstate->tmpcontext);
2530  }
2531 
2532  aggstate->table_filled = true;
2533  /* Initialize to walk the first hash table */
2534  select_current_set(aggstate, 0, true);
2536  &aggstate->perhash[0].hashiter);
2537 }
static TupleTableSlot * fetch_input_tuple(AggState *aggstate)
Definition: nodeAgg.c:674
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:586
AggSplit aggsplit
Definition: execnodes.h:1800
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:768
ExprContext * tmpcontext
Definition: execnodes.h:1808
static AggStatePerGroup * lookup_hash_entries(AggState *aggstate)
Definition: nodeAgg.c:2078
bool table_filled
Definition: execnodes.h:1827
#define TupIsNull(slot)
Definition: tuptable.h:138
AggStatePerHash perhash
Definition: execnodes.h:1829
TupleHashIterator hashiter
Definition: nodeAgg.c:508
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:632
static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGroup *pergroups)
Definition: nodeAgg.c:968
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
static void combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1109
TupleHashTable hashtable
Definition: nodeAgg.c:507
#define ResetExprContext(econtext)
Definition: executor.h:470
static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

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

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

Definition at line 2543 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, TRUE, TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, and TupleTableSlot::tts_values.

Referenced by agg_retrieve_direct(), and ExecAgg().

2544 {
2545  ExprContext *econtext;
2546  AggStatePerAgg peragg;
2547  AggStatePerGroup pergroup;
2548  TupleHashEntryData *entry;
2549  TupleTableSlot *firstSlot;
2550  TupleTableSlot *result;
2551  AggStatePerHash perhash;
2552 
2553  /*
2554  * get state info from node.
2555  *
2556  * econtext is the per-output-tuple expression context.
2557  */
2558  econtext = aggstate->ss.ps.ps_ExprContext;
2559  peragg = aggstate->peragg;
2560  firstSlot = aggstate->ss.ss_ScanTupleSlot;
2561 
2562  /*
2563  * Note that perhash (and therefore anything accessed through it) can
2564  * change inside the loop, as we change between grouping sets.
2565  */
2566  perhash = &aggstate->perhash[aggstate->current_set];
2567 
2568  /*
2569  * We loop retrieving groups until we find one satisfying
2570  * aggstate->ss.ps.qual
2571  */
2572  while (!aggstate->agg_done)
2573  {
2574  TupleTableSlot *hashslot = perhash->hashslot;
2575  int i;
2576 
2578 
2579  /*
2580  * Find the next entry in the hash table
2581  */
2582  entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);
2583  if (entry == NULL)
2584  {
2585  int nextset = aggstate->current_set + 1;
2586 
2587  if (nextset < aggstate->num_hashes)
2588  {
2589  /*
2590  * Switch to next grouping set, reinitialize, and restart the
2591  * loop.
2592  */
2593  select_current_set(aggstate, nextset, true);
2594 
2595  perhash = &aggstate->perhash[aggstate->current_set];
2596 
2597  ResetTupleHashIterator(perhash->hashtable, &perhash->hashiter);
2598 
2599  continue;
2600  }
2601  else
2602  {
2603  /* No more hashtables, so done */
2604  aggstate->agg_done = TRUE;
2605  return NULL;
2606  }
2607  }
2608 
2609  /*
2610  * Clear the per-output-tuple context for each group
2611  *
2612  * We intentionally don't use ReScanExprContext here; if any aggs have
2613  * registered shutdown callbacks, they mustn't be called yet, since we
2614  * might not be done with that agg.
2615  */
2616  ResetExprContext(econtext);
2617 
2618  /*
2619  * Transform representative tuple back into one with the right
2620  * columns.
2621  */
2622  ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);
2623  slot_getallattrs(hashslot);
2624 
2625  ExecClearTuple(firstSlot);
2626  memset(firstSlot->tts_isnull, true,
2627  firstSlot->tts_tupleDescriptor->natts * sizeof(bool));
2628 
2629  for (i = 0; i < perhash->numhashGrpCols; i++)
2630  {
2631  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
2632 
2633  firstSlot->tts_values[varNumber] = hashslot->tts_values[i];
2634  firstSlot->tts_isnull[varNumber] = hashslot->tts_isnull[i];
2635  }
2636  ExecStoreVirtualTuple(firstSlot);
2637 
2638  pergroup = (AggStatePerGroup) entry->additional;
2639 
2640  /*
2641  * Use the representative input tuple for any references to
2642  * non-aggregated input columns in the qual and tlist.
2643  */
2644  econtext->ecxt_outertuple = firstSlot;
2645 
2646  prepare_projection_slot(aggstate,
2647  econtext->ecxt_outertuple,
2648  aggstate->current_set);
2649 
2650  finalize_aggregates(aggstate, peragg, pergroup);
2651 
2652  result = project_aggregates(aggstate);
2653  if (result)
2654  return result;
2655  }
2656 
2657  /* No more groups */
2658  return NULL;
2659 }
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:1789
#define ScanTupleHashTable(htable, iter)
Definition: execnodes.h:634
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:586
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.c:515
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:384
bool agg_done
Definition: execnodes.h:1812
ScanState ss
Definition: execnodes.h:1795
ExprContext * ps_ExprContext
Definition: execnodes.h:881
MinimalTuple firstTuple
Definition: execnodes.h:589
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
Datum * tts_values
Definition: tuptable.h:125
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1103
static TupleTableSlot * project_aggregates(AggState *aggstate)
Definition: nodeAgg.c:1780
int current_set
Definition: execnodes.h:1814
int natts
Definition: tupdesc.h:73
static void prepare_projection_slot(AggState *aggstate, TupleTableSlot *slot, int currentSet)
Definition: nodeAgg.c:1672
PlanState ps
Definition: execnodes.h:1100
static void finalize_aggregates(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1717
bool * tts_isnull
Definition: tuptable.h:126
AggStatePerHash perhash
Definition: execnodes.h:1829
void slot_getallattrs(TupleTableSlot *slot)
Definition: heaptuple.c:1238
TupleHashIterator hashiter
Definition: nodeAgg.c:508
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:632
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
AggStatePerAgg peragg
Definition: execnodes.h:1804
int i
#define TRUE
Definition: c.h:215
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
TupleTableSlot * hashslot
Definition: nodeAgg.c:509
TupleHashTable hashtable
Definition: nodeAgg.c:507
#define ResetExprContext(econtext)
Definition: executor.h:470
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488
int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

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

4032 {
4033  if (fcinfo->context && IsA(fcinfo->context, AggState))
4034  {
4035  if (aggcontext)
4036  {
4037  AggState *aggstate = ((AggState *) fcinfo->context);
4038  ExprContext *cxt = aggstate->curaggcontext;
4039 
4040  *aggcontext = cxt->ecxt_per_tuple_memory;
4041  }
4042  return AGG_CONTEXT_AGGREGATE;
4043  }
4044  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4045  {
4046  if (aggcontext)
4047  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4048  return AGG_CONTEXT_WINDOW;
4049  }
4050 
4051  /* this is just to prevent "uninitialized variable" warnings */
4052  if (aggcontext)
4053  *aggcontext = NULL;
4054  return 0;
4055 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
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:1809
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:695
Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4068 of file nodeAgg.c.

References AggStatePerTransData::aggref, FunctionCallInfoData::context, and IsA.

Referenced by ordered_set_startup().

4069 {
4070  if (fcinfo->context && IsA(fcinfo->context, AggState))
4071  {
4072  AggStatePerTrans curpertrans;
4073 
4074  curpertrans = ((AggState *) fcinfo->context)->curpertrans;
4075 
4076  if (curpertrans)
4077  return curpertrans->aggref;
4078  }
4079  return NULL;
4080 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
fmNodePtr context
Definition: fmgr.h:80
MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4093 of file nodeAgg.c.

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

Referenced by hypothetical_dense_rank_final().

4094 {
4095  if (fcinfo->context && IsA(fcinfo->context, AggState))
4096  {
4097  AggState *aggstate = (AggState *) fcinfo->context;
4098 
4099  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4100  }
4101  return NULL;
4102 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
fmNodePtr context
Definition: fmgr.h:80
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
ExprContext * tmpcontext
Definition: execnodes.h:1808
Datum aggregate_dummy ( PG_FUNCTION_ARGS  )

Definition at line 4148 of file nodeAgg.c.

References elog, and ERROR.

4149 {
4150  elog(ERROR, "aggregate function %u called as normal function",
4151  fcinfo->flinfo->fn_oid);
4152  return (Datum) 0; /* keep compiler quiet */
4153 }
#define ERROR
Definition: elog.h:43
uintptr_t Datum
Definition: postgres.h:372
#define elog
Definition: elog.h:219
void AggRegisterCallback ( FunctionCallInfo  fcinfo,
ExprContextCallbackFunction  func,
Datum  arg 
)

Definition at line 4120 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4123 {
4124  if (fcinfo->context && IsA(fcinfo->context, AggState))
4125  {
4126  AggState *aggstate = (AggState *) fcinfo->context;
4127  ExprContext *cxt = aggstate->curaggcontext;
4128 
4129  RegisterExprContextCallback(cxt, func, arg);
4130 
4131  return;
4132  }
4133  elog(ERROR, "aggregate function cannot register a callback in this context");
4134 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
fmNodePtr context
Definition: fmgr.h:80
#define ERROR
Definition: elog.h:43
ExprContext * curaggcontext
Definition: execnodes.h:1809
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:737
void * arg
#define elog
Definition: elog.h:219
static void build_hash_table ( AggState aggstate)
static

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

1862 {
1863  MemoryContext tmpmem = aggstate->tmpcontext->ecxt_per_tuple_memory;
1864  Size additionalsize;
1865  int i;
1866 
1867  Assert(aggstate->aggstrategy == AGG_HASHED || aggstate->aggstrategy == AGG_MIXED);
1868 
1869  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1870 
1871  for (i = 0; i < aggstate->num_hashes; ++i)
1872  {
1873  AggStatePerHash perhash = &aggstate->perhash[i];
1874 
1875  Assert(perhash->aggnode->numGroups > 0);
1876 
1877  perhash->hashtable = BuildTupleHashTable(perhash->numCols,
1878  perhash->hashGrpColIdxHash,
1879  perhash->eqfunctions,
1880  perhash->hashfunctions,
1881  perhash->aggnode->numGroups,
1882  additionalsize,
1884  tmpmem,
1885  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1886  }
1887 }
FmgrInfo * eqfunctions
Definition: nodeAgg.c:511
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
AggSplit aggsplit
Definition: execnodes.h:1800
int numtrans
Definition: execnodes.h:1798
ExprContext * tmpcontext
Definition: execnodes.h:1808
AggStrategy aggstrategy
Definition: execnodes.h:1799
AggStatePerHash perhash
Definition: execnodes.h:1829
int num_hashes
Definition: execnodes.h:1828
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.c:516
ExprContext * hashcontext
Definition: execnodes.h:1806
struct AggStatePerGroupData AggStatePerGroupData
FmgrInfo * hashfunctions
Definition: nodeAgg.c:510
#define Assert(condition)
Definition: c.h:664
size_t Size
Definition: c.h:350
long numGroups
Definition: plannodes.h:788
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:769
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:507
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 3410 of file nodeAgg.c.

References AGG_HASHED, AGG_MIXED, AggStatePerTransData::aggCollation, AggStatePerTransData::aggdirectargs, Aggref::aggdirectargs, Aggref::aggdistinct, AggStatePerTransData::aggfilter, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggkind, AGGKIND_IS_ORDERED_SET, Aggref::aggorder, AggStatePerTransData::aggref, 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, ExecInitExpr(), ExecInitExprList(), 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, initValue(), AggStatePerTransData::initValueIsNull, Aggref::inputcollid, AggStatePerTransData::inputtypeByVal, AggStatePerTransData::inputtypeLen, INTERNALOID, InvalidOid, IsBinaryCoercible(), lfirst, list_length(), Max, AggState::maxsets, NIL, SortGroupClause::nulls_first, AggState::numaggs, 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().

3417 {
3418  int numGroupingSets = Max(aggstate->maxsets, 1);
3419  Expr *serialfnexpr = NULL;
3420  Expr *deserialfnexpr = NULL;
3421  ListCell *lc;
3422  int numInputs;
3423  int numDirectArgs;
3424  List *sortlist;
3425  int numSortCols;
3426  int numDistinctCols;
3427  int naggs;
3428  int i;
3429 
3430  /* Begin filling in the pertrans data */
3431  pertrans->aggref = aggref;
3432  pertrans->aggCollation = aggref->inputcollid;
3433  pertrans->transfn_oid = aggtransfn;
3434  pertrans->serialfn_oid = aggserialfn;
3435  pertrans->deserialfn_oid = aggdeserialfn;
3436  pertrans->initValue = initValue;
3437  pertrans->initValueIsNull = initValueIsNull;
3438 
3439  /* Count the "direct" arguments, if any */
3440  numDirectArgs = list_length(aggref->aggdirectargs);
3441 
3442  /* Count the number of aggregated input columns */
3443  pertrans->numInputs = numInputs = list_length(aggref->args);
3444 
3445  pertrans->aggtranstype = aggtranstype;
3446 
3447  /* Detect how many arguments to pass to the transfn */
3448  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3449  pertrans->numTransInputs = numInputs;
3450  else
3451  pertrans->numTransInputs = numArguments;
3452 
3453  /*
3454  * When combining states, we have no use at all for the aggregate
3455  * function's transfn. Instead we use the combinefn. In this case, the
3456  * transfn and transfn_oid fields of pertrans refer to the combine
3457  * function rather than the transition function.
3458  */
3459  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
3460  {
3461  Expr *combinefnexpr;
3462 
3463  build_aggregate_combinefn_expr(aggtranstype,
3464  aggref->inputcollid,
3465  aggtransfn,
3466  &combinefnexpr);
3467  fmgr_info(aggtransfn, &pertrans->transfn);
3468  fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
3469 
3471  &pertrans->transfn,
3472  2,
3473  pertrans->aggCollation,
3474  (void *) aggstate, NULL);
3475 
3476  /*
3477  * Ensure that a combine function to combine INTERNAL states is not
3478  * strict. This should have been checked during CREATE AGGREGATE, but
3479  * the strict property could have been changed since then.
3480  */
3481  if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
3482  ereport(ERROR,
3483  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3484  errmsg("combine function for aggregate %u must be declared as STRICT",
3485  aggref->aggfnoid)));
3486  }
3487  else
3488  {
3489  Expr *transfnexpr;
3490 
3491  /*
3492  * Set up infrastructure for calling the transfn. Note that invtrans
3493  * is not needed here.
3494  */
3495  build_aggregate_transfn_expr(inputTypes,
3496  numArguments,
3497  numDirectArgs,
3498  aggref->aggvariadic,
3499  aggtranstype,
3500  aggref->inputcollid,
3501  aggtransfn,
3502  InvalidOid,
3503  &transfnexpr,
3504  NULL);
3505  fmgr_info(aggtransfn, &pertrans->transfn);
3506  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
3507 
3509  &pertrans->transfn,
3510  pertrans->numTransInputs + 1,
3511  pertrans->aggCollation,
3512  (void *) aggstate, NULL);
3513 
3514  /*
3515  * If the transfn is strict and the initval is NULL, make sure input
3516  * type and transtype are the same (or at least binary-compatible), so
3517  * that it's OK to use the first aggregated input value as the initial
3518  * transValue. This should have been checked at agg definition time,
3519  * but we must check again in case the transfn's strictness property
3520  * has been changed.
3521  */
3522  if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
3523  {
3524  if (numArguments <= numDirectArgs ||
3525  !IsBinaryCoercible(inputTypes[numDirectArgs],
3526  aggtranstype))
3527  ereport(ERROR,
3528  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3529  errmsg("aggregate %u needs to have compatible input type and transition type",
3530  aggref->aggfnoid)));
3531  }
3532  }
3533 
3534  /* get info about the state value's datatype */
3535  get_typlenbyval(aggtranstype,
3536  &pertrans->transtypeLen,
3537  &pertrans->transtypeByVal);
3538 
3539  if (OidIsValid(aggserialfn))
3540  {
3541  build_aggregate_serialfn_expr(aggserialfn,
3542  &serialfnexpr);
3543  fmgr_info(aggserialfn, &pertrans->serialfn);
3544  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
3545 
3547  &pertrans->serialfn,
3548  1,
3549  InvalidOid,
3550  (void *) aggstate, NULL);
3551  }
3552 
3553  if (OidIsValid(aggdeserialfn))
3554  {
3555  build_aggregate_deserialfn_expr(aggdeserialfn,
3556  &deserialfnexpr);
3557  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
3558  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
3559 
3561  &pertrans->deserialfn,
3562  2,
3563  InvalidOid,
3564  (void *) aggstate, NULL);
3565 
3566  }
3567 
3568  /* Initialize the input and FILTER expressions */
3569  naggs = aggstate->numaggs;
3570  pertrans->aggfilter = ExecInitExpr(aggref->aggfilter,
3571  (PlanState *) aggstate);
3572  pertrans->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
3573  (PlanState *) aggstate);
3574 
3575  /*
3576  * Complain if the aggregate's arguments contain any aggregates; nested
3577  * agg functions are semantically nonsensical. (This should have been
3578  * caught earlier, but we defend against it here anyway.)
3579  */
3580  if (naggs != aggstate->numaggs)
3581  ereport(ERROR,
3582  (errcode(ERRCODE_GROUPING_ERROR),
3583  errmsg("aggregate function calls cannot be nested")));
3584 
3585  /*
3586  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
3587  * have a list of SortGroupClause nodes; fish out the data in them and
3588  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
3589  * however; the agg's transfn and finalfn are responsible for that.
3590  *
3591  * Note that by construction, if there is a DISTINCT clause then the ORDER
3592  * BY clause is a prefix of it (see transformDistinctClause).
3593  */
3594  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3595  {
3596  sortlist = NIL;
3597  numSortCols = numDistinctCols = 0;
3598  }
3599  else if (aggref->aggdistinct)
3600  {
3601  sortlist = aggref->aggdistinct;
3602  numSortCols = numDistinctCols = list_length(sortlist);
3603  Assert(numSortCols >= list_length(aggref->aggorder));
3604  }
3605  else
3606  {
3607  sortlist = aggref->aggorder;
3608  numSortCols = list_length(sortlist);
3609  numDistinctCols = 0;
3610  }
3611 
3612  pertrans->numSortCols = numSortCols;
3613  pertrans->numDistinctCols = numDistinctCols;
3614 
3615  if (numSortCols > 0)
3616  {
3617  /*
3618  * Get a tupledesc and slot corresponding to the aggregated inputs
3619  * (including sort expressions) of the agg.
3620  */
3621  pertrans->sortdesc = ExecTypeFromTL(aggref->args, false);
3622  pertrans->sortslot = ExecInitExtraTupleSlot(estate);
3623  ExecSetSlotDescriptor(pertrans->sortslot, pertrans->sortdesc);
3624 
3625  /*
3626  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
3627  * (yet)
3628  */
3629  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
3630 
3631  /* If we have only one input, we need its len/byval info. */
3632  if (numInputs == 1)
3633  {
3634  get_typlenbyval(inputTypes[numDirectArgs],
3635  &pertrans->inputtypeLen,
3636  &pertrans->inputtypeByVal);
3637  }
3638  else if (numDistinctCols > 0)
3639  {
3640  /* we will need an extra slot to store prior values */
3641  pertrans->uniqslot = ExecInitExtraTupleSlot(estate);
3642  ExecSetSlotDescriptor(pertrans->uniqslot,
3643  pertrans->sortdesc);
3644  }
3645 
3646  /* Extract the sort information for use later */
3647  pertrans->sortColIdx =
3648  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
3649  pertrans->sortOperators =
3650  (Oid *) palloc(numSortCols * sizeof(Oid));
3651  pertrans->sortCollations =
3652  (Oid *) palloc(numSortCols * sizeof(Oid));
3653  pertrans->sortNullsFirst =
3654  (bool *) palloc(numSortCols * sizeof(bool));
3655 
3656  i = 0;
3657  foreach(lc, sortlist)
3658  {
3659  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
3660  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
3661 
3662  /* the parser should have made sure of this */
3663  Assert(OidIsValid(sortcl->sortop));
3664 
3665  pertrans->sortColIdx[i] = tle->resno;
3666  pertrans->sortOperators[i] = sortcl->sortop;
3667  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
3668  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
3669  i++;
3670  }
3671  Assert(i == numSortCols);
3672  }
3673 
3674  if (aggref->aggdistinct)
3675  {
3676  Assert(numArguments > 0);
3677 
3678  /*
3679  * We need the equal function for each DISTINCT comparison we will
3680  * make.
3681  */
3682  pertrans->equalfns =
3683  (FmgrInfo *) palloc(numDistinctCols * sizeof(FmgrInfo));
3684 
3685  i = 0;
3686  foreach(lc, aggref->aggdistinct)
3687  {
3688  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
3689 
3690  fmgr_info(get_opcode(sortcl->eqop), &pertrans->equalfns[i]);
3691  i++;
3692  }
3693  Assert(i == numDistinctCols);
3694  }
3695 
3696  pertrans->sortstates = (Tuplesortstate **)
3697  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
3698 }
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
int numaggs
Definition: execnodes.h:1797
Oid inputcollid
Definition: primnodes.h:297
Definition: nodes.h:509
AggSplit aggsplit
Definition: execnodes.h:1800
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:532
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:768
TupleDesc sortdesc
Definition: nodeAgg.c:356
FmgrInfo transfn
Definition: nodeAgg.c:301
FunctionCallInfoData transfn_fcinfo
Definition: nodeAgg.c:388
#define AGGKIND_IS_ORDERED_SET(kind)
Definition: pg_aggregate.h:129
int maxsets
Definition: execnodes.h:1818
AggStrategy aggstrategy
Definition: execnodes.h:1799
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
Tuplesortstate ** sortstates
Definition: nodeAgg.c:380
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:1369
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:266
List * aggdirectargs
Definition: primnodes.h:300
AttrNumber * sortColIdx
Definition: nodeAgg.c:320
#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:391
FmgrInfo deserialfn
Definition: nodeAgg.c:307
#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:789
#define Assert(condition)
Definition: c.h:664
#define lfirst(lc)
Definition: pg_list.h:106
FmgrInfo serialfn
Definition: nodeAgg.c:304
void build_aggregate_serialfn_expr(Oid serialfn_oid, Expr **serialfnexpr)
Definition: parse_agg.c:1972
Expr * expr
Definition: primnodes.h:1368
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:364
ExprState * aggfilter
Definition: nodeAgg.c:294
void * palloc(Size size)
Definition: mcxt.c:848
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
FmgrInfo * equalfns
Definition: nodeAgg.c:330
char aggkind
Definition: primnodes.h:308
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:113
TupleTableSlot * sortslot
Definition: nodeAgg.c:363
List * aggdirectargs
Definition: nodeAgg.c:295
FunctionCallInfoData deserialfn_fcinfo
Definition: nodeAgg.c:393
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
bool * sortNullsFirst
Definition: nodeAgg.c:323
static void combine_aggregates ( AggState aggstate,
AggStatePerGroup  pergroup 
)
static

Definition at line 1109 of file nodeAgg.c.

References advance_combine_function(), FunctionCallInfoData::arg, FunctionCallInfoData::argnull, Assert, AggStatePerTransData::deserialfn, AggStatePerTransData::deserialfn_fcinfo, AggStatePerTransData::deserialfn_oid, ExprContext::ecxt_per_tuple_memory, AggState::evalproj, 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().

1110 {
1111  int transno;
1112  int numTrans = aggstate->numtrans;
1113  TupleTableSlot *slot;
1114 
1115  /* combine not supported with grouping sets */
1116  Assert(aggstate->phase->numsets <= 1);
1117 
1118  /* compute input for all aggregates */
1119  slot = ExecProject(aggstate->evalproj);
1120 
1121  for (transno = 0; transno < numTrans; transno++)
1122  {
1123  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1124  AggStatePerGroup pergroupstate = &pergroup[transno];
1125  FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo;
1126  int inputoff = pertrans->inputoff;
1127 
1128  Assert(slot->tts_nvalid > inputoff);
1129 
1130  /*
1131  * deserialfn_oid will be set if we must deserialize the input state
1132  * before calling the combine function
1133  */
1134  if (OidIsValid(pertrans->deserialfn_oid))
1135  {
1136  /* Don't call a strict deserialization function with NULL input */
1137  if (pertrans->deserialfn.fn_strict && slot->tts_isnull[inputoff])
1138  {
1139  fcinfo->arg[1] = slot->tts_values[inputoff];
1140  fcinfo->argnull[1] = slot->tts_isnull[inputoff];
1141  }
1142  else
1143  {
1144  FunctionCallInfo dsinfo = &pertrans->deserialfn_fcinfo;
1145  MemoryContext oldContext;
1146 
1147  dsinfo->arg[0] = slot->tts_values[inputoff];
1148  dsinfo->argnull[0] = slot->tts_isnull[inputoff];
1149  /* Dummy second argument for type-safety reasons */
1150  dsinfo->arg[1] = PointerGetDatum(NULL);
1151  dsinfo->argnull[1] = false;
1152 
1153  /*
1154  * We run the deserialization functions in per-input-tuple
1155  * memory context.
1156  */
1157  oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
1158 
1159  fcinfo->arg[1] = FunctionCallInvoke(dsinfo);
1160  fcinfo->argnull[1] = dsinfo->isnull;
1161 
1162  MemoryContextSwitchTo(oldContext);
1163  }
1164  }
1165  else
1166  {
1167  fcinfo->arg[1] = slot->tts_values[inputoff];
1168  fcinfo->argnull[1] = slot->tts_isnull[inputoff];
1169  }
1170 
1171  advance_combine_function(aggstate, pertrans, pergroupstate);
1172  }
1173 }
#define PointerGetDatum(X)
Definition: postgres.h:562
ProjectionInfo * evalproj
Definition: execnodes.h:1833
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:1805
#define OidIsValid(objectId)
Definition: c.h:532
int numtrans
Definition: execnodes.h:1798
ExprContext * tmpcontext
Definition: execnodes.h:1808
FunctionCallInfoData transfn_fcinfo
Definition: nodeAgg.c:388
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
static void advance_combine_function(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:1185
AggStatePerPhase phase
Definition: execnodes.h:1801
FmgrInfo deserialfn
Definition: nodeAgg.c:307
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
#define Assert(condition)
Definition: c.h:664
FunctionCallInfoData deserialfn_fcinfo
Definition: nodeAgg.c:393
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:329
static TupleTableSlot* ExecAgg ( PlanState pstate)
static

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

2108 {
2109  AggState *node = castNode(AggState, pstate);
2110  TupleTableSlot *result = NULL;
2111 
2113 
2114  if (!node->agg_done)
2115  {
2116  /* Dispatch based on strategy */
2117  switch (node->phase->aggstrategy)
2118  {
2119  case AGG_HASHED:
2120  if (!node->table_filled)
2121  agg_fill_hash_table(node);
2122  /* FALLTHROUGH */
2123  case AGG_MIXED:
2124  result = agg_retrieve_hash_table(node);
2125  break;
2126  case AGG_PLAIN:
2127  case AGG_SORTED:
2128  result = agg_retrieve_direct(node);
2129  break;
2130  }
2131 
2132  if (!TupIsNull(result))
2133  return result;
2134  }
2135 
2136  return NULL;
2137 }
static void agg_fill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2496
bool agg_done
Definition: execnodes.h:1812
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
bool table_filled
Definition: execnodes.h:1827
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2543
static TupleTableSlot * agg_retrieve_direct(AggState *aggstate)
Definition: nodeAgg.c:2143
#define TupIsNull(slot)
Definition: tuptable.h:138
AggStrategy aggstrategy
Definition: nodeAgg.c:489
AggStatePerPhase phase
Definition: execnodes.h:1801
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
void ExecEndAgg ( AggState node)

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

3851 {
3853  int transno;
3854  int numGroupingSets = Max(node->maxsets, 1);
3855  int setno;
3856 
3857  /* Make sure we have closed any open tuplesorts */
3858 
3859  if (node->sort_in)
3860  tuplesort_end(node->sort_in);
3861  if (node->sort_out)
3862  tuplesort_end(node->sort_out);
3863 
3864  for (transno = 0; transno < node->numtrans; transno++)
3865  {
3866  AggStatePerTrans pertrans = &node->pertrans[transno];
3867 
3868  for (setno = 0; setno < numGroupingSets; setno++)
3869  {
3870  if (pertrans->sortstates[setno])
3871  tuplesort_end(pertrans->sortstates[setno]);
3872  }
3873  }
3874 
3875  /* And ensure any agg shutdown callbacks have been called */
3876  for (setno = 0; setno < numGroupingSets; setno++)
3877  ReScanExprContext(node->aggcontexts[setno]);
3878  if (node->hashcontext)
3880 
3881  /*
3882  * We don't actually free any ExprContexts here (see comment in
3883  * ExecFreeExprContext), just unlinking the output one from the plan node
3884  * suffices.
3885  */
3886  ExecFreeExprContext(&node->ss.ps);
3887 
3888  /* clean up tuple table */
3890 
3891  outerPlan = outerPlanState(node);
3892  ExecEndNode(outerPlan);
3893 }
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:523
Tuplesortstate * sort_out
Definition: execnodes.h:1821
ScanState ss
Definition: execnodes.h:1795
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1103
AggStatePerTrans pertrans
Definition: execnodes.h:1805
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:521
int numtrans
Definition: execnodes.h:1798
PlanState ps
Definition: execnodes.h:1100
int maxsets
Definition: execnodes.h:1818
Tuplesortstate * sort_in
Definition: execnodes.h:1820
#define outerPlanState(node)
Definition: execnodes.h:893
Tuplesortstate ** sortstates
Definition: nodeAgg.c:380
#define outerPlan(node)
Definition: plannodes.h:174
ExprContext * hashcontext
Definition: execnodes.h:1806
#define Max(x, y)
Definition: c.h:789
ExprContext ** aggcontexts
Definition: execnodes.h:1807
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:381
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1167
AggState* ExecInitAgg ( Agg node,
EState estate,
int  eflags 
)

Definition at line 2670 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, AGGFNOID, Aggref::aggfnoid, Aggref::agglevelsup, AggrefExprState::aggno, AggStatePerPhaseData::aggnode, AggStatePerHashData::aggnode, AggStatePerTransData::aggref, AggStatePerAggData::aggref, AggrefExprState::aggref, AggState::aggs, Aggref::aggsplit, Agg::aggsplit, AggState::aggsplit, AggStatePerPhaseData::aggstrategy, Agg::aggstrategy, AggState::aggstrategy, Aggref::aggtranstype, Aggref::aggtype, AggState::all_grouped_cols, 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::curpertrans, AggState::current_phase, AggState::current_set, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_DESERIALIZE, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, elog, AggStatePerPhaseData::eqfunctions, AggStatePerHashData::eqfunctions, ERROR, AggState::evaldesc, AggState::evalproj, AggState::evalslot, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, EXEC_FLAG_REWIND, ExecAgg(), ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecAssignResultTypeFromTL(), ExecAssignScanTypeFromOuterPlan(), ExecBuildProjectionInfo(), 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::hash_pergroup, AggState::hashcontext, AggStatePerHashData::hashfunctions, AggStatePerHashData::hashslot, HeapTupleIsValid, i, initialize_phase(), initValue(), AggState::input_done, Aggref::inputcollid, AggStatePerTransData::inputoff, INTERNALOID, InvalidOid, InvokeFunctionExecuteHook, lappend(), lcons_int(), Plan::lefttree, lfirst, lfirst_node, list_length(), list_nth_node, makeNode, Max, AggState::maxsets, NIL, AggState::num_hashes, 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::perhash, AggState::pertrans, pg_proc_aclcheck(), AggState::phases, 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(), AggState::sort_in, AggState::sort_out, AggState::sort_slot, AggStatePerPhaseData::sortnode, AggState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, SysCacheGetAttr(), AggState::table_filled, AggState::tmpcontext, AggStatePerAggData::transno, and TupleTableSlot::tts_tupleDescriptor.

Referenced by ExecInitNode().

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

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

3897 {
3898  ExprContext *econtext = node->ss.ps.ps_ExprContext;
3900  Agg *aggnode = (Agg *) node->ss.ps.plan;
3901  int transno;
3902  int numGroupingSets = Max(node->maxsets, 1);
3903  int setno;
3904 
3905  node->agg_done = false;
3906 
3907  if (node->aggstrategy == AGG_HASHED)
3908  {
3909  /*
3910  * In the hashed case, if we haven't yet built the hash table then we
3911  * can just return; nothing done yet, so nothing to undo. If subnode's
3912  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
3913  * else no reason to re-scan it at all.
3914  */
3915  if (!node->table_filled)
3916  return;
3917 
3918  /*
3919  * If we do have the hash table, and the subplan does not have any
3920  * parameter changes, and none of our own parameter changes affect
3921  * input expressions of the aggregated functions, then we can just
3922  * rescan the existing hash table; no need to build it again.
3923  */
3924  if (outerPlan->chgParam == NULL &&
3925  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
3926  {
3928  &node->perhash[0].hashiter);
3929  select_current_set(node, 0, true);
3930  return;
3931  }
3932  }
3933 
3934  /* Make sure we have closed any open tuplesorts */
3935  for (transno = 0; transno < node->numtrans; transno++)
3936  {
3937  for (setno = 0; setno < numGroupingSets; setno++)
3938  {
3939  AggStatePerTrans pertrans = &node->pertrans[transno];
3940 
3941  if (pertrans->sortstates[setno])
3942  {
3943  tuplesort_end(pertrans->sortstates[setno]);
3944  pertrans->sortstates[setno] = NULL;
3945  }
3946  }
3947  }
3948 
3949  /*
3950  * We don't need to ReScanExprContext the output tuple context here;
3951  * ExecReScan already did it. But we do need to reset our per-grouping-set
3952  * contexts, which may have transvalues stored in them. (We use rescan
3953  * rather than just reset because transfns may have registered callbacks
3954  * that need to be run now.) For the AGG_HASHED case, see below.
3955  */
3956 
3957  for (setno = 0; setno < numGroupingSets; setno++)
3958  {
3959  ReScanExprContext(node->aggcontexts[setno]);
3960  }
3961 
3962  /* Release first tuple of group, if we have made a copy */
3963  if (node->grp_firstTuple != NULL)
3964  {
3966  node->grp_firstTuple = NULL;
3967  }
3969 
3970  /* Forget current agg values */
3971  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
3972  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
3973 
3974  /*
3975  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
3976  * the hashcontext. This used to be an issue, but now, resetting a context
3977  * automatically deletes sub-contexts too.
3978  */
3979  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
3980  {
3982  /* Rebuild an empty hash table */
3983  build_hash_table(node);
3984  node->table_filled = false;
3985  /* iterator will be reset when the table is filled */
3986  }
3987 
3988  if (node->aggstrategy != AGG_HASHED)
3989  {
3990  /*
3991  * Reset the per-group state (in particular, mark transvalues null)
3992  */
3993  MemSet(node->pergroup, 0,
3994  sizeof(AggStatePerGroupData) * node->numaggs * numGroupingSets);
3995 
3996  /* reset to phase 1 */
3997  initialize_phase(node, 1);
3998 
3999  node->input_done = false;
4000  node->projected_set = -1;
4001  }
4002 
4003  if (outerPlan->chgParam == NULL)
4004  ExecReScan(outerPlan);
4005 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:586
Datum * ecxt_aggvalues
Definition: execnodes.h:213
int numaggs
Definition: execnodes.h:1797
bool agg_done
Definition: execnodes.h:1812
ScanState ss
Definition: execnodes.h:1795
ExprContext * ps_ExprContext
Definition: execnodes.h:881
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define MemSet(start, val, len)
Definition: c.h:846
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1103
AggStatePerTrans pertrans
Definition: execnodes.h:1805
int projected_set
Definition: execnodes.h:1813
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
HeapTuple grp_firstTuple
Definition: execnodes.h:1825
int numtrans
Definition: execnodes.h:1798
PlanState ps
Definition: execnodes.h:1100
int maxsets
Definition: execnodes.h:1818
bool table_filled
Definition: execnodes.h:1827
AggStrategy aggstrategy
Definition: execnodes.h:1799
#define outerPlanState(node)
Definition: execnodes.h:893
Tuplesortstate ** sortstates
Definition: nodeAgg.c:380
Bitmapset * aggParams
Definition: plannodes.h:789
static void build_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1861
AggStatePerHash perhash
Definition: execnodes.h:1829
Bitmapset * chgParam
Definition: execnodes.h:875
#define outerPlan(node)
Definition: plannodes.h:174
TupleHashIterator hashiter
Definition: nodeAgg.c:508
bool input_done
Definition: execnodes.h:1811
ExprContext * hashcontext
Definition: execnodes.h:1806
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
AggStatePerGroup pergroup
Definition: execnodes.h:1824
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:604
Plan * plan
Definition: execnodes.h:847
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:632
#define Max(x, y)
Definition: c.h:789
ExprContext ** aggcontexts
Definition: execnodes.h:1807
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:381
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:1167
TupleHashTable hashtable
Definition: nodeAgg.c:507
static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

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

675 {
676  TupleTableSlot *slot;
677 
678  if (aggstate->sort_in)
679  {
680  /* make sure we check for interrupts in either path through here */
682  if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
683  aggstate->sort_slot, NULL))
684  return NULL;
685  slot = aggstate->sort_slot;
686  }
687  else
688  slot = ExecProcNode(outerPlanState(aggstate));
689 
690  if (!TupIsNull(slot) && aggstate->sort_out)
691  tuplesort_puttupleslot(aggstate->sort_out, slot);
692 
693  return slot;
694 }
TupleTableSlot * sort_slot
Definition: execnodes.h:1822
Tuplesortstate * sort_out
Definition: execnodes.h:1821
Tuplesortstate * sort_in
Definition: execnodes.h:1820
#define outerPlanState(node)
Definition: execnodes.h:893
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2113
#define TupIsNull(slot)
Definition: tuptable.h:138
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:246
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1364
static void finalize_aggregate ( AggState aggstate,
AggStatePerAgg  peragg,
AggStatePerGroup  pergroupstate,
Datum resultVal,
bool resultIsNull 
)
static

Definition at line 1492 of file nodeAgg.c.

References AggStatePerTransData::aggCollation, AggStatePerTransData::aggdirectargs, FunctionCallInfoData::arg, FunctionCallInfoData::argnull, AggState::curpertrans, 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().

1496 {
1497  FunctionCallInfoData fcinfo;
1498  bool anynull = false;
1499  MemoryContext oldContext;
1500  int i;
1501  ListCell *lc;
1502  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1503 
1505 
1506  /*
1507  * Evaluate any direct arguments. We do this even if there's no finalfn
1508  * (which is unlikely anyway), so that side-effects happen as expected.
1509  * The direct arguments go into arg positions 1 and up, leaving position 0
1510  * for the transition state value.
1511  */
1512  i = 1;
1513  foreach(lc, pertrans->aggdirectargs)
1514  {
1515  ExprState *expr = (ExprState *) lfirst(lc);
1516 
1517  fcinfo.arg[i] = ExecEvalExpr(expr,
1518  aggstate->ss.ps.ps_ExprContext,
1519  &fcinfo.argnull[i]);
1520  anynull |= fcinfo.argnull[i];
1521  i++;
1522  }
1523 
1524  /*
1525  * Apply the agg's finalfn if one is provided, else return transValue.
1526  */
1527  if (OidIsValid(peragg->finalfn_oid))
1528  {
1529  int numFinalArgs = peragg->numFinalArgs;
1530 
1531  /* set up aggstate->curpertrans for AggGetAggref() */
1532  aggstate->curpertrans = pertrans;
1533 
1534  InitFunctionCallInfoData(fcinfo, &peragg->finalfn,
1535  numFinalArgs,
1536  pertrans->aggCollation,
1537  (void *) aggstate, NULL);
1538 
1539  /* Fill in the transition state value */
1540  fcinfo.arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
1541  pergroupstate->transValueIsNull,
1542  pertrans->transtypeLen);
1543  fcinfo.argnull[0] = pergroupstate->transValueIsNull;
1544  anynull |= pergroupstate->transValueIsNull;
1545 
1546  /* Fill any remaining argument positions with nulls */
1547  for (; i < numFinalArgs; i++)
1548  {
1549  fcinfo.arg[i] = (Datum) 0;
1550  fcinfo.argnull[i] = true;
1551  anynull = true;
1552  }
1553 
1554  if (fcinfo.flinfo->fn_strict && anynull)
1555  {
1556  /* don't call a strict function with NULL inputs */
1557  *resultVal = (Datum) 0;
1558  *resultIsNull = true;
1559  }
1560  else
1561  {
1562  *resultVal = FunctionCallInvoke(&fcinfo);
1563  *resultIsNull = fcinfo.isnull;
1564  }
1565  aggstate->curpertrans = NULL;
1566  }
1567  else
1568  {
1569  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1570  *resultVal = pergroupstate->transValue;
1571  *resultIsNull = pergroupstate->transValueIsNull;
1572  }
1573 
1574  /*
1575  * If result is pass-by-ref, make sure it is in the right context.
1576  */
1577  if (!peragg->resulttypeByVal && !*resultIsNull &&
1579  DatumGetPointer(*resultVal)))
1580  *resultVal = datumCopy(*resultVal,
1581  peragg->resulttypeByVal,
1582  peragg->resulttypeLen);
1583 
1584  MemoryContextSwitchTo(oldContext);
1585 }
ScanState ss
Definition: execnodes.h:1795
ExprContext * ps_ExprContext
Definition: execnodes.h:881
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:1805
#define OidIsValid(objectId)
Definition: c.h:532
PlanState ps
Definition: execnodes.h:1100
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:286
#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
int16 resulttypeLen
Definition: nodeAgg.c:439
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
AggStatePerTrans curpertrans
Definition: execnodes.h:1810
bool resulttypeByVal
Definition: nodeAgg.c:440
List * aggdirectargs
Definition: nodeAgg.c:295
FmgrInfo finalfn
Definition: nodeAgg.c:425
static void finalize_aggregates ( AggState aggstate,
AggStatePerAgg  peragg,
AggStatePerGroup  pergroup 
)
static

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

1720 {
1721  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1722  Datum *aggvalues = econtext->ecxt_aggvalues;
1723  bool *aggnulls = econtext->ecxt_aggnulls;
1724  int aggno;
1725  int transno;
1726 
1727  /*
1728  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1729  * inputs and run the transition functions.
1730  */
1731  for (transno = 0; transno < aggstate->numtrans; transno++)
1732  {
1733  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1734  AggStatePerGroup pergroupstate;
1735 
1736  pergroupstate = &pergroup[transno];
1737 
1738  if (pertrans->numSortCols > 0)
1739  {
1740  Assert(aggstate->aggstrategy != AGG_HASHED &&
1741  aggstate->aggstrategy != AGG_MIXED);
1742 
1743  if (pertrans->numInputs == 1)
1745  pertrans,
1746  pergroupstate);
1747  else
1749  pertrans,
1750  pergroupstate);
1751  }
1752  }
1753 
1754  /*
1755  * Run the final functions.
1756  */
1757  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1758  {
1759  AggStatePerAgg peragg = &peraggs[aggno];
1760  int transno = peragg->transno;
1761  AggStatePerGroup pergroupstate;
1762 
1763  pergroupstate = &pergroup[transno];
1764 
1765  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1766  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1767  &aggvalues[aggno], &aggnulls[aggno]);
1768  else
1769  finalize_aggregate(aggstate, peragg, pergroupstate,
1770  &aggvalues[aggno], &aggnulls[aggno]);
1771  }
1772 }
Datum * ecxt_aggvalues
Definition: execnodes.h:213
int numaggs
Definition: execnodes.h:1797
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1594
ScanState ss
Definition: execnodes.h:1795
ExprContext * ps_ExprContext
Definition: execnodes.h:881
AggSplit aggsplit
Definition: execnodes.h:1800
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1492
AggStatePerTrans pertrans
Definition: execnodes.h:1805
int numtrans
Definition: execnodes.h:1798
PlanState ps
Definition: execnodes.h:1100
AggStrategy aggstrategy
Definition: execnodes.h:1799
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:1399
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
#define Assert(condition)
Definition: c.h:664
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:769
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:1306
static void finalize_partialaggregate ( AggState aggstate,
AggStatePerAgg  peragg,
AggStatePerGroup  pergroupstate,
Datum resultVal,
bool resultIsNull 
)
static

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

1598 {
1599  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1600  MemoryContext oldContext;
1601 
1603 
1604  /*
1605  * serialfn_oid will be set if we must serialize the transvalue before
1606  * returning it
1607  */
1608  if (OidIsValid(pertrans->serialfn_oid))
1609  {
1610  /* Don't call a strict serialization function with NULL input. */
1611  if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
1612  {
1613  *resultVal = (Datum) 0;
1614  *resultIsNull = true;
1615  }
1616  else
1617  {
1618  FunctionCallInfo fcinfo = &pertrans->serialfn_fcinfo;
1619 
1620  fcinfo->arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
1621  pergroupstate->transValueIsNull,
1622  pertrans->transtypeLen);
1623  fcinfo->argnull[0] = pergroupstate->transValueIsNull;
1624 
1625  *resultVal = FunctionCallInvoke(fcinfo);
1626  *resultIsNull = fcinfo->isnull;
1627  }
1628  }
1629  else
1630  {
1631  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1632  *resultVal = pergroupstate->transValue;
1633  *resultIsNull = pergroupstate->transValueIsNull;
1634  }
1635 
1636  /* If result is pass-by-ref, make sure it is in the right context. */
1637  if (!peragg->resulttypeByVal && !*resultIsNull &&
1639  DatumGetPointer(*resultVal)))
1640  *resultVal = datumCopy(*resultVal,
1641  peragg->resulttypeByVal,
1642  peragg->resulttypeLen);
1643 
1644  MemoryContextSwitchTo(oldContext);
1645 }
ScanState ss
Definition: execnodes.h:1795
ExprContext * ps_ExprContext
Definition: execnodes.h:881
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:1805
#define OidIsValid(objectId)
Definition: c.h:532
PlanState ps
Definition: execnodes.h:1100
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:391
int16 resulttypeLen
Definition: nodeAgg.c:439
Datum arg[FUNC_MAX_ARGS]
Definition: fmgr.h:85
FmgrInfo serialfn
Definition: nodeAgg.c:304
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:566
#define DatumGetPointer(X)
Definition: postgres.h:555
bool resulttypeByVal
Definition: nodeAgg.c:440
static int find_compatible_peragg ( Aggref newagg,
AggState aggstate,
int  lastaggno,
List **  same_input_transnos 
)
static

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

Referenced by ExecInitAgg().

3732 {
3733  int aggno;
3734  AggStatePerAgg peraggs;
3735 
3736  *same_input_transnos = NIL;
3737 
3738  /* we mustn't reuse the aggref if it contains volatile function calls */
3739  if (contain_volatile_functions((Node *) newagg))
3740  return -1;
3741 
3742  peraggs = aggstate->peragg;
3743 
3744  /*
3745  * Search through the list of already seen aggregates. If we find an
3746  * existing aggregate with the same aggregate function and input
3747  * parameters as an existing one, then we can re-use that one. While
3748  * searching, we'll also collect a list of Aggrefs with the same input
3749  * parameters. If no matching Aggref is found, the caller can potentially
3750  * still re-use the transition state of one of them.
3751  */
3752  for (aggno = 0; aggno <= lastaggno; aggno++)
3753  {
3754  AggStatePerAgg peragg;
3755  Aggref *existingRef;
3756 
3757  peragg = &peraggs[aggno];
3758  existingRef = peragg->aggref;
3759 
3760  /* all of the following must be the same or it's no match */
3761  if (newagg->inputcollid != existingRef->inputcollid ||
3762  newagg->aggtranstype != existingRef->aggtranstype ||
3763  newagg->aggstar != existingRef->aggstar ||
3764  newagg->aggvariadic != existingRef->aggvariadic ||
3765  newagg->aggkind != existingRef->aggkind ||
3766  !equal(newagg->aggdirectargs, existingRef->aggdirectargs) ||
3767  !equal(newagg->args, existingRef->args) ||
3768  !equal(newagg->aggorder, existingRef->aggorder) ||
3769  !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
3770  !equal(newagg->aggfilter, existingRef->aggfilter))
3771  continue;
3772 
3773  /* if it's the same aggregate function then report exact match */
3774  if (newagg->aggfnoid == existingRef->aggfnoid &&
3775  newagg->aggtype == existingRef->aggtype &&
3776  newagg->aggcollid == existingRef->aggcollid)
3777  {
3778  list_free(*same_input_transnos);
3779  *same_input_transnos = NIL;
3780  return aggno;
3781  }
3782 
3783  /*
3784  * Not identical, but it had the same inputs. Return it to the caller,
3785  * in case we can re-use its per-trans state.
3786  */
3787  *same_input_transnos = lappend_int(*same_input_transnos,
3788  peragg->transno);
3789  }
3790 
3791  return -1;
3792 }
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:2964
Oid inputcollid
Definition: primnodes.h:297
Definition: nodes.h:509
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:413
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:1804
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
static int find_compatible_pertrans ( AggState aggstate,
Aggref newagg,
Oid  aggtransfn,
Oid  aggtranstype,
Oid  aggserialfn,
Oid  aggdeserialfn,
Datum  initValue,
bool  initValueIsNull,
List transnos 
)
static

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

3808 {
3809  ListCell *lc;
3810 
3811  foreach(lc, transnos)
3812  {
3813  int transno = lfirst_int(lc);
3814  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3815 
3816  /*
3817  * if the transfns or transition state types are not the same then the
3818  * state can't be shared.
3819  */
3820  if (aggtransfn != pertrans->transfn_oid ||
3821  aggtranstype != pertrans->aggtranstype)
3822  continue;
3823 
3824  /*
3825  * The serialization and deserialization functions must match, if
3826  * present, as we're unable to share the trans state for aggregates
3827  * which will serialize or deserialize into different formats.
3828  * Remember that these will be InvalidOid if they're not required for
3829  * this agg node.
3830  */
3831  if (aggserialfn != pertrans->serialfn_oid ||
3832  aggdeserialfn != pertrans->deserialfn_oid)
3833  continue;
3834 
3835  /* Check that the initial condition matches, too. */
3836  if (initValueIsNull && pertrans->initValueIsNull)
3837  return transno;
3838 
3839  if (!initValueIsNull && !pertrans->initValueIsNull &&
3840  datumIsEqual(initValue, pertrans->initValue,
3841  pertrans->transtypeByVal, pertrans->transtypeLen))
3842  {
3843  return transno;
3844  }
3845  }
3846  return -1;
3847 }
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:219
AggStatePerTrans pertrans
Definition: execnodes.h:1805
#define lfirst_int(lc)
Definition: pg_list.h:107
static int initValue(long lng_val)
Definition: informix.c:702
static void find_hash_columns ( AggState aggstate)
static

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

1911 {
1912  Bitmapset *base_colnos;
1913  List *outerTlist = outerPlanState(aggstate)->plan->targetlist;
1914  int numHashes = aggstate->num_hashes;
1915  int j;
1916 
1917  /* Find Vars that will be needed in tlist and qual */
1918  base_colnos = find_unaggregated_cols(aggstate);
1919 
1920  for (j = 0; j < numHashes; ++j)
1921  {
1922  AggStatePerHash perhash = &aggstate->perhash[j];
1923  Bitmapset *colnos = bms_copy(base_colnos);
1924  AttrNumber *grpColIdx = perhash->aggnode->grpColIdx;
1925  List *hashTlist = NIL;
1926  TupleDesc hashDesc;
1927  int i;
1928 
1929  perhash->largestGrpColIdx = 0;
1930 
1931  /*
1932  * If we're doing grouping sets, then some Vars might be referenced in
1933  * tlist/qual for the benefit of other grouping sets, but not needed
1934  * when hashing; i.e. prepare_projection_slot will null them out, so
1935  * there'd be no point storing them. Use prepare_projection_slot's
1936  * logic to determine which.
1937  */
1938  if (aggstate->phases[0].grouped_cols)
1939  {
1940  Bitmapset *grouped_cols = aggstate->phases[0].grouped_cols[j];
1941  ListCell *lc;
1942 
1943  foreach(lc, aggstate->all_grouped_cols)
1944  {
1945  int attnum = lfirst_int(lc);
1946 
1947  if (!bms_is_member(attnum, grouped_cols))
1948  colnos = bms_del_member(colnos, attnum);
1949  }
1950  }
1951  /* Add in all the grouping columns */
1952  for (i = 0; i < perhash->numCols; i++)
1953  colnos = bms_add_member(colnos, grpColIdx[i]);
1954 
1955  perhash->hashGrpColIdxInput =
1956  palloc(bms_num_members(colnos) * sizeof(AttrNumber));
1957  perhash->hashGrpColIdxHash =
1958  palloc(perhash->numCols * sizeof(AttrNumber));
1959 
1960  /*
1961  * First build mapping for columns directly hashed. These are the
1962  * first, because they'll be accessed when computing hash values and
1963  * comparing tuples for exact matches. We also build simple mapping
1964  * for execGrouping, so it knows where to find the to-be-hashed /
1965  * compared columns in the input.
1966  */
1967  for (i = 0; i < perhash->numCols; i++)
1968  {
1969  perhash->hashGrpColIdxInput[i] = grpColIdx[i];
1970  perhash->hashGrpColIdxHash[i] = i + 1;
1971  perhash->numhashGrpCols++;
1972  /* delete already mapped columns */
1973  bms_del_member(colnos, grpColIdx[i]);
1974  }
1975 
1976  /* and add the remaining columns */
1977  while ((i = bms_first_member(colnos)) >= 0)
1978  {
1979  perhash->hashGrpColIdxInput[perhash->numhashGrpCols] = i;
1980  perhash->numhashGrpCols++;
1981  }
1982 
1983  /* and build a tuple descriptor for the hashtable */
1984  for (i = 0; i < perhash->numhashGrpCols; i++)
1985  {
1986  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
1987 
1988  hashTlist = lappend(hashTlist, list_nth(outerTlist, varNumber));
1989  perhash->largestGrpColIdx =
1990  Max(varNumber + 1, perhash->largestGrpColIdx);
1991  }
1992 
1993  hashDesc = ExecTypeFromTL(hashTlist, false);
1994  ExecSetSlotDescriptor(perhash->hashslot, hashDesc);
1995 
1996  list_free(hashTlist);
1997  bms_free(colnos);
1998  }
1999 
2000  bms_free(base_colnos);
2001 }
#define NIL
Definition: pg_list.h:69
int bms_first_member(Bitmapset *a)
Definition: bitmapset.c:885
AggStatePerPhase phases
Definition: execnodes.h:1819
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.c:515
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:111
AttrNumber * grpColIdx
Definition: plannodes.h:786
List * all_grouped_cols
Definition: execnodes.h:1816
Bitmapset ** grouped_cols
Definition: nodeAgg.c:492
#define lfirst_int(lc)
Definition: pg_list.h:107
#define outerPlanState(node)
Definition: execnodes.h:893
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:1829
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:1828
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.c:516
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:789
static Bitmapset * find_unaggregated_cols(AggState *aggstate)
Definition: nodeAgg.c:1807
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:509
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
static Bitmapset * find_unaggregated_cols ( AggState aggstate)
static

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

1808 {
1809  Agg *node = (Agg *) aggstate->ss.ps.plan;
1810  Bitmapset *colnos;
1811 
1812  colnos = NULL;
1814  &colnos);
1815  (void) find_unaggregated_cols_walker((Node *) node->plan.qual,
1816  &colnos);
1817  return colnos;
1818 }
List * qual
Definition: plannodes.h:145
ScanState ss
Definition: execnodes.h:1795
Definition: nodes.h:509
PlanState ps
Definition: execnodes.h:1100
static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
Definition: nodeAgg.c:1821
Plan plan
Definition: plannodes.h:782
Plan * plan
Definition: execnodes.h:847
List * targetlist
Definition: plannodes.h:144
Definition: plannodes.h:780
static bool find_unaggregated_cols_walker ( Node node,
Bitmapset **  colnos 
)
static

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

1822 {
1823  if (node == NULL)
1824  return false;
1825  if (IsA(node, Var))
1826  {
1827  Var *var = (Var *) node;
1828 
1829  /* setrefs.c should have set the varno to OUTER_VAR */
1830  Assert(var->varno == OUTER_VAR);
1831  Assert(var->varlevelsup == 0);
1832  *colnos = bms_add_member(*colnos, var->varattno);
1833  return false;
1834  }
1835  if (IsA(node, Aggref) ||IsA(node, GroupingFunc))
1836  {
1837  /* do not descend into aggregate exprs */
1838  return false;
1839  }
1841  (void *) colnos);
1842 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
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:1821
Index varno
Definition: primnodes.h:166
#define Assert(condition)
Definition: c.h:664
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1843
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define OUTER_VAR
Definition: primnodes.h:154
static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 3702 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

3703 {
3704  Oid typinput,
3705  typioparam;
3706  char *strInitVal;
3707  Datum initVal;
3708 
3709  getTypeInputInfo(transtype, &typinput, &typioparam);
3710  strInitVal = TextDatumGetCString(textInitVal);
3711  initVal = OidInputFunctionCall(typinput, strInitVal,
3712  typioparam, -1);
3713  pfree(strInitVal);
3714  return initVal;
3715 }
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:2599
#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:1738
Size hash_agg_entry_size ( int  numAggs)

Definition at line 2012 of file nodeAgg.c.

References MAXALIGN.

Referenced by create_distinct_paths(), and estimate_hashagg_tablesize().

2013 {
2014  Size entrysize;
2015 
2016  /* This must match build_hash_table */
2017  entrysize = sizeof(TupleHashEntryData) +
2018  numAggs * sizeof(AggStatePerGroupData);
2019  entrysize = MAXALIGN(entrysize);
2020 
2021  return entrysize;
2022 }
struct TupleHashEntryData TupleHashEntryData
size_t Size
Definition: c.h:350
#define MAXALIGN(LEN)
Definition: c.h:576
static void initialize_aggregate ( AggState aggstate,
AggStatePerTrans  pertrans,
AggStatePerGroup  pergroupstate 
)
static

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

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

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

794 {
795  int transno;
796  int numGroupingSets = Max(aggstate->phase->numsets, 1);
797  int setno = 0;
798  int numTrans = aggstate->numtrans;
799  AggStatePerTrans transstates = aggstate->pertrans;
800 
801  if (numReset == 0)
802  numReset = numGroupingSets;
803 
804  for (transno = 0; transno < numTrans; transno++)
805  {
806  AggStatePerTrans pertrans = &transstates[transno];
807 
808  if (numReset < 0)
809  {
810  AggStatePerGroup pergroupstate;
811 
812  pergroupstate = &pergroup[transno];
813 
814  initialize_aggregate(aggstate, pertrans, pergroupstate);
815  }
816  else
817  {
818  for (setno = 0; setno < numReset; setno++)
819  {
820  AggStatePerGroup pergroupstate;
821 
822  pergroupstate = &pergroup[transno + (setno * numTrans)];
823 
824  select_current_set(aggstate, setno, false);
825 
826  initialize_aggregate(aggstate, pertrans, pergroupstate);
827  }
828  }
829  }
830 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:586
AggStatePerTrans pertrans
Definition: execnodes.h:1805
int numtrans
Definition: execnodes.h:1798
static void initialize_aggregate(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:705
AggStatePerPhase phase
Definition: execnodes.h:1801
#define Max(x, y)
Definition: c.h:789
static void initialize_phase ( AggState aggstate,
int  newphase 
)
static

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

605 {
606  Assert(newphase <= 1 || newphase == aggstate->current_phase + 1);
607 
608  /*
609  * Whatever the previous state, we're now done with whatever input
610  * tuplesort was in use.
611  */
612  if (aggstate->sort_in)
613  {
614  tuplesort_end(aggstate->sort_in);
615  aggstate->sort_in = NULL;
616  }
617 
618  if (newphase <= 1)
619  {
620  /*
621  * Discard any existing output tuplesort.
622  */
623  if (aggstate->sort_out)
624  {
625  tuplesort_end(aggstate->sort_out);
626  aggstate->sort_out = NULL;
627  }
628  }
629  else
630  {
631  /*
632  * The old output tuplesort becomes the new input one, and this is the
633  * right time to actually sort it.
634  */
635  aggstate->sort_in = aggstate->sort_out;
636  aggstate->sort_out = NULL;
637  Assert(aggstate->sort_in);
638  tuplesort_performsort(aggstate->sort_in);
639  }
640 
641  /*
642  * If this isn't the last phase, we need to sort appropriately for the
643  * next phase in sequence.
644  */
645  if (newphase > 0 && newphase < aggstate->numphases - 1)
646  {
647  Sort *sortnode = aggstate->phases[newphase + 1].sortnode;
648  PlanState *outerNode = outerPlanState(aggstate);
649  TupleDesc tupDesc = ExecGetResultType(outerNode);
650 
651  aggstate->sort_out = tuplesort_begin_heap(tupDesc,
652  sortnode->numCols,
653  sortnode->sortColIdx,
654  sortnode->sortOperators,
655  sortnode->collations,
656  sortnode->nullsFirst,
657  work_mem,
658  false);
659  }
660 
661  aggstate->current_phase = newphase;
662  aggstate->phase = &aggstate->phases[newphase];
663 }
AggStatePerPhase phases
Definition: execnodes.h:1819
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1773
Tuplesortstate * sort_out
Definition: execnodes.h:1821
int current_phase
Definition: execnodes.h:1803
bool * nullsFirst
Definition: plannodes.h:749
Oid * sortOperators
Definition: plannodes.h:747
Tuplesortstate * sort_in
Definition: execnodes.h:1820
#define outerPlanState(node)
Definition: execnodes.h:893
int numCols
Definition: plannodes.h:745
AggStatePerPhase phase
Definition: execnodes.h:1801
int work_mem
Definition: globals.c:113
#define Assert(condition)
Definition: c.h:664
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:474
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:756
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1167
Oid * collations
Definition: plannodes.h:748
static AggStatePerGroup * lookup_hash_entries ( AggState aggstate)
static

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

2079 {
2080  int numHashes = aggstate->num_hashes;
2081  AggStatePerGroup *pergroup = aggstate->hash_pergroup;
2082  int setno;
2083 
2084  for (setno = 0; setno < numHashes; setno++)
2085  {
2086  select_current_set(aggstate, setno, true);
2087  pergroup[setno] = lookup_hash_entry(aggstate)->additional;
2088  }
2089 
2090  return pergroup;
2091 }
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:1830
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:586
static TupleHashEntryData * lookup_hash_entry(AggState *aggstate)
Definition: nodeAgg.c:2033
int num_hashes
Definition: execnodes.h:1828
static TupleHashEntryData * lookup_hash_entry ( AggState aggstate)
static

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

2034 {
2035  TupleTableSlot *inputslot = aggstate->tmpcontext->ecxt_outertuple;
2036  AggStatePerHash perhash = &aggstate->perhash[aggstate->current_set];
2037  TupleTableSlot *hashslot = perhash->hashslot;
2038  TupleHashEntryData *entry;
2039  bool isnew;
2040  int i;
2041 
2042  /* transfer just the needed columns into hashslot */
2043  slot_getsomeattrs(inputslot, perhash->largestGrpColIdx);
2044  ExecClearTuple(hashslot);
2045 
2046  for (i = 0; i < perhash->numhashGrpCols; i++)
2047  {
2048  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
2049 
2050  hashslot->tts_values[i] = inputslot->tts_values[varNumber];
2051  hashslot->tts_isnull[i] = inputslot->tts_isnull[varNumber];
2052  }
2053  ExecStoreVirtualTuple(hashslot);
2054 
2055  /* find or create the hashtable entry using the filtered tuple */
2056  entry = LookupTupleHashEntry(perhash->hashtable, hashslot, &isnew);
2057 
2058  if (isnew)
2059  {
2060  entry->additional = (AggStatePerGroup)
2062  sizeof(AggStatePerGroupData) * aggstate->numtrans);
2063  /* initialize aggregates for new tuple group */
2065  -1);
2066  }
2067 
2068  return entry;
2069 }
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:1789
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.c:515
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
Datum * tts_values
Definition: tuptable.h:125
int current_set
Definition: execnodes.h:1814
int numtrans
Definition: execnodes.h:1798
ExprContext * tmpcontext
Definition: execnodes.h:1808
void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition: heaptuple.c:1282
static void initialize_aggregates(AggState *aggstate, AggStatePerGroup pergroup, int numReset)
Definition: nodeAgg.c:791
MemoryContext tablecxt
Definition: execnodes.h:610
bool * tts_isnull
Definition: tuptable.h:126
AggStatePerHash perhash
Definition: execnodes.h:1829
TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew)
Definition: execGrouping.c:351
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:706
int i
TupleTableSlot * hashslot
Definition: nodeAgg.c:509
TupleHashTable hashtable
Definition: nodeAgg.c:507
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:488
static void prepare_projection_slot ( AggState aggstate,
TupleTableSlot slot,
int  currentSet 
)
static

Definition at line 1672 of file nodeAgg.c.

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

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table().

1673 {
1674  if (aggstate->phase->grouped_cols)
1675  {
1676  Bitmapset *grouped_cols = aggstate->phase->grouped_cols[currentSet];
1677 
1678  aggstate->grouped_cols = grouped_cols;
1679 
1680  if (slot->tts_isempty)
1681  {
1682  /*
1683  * Force all values to be NULL if working on an empty input tuple
1684  * (i.e. an empty grouping set for which no input rows were
1685  * supplied).
1686  */
1687  ExecStoreAllNullTuple(slot);
1688  }
1689  else if (aggstate->all_grouped_cols)
1690  {
1691  ListCell *lc;
1692 
1693  /* all_grouped_cols is arranged in desc order */
1695 
1696  foreach(lc, aggstate->all_grouped_cols)
1697  {
1698  int attnum = lfirst_int(lc);
1699 
1700  if (!bms_is_member(attnum, grouped_cols))
1701  slot->tts_isnull[attnum - 1] = true;
1702  }
1703  }
1704  }
1705 }
bool tts_isempty
Definition: tuptable.h:116
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
Definition: execTuples.c:512
List * all_grouped_cols
Definition: execnodes.h:1816
void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition: heaptuple.c:1282
#define linitial_int(l)
Definition: pg_list.h:112
Bitmapset ** grouped_cols
Definition: nodeAgg.c:492
#define lfirst_int(lc)
Definition: pg_list.h:107
bool * tts_isnull
Definition: tuptable.h:126
Bitmapset * grouped_cols
Definition: execnodes.h:1815
AggStatePerPhase phase
Definition: execnodes.h:1801
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420