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:282
void tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
Definition: tuplesort.c:1485
ProjectionInfo * evalproj
Definition: execnodes.h:1800
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
Datum * tts_values
Definition: tuptable.h:125
AggStatePerTrans pertrans
Definition: execnodes.h:1772
int numtrans
Definition: execnodes.h:1765
ExprContext * tmpcontext
Definition: execnodes.h:1775
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:1795
TupleTableSlot * evalslot
Definition: execnodes.h:1799
AggStatePerPhase phase
Definition: execnodes.h:1768
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:310
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:1775
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:1776
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:1777
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:1775
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:1776
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:1777
static void agg_fill_hash_table ( AggState aggstate)
static

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

2486 {
2487  TupleTableSlot *outerslot;
2488  ExprContext *tmpcontext = aggstate->tmpcontext;
2489 
2490  /*
2491  * Process each outer-plan tuple, and then fetch the next one, until we
2492  * exhaust the outer plan.
2493  */
2494  for (;;)
2495  {
2496  AggStatePerGroup *pergroups;
2497 
2498  outerslot = fetch_input_tuple(aggstate);
2499  if (TupIsNull(outerslot))
2500  break;
2501 
2502  /* set up for lookup_hash_entries and advance_aggregates */
2503  tmpcontext->ecxt_outertuple = outerslot;
2504 
2505  /* Find or build hashtable entries */
2506  pergroups = lookup_hash_entries(aggstate);
2507 
2508  /* Advance the aggregates */
2509  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2510  combine_aggregates(aggstate, pergroups[0]);
2511  else
2512  advance_aggregates(aggstate, NULL, pergroups);
2513 
2514  /*
2515  * Reset per-input-tuple context after each tuple, but note that the
2516  * hash lookups do this too
2517  */
2518  ResetExprContext(aggstate->tmpcontext);
2519  }
2520 
2521  aggstate->table_filled = true;
2522  /* Initialize to walk the first hash table */
2523  select_current_set(aggstate, 0, true);
2525  &aggstate->perhash[0].hashiter);
2526 }
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:1767
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:768
ExprContext * tmpcontext
Definition: execnodes.h:1775
static AggStatePerGroup * lookup_hash_entries(AggState *aggstate)
Definition: nodeAgg.c:2070
bool table_filled
Definition: execnodes.h:1794
#define TupIsNull(slot)
Definition: tuptable.h:138
AggStatePerHash perhash
Definition: execnodes.h:1796
TupleHashIterator hashiter
Definition: nodeAgg.c:508
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:629
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:451
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 pointers */
2377 
2378  /* set up for first advance_aggregates call */
2379  tmpcontext->ecxt_outertuple = firstSlot;
2380 
2381  /*
2382  * Process each outer-plan tuple, and then fetch the next one,
2383  * until we exhaust the outer plan or cross a group boundary.
2384  */
2385  for (;;)
2386  {
2387  /*
2388  * During phase 1 only of a mixed agg, we need to update
2389  * hashtables as well in advance_aggregates.
2390  */
2391  if (aggstate->aggstrategy == AGG_MIXED &&
2392  aggstate->current_phase == 1)
2393  {
2394  hash_pergroups = lookup_hash_entries(aggstate);
2395  }
2396  else
2397  hash_pergroups = NULL;
2398 
2399  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2400  combine_aggregates(aggstate, pergroup);
2401  else
2402  advance_aggregates(aggstate, pergroup, hash_pergroups);
2403 
2404  /* Reset per-input-tuple context after each tuple */
2405  ResetExprContext(tmpcontext);
2406 
2407  outerslot = fetch_input_tuple(aggstate);
2408  if (TupIsNull(outerslot))
2409  {
2410  /* no more outer-plan tuples available */
2411  if (hasGroupingSets)
2412  {
2413  aggstate->input_done = true;
2414  break;
2415  }
2416  else
2417  {
2418  aggstate->agg_done = true;
2419  break;
2420  }
2421  }
2422  /* set up for next advance_aggregates call */
2423  tmpcontext->ecxt_outertuple = outerslot;
2424 
2425  /*
2426  * If we are grouping, check whether we've crossed a group
2427  * boundary.
2428  */
2429  if (node->aggstrategy != AGG_PLAIN)
2430  {
2431  if (!execTuplesMatch(firstSlot,
2432  outerslot,
2433  node->numCols,
2434  node->grpColIdx,
2435  aggstate->phase->eqfunctions,
2436  tmpcontext->ecxt_per_tuple_memory))
2437  {
2438  aggstate->grp_firstTuple = ExecCopySlotTuple(outerslot);
2439  break;
2440  }
2441  }
2442  }
2443  }
2444 
2445  /*
2446  * Use the representative input tuple for any references to
2447  * non-aggregated input columns in aggregate direct args, the node
2448  * qual, and the tlist. (If we are not grouping, and there are no
2449  * input rows at all, we will come here with an empty firstSlot
2450  * ... but if not grouping, there can't be any references to
2451  * non-aggregated input columns, so no problem.)
2452  */
2453  econtext->ecxt_outertuple = firstSlot;
2454  }
2455 
2456  Assert(aggstate->projected_set >= 0);
2457 
2458  currentSet = aggstate->projected_set;
2459 
2460  prepare_projection_slot(aggstate, econtext->ecxt_outertuple, currentSet);
2461 
2462  select_current_set(aggstate, currentSet, false);
2463 
2464  finalize_aggregates(aggstate,
2465  peragg,
2466  pergroup + (currentSet * aggstate->numtrans));
2467 
2468  /*
2469  * If there's no row to project right now, we must continue rather
2470  * than returning a null since there might be more groups.
2471  */
2472  result = project_aggregates(aggstate);
2473  if (result)
2474  return result;
2475  }
2476 
2477  /* No more groups */
2478  return NULL;
2479 }
static TupleTableSlot * fetch_input_tuple(AggState *aggstate)
Definition: nodeAgg.c:674
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:586
int numCols
Definition: plannodes.h:785
AttrNumber * grpColIdx
Definition: plannodes.h:786
bool agg_done
Definition: execnodes.h:1779
ScanState ss
Definition: execnodes.h:1762
ExprContext * ps_ExprContext
Definition: execnodes.h:862
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:1770
bool execTuplesMatch(TupleTableSlot *slot1, TupleTableSlot *slot2, int numCols, AttrNumber *matchColIdx, FmgrInfo *eqfunctions, MemoryContext evalContext)
Definition: execGrouping.c:69
AggSplit aggsplit
Definition: execnodes.h:1767
return result
Definition: formatting.c:1633
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1082
int projected_set
Definition: execnodes.h:1780
HeapTuple grp_firstTuple
Definition: execnodes.h:1792
static TupleTableSlot * project_aggregates(AggState *aggstate)
Definition: nodeAgg.c:1772
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:768
int numtrans
Definition: execnodes.h:1765
ExprContext * tmpcontext
Definition: execnodes.h:1775
static void prepare_projection_slot(AggState *aggstate, TupleTableSlot *slot, int currentSet)
Definition: nodeAgg.c:1664
PlanState ps
Definition: execnodes.h:1079
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:783
bool table_filled
Definition: execnodes.h:1794
AggStrategy aggstrategy
Definition: execnodes.h:1766
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition: nodeAgg.c:2532
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:1796
HeapTuple ExecCopySlotTuple(TupleTableSlot *slot)
Definition: execTuples.c:545
TupleHashIterator hashiter
Definition: nodeAgg.c:508
bool input_done
Definition: execnodes.h:1778
AggStatePerPhase phase
Definition: execnodes.h:1768
AggStatePerGroup pergroup
Definition: execnodes.h:1791
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:604
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:629
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:1774
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:1769
AggStatePerAgg peragg
Definition: execnodes.h:1771
int i
static void combine_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1103
Definition: plannodes.h:780
TupleHashTable hashtable
Definition: nodeAgg.c:507
#define ResetExprContext(econtext)
Definition: executor.h:451
static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

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

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

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

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

Definition at line 4054 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

4055 {
4056  if (fcinfo->context && IsA(fcinfo->context, AggState))
4057  {
4058  AggStatePerTrans curpertrans;
4059 
4060  curpertrans = ((AggState *) fcinfo->context)->curpertrans;
4061 
4062  if (curpertrans)
4063  return curpertrans->aggref;
4064  }
4065  return NULL;
4066 }
#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 4079 of file nodeAgg.c.

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

Referenced by hypothetical_dense_rank_final().

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

Definition at line 4134 of file nodeAgg.c.

References elog, and ERROR.

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

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

Referenced by ordered_set_startup().

4109 {
4110  if (fcinfo->context && IsA(fcinfo->context, AggState))
4111  {
4112  AggState *aggstate = (AggState *) fcinfo->context;
4113  ExprContext *cxt = aggstate->curaggcontext;
4114 
4115  RegisterExprContextCallback(cxt, func, arg);
4116 
4117  return;
4118  }
4119  elog(ERROR, "aggregate function cannot register a callback in this context");
4120 }
#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:1776
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
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
AggSplit aggsplit
Definition: execnodes.h:1767
int numtrans
Definition: execnodes.h:1765
ExprContext * tmpcontext
Definition: execnodes.h:1775
AggStrategy aggstrategy
Definition: execnodes.h:1766
AggStatePerHash perhash
Definition: execnodes.h:1796
int num_hashes
Definition: execnodes.h:1795
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.c:516
ExprContext * hashcontext
Definition: execnodes.h:1773
struct AggStatePerGroupData AggStatePerGroupData
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:788
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:769
TupleHashTable BuildTupleHashTable(int numCols, AttrNumber *keyColIdx, FmgrInfo *eqfunctions, FmgrInfo *hashfunctions, long nbuckets, Size additionalsize, MemoryContext tablecxt, MemoryContext tempcxt, bool use_variable_hash_iv)
Definition: execGrouping.c:290
int i
TupleHashTable hashtable
Definition: nodeAgg.c:507
static void build_pertrans_for_aggref ( AggStatePerTrans  pertrans,
AggState aggstate,
EState estate,
Aggref aggref,
Oid  aggtransfn,
Oid  aggtranstype,
Oid  aggserialfn,
Oid  aggdeserialfn,
Datum  initValue,
bool  initValueIsNull,
Oid inputTypes,
int  numArguments 
)
static

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

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

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

3837 {
3839  int transno;
3840  int numGroupingSets = Max(node->maxsets, 1);
3841  int setno;
3842 
3843  /* Make sure we have closed any open tuplesorts */
3844 
3845  if (node->sort_in)
3846  tuplesort_end(node->sort_in);
3847  if (node->sort_out)
3848  tuplesort_end(node->sort_out);
3849 
3850  for (transno = 0; transno < node->numtrans; transno++)
3851  {
3852  AggStatePerTrans pertrans = &node->pertrans[transno];
3853 
3854  for (setno = 0; setno < numGroupingSets; setno++)
3855  {
3856  if (pertrans->sortstates[setno])
3857  tuplesort_end(pertrans->sortstates[setno]);
3858  }
3859  }
3860 
3861  /* And ensure any agg shutdown callbacks have been called */
3862  for (setno = 0; setno < numGroupingSets; setno++)
3863  ReScanExprContext(node->aggcontexts[setno]);
3864  if (node->hashcontext)
3866 
3867  /*
3868  * We don't actually free any ExprContexts here (see comment in
3869  * ExecFreeExprContext), just unlinking the output one from the plan node
3870  * suffices.
3871  */
3872  ExecFreeExprContext(&node->ss.ps);
3873 
3874  /* clean up tuple table */
3876 
3877  outerPlan = outerPlanState(node);
3878  ExecEndNode(outerPlan);
3879 }
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:654
Tuplesortstate * sort_out
Definition: execnodes.h:1788
ScanState ss
Definition: execnodes.h:1762
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1082
AggStatePerTrans pertrans
Definition: execnodes.h:1772
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:516
int numtrans
Definition: execnodes.h:1765
PlanState ps
Definition: execnodes.h:1079
int maxsets
Definition: execnodes.h:1785
Tuplesortstate * sort_in
Definition: execnodes.h:1787
#define outerPlanState(node)
Definition: execnodes.h:874
Tuplesortstate ** sortstates
Definition: nodeAgg.c:380
#define outerPlan(node)
Definition: plannodes.h:174
ExprContext * hashcontext
Definition: execnodes.h:1773
#define Max(x, y)
Definition: c.h:800
ExprContext ** aggcontexts
Definition: execnodes.h:1774
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 2657 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().

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

3883 {
3884  ExprContext *econtext = node->ss.ps.ps_ExprContext;
3886  Agg *aggnode = (Agg *) node->ss.ps.plan;
3887  int transno;
3888  int numGroupingSets = Max(node->maxsets, 1);
3889  int setno;
3890 
3891  node->agg_done = false;
3892 
3893  if (node->aggstrategy == AGG_HASHED)
3894  {
3895  /*
3896  * In the hashed case, if we haven't yet built the hash table then we
3897  * can just return; nothing done yet, so nothing to undo. If subnode's
3898  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
3899  * else no reason to re-scan it at all.
3900  */
3901  if (!node->table_filled)
3902  return;
3903 
3904  /*
3905  * If we do have the hash table, and the subplan does not have any
3906  * parameter changes, and none of our own parameter changes affect
3907  * input expressions of the aggregated functions, then we can just
3908  * rescan the existing hash table; no need to build it again.
3909  */
3910  if (outerPlan->chgParam == NULL &&
3911  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
3912  {
3914  &node->perhash[0].hashiter);
3915  select_current_set(node, 0, true);
3916  return;
3917  }
3918  }
3919 
3920  /* Make sure we have closed any open tuplesorts */
3921  for (transno = 0; transno < node->numtrans; transno++)
3922  {
3923  for (setno = 0; setno < numGroupingSets; setno++)
3924  {
3925  AggStatePerTrans pertrans = &node->pertrans[transno];
3926 
3927  if (pertrans->sortstates[setno])
3928  {
3929  tuplesort_end(pertrans->sortstates[setno]);
3930  pertrans->sortstates[setno] = NULL;
3931  }
3932  }
3933  }
3934 
3935  /*
3936  * We don't need to ReScanExprContext the output tuple context here;
3937  * ExecReScan already did it. But we do need to reset our per-grouping-set
3938  * contexts, which may have transvalues stored in them. (We use rescan
3939  * rather than just reset because transfns may have registered callbacks
3940  * that need to be run now.) For the AGG_HASHED case, see below.
3941  */
3942 
3943  for (setno = 0; setno < numGroupingSets; setno++)
3944  {
3945  ReScanExprContext(node->aggcontexts[setno]);
3946  }
3947 
3948  /* Release first tuple of group, if we have made a copy */
3949  if (node->grp_firstTuple != NULL)
3950  {
3952  node->grp_firstTuple = NULL;
3953  }
3955 
3956  /* Forget current agg values */
3957  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
3958  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
3959 
3960  /*
3961  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
3962  * the hashcontext. This used to be an issue, but now, resetting a context
3963  * automatically deletes sub-contexts too.
3964  */
3965  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
3966  {
3968  /* Rebuild an empty hash table */
3969  build_hash_table(node);
3970  node->table_filled = false;
3971  /* iterator will be reset when the table is filled */
3972  }
3973 
3974  if (node->aggstrategy != AGG_HASHED)
3975  {
3976  /*
3977  * Reset the per-group state (in particular, mark transvalues null)
3978  */
3979  MemSet(node->pergroup, 0,
3980  sizeof(AggStatePerGroupData) * node->numaggs * numGroupingSets);
3981 
3982  /* reset to phase 1 */
3983  initialize_phase(node, 1);
3984 
3985  node->input_done = false;
3986  node->projected_set = -1;
3987  }
3988 
3989  if (outerPlan->chgParam == NULL)
3990  ExecReScan(outerPlan);
3991 }
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:1764
bool agg_done
Definition: execnodes.h:1779
ScanState ss
Definition: execnodes.h:1762
ExprContext * ps_ExprContext
Definition: execnodes.h:862
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:1082
AggStatePerTrans pertrans
Definition: execnodes.h:1772
int projected_set
Definition: execnodes.h:1780
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
HeapTuple grp_firstTuple
Definition: execnodes.h:1792
int numtrans
Definition: execnodes.h:1765
PlanState ps
Definition: execnodes.h:1079
int maxsets
Definition: execnodes.h:1785
bool table_filled
Definition: execnodes.h:1794
AggStrategy aggstrategy
Definition: execnodes.h:1766
#define outerPlanState(node)
Definition: execnodes.h:874
Tuplesortstate ** sortstates
Definition: nodeAgg.c:380
Bitmapset * aggParams
Definition: plannodes.h:789
static void build_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1853
AggStatePerHash perhash
Definition: execnodes.h:1796
Bitmapset * chgParam
Definition: execnodes.h:856
#define outerPlan(node)
Definition: plannodes.h:174
TupleHashIterator hashiter
Definition: nodeAgg.c:508
bool input_done
Definition: execnodes.h:1778
ExprContext * hashcontext
Definition: execnodes.h:1773
bool * ecxt_aggnulls
Definition: execnodes.h:214
uintptr_t Datum
Definition: postgres.h:372
AggStatePerGroup pergroup
Definition: execnodes.h:1791
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:604
Plan * plan
Definition: execnodes.h:832
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:629
#define Max(x, y)
Definition: c.h:800
ExprContext ** aggcontexts
Definition: execnodes.h:1774
#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:780
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1167
TupleHashTable hashtable
Definition: nodeAgg.c:507
static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

Definition at line 674 of file nodeAgg.c.

References 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:1789
Tuplesortstate * sort_out
Definition: execnodes.h:1788
Tuplesortstate * sort_in
Definition: execnodes.h:1787
#define outerPlanState(node)
Definition: execnodes.h:874
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:1762
ExprContext * ps_ExprContext
Definition: execnodes.h:862
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:1772
#define OidIsValid(objectId)
Definition: c.h:538
PlanState ps
Definition: execnodes.h:1079
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:267
#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:1777
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:1764
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1586
ScanState ss
Definition: execnodes.h:1762
ExprContext * ps_ExprContext
Definition: execnodes.h:862
AggSplit aggsplit
Definition: execnodes.h:1767
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:1484
AggStatePerTrans pertrans
Definition: execnodes.h:1772
int numtrans
Definition: execnodes.h:1765
PlanState ps
Definition: execnodes.h:1079
AggStrategy aggstrategy
Definition: execnodes.h:1766
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:769
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:1762
ExprContext * ps_ExprContext
Definition: execnodes.h:862
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:203
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:1772
#define OidIsValid(objectId)
Definition: c.h:538
PlanState ps
Definition: execnodes.h:1079
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 3716 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().

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

3794 {
3795  ListCell *lc;
3796 
3797  foreach(lc, transnos)
3798  {
3799  int transno = lfirst_int(lc);
3800  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3801 
3802  /*
3803  * if the transfns or transition state types are not the same then the
3804  * state can't be shared.
3805  */
3806  if (aggtransfn != pertrans->transfn_oid ||
3807  aggtranstype != pertrans->aggtranstype)
3808  continue;
3809 
3810  /*
3811  * The serialization and deserialization functions must match, if
3812  * present, as we're unable to share the trans state for aggregates
3813  * which will serialize or deserialize into different formats.
3814  * Remember that these will be InvalidOid if they're not required for
3815  * this agg node.
3816  */
3817  if (aggserialfn != pertrans->serialfn_oid ||
3818  aggdeserialfn != pertrans->deserialfn_oid)
3819  continue;
3820 
3821  /* Check that the initial condition matches, too. */
3822  if (initValueIsNull && pertrans->initValueIsNull)
3823  return transno;
3824 
3825  if (!initValueIsNull && !pertrans->initValueIsNull &&
3826  datumIsEqual(initValue, pertrans->initValue,
3827  pertrans->transtypeByVal, pertrans->transtypeLen))
3828  {
3829  return transno;
3830  }
3831  }
3832  return -1;
3833 }
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:219
AggStatePerTrans pertrans
Definition: execnodes.h:1772
#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:1786
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.c:515
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:111
AttrNumber * grpColIdx
Definition: plannodes.h:786
List * all_grouped_cols
Definition: execnodes.h:1783
Bitmapset ** grouped_cols
Definition: nodeAgg.c:492
#define lfirst_int(lc)
Definition: pg_list.h:107
#define outerPlanState(node)
Definition: execnodes.h:874
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:1796
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:1795
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:1762
Definition: nodes.h:509
PlanState ps
Definition: execnodes.h:1079
static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
Definition: nodeAgg.c:1813
Plan plan
Definition: plannodes.h:782
Plan * plan
Definition: execnodes.h:832
#define NULL
Definition: c.h:229
List * targetlist
Definition: plannodes.h:144
Definition: plannodes.h:780
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:1843
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define OUTER_VAR
Definition: primnodes.h:154
static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 3688 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

3689 {
3690  Oid typinput,
3691  typioparam;
3692  char *strInitVal;
3693  Datum initVal;
3694 
3695  getTypeInputInfo(transtype, &typinput, &typioparam);
3696  strInitVal = TextDatumGetCString(textInitVal);
3697  initVal = OidInputFunctionCall(typinput, strInitVal,
3698  typioparam, -1);
3699  pfree(strInitVal);
3700  return initVal;
3701 }
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:1781
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:1776
int work_mem
Definition: globals.c:113
Tuplesortstate * tuplesort_begin_heap(TupleDesc tupDesc, int nkeys, AttrNumber *attNums, Oid *sortOperators, Oid *sortCollations, bool *nullsFirstFlags, int workMem, bool randomAccess)
Definition: tuplesort.c:756
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1167
bool * sortNullsFirst
Definition: nodeAgg.c:323
static void initialize_aggregates ( AggState aggstate,
AggStatePerGroup  pergroup,
int  numReset 
)
static

Definition at line 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:1772
int numtrans
Definition: execnodes.h:1765
static void initialize_aggregate(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:703
AggStatePerPhase phase
Definition: execnodes.h:1768
#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:1786
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1773
Tuplesortstate * sort_out
Definition: execnodes.h:1788
int current_phase
Definition: execnodes.h:1770
bool * nullsFirst
Definition: plannodes.h:749
Oid * sortOperators
Definition: plannodes.h:747
Tuplesortstate * sort_in
Definition: execnodes.h:1787
#define outerPlanState(node)
Definition: execnodes.h:874
int numCols
Definition: plannodes.h:745
AggStatePerPhase phase
Definition: execnodes.h:1768
int work_mem
Definition: globals.c:113
#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:746
Tuplesortstate * tuplesort_begin_heap(TupleDesc tupDesc, int nkeys, AttrNumber *attNums, Oid *sortOperators, Oid *sortCollations, bool *nullsFirstFlags, int workMem, bool randomAccess)
Definition: tuplesort.c:756
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1167
Oid * collations
Definition: plannodes.h:748
static AggStatePerGroup * lookup_hash_entries ( AggState aggstate)
static

Definition at line 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:1797
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:1795
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:1756
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:1781
int numtrans
Definition: execnodes.h:1765
ExprContext * tmpcontext
Definition: execnodes.h:1775
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:607
bool * tts_isnull
Definition: tuptable.h:126
AggStatePerHash perhash
Definition: execnodes.h:1796
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:1783
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