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)
 
TupleTableSlotExecAgg (AggState *node)
 
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 962 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().

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

Referenced by combine_aggregates().

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

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

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

Definition at line 2486 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(), NULL, AggState::perhash, ResetExprContext, ResetTupleHashIterator, select_current_set(), AggState::table_filled, AggState::tmpcontext, and TupIsNull.

Referenced by ExecAgg().

2487 {
2488  TupleTableSlot *outerslot;
2489  ExprContext *tmpcontext = aggstate->tmpcontext;
2490 
2491  /*
2492  * Process each outer-plan tuple, and then fetch the next one, until we
2493  * exhaust the outer plan.
2494  */
2495  for (;;)
2496  {
2497  AggStatePerGroup *pergroups;
2498 
2499  outerslot = fetch_input_tuple(aggstate);
2500  if (TupIsNull(outerslot))
2501  break;
2502 
2503  /* set up for lookup_hash_entries and advance_aggregates */
2504  tmpcontext->ecxt_outertuple = outerslot;
2505 
2506  /* Find or build hashtable entries */
2507  pergroups = lookup_hash_entries(aggstate);
2508 
2509  /* Advance the aggregates */
2510  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2511  combine_aggregates(aggstate, pergroups[0]);
2512  else
2513  advance_aggregates(aggstate, NULL, pergroups);
2514 
2515  /*
2516  * Reset per-input-tuple context after each tuple, but note that the
2517  * hash lookups do this too
2518  */
2519  ResetExprContext(aggstate->tmpcontext);
2520  }
2521 
2522  aggstate->table_filled = true;
2523  /* Initialize to walk the first hash table */
2524  select_current_set(aggstate, 0, true);
2526  &aggstate->perhash[0].hashiter);
2527 }
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:1747
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:767
ExprContext * tmpcontext
Definition: execnodes.h:1755
static AggStatePerGroup * lookup_hash_entries(AggState *aggstate)
Definition: nodeAgg.c:2070
bool table_filled
Definition: execnodes.h:1775
#define TupIsNull(slot)
Definition: tuptable.h:138
AggStatePerHash perhash
Definition: execnodes.h:1777
TupleHashIterator hashiter
Definition: nodeAgg.c:508
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:609
static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGroup *pergroups)
Definition: nodeAgg.c:962
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:199
#define NULL
Definition: c.h:229
static void combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1103
TupleHashTable hashtable
Definition: nodeAgg.c:507
#define ResetExprContext(econtext)
Definition: executor.h:450
static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

Definition at line 2132 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, NULL, 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, result, select_current_set(), AggState::ss, ScanState::ss_ScanTupleSlot, AggState::table_filled, AggState::tmpcontext, and TupIsNull.

Referenced by ExecAgg().

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

Definition at line 2533 of file nodeAgg.c.

References TupleHashEntryData::additional, AggState::agg_done, AggState::current_set, ExprContext::ecxt_outertuple, ExecClearTuple(), ExecStoreMinimalTuple(), ExecStoreVirtualTuple(), finalize_aggregates(), TupleHashEntryData::firstTuple, AggStatePerHashData::hashGrpColIdxInput, AggStatePerHashData::hashiter, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, i, tupleDesc::natts, NULL, AggStatePerHashData::numhashGrpCols, AggState::peragg, AggState::perhash, prepare_projection_slot(), project_aggregates(), ScanState::ps, PlanState::ps_ExprContext, ResetExprContext, ResetTupleHashIterator, result, 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().

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

Definition at line 4018 of file nodeAgg.c.

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

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

4019 {
4020  if (fcinfo->context && IsA(fcinfo->context, AggState))
4021  {
4022  if (aggcontext)
4023  {
4024  AggState *aggstate = ((AggState *) fcinfo->context);
4025  ExprContext *cxt = aggstate->curaggcontext;
4026 
4027  *aggcontext = cxt->ecxt_per_tuple_memory;
4028  }
4029  return AGG_CONTEXT_AGGREGATE;
4030  }
4031  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
4032  {
4033  if (aggcontext)
4034  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
4035  return AGG_CONTEXT_WINDOW;
4036  }
4037 
4038  /* this is just to prevent "uninitialized variable" warnings */
4039  if (aggcontext)
4040  *aggcontext = NULL;
4041  return 0;
4042 }
#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:693
ExprContext * curaggcontext
Definition: execnodes.h:1756
#define NULL
Definition: c.h:229
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:694
Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 4055 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4056 {
4057  if (fcinfo->context && IsA(fcinfo->context, AggState))
4058  {
4059  AggStatePerTrans curpertrans;
4060 
4061  curpertrans = ((AggState *) fcinfo->context)->curpertrans;
4062 
4063  if (curpertrans)
4064  return curpertrans->aggref;
4065  }
4066  return NULL;
4067 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
fmNodePtr context
Definition: fmgr.h:80
#define NULL
Definition: c.h:229
MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 4080 of file nodeAgg.c.

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

Referenced by hypothetical_dense_rank_final().

4081 {
4082  if (fcinfo->context && IsA(fcinfo->context, AggState))
4083  {
4084  AggState *aggstate = (AggState *) fcinfo->context;
4085 
4086  return aggstate->tmpcontext->ecxt_per_tuple_memory;
4087  }
4088  return NULL;
4089 }
#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:1755
#define NULL
Definition: c.h:229
Datum aggregate_dummy ( PG_FUNCTION_ARGS  )

Definition at line 4135 of file nodeAgg.c.

References elog, and ERROR.

4136 {
4137  elog(ERROR, "aggregate function %u called as normal function",
4138  fcinfo->flinfo->fn_oid);
4139  return (Datum) 0; /* keep compiler quiet */
4140 }
#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 4107 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4110 {
4111  if (fcinfo->context && IsA(fcinfo->context, AggState))
4112  {
4113  AggState *aggstate = (AggState *) fcinfo->context;
4114  ExprContext *cxt = aggstate->curaggcontext;
4115 
4116  RegisterExprContextCallback(cxt, func, arg);
4117 
4118  return;
4119  }
4120  elog(ERROR, "aggregate function cannot register a callback in this context");
4121 }
#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:1756
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:732
void * arg
#define elog
Definition: elog.h:219
static void build_hash_table ( AggState aggstate)
static

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

1854 {
1855  MemoryContext tmpmem = aggstate->tmpcontext->ecxt_per_tuple_memory;
1856  Size additionalsize;
1857  int i;
1858 
1859  Assert(aggstate->aggstrategy == AGG_HASHED || aggstate->aggstrategy == AGG_MIXED);
1860 
1861  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1862 
1863  for (i = 0; i < aggstate->num_hashes; ++i)
1864  {
1865  AggStatePerHash perhash = &aggstate->perhash[i];
1866 
1867  Assert(perhash->aggnode->numGroups > 0);
1868 
1869  perhash->hashtable = BuildTupleHashTable(perhash->numCols,
1870  perhash->hashGrpColIdxHash,
1871  perhash->eqfunctions,
1872  perhash->hashfunctions,
1873  perhash->aggnode->numGroups,
1874  additionalsize,
1876  tmpmem,
1877  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1878  }
1879 }
FmgrInfo * eqfunctions
Definition: nodeAgg.c:511
struct AggStatePerGroupData AggStatePerGroupData
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
AggSplit aggsplit
Definition: execnodes.h:1747
int numtrans
Definition: execnodes.h:1745
ExprContext * tmpcontext
Definition: execnodes.h:1755
AggStrategy aggstrategy
Definition: execnodes.h:1746
AggStatePerHash perhash
Definition: execnodes.h:1777
int num_hashes
Definition: execnodes.h:1776
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.c:516
ExprContext * hashcontext
Definition: execnodes.h:1753
FmgrInfo * hashfunctions
Definition: nodeAgg.c:510
#define Assert(condition)
Definition: c.h:675
size_t Size
Definition: c.h:356
long numGroups
Definition: plannodes.h:790
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:768
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 3397 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, NULL, 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().

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

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

Definition at line 2099 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, NULL, AggState::phase, result, AggState::table_filled, and TupIsNull.

Referenced by ExecProcNode().

2100 {
2102 
2103  if (!node->agg_done)
2104  {
2105  /* Dispatch based on strategy */
2106  switch (node->phase->aggstrategy)
2107  {
2108  case AGG_HASHED:
2109  if (!node->table_filled)
2110  agg_fill_hash_table(node);
2111  /* FALLTHROUGH */
2112  case AGG_MIXED:
2113  result = agg_retrieve_hash_table(node);
2114  break;
2115  case AGG_PLAIN:
2116  case AGG_SORTED:
2117  result = agg_retrieve_direct(node);
2118  break;
2119  }
2120 
2121  if (!TupIsNull(result))
2122  return result;
2123  }
2124 
2125  return NULL;
2126 }
static void agg_fill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2486
bool agg_done
Definition: execnodes.h:1759
return result
Definition: formatting.c:1632
bool table_filled
Definition: execnodes.h:1775
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2533
static TupleTableSlot * agg_retrieve_direct(AggState *aggstate)
Definition: nodeAgg.c:2132
#define TupIsNull(slot)
Definition: tuptable.h:138
AggStrategy aggstrategy
Definition: nodeAgg.c:489
AggStatePerPhase phase
Definition: execnodes.h:1748
#define NULL
Definition: c.h:229
void ExecEndAgg ( AggState node)

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

3838 {
3840  int transno;
3841  int numGroupingSets = Max(node->maxsets, 1);
3842  int setno;
3843 
3844  /* Make sure we have closed any open tuplesorts */
3845 
3846  if (node->sort_in)
3847  tuplesort_end(node->sort_in);
3848  if (node->sort_out)
3849  tuplesort_end(node->sort_out);
3850 
3851  for (transno = 0; transno < node->numtrans; transno++)
3852  {
3853  AggStatePerTrans pertrans = &node->pertrans[transno];
3854 
3855  for (setno = 0; setno < numGroupingSets; setno++)
3856  {
3857  if (pertrans->sortstates[setno])
3858  tuplesort_end(pertrans->sortstates[setno]);
3859  }
3860  }
3861 
3862  /* And ensure any agg shutdown callbacks have been called */
3863  for (setno = 0; setno < numGroupingSets; setno++)
3864  ReScanExprContext(node->aggcontexts[setno]);
3865  if (node->hashcontext)
3867 
3868  /*
3869  * We don't actually free any ExprContexts here (see comment in
3870  * ExecFreeExprContext), just unlinking the output one from the plan node
3871  * suffices.
3872  */
3873  ExecFreeExprContext(&node->ss.ps);
3874 
3875  /* clean up tuple table */
3877 
3878  outerPlan = outerPlanState(node);
3879  ExecEndNode(outerPlan);
3880 }
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:654
Tuplesortstate * sort_out
Definition: execnodes.h:1769
ScanState ss
Definition: execnodes.h:1742
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1061
AggStatePerTrans pertrans
Definition: execnodes.h:1752
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:516
int numtrans
Definition: execnodes.h:1745
PlanState ps
Definition: execnodes.h:1058
int maxsets
Definition: execnodes.h:1766
Tuplesortstate * sort_in
Definition: execnodes.h:1768
#define outerPlanState(node)
Definition: execnodes.h:855
Tuplesortstate ** sortstates
Definition: nodeAgg.c:380
#define outerPlan(node)
Definition: plannodes.h:174
ExprContext * hashcontext
Definition: execnodes.h:1753
#define Max(x, y)
Definition: c.h:800
ExprContext ** aggcontexts
Definition: execnodes.h:1754
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:376
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1167
AggState* ExecInitAgg ( Agg node,
EState estate,
int  eflags 
)

Definition at line 2658 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, ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecAssignResultTypeFromTL(), ExecAssignScanTypeFromOuterPlan(), ExecBuildProjectionInfo(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlot(), ExecInitScanTupleSlot(), 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, NULL, 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().

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

3884 {
3885  ExprContext *econtext = node->ss.ps.ps_ExprContext;
3887  Agg *aggnode = (Agg *) node->ss.ps.plan;
3888  int transno;
3889  int numGroupingSets = Max(node->maxsets, 1);
3890  int setno;
3891 
3892  node->agg_done = false;
3893 
3894  if (node->aggstrategy == AGG_HASHED)
3895  {
3896  /*
3897  * In the hashed case, if we haven't yet built the hash table then we
3898  * can just return; nothing done yet, so nothing to undo. If subnode's
3899  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
3900  * else no reason to re-scan it at all.
3901  */
3902  if (!node->table_filled)
3903  return;
3904 
3905  /*
3906  * If we do have the hash table, and the subplan does not have any
3907  * parameter changes, and none of our own parameter changes affect
3908  * input expressions of the aggregated functions, then we can just
3909  * rescan the existing hash table; no need to build it again.
3910  */
3911  if (outerPlan->chgParam == NULL &&
3912  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
3913  {
3915  &node->perhash[0].hashiter);
3916  select_current_set(node, 0, true);
3917  return;
3918  }
3919  }
3920 
3921  /* Make sure we have closed any open tuplesorts */
3922  for (transno = 0; transno < node->numtrans; transno++)
3923  {
3924  for (setno = 0; setno < numGroupingSets; setno++)
3925  {
3926  AggStatePerTrans pertrans = &node->pertrans[transno];
3927 
3928  if (pertrans->sortstates[setno])
3929  {
3930  tuplesort_end(pertrans->sortstates[setno]);
3931  pertrans->sortstates[setno] = NULL;
3932  }
3933  }
3934  }
3935 
3936  /*
3937  * We don't need to ReScanExprContext the output tuple context here;
3938  * ExecReScan already did it. But we do need to reset our per-grouping-set
3939  * contexts, which may have transvalues stored in them. (We use rescan
3940  * rather than just reset because transfns may have registered callbacks
3941  * that need to be run now.) For the AGG_HASHED case, see below.
3942  */
3943 
3944  for (setno = 0; setno < numGroupingSets; setno++)
3945  {
3946  ReScanExprContext(node->aggcontexts[setno]);
3947  }
3948 
3949  /* Release first tuple of group, if we have made a copy */
3950  if (node->grp_firstTuple != NULL)
3951  {
3953  node->grp_firstTuple = NULL;
3954  }
3956 
3957  /* Forget current agg values */
3958  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
3959  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
3960 
3961  /*
3962  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
3963  * the hashcontext. This used to be an issue, but now, resetting a context
3964  * automatically deletes sub-contexts too.
3965  */
3966  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
3967  {
3969  /* Rebuild an empty hash table */
3970  build_hash_table(node);
3971  node->table_filled = false;
3972  /* iterator will be reset when the table is filled */
3973  }
3974 
3975  if (node->aggstrategy != AGG_HASHED)
3976  {
3977  /*
3978  * Reset the per-group state (in particular, mark transvalues null)
3979  */
3980  MemSet(node->pergroup, 0,
3981  sizeof(AggStatePerGroupData) * node->numaggs * numGroupingSets);
3982 
3983  /* reset to phase 1 */
3984  initialize_phase(node, 1);
3985 
3986  node->input_done = false;
3987  node->projected_set = -1;
3988  }
3989 
3990  if (outerPlan->chgParam == NULL)
3991  ExecReScan(outerPlan);
3992 }
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:1744
bool agg_done
Definition: execnodes.h:1759
ScanState ss
Definition: execnodes.h:1742
ExprContext * ps_ExprContext
Definition: execnodes.h:843
void ExecReScan(PlanState *node)
Definition: execAmi.c:75
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
#define MemSet(start, val, len)
Definition: c.h:857
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1061
AggStatePerTrans pertrans
Definition: execnodes.h:1752
int projected_set
Definition: execnodes.h:1760
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
HeapTuple grp_firstTuple
Definition: execnodes.h:1773
int numtrans
Definition: execnodes.h:1745
PlanState ps
Definition: execnodes.h:1058
int maxsets
Definition: execnodes.h:1766
bool table_filled
Definition: execnodes.h:1775
AggStrategy aggstrategy
Definition: execnodes.h:1746
#define outerPlanState(node)
Definition: execnodes.h:855
Tuplesortstate ** sortstates
Definition: nodeAgg.c:380
Bitmapset * aggParams
Definition: plannodes.h:791
static void build_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1853
AggStatePerHash perhash
Definition: execnodes.h:1777
Bitmapset * chgParam
Definition: execnodes.h:837
#define outerPlan(node)
Definition: plannodes.h:174
TupleHashIterator hashiter
Definition: nodeAgg.c:508
bool input_done
Definition: execnodes.h:1758
ExprContext * hashcontext
Definition: execnodes.h:1753
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
AggStatePerGroup pergroup
Definition: execnodes.h:1772
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:604
Plan * plan
Definition: execnodes.h:813
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:609
#define Max(x, y)
Definition: c.h:800
ExprContext ** aggcontexts
Definition: execnodes.h:1754
#define NULL
Definition: c.h:229
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:376
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
Definition: plannodes.h:782
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 ExecProcNode(), NULL, 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  if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
681  aggstate->sort_slot, NULL))
682  return NULL;
683  slot = aggstate->sort_slot;
684  }
685  else
686  slot = ExecProcNode(outerPlanState(aggstate));
687 
688  if (!TupIsNull(slot) && aggstate->sort_out)
689  tuplesort_puttupleslot(aggstate->sort_out, slot);
690 
691  return slot;
692 }
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:398
TupleTableSlot * sort_slot
Definition: execnodes.h:1770
Tuplesortstate * sort_out
Definition: execnodes.h:1769
Tuplesortstate * sort_in
Definition: execnodes.h:1768
#define outerPlanState(node)
Definition: execnodes.h:855
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2113
#define TupIsNull(slot)
Definition: tuptable.h:138
#define NULL
Definition: c.h:229
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 1484 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(), NULL, 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().

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

1712 {
1713  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1714  Datum *aggvalues = econtext->ecxt_aggvalues;
1715  bool *aggnulls = econtext->ecxt_aggnulls;
1716  int aggno;
1717  int transno;
1718 
1719  /*
1720  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1721  * inputs and run the transition functions.
1722  */
1723  for (transno = 0; transno < aggstate->numtrans; transno++)
1724  {
1725  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1726  AggStatePerGroup pergroupstate;
1727 
1728  pergroupstate = &pergroup[transno];
1729 
1730  if (pertrans->numSortCols > 0)
1731  {
1732  Assert(aggstate->aggstrategy != AGG_HASHED &&
1733  aggstate->aggstrategy != AGG_MIXED);
1734 
1735  if (pertrans->numInputs == 1)
1737  pertrans,
1738  pergroupstate);
1739  else
1741  pertrans,
1742  pergroupstate);
1743  }
1744  }
1745 
1746  /*
1747  * Run the final functions.
1748  */
1749  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1750  {
1751  AggStatePerAgg peragg = &peraggs[aggno];
1752  int transno = peragg->transno;
1753  AggStatePerGroup pergroupstate;
1754 
1755  pergroupstate = &pergroup[transno];
1756 
1757  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1758  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1759  &aggvalues[aggno], &aggnulls[aggno]);
1760  else
1761  finalize_aggregate(aggstate, peragg, pergroupstate,
1762  &aggvalues[aggno], &aggnulls[aggno]);
1763  }
1764 }
Datum * ecxt_aggvalues
Definition: execnodes.h:213
int numaggs
Definition: execnodes.h:1744
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1586
ScanState ss
Definition: execnodes.h:1742
ExprContext * ps_ExprContext
Definition: execnodes.h:843
AggSplit aggsplit
Definition: execnodes.h:1747
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1484
AggStatePerTrans pertrans
Definition: execnodes.h:1752
int numtrans
Definition: execnodes.h:1745
PlanState ps
Definition: execnodes.h:1058
AggStrategy aggstrategy
Definition: execnodes.h:1746
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:1393
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
#define Assert(condition)
Definition: c.h:675
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:768
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:1300
static void finalize_partialaggregate ( AggState aggstate,
AggStatePerAgg  peragg,
AggStatePerGroup  pergroupstate,
Datum resultVal,
bool resultIsNull 
)
static

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

1590 {
1591  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1592  MemoryContext oldContext;
1593 
1595 
1596  /*
1597  * serialfn_oid will be set if we must serialize the transvalue before
1598  * returning it
1599  */
1600  if (OidIsValid(pertrans->serialfn_oid))
1601  {
1602  /* Don't call a strict serialization function with NULL input. */
1603  if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
1604  {
1605  *resultVal = (Datum) 0;
1606  *resultIsNull = true;
1607  }
1608  else
1609  {
1610  FunctionCallInfo fcinfo = &pertrans->serialfn_fcinfo;
1611 
1612  fcinfo->arg[0] = MakeExpandedObjectReadOnly(pergroupstate->transValue,
1613  pergroupstate->transValueIsNull,
1614  pertrans->transtypeLen);
1615  fcinfo->argnull[0] = pergroupstate->transValueIsNull;
1616 
1617  *resultVal = FunctionCallInvoke(fcinfo);
1618  *resultIsNull = fcinfo->isnull;
1619  }
1620  }
1621  else
1622  {
1623  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1624  *resultVal = pergroupstate->transValue;
1625  *resultIsNull = pergroupstate->transValueIsNull;
1626  }
1627 
1628  /* If result is pass-by-ref, make sure it is in the right context. */
1629  if (!peragg->resulttypeByVal && !*resultIsNull &&
1631  DatumGetPointer(*resultVal)))
1632  *resultVal = datumCopy(*resultVal,
1633  peragg->resulttypeByVal,
1634  peragg->resulttypeLen);
1635 
1636  MemoryContextSwitchTo(oldContext);
1637 }
ScanState ss
Definition: execnodes.h:1742
ExprContext * ps_ExprContext
Definition: execnodes.h:843
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:1752
#define OidIsValid(objectId)
Definition: c.h:538
PlanState ps
Definition: execnodes.h:1058
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:567
#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 3717 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().

3719 {
3720  int aggno;
3721  AggStatePerAgg peraggs;
3722 
3723  *same_input_transnos = NIL;
3724 
3725  /* we mustn't reuse the aggref if it contains volatile function calls */
3726  if (contain_volatile_functions((Node *) newagg))
3727  return -1;
3728 
3729  peraggs = aggstate->peragg;
3730 
3731  /*
3732  * Search through the list of already seen aggregates. If we find an
3733  * existing aggregate with the same aggregate function and input
3734  * parameters as an existing one, then we can re-use that one. While
3735  * searching, we'll also collect a list of Aggrefs with the same input
3736  * parameters. If no matching Aggref is found, the caller can potentially
3737  * still re-use the transition state of one of them.
3738  */
3739  for (aggno = 0; aggno <= lastaggno; aggno++)
3740  {
3741  AggStatePerAgg peragg;
3742  Aggref *existingRef;
3743 
3744  peragg = &peraggs[aggno];
3745  existingRef = peragg->aggref;
3746 
3747  /* all of the following must be the same or it's no match */
3748  if (newagg->inputcollid != existingRef->inputcollid ||
3749  newagg->aggtranstype != existingRef->aggtranstype ||
3750  newagg->aggstar != existingRef->aggstar ||
3751  newagg->aggvariadic != existingRef->aggvariadic ||
3752  newagg->aggkind != existingRef->aggkind ||
3753  !equal(newagg->aggdirectargs, existingRef->aggdirectargs) ||
3754  !equal(newagg->args, existingRef->args) ||
3755  !equal(newagg->aggorder, existingRef->aggorder) ||
3756  !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
3757  !equal(newagg->aggfilter, existingRef->aggfilter))
3758  continue;
3759 
3760  /* if it's the same aggregate function then report exact match */
3761  if (newagg->aggfnoid == existingRef->aggfnoid &&
3762  newagg->aggtype == existingRef->aggtype &&
3763  newagg->aggcollid == existingRef->aggcollid)
3764  {
3765  list_free(*same_input_transnos);
3766  *same_input_transnos = NIL;
3767  return aggno;
3768  }
3769 
3770  /*
3771  * Not identical, but it had the same inputs. Return it to the caller,
3772  * in case we can re-use its per-trans state.
3773  */
3774  *same_input_transnos = lappend_int(*same_input_transnos,
3775  peragg->transno);
3776  }
3777 
3778  return -1;
3779 }
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:2962
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:951
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:1751
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 3790 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().

3795 {
3796  ListCell *lc;
3797 
3798  foreach(lc, transnos)
3799  {
3800  int transno = lfirst_int(lc);
3801  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3802 
3803  /*
3804  * if the transfns or transition state types are not the same then the
3805  * state can't be shared.
3806  */
3807  if (aggtransfn != pertrans->transfn_oid ||
3808  aggtranstype != pertrans->aggtranstype)
3809  continue;
3810 
3811  /*
3812  * The serialization and deserialization functions must match, if
3813  * present, as we're unable to share the trans state for aggregates
3814  * which will serialize or deserialize into different formats.
3815  * Remember that these will be InvalidOid if they're not required for
3816  * this agg node.
3817  */
3818  if (aggserialfn != pertrans->serialfn_oid ||
3819  aggdeserialfn != pertrans->deserialfn_oid)
3820  continue;
3821 
3822  /* Check that the initial condition matches, too. */
3823  if (initValueIsNull && pertrans->initValueIsNull)
3824  return transno;
3825 
3826  if (!initValueIsNull && !pertrans->initValueIsNull &&
3827  datumIsEqual(initValue, pertrans->initValue,
3828  pertrans->transtypeByVal, pertrans->transtypeLen))
3829  {
3830  return transno;
3831  }
3832  }
3833  return -1;
3834 }
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:219
AggStatePerTrans pertrans
Definition: execnodes.h:1752
#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 1902 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().

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

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

Referenced by find_hash_columns().

1800 {
1801  Agg *node = (Agg *) aggstate->ss.ps.plan;
1802  Bitmapset *colnos;
1803 
1804  colnos = NULL;
1806  &colnos);
1807  (void) find_unaggregated_cols_walker((Node *) node->plan.qual,
1808  &colnos);
1809  return colnos;
1810 }
List * qual
Definition: plannodes.h:145
ScanState ss
Definition: execnodes.h:1742
Definition: nodes.h:509
PlanState ps
Definition: execnodes.h:1058
static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
Definition: nodeAgg.c:1813
Plan plan
Definition: plannodes.h:784
Plan * plan
Definition: execnodes.h:813
#define NULL
Definition: c.h:229
List * targetlist
Definition: plannodes.h:144
Definition: plannodes.h:782
static bool find_unaggregated_cols_walker ( Node node,
Bitmapset **  colnos 
)
static

Definition at line 1813 of file nodeAgg.c.

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

Referenced by find_unaggregated_cols().

1814 {
1815  if (node == NULL)
1816  return false;
1817  if (IsA(node, Var))
1818  {
1819  Var *var = (Var *) node;
1820 
1821  /* setrefs.c should have set the varno to OUTER_VAR */
1822  Assert(var->varno == OUTER_VAR);
1823  Assert(var->varlevelsup == 0);
1824  *colnos = bms_add_member(*colnos, var->varattno);
1825  return false;
1826  }
1827  if (IsA(node, Aggref) ||IsA(node, GroupingFunc))
1828  {
1829  /* do not descend into aggregate exprs */
1830  return false;
1831  }
1833  (void *) colnos);
1834 }
#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:1813
Index varno
Definition: primnodes.h:166
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1865
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 3689 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

3690 {
3691  Oid typinput,
3692  typioparam;
3693  char *strInitVal;
3694  Datum initVal;
3695 
3696  getTypeInputInfo(transtype, &typinput, &typioparam);
3697  strInitVal = TextDatumGetCString(textInitVal);
3698  initVal = OidInputFunctionCall(typinput, strInitVal,
3699  typioparam, -1);
3700  pfree(strInitVal);
3701  return initVal;
3702 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:950
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 2004 of file nodeAgg.c.

References MAXALIGN.

Referenced by create_distinct_paths(), and estimate_hashagg_tablesize().

2005 {
2006  Size entrysize;
2007 
2008  /* This must match build_hash_table */
2009  entrysize = sizeof(TupleHashEntryData) +
2010  numAggs * sizeof(AggStatePerGroupData);
2011  entrysize = MAXALIGN(entrysize);
2012 
2013  return entrysize;
2014 }
struct TupleHashEntryData TupleHashEntryData
size_t Size
Definition: c.h:356
#define MAXALIGN(LEN)
Definition: c.h:588
static void initialize_aggregate ( AggState aggstate,
AggStatePerTrans  pertrans,
AggStatePerGroup  pergroupstate 
)
static

Definition at line 703 of file nodeAgg.c.

References tupleDesc::attrs, 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, tuplesort_begin_datum(), tuplesort_begin_heap(), tuplesort_end(), and work_mem.

Referenced by initialize_aggregates().

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

788 {
789  int transno;
790  int numGroupingSets = Max(aggstate->phase->numsets, 1);
791  int setno = 0;
792  int numTrans = aggstate->numtrans;
793  AggStatePerTrans transstates = aggstate->pertrans;
794 
795  if (numReset == 0)
796  numReset = numGroupingSets;
797 
798  for (transno = 0; transno < numTrans; transno++)
799  {
800  AggStatePerTrans pertrans = &transstates[transno];
801 
802  if (numReset < 0)
803  {
804  AggStatePerGroup pergroupstate;
805 
806  pergroupstate = &pergroup[transno];
807 
808  initialize_aggregate(aggstate, pertrans, pergroupstate);
809  }
810  else
811  {
812  for (setno = 0; setno < numReset; setno++)
813  {
814  AggStatePerGroup pergroupstate;
815 
816  pergroupstate = &pergroup[transno + (setno * numTrans)];
817 
818  select_current_set(aggstate, setno, false);
819 
820  initialize_aggregate(aggstate, pertrans, pergroupstate);
821  }
822  }
823  }
824 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:586
AggStatePerTrans pertrans
Definition: execnodes.h:1752
int numtrans
Definition: execnodes.h:1745
static void initialize_aggregate(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:703
AggStatePerPhase phase
Definition: execnodes.h:1748
#define Max(x, y)
Definition: c.h:800
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(), NULL, 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:1767
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1773
Tuplesortstate * sort_out
Definition: execnodes.h:1769
int current_phase
Definition: execnodes.h:1750
bool * nullsFirst
Definition: plannodes.h:751
Oid * sortOperators
Definition: plannodes.h:749
Tuplesortstate * sort_in
Definition: execnodes.h:1768
#define outerPlanState(node)
Definition: execnodes.h:855
int numCols
Definition: plannodes.h:747
AggStatePerPhase phase
Definition: execnodes.h:1748
int work_mem
Definition: globals.c:112
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:469
AttrNumber * sortColIdx
Definition: plannodes.h:748
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:750
static AggStatePerGroup * lookup_hash_entries ( AggState aggstate)
static

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

2071 {
2072  int numHashes = aggstate->num_hashes;
2073  AggStatePerGroup *pergroup = aggstate->hash_pergroup;
2074  int setno;
2075 
2076  for (setno = 0; setno < numHashes; setno++)
2077  {
2078  select_current_set(aggstate, setno, true);
2079  pergroup[setno] = lookup_hash_entry(aggstate)->additional;
2080  }
2081 
2082  return pergroup;
2083 }
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:1778
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:2025
int num_hashes
Definition: execnodes.h:1776
static TupleHashEntryData * lookup_hash_entry ( AggState aggstate)
static

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

2026 {
2027  TupleTableSlot *inputslot = aggstate->tmpcontext->ecxt_outertuple;
2028  AggStatePerHash perhash = &aggstate->perhash[aggstate->current_set];
2029  TupleTableSlot *hashslot = perhash->hashslot;
2030  TupleHashEntryData *entry;
2031  bool isnew;
2032  int i;
2033 
2034  /* transfer just the needed columns into hashslot */
2035  slot_getsomeattrs(inputslot, perhash->largestGrpColIdx);
2036  ExecClearTuple(hashslot);
2037 
2038  for (i = 0; i < perhash->numhashGrpCols; i++)
2039  {
2040  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
2041 
2042  hashslot->tts_values[i] = inputslot->tts_values[varNumber];
2043  hashslot->tts_isnull[i] = inputslot->tts_isnull[varNumber];
2044  }
2045  ExecStoreVirtualTuple(hashslot);
2046 
2047  /* find or create the hashtable entry using the filtered tuple */
2048  entry = LookupTupleHashEntry(perhash->hashtable, hashslot, &isnew);
2049 
2050  if (isnew)
2051  {
2052  entry->additional = (AggStatePerGroup)
2054  sizeof(AggStatePerGroupData) * aggstate->numtrans);
2055  /* initialize aggregates for new tuple group */
2057  -1);
2058  }
2059 
2060  return entry;
2061 }
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:1736
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:1761
int numtrans
Definition: execnodes.h:1745
ExprContext * tmpcontext
Definition: execnodes.h:1755
void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition: heaptuple.c:1281
static void initialize_aggregates(AggState *aggstate, AggStatePerGroup pergroup, int numReset)
Definition: nodeAgg.c:785
MemoryContext tablecxt
Definition: execnodes.h:587
bool * tts_isnull
Definition: tuptable.h:126
AggStatePerHash perhash
Definition: execnodes.h:1777
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:707
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 1664 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().

1665 {
1666  if (aggstate->phase->grouped_cols)
1667  {
1668  Bitmapset *grouped_cols = aggstate->phase->grouped_cols[currentSet];
1669 
1670  aggstate->grouped_cols = grouped_cols;
1671 
1672  if (slot->tts_isempty)
1673  {
1674  /*
1675  * Force all values to be NULL if working on an empty input tuple
1676  * (i.e. an empty grouping set for which no input rows were
1677  * supplied).
1678  */
1679  ExecStoreAllNullTuple(slot);
1680  }
1681  else if (aggstate->all_grouped_cols)
1682  {
1683  ListCell *lc;
1684 
1685  /* all_grouped_cols is arranged in desc order */
1687 
1688  foreach(lc, aggstate->all_grouped_cols)
1689  {
1690  int attnum = lfirst_int(lc);
1691 
1692  if (!bms_is_member(attnum, grouped_cols))
1693  slot->tts_isnull[attnum - 1] = true;
1694  }
1695  }
1696  }
1697 }
bool tts_isempty
Definition: tuptable.h:116
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
Definition: execTuples.c:512
List * all_grouped_cols
Definition: execnodes.h:1763
void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition: heaptuple.c:1281
#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