PostgreSQL Source Code  git master
nodeAgg.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "executor/nodeAgg.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/expandeddatum.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/tuplesort.h"
Include dependency graph for nodeAgg.c:

Go to the source code of this file.

Functions

static void select_current_set (AggState *aggstate, int setno, bool is_hash)
 
static void initialize_phase (AggState *aggstate, int newphase)
 
static TupleTableSlotfetch_input_tuple (AggState *aggstate)
 
static void initialize_aggregates (AggState *aggstate, AggStatePerGroup *pergroups, int numReset)
 
static void advance_transition_function (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void advance_aggregates (AggState *aggstate)
 
static void process_ordered_aggregate_single (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void process_ordered_aggregate_multi (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void finalize_aggregate (AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
 
static void finalize_partialaggregate (AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
 
static void prepare_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 void lookup_hash_entries (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_direct (AggState *aggstate)
 
static void agg_fill_hash_table (AggState *aggstate)
 
static TupleTableSlotagg_retrieve_hash_table (AggState *aggstate)
 
static Datum GetAggInitVal (Datum textInitVal, Oid transtype)
 
static void build_pertrans_for_aggref (AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
 
static int find_compatible_peragg (Aggref *newagg, AggState *aggstate, int lastaggno, List **same_input_transnos)
 
static int find_compatible_pertrans (AggState *aggstate, Aggref *newagg, bool shareable, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, List *transnos)
 
static void initialize_aggregate (AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
 
static void find_hash_columns (AggState *aggstate)
 
Size hash_agg_entry_size (int numAggs)
 
static TupleTableSlotExecAgg (PlanState *pstate)
 
AggStateExecInitAgg (Agg *node, EState *estate, int eflags)
 
void ExecEndAgg (AggState *node)
 
void ExecReScanAgg (AggState *node)
 
int AggCheckCallContext (FunctionCallInfo fcinfo, MemoryContext *aggcontext)
 
AggrefAggGetAggref (FunctionCallInfo fcinfo)
 
MemoryContext AggGetTempMemoryContext (FunctionCallInfo fcinfo)
 
bool AggStateIsShared (FunctionCallInfo fcinfo)
 
void AggRegisterCallback (FunctionCallInfo fcinfo, ExprContextCallbackFunction func, Datum arg)
 
Datum aggregate_dummy (PG_FUNCTION_ARGS)
 

Function Documentation

◆ advance_aggregates()

static void advance_aggregates ( AggState aggstate)
static

Definition at line 675 of file nodeAgg.c.

References AggStatePerPhaseData::evaltrans, ExecEvalExprSwitchContext(), AggState::phase, and AggState::tmpcontext.

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

676 {
677  bool dummynull;
678 
680  aggstate->tmpcontext,
681  &dummynull);
682 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:300
ExprState * evaltrans
Definition: nodeAgg.h:282
ExprContext * tmpcontext
Definition: execnodes.h:2044
AggStatePerPhase phase
Definition: execnodes.h:2037

◆ advance_transition_function()

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

Definition at line 551 of file nodeAgg.c.

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

Referenced by process_ordered_aggregate_multi(), and process_ordered_aggregate_single().

554 {
555  FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
556  MemoryContext oldContext;
557  Datum newVal;
558 
559  if (pertrans->transfn.fn_strict)
560  {
561  /*
562  * For a strict transfn, nothing happens when there's a NULL input; we
563  * just keep the prior transValue.
564  */
565  int numTransInputs = pertrans->numTransInputs;
566  int i;
567 
568  for (i = 1; i <= numTransInputs; i++)
569  {
570  if (fcinfo->args[i].isnull)
571  return;
572  }
573  if (pergroupstate->noTransValue)
574  {
575  /*
576  * transValue has not been initialized. This is the first non-NULL
577  * input value. We use it as the initial value for transValue. (We
578  * already checked that the agg's input type is binary-compatible
579  * with its transtype, so straight copy here is OK.)
580  *
581  * We must copy the datum into aggcontext if it is pass-by-ref. We
582  * do not need to pfree the old transValue, since it's NULL.
583  */
584  oldContext = MemoryContextSwitchTo(
586  pergroupstate->transValue = datumCopy(fcinfo->args[1].value,
587  pertrans->transtypeByVal,
588  pertrans->transtypeLen);
589  pergroupstate->transValueIsNull = false;
590  pergroupstate->noTransValue = false;
591  MemoryContextSwitchTo(oldContext);
592  return;
593  }
594  if (pergroupstate->transValueIsNull)
595  {
596  /*
597  * Don't call a strict function with NULL inputs. Note it is
598  * possible to get here despite the above tests, if the transfn is
599  * strict *and* returned a NULL on a prior cycle. If that happens
600  * we will propagate the NULL all the way to the end.
601  */
602  return;
603  }
604  }
605 
606  /* We run the transition functions in per-input-tuple memory context */
607  oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
608 
609  /* set up aggstate->curpertrans for AggGetAggref() */
610  aggstate->curpertrans = pertrans;
611 
612  /*
613  * OK to call the transition function
614  */
615  fcinfo->args[0].value = pergroupstate->transValue;
616  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
617  fcinfo->isnull = false; /* just in case transfn doesn't set it */
618 
619  newVal = FunctionCallInvoke(fcinfo);
620 
621  aggstate->curpertrans = NULL;
622 
623  /*
624  * If pass-by-ref datatype, must copy the new value into aggcontext and
625  * free the prior transValue. But if transfn returned a pointer to its
626  * first input, we don't need to do anything. Also, if transfn returned a
627  * pointer to a R/W expanded object that is already a child of the
628  * aggcontext, assume we can adopt that value without copying it.
629  */
630  if (!pertrans->transtypeByVal &&
631  DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
632  {
633  if (!fcinfo->isnull)
634  {
637  false,
638  pertrans->transtypeLen) &&
640  /* do nothing */ ;
641  else
642  newVal = datumCopy(newVal,
643  pertrans->transtypeByVal,
644  pertrans->transtypeLen);
645  }
646  if (!pergroupstate->transValueIsNull)
647  {
648  if (DatumIsReadWriteExpandedObject(pergroupstate->transValue,
649  false,
650  pertrans->transtypeLen))
651  DeleteExpandedObject(pergroupstate->transValue);
652  else
653  pfree(DatumGetPointer(pergroupstate->transValue));
654  }
655  }
656 
657  pergroupstate->transValue = newVal;
658  pergroupstate->transValueIsNull = fcinfo->isnull;
659 
660  MemoryContextSwitchTo(oldContext);
661 }
MemoryContext MemoryContextGetParent(MemoryContext context)
Definition: mcxt.c:439
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:231
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:161
ExprContext * tmpcontext
Definition: execnodes.h:2044
FmgrInfo transfn
Definition: nodeAgg.h:80
void pfree(void *pointer)
Definition: mcxt.c:1056
bool fn_strict
Definition: fmgr.h:61
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:167
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
Datum value
Definition: postgres.h:378
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
ExpandedObjectHeader * DatumGetEOHP(Datum d)
Definition: expandeddatum.c:29
ExprContext * curaggcontext
Definition: execnodes.h:2046
uintptr_t Datum
Definition: postgres.h:367
void DeleteExpandedObject(Datum d)
#define DatumIsReadWriteExpandedObject(d, isnull, typlen)
#define DatumGetPointer(X)
Definition: postgres.h:549
int i
AggStatePerTrans curpertrans
Definition: execnodes.h:2049

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

Definition at line 1927 of file nodeAgg.c.

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

Referenced by ExecAgg().

1928 {
1929  TupleTableSlot *outerslot;
1930  ExprContext *tmpcontext = aggstate->tmpcontext;
1931 
1932  /*
1933  * Process each outer-plan tuple, and then fetch the next one, until we
1934  * exhaust the outer plan.
1935  */
1936  for (;;)
1937  {
1938  outerslot = fetch_input_tuple(aggstate);
1939  if (TupIsNull(outerslot))
1940  break;
1941 
1942  /* set up for lookup_hash_entries and advance_aggregates */
1943  tmpcontext->ecxt_outertuple = outerslot;
1944 
1945  /* Find or build hashtable entries */
1946  lookup_hash_entries(aggstate);
1947 
1948  /* Advance the aggregates (or combine functions) */
1949  advance_aggregates(aggstate);
1950 
1951  /*
1952  * Reset per-input-tuple context after each tuple, but note that the
1953  * hash lookups do this too
1954  */
1955  ResetExprContext(aggstate->tmpcontext);
1956  }
1957 
1958  aggstate->table_filled = true;
1959  /* Initialize to walk the first hash table */
1960  select_current_set(aggstate, 0, true);
1962  &aggstate->perhash[0].hashiter);
1963 }
static TupleTableSlot * fetch_input_tuple(AggState *aggstate)
Definition: nodeAgg.c:391
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:302
static void advance_aggregates(AggState *aggstate)
Definition: nodeAgg.c:675
ExprContext * tmpcontext
Definition: execnodes.h:2044
bool table_filled
Definition: execnodes.h:2068
#define TupIsNull(slot)
Definition: tuptable.h:292
AggStatePerHash perhash
Definition: execnodes.h:2070
TupleHashIterator hashiter
Definition: nodeAgg.h:295
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:721
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:227
TupleHashTable hashtable
Definition: nodeAgg.h:294
static void lookup_hash_entries(AggState *aggstate)
Definition: nodeAgg.c:1524
#define ResetExprContext(econtext)
Definition: executor.h:495

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

Definition at line 1587 of file nodeAgg.c.

References advance_aggregates(), AggState::agg_done, AGG_MIXED, AGG_PLAIN, agg_retrieve_hash_table(), AggState::aggcontexts, AggStatePerPhaseData::aggnode, Agg::aggstrategy, AggState::aggstrategy, Assert, AggState::current_phase, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, AggStatePerPhaseData::eqfunctions, ExecCopySlotHeapTuple(), ExecForceStoreHeapTuple(), ExecQual(), ExecQualAndReset(), fetch_input_tuple(), finalize_aggregates(), AggState::grp_firstTuple, AggStatePerPhaseData::gset_lengths, AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, i, initialize_aggregates(), initialize_phase(), AggState::input_done, lookup_hash_entries(), Max, Agg::numCols, AggState::numphases, AggStatePerPhaseData::numsets, AggState::peragg, AggState::pergroups, AggState::perhash, AggState::phase, prepare_projection_slot(), project_aggregates(), AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, ReScanExprContext(), ResetExprContext, ResetTupleHashIterator, select_current_set(), AggState::ss, ScanState::ss_ScanTupleSlot, AggState::table_filled, AggState::tmpcontext, and TupIsNull.

Referenced by ExecAgg().

1588 {
1589  Agg *node = aggstate->phase->aggnode;
1590  ExprContext *econtext;
1591  ExprContext *tmpcontext;
1592  AggStatePerAgg peragg;
1593  AggStatePerGroup *pergroups;
1594  TupleTableSlot *outerslot;
1595  TupleTableSlot *firstSlot;
1596  TupleTableSlot *result;
1597  bool hasGroupingSets = aggstate->phase->numsets > 0;
1598  int numGroupingSets = Max(aggstate->phase->numsets, 1);
1599  int currentSet;
1600  int nextSetSize;
1601  int numReset;
1602  int i;
1603 
1604  /*
1605  * get state info from node
1606  *
1607  * econtext is the per-output-tuple expression context
1608  *
1609  * tmpcontext is the per-input-tuple expression context
1610  */
1611  econtext = aggstate->ss.ps.ps_ExprContext;
1612  tmpcontext = aggstate->tmpcontext;
1613 
1614  peragg = aggstate->peragg;
1615  pergroups = aggstate->pergroups;
1616  firstSlot = aggstate->ss.ss_ScanTupleSlot;
1617 
1618  /*
1619  * We loop retrieving groups until we find one matching
1620  * aggstate->ss.ps.qual
1621  *
1622  * For grouping sets, we have the invariant that aggstate->projected_set
1623  * is either -1 (initial call) or the index (starting from 0) in
1624  * gset_lengths for the group we just completed (either by projecting a
1625  * row or by discarding it in the qual).
1626  */
1627  while (!aggstate->agg_done)
1628  {
1629  /*
1630  * Clear the per-output-tuple context for each group, as well as
1631  * aggcontext (which contains any pass-by-ref transvalues of the old
1632  * group). Some aggregate functions store working state in child
1633  * contexts; those now get reset automatically without us needing to
1634  * do anything special.
1635  *
1636  * We use ReScanExprContext not just ResetExprContext because we want
1637  * any registered shutdown callbacks to be called. That allows
1638  * aggregate functions to ensure they've cleaned up any non-memory
1639  * resources.
1640  */
1641  ReScanExprContext(econtext);
1642 
1643  /*
1644  * Determine how many grouping sets need to be reset at this boundary.
1645  */
1646  if (aggstate->projected_set >= 0 &&
1647  aggstate->projected_set < numGroupingSets)
1648  numReset = aggstate->projected_set + 1;
1649  else
1650  numReset = numGroupingSets;
1651 
1652  /*
1653  * numReset can change on a phase boundary, but that's OK; we want to
1654  * reset the contexts used in _this_ phase, and later, after possibly
1655  * changing phase, initialize the right number of aggregates for the
1656  * _new_ phase.
1657  */
1658 
1659  for (i = 0; i < numReset; i++)
1660  {
1661  ReScanExprContext(aggstate->aggcontexts[i]);
1662  }
1663 
1664  /*
1665  * Check if input is complete and there are no more groups to project
1666  * in this phase; move to next phase or mark as done.
1667  */
1668  if (aggstate->input_done == true &&
1669  aggstate->projected_set >= (numGroupingSets - 1))
1670  {
1671  if (aggstate->current_phase < aggstate->numphases - 1)
1672  {
1673  initialize_phase(aggstate, aggstate->current_phase + 1);
1674  aggstate->input_done = false;
1675  aggstate->projected_set = -1;
1676  numGroupingSets = Max(aggstate->phase->numsets, 1);
1677  node = aggstate->phase->aggnode;
1678  numReset = numGroupingSets;
1679  }
1680  else if (aggstate->aggstrategy == AGG_MIXED)
1681  {
1682  /*
1683  * Mixed mode; we've output all the grouped stuff and have
1684  * full hashtables, so switch to outputting those.
1685  */
1686  initialize_phase(aggstate, 0);
1687  aggstate->table_filled = true;
1689  &aggstate->perhash[0].hashiter);
1690  select_current_set(aggstate, 0, true);
1691  return agg_retrieve_hash_table(aggstate);
1692  }
1693  else
1694  {
1695  aggstate->agg_done = true;
1696  break;
1697  }
1698  }
1699 
1700  /*
1701  * Get the number of columns in the next grouping set after the last
1702  * projected one (if any). This is the number of columns to compare to
1703  * see if we reached the boundary of that set too.
1704  */
1705  if (aggstate->projected_set >= 0 &&
1706  aggstate->projected_set < (numGroupingSets - 1))
1707  nextSetSize = aggstate->phase->gset_lengths[aggstate->projected_set + 1];
1708  else
1709  nextSetSize = 0;
1710 
1711  /*----------
1712  * If a subgroup for the current grouping set is present, project it.
1713  *
1714  * We have a new group if:
1715  * - we're out of input but haven't projected all grouping sets
1716  * (checked above)
1717  * OR
1718  * - we already projected a row that wasn't from the last grouping
1719  * set
1720  * AND
1721  * - the next grouping set has at least one grouping column (since
1722  * empty grouping sets project only once input is exhausted)
1723  * AND
1724  * - the previous and pending rows differ on the grouping columns
1725  * of the next grouping set
1726  *----------
1727  */
1728  tmpcontext->ecxt_innertuple = econtext->ecxt_outertuple;
1729  if (aggstate->input_done ||
1730  (node->aggstrategy != AGG_PLAIN &&
1731  aggstate->projected_set != -1 &&
1732  aggstate->projected_set < (numGroupingSets - 1) &&
1733  nextSetSize > 0 &&
1734  !ExecQualAndReset(aggstate->phase->eqfunctions[nextSetSize - 1],
1735  tmpcontext)))
1736  {
1737  aggstate->projected_set += 1;
1738 
1739  Assert(aggstate->projected_set < numGroupingSets);
1740  Assert(nextSetSize > 0 || aggstate->input_done);
1741  }
1742  else
1743  {
1744  /*
1745  * We no longer care what group we just projected, the next
1746  * projection will always be the first (or only) grouping set
1747  * (unless the input proves to be empty).
1748  */
1749  aggstate->projected_set = 0;
1750 
1751  /*
1752  * If we don't already have the first tuple of the new group,
1753  * fetch it from the outer plan.
1754  */
1755  if (aggstate->grp_firstTuple == NULL)
1756  {
1757  outerslot = fetch_input_tuple(aggstate);
1758  if (!TupIsNull(outerslot))
1759  {
1760  /*
1761  * Make a copy of the first input tuple; we will use this
1762  * for comparisons (in group mode) and for projection.
1763  */
1764  aggstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
1765  }
1766  else
1767  {
1768  /* outer plan produced no tuples at all */
1769  if (hasGroupingSets)
1770  {
1771  /*
1772  * If there was no input at all, we need to project
1773  * rows only if there are grouping sets of size 0.
1774  * Note that this implies that there can't be any
1775  * references to ungrouped Vars, which would otherwise
1776  * cause issues with the empty output slot.
1777  *
1778  * XXX: This is no longer true, we currently deal with
1779  * this in finalize_aggregates().
1780  */
1781  aggstate->input_done = true;
1782 
1783  while (aggstate->phase->gset_lengths[aggstate->projected_set] > 0)
1784  {
1785  aggstate->projected_set += 1;
1786  if (aggstate->projected_set >= numGroupingSets)
1787  {
1788  /*
1789  * We can't set agg_done here because we might
1790  * have more phases to do, even though the
1791  * input is empty. So we need to restart the
1792  * whole outer loop.
1793  */
1794  break;
1795  }
1796  }
1797 
1798  if (aggstate->projected_set >= numGroupingSets)
1799  continue;
1800  }
1801  else
1802  {
1803  aggstate->agg_done = true;
1804  /* If we are grouping, we should produce no tuples too */
1805  if (node->aggstrategy != AGG_PLAIN)
1806  return NULL;
1807  }
1808  }
1809  }
1810 
1811  /*
1812  * Initialize working state for a new input tuple group.
1813  */
1814  initialize_aggregates(aggstate, pergroups, numReset);
1815 
1816  if (aggstate->grp_firstTuple != NULL)
1817  {
1818  /*
1819  * Store the copied first input tuple in the tuple table slot
1820  * reserved for it. The tuple will be deleted when it is
1821  * cleared from the slot.
1822  */
1824  firstSlot, true);
1825  aggstate->grp_firstTuple = NULL; /* don't keep two pointers */
1826 
1827  /* set up for first advance_aggregates call */
1828  tmpcontext->ecxt_outertuple = firstSlot;
1829 
1830  /*
1831  * Process each outer-plan tuple, and then fetch the next one,
1832  * until we exhaust the outer plan or cross a group boundary.
1833  */
1834  for (;;)
1835  {
1836  /*
1837  * During phase 1 only of a mixed agg, we need to update
1838  * hashtables as well in advance_aggregates.
1839  */
1840  if (aggstate->aggstrategy == AGG_MIXED &&
1841  aggstate->current_phase == 1)
1842  {
1843  lookup_hash_entries(aggstate);
1844  }
1845 
1846  /* Advance the aggregates (or combine functions) */
1847  advance_aggregates(aggstate);
1848 
1849  /* Reset per-input-tuple context after each tuple */
1850  ResetExprContext(tmpcontext);
1851 
1852  outerslot = fetch_input_tuple(aggstate);
1853  if (TupIsNull(outerslot))
1854  {
1855  /* no more outer-plan tuples available */
1856  if (hasGroupingSets)
1857  {
1858  aggstate->input_done = true;
1859  break;
1860  }
1861  else
1862  {
1863  aggstate->agg_done = true;
1864  break;
1865  }
1866  }
1867  /* set up for next advance_aggregates call */
1868  tmpcontext->ecxt_outertuple = outerslot;
1869 
1870  /*
1871  * If we are grouping, check whether we've crossed a group
1872  * boundary.
1873  */
1874  if (node->aggstrategy != AGG_PLAIN)
1875  {
1876  tmpcontext->ecxt_innertuple = firstSlot;
1877  if (!ExecQual(aggstate->phase->eqfunctions[node->numCols - 1],
1878  tmpcontext))
1879  {
1880  aggstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
1881  break;
1882  }
1883  }
1884  }
1885  }
1886 
1887  /*
1888  * Use the representative input tuple for any references to
1889  * non-aggregated input columns in aggregate direct args, the node
1890  * qual, and the tlist. (If we are not grouping, and there are no
1891  * input rows at all, we will come here with an empty firstSlot
1892  * ... but if not grouping, there can't be any references to
1893  * non-aggregated input columns, so no problem.)
1894  */
1895  econtext->ecxt_outertuple = firstSlot;
1896  }
1897 
1898  Assert(aggstate->projected_set >= 0);
1899 
1900  currentSet = aggstate->projected_set;
1901 
1902  prepare_projection_slot(aggstate, econtext->ecxt_outertuple, currentSet);
1903 
1904  select_current_set(aggstate, currentSet, false);
1905 
1906  finalize_aggregates(aggstate,
1907  peragg,
1908  pergroups[currentSet]);
1909 
1910  /*
1911  * If there's no row to project right now, we must continue rather
1912  * than returning a null since there might be more groups.
1913  */
1914  result = project_aggregates(aggstate);
1915  if (result)
1916  return result;
1917  }
1918 
1919  /* No more groups */
1920  return NULL;
1921 }
ExprState ** eqfunctions
Definition: nodeAgg.h:277
static TupleTableSlot * fetch_input_tuple(AggState *aggstate)
Definition: nodeAgg.c:391
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:302
int numCols
Definition: plannodes.h:811
bool agg_done
Definition: execnodes.h:2051
ScanState ss
Definition: execnodes.h:2031
ExprContext * ps_ExprContext
Definition: execnodes.h:978
int current_phase
Definition: execnodes.h:2039
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1329
int projected_set
Definition: execnodes.h:2052
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:365
HeapTuple grp_firstTuple
Definition: execnodes.h:2066
static TupleTableSlot * project_aggregates(AggState *aggstate)
Definition: nodeAgg.c:1183
static void advance_aggregates(AggState *aggstate)
Definition: nodeAgg.c:675
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1439
ExprContext * tmpcontext
Definition: execnodes.h:2044
static void prepare_projection_slot(AggState *aggstate, TupleTableSlot *slot, int currentSet)
Definition: nodeAgg.c:1075
PlanState ps
Definition: execnodes.h:1326
AggStrategy aggstrategy
Definition: plannodes.h:809
bool table_filled
Definition: execnodes.h:2068
AggStrategy aggstrategy
Definition: execnodes.h:2035
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1969
static void finalize_aggregates(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1120
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:225
#define TupIsNull(slot)
Definition: tuptable.h:292
AggStatePerHash perhash
Definition: execnodes.h:2070
static void initialize_aggregates(AggState *aggstate, AggStatePerGroup *pergroups, int numReset)
Definition: nodeAgg.c:510
TupleHashIterator hashiter
Definition: nodeAgg.h:295
bool input_done
Definition: execnodes.h:2050
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:392
AggStatePerPhase phase
Definition: execnodes.h:2037
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:321
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:721
static HeapTuple ExecCopySlotHeapTuple(TupleTableSlot *slot)
Definition: tuptable.h:452
#define Max(x, y)
Definition: c.h:905
ExprContext ** aggcontexts
Definition: execnodes.h:2043
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:227
#define Assert(condition)
Definition: c.h:739
AggStatePerGroup * pergroups
Definition: execnodes.h:2064
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:402
int numphases
Definition: execnodes.h:2038
AggStatePerAgg peragg
Definition: execnodes.h:2040
int i
Definition: plannodes.h:806
TupleHashTable hashtable
Definition: nodeAgg.h:294
static void lookup_hash_entries(AggState *aggstate)
Definition: nodeAgg.c:1524
#define ResetExprContext(econtext)
Definition: executor.h:495

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

Definition at line 1969 of file nodeAgg.c.

References TupleHashEntryData::additional, AggState::agg_done, CHECK_FOR_INTERRUPTS, AggState::current_set, ExprContext::ecxt_outertuple, ExecClearTuple(), ExecStoreMinimalTuple(), ExecStoreVirtualTuple(), finalize_aggregates(), TupleHashEntryData::firstTuple, AggStatePerHashData::hashGrpColIdxInput, AggStatePerHashData::hashiter, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, i, TupleDescData::natts, AggStatePerHashData::numhashGrpCols, AggState::peragg, AggState::perhash, prepare_projection_slot(), project_aggregates(), ScanState::ps, PlanState::ps_ExprContext, ResetExprContext, ResetTupleHashIterator, ScanTupleHashTable, select_current_set(), slot_getallattrs(), AggState::ss, ScanState::ss_ScanTupleSlot, TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, and TupleTableSlot::tts_values.

Referenced by agg_retrieve_direct(), and ExecAgg().

1970 {
1971  ExprContext *econtext;
1972  AggStatePerAgg peragg;
1973  AggStatePerGroup pergroup;
1974  TupleHashEntryData *entry;
1975  TupleTableSlot *firstSlot;
1976  TupleTableSlot *result;
1977  AggStatePerHash perhash;
1978 
1979  /*
1980  * get state info from node.
1981  *
1982  * econtext is the per-output-tuple expression context.
1983  */
1984  econtext = aggstate->ss.ps.ps_ExprContext;
1985  peragg = aggstate->peragg;
1986  firstSlot = aggstate->ss.ss_ScanTupleSlot;
1987 
1988  /*
1989  * Note that perhash (and therefore anything accessed through it) can
1990  * change inside the loop, as we change between grouping sets.
1991  */
1992  perhash = &aggstate->perhash[aggstate->current_set];
1993 
1994  /*
1995  * We loop retrieving groups until we find one satisfying
1996  * aggstate->ss.ps.qual
1997  */
1998  while (!aggstate->agg_done)
1999  {
2000  TupleTableSlot *hashslot = perhash->hashslot;
2001  int i;
2002 
2004 
2005  /*
2006  * Find the next entry in the hash table
2007  */
2008  entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);
2009  if (entry == NULL)
2010  {
2011  int nextset = aggstate->current_set + 1;
2012 
2013  if (nextset < aggstate->num_hashes)
2014  {
2015  /*
2016  * Switch to next grouping set, reinitialize, and restart the
2017  * loop.
2018  */
2019  select_current_set(aggstate, nextset, true);
2020 
2021  perhash = &aggstate->perhash[aggstate->current_set];
2022 
2023  ResetTupleHashIterator(perhash->hashtable, &perhash->hashiter);
2024 
2025  continue;
2026  }
2027  else
2028  {
2029  /* No more hashtables, so done */
2030  aggstate->agg_done = true;
2031  return NULL;
2032  }
2033  }
2034 
2035  /*
2036  * Clear the per-output-tuple context for each group
2037  *
2038  * We intentionally don't use ReScanExprContext here; if any aggs have
2039  * registered shutdown callbacks, they mustn't be called yet, since we
2040  * might not be done with that agg.
2041  */
2042  ResetExprContext(econtext);
2043 
2044  /*
2045  * Transform representative tuple back into one with the right
2046  * columns.
2047  */
2048  ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);
2049  slot_getallattrs(hashslot);
2050 
2051  ExecClearTuple(firstSlot);
2052  memset(firstSlot->tts_isnull, true,
2053  firstSlot->tts_tupleDescriptor->natts * sizeof(bool));
2054 
2055  for (i = 0; i < perhash->numhashGrpCols; i++)
2056  {
2057  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
2058 
2059  firstSlot->tts_values[varNumber] = hashslot->tts_values[i];
2060  firstSlot->tts_isnull[varNumber] = hashslot->tts_isnull[i];
2061  }
2062  ExecStoreVirtualTuple(firstSlot);
2063 
2064  pergroup = (AggStatePerGroup) entry->additional;
2065 
2066  /*
2067  * Use the representative input tuple for any references to
2068  * non-aggregated input columns in the qual and tlist.
2069  */
2070  econtext->ecxt_outertuple = firstSlot;
2071 
2072  prepare_projection_slot(aggstate,
2073  econtext->ecxt_outertuple,
2074  aggstate->current_set);
2075 
2076  finalize_aggregates(aggstate, peragg, pergroup);
2077 
2078  result = project_aggregates(aggstate);
2079  if (result)
2080  return result;
2081  }
2082 
2083  /* No more groups */
2084  return NULL;
2085 }
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2025
#define ScanTupleHashTable(htable, iter)
Definition: execnodes.h:723
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:302
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.h:302
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1416
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
bool agg_done
Definition: execnodes.h:2051
ScanState ss
Definition: execnodes.h:2031
ExprContext * ps_ExprContext
Definition: execnodes.h:978
MinimalTuple firstTuple
Definition: execnodes.h:676
Datum * tts_values
Definition: tuptable.h:126
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1329
static TupleTableSlot * project_aggregates(AggState *aggstate)
Definition: nodeAgg.c:1183
int current_set
Definition: execnodes.h:2054
static void prepare_projection_slot(AggState *aggstate, TupleTableSlot *slot, int currentSet)
Definition: nodeAgg.c:1075
PlanState ps
Definition: execnodes.h:1326
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:354
static void finalize_aggregates(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroup)
Definition: nodeAgg.c:1120
bool * tts_isnull
Definition: tuptable.h:128
AggStatePerHash perhash
Definition: execnodes.h:2070
TupleHashIterator hashiter
Definition: nodeAgg.h:295
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:721
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:227
AggStatePerAgg peragg
Definition: execnodes.h:2040
int i
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
TupleTableSlot * hashslot
Definition: nodeAgg.h:296
TupleHashTable hashtable
Definition: nodeAgg.h:294
#define ResetExprContext(econtext)
Definition: executor.h:495
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522

◆ AggCheckCallContext()

int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

Definition at line 3571 of file nodeAgg.c.

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

Referenced by array_agg_array_finalfn(), array_agg_array_transfn(), array_agg_finalfn(), array_agg_transfn(), bytea_string_agg_finalfn(), fetch_array_arg_replace_nulls(), float4_accum(), float8_accum(), float8_combine(), float8_regr_accum(), float8_regr_combine(), hypothetical_dense_rank_final(), hypothetical_rank_common(), int2_avg_accum(), int2_avg_accum_inv(), int2_sum(), int4_avg_accum(), int4_avg_accum_inv(), int4_avg_combine(), int4_sum(), int8_avg_combine(), int8_avg_deserialize(), int8_avg_serialize(), int8dec(), int8inc(), json_agg_finalfn(), json_agg_transfn(), json_object_agg_finalfn(), json_object_agg_transfn(), jsonb_agg_finalfn(), jsonb_agg_transfn(), jsonb_object_agg_finalfn(), jsonb_object_agg_transfn(), makeBoolAggState(), makeNumericAggState(), makeStringAggState(), mode_final(), numeric_accum_inv(), numeric_avg_combine(), numeric_avg_deserialize(), numeric_avg_serialize(), numeric_combine(), numeric_deserialize(), numeric_poly_combine(), numeric_poly_deserialize(), numeric_poly_serialize(), numeric_serialize(), ordered_set_startup(), percentile_cont_final_common(), percentile_cont_multi_final_common(), percentile_disc_final(), percentile_disc_multi_final(), and string_agg_finalfn().

3572 {
3573  if (fcinfo->context && IsA(fcinfo->context, AggState))
3574  {
3575  if (aggcontext)
3576  {
3577  AggState *aggstate = ((AggState *) fcinfo->context);
3578  ExprContext *cxt = aggstate->curaggcontext;
3579 
3580  *aggcontext = cxt->ecxt_per_tuple_memory;
3581  }
3582  return AGG_CONTEXT_AGGREGATE;
3583  }
3584  if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
3585  {
3586  if (aggcontext)
3587  *aggcontext = ((WindowAggState *) fcinfo->context)->curaggcontext;
3588  return AGG_CONTEXT_WINDOW;
3589  }
3590 
3591  /* this is just to prevent "uninitialized variable" warnings */
3592  if (aggcontext)
3593  *aggcontext = NULL;
3594  return 0;
3595 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:231
fmNodePtr context
Definition: fmgr.h:88
#define AGG_CONTEXT_AGGREGATE
Definition: fmgr.h:724
ExprContext * curaggcontext
Definition: execnodes.h:2046
#define AGG_CONTEXT_WINDOW
Definition: fmgr.h:725

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 3615 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

3616 {
3617  if (fcinfo->context && IsA(fcinfo->context, AggState))
3618  {
3619  AggState *aggstate = (AggState *) fcinfo->context;
3620  AggStatePerAgg curperagg;
3621  AggStatePerTrans curpertrans;
3622 
3623  /* check curperagg (valid when in a final function) */
3624  curperagg = aggstate->curperagg;
3625 
3626  if (curperagg)
3627  return curperagg->aggref;
3628 
3629  /* check curpertrans (valid when in a transition function) */
3630  curpertrans = aggstate->curpertrans;
3631 
3632  if (curpertrans)
3633  return curpertrans->aggref;
3634  }
3635  return NULL;
3636 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
fmNodePtr context
Definition: fmgr.h:88
Aggref * aggref
Definition: nodeAgg.h:186
Aggref * aggref
Definition: nodeAgg.h:43
AggStatePerAgg curperagg
Definition: execnodes.h:2047
AggStatePerTrans curpertrans
Definition: execnodes.h:2049

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 3649 of file nodeAgg.c.

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

3650 {
3651  if (fcinfo->context && IsA(fcinfo->context, AggState))
3652  {
3653  AggState *aggstate = (AggState *) fcinfo->context;
3654 
3655  return aggstate->tmpcontext->ecxt_per_tuple_memory;
3656  }
3657  return NULL;
3658 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:231
fmNodePtr context
Definition: fmgr.h:88
ExprContext * tmpcontext
Definition: execnodes.h:2044

◆ aggregate_dummy()

Datum aggregate_dummy ( PG_FUNCTION_ARGS  )

Definition at line 3742 of file nodeAgg.c.

References elog, and ERROR.

3743 {
3744  elog(ERROR, "aggregate function %u called as normal function",
3745  fcinfo->flinfo->fn_oid);
3746  return (Datum) 0; /* keep compiler quiet */
3747 }
#define ERROR
Definition: elog.h:43
uintptr_t Datum
Definition: postgres.h:367
#define elog(elevel,...)
Definition: elog.h:228

◆ AggRegisterCallback()

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

Definition at line 3714 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

3717 {
3718  if (fcinfo->context && IsA(fcinfo->context, AggState))
3719  {
3720  AggState *aggstate = (AggState *) fcinfo->context;
3721  ExprContext *cxt = aggstate->curaggcontext;
3722 
3723  RegisterExprContextCallback(cxt, func, arg);
3724 
3725  return;
3726  }
3727  elog(ERROR, "aggregate function cannot register a callback in this context");
3728 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
fmNodePtr context
Definition: fmgr.h:88
#define ERROR
Definition: elog.h:43
ExprContext * curaggcontext
Definition: execnodes.h:2046
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:863
#define elog(elevel,...)
Definition: elog.h:228
void * arg

◆ AggStateIsShared()

bool AggStateIsShared ( FunctionCallInfo  fcinfo)

Definition at line 3675 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

3676 {
3677  if (fcinfo->context && IsA(fcinfo->context, AggState))
3678  {
3679  AggState *aggstate = (AggState *) fcinfo->context;
3680  AggStatePerAgg curperagg;
3681  AggStatePerTrans curpertrans;
3682 
3683  /* check curperagg (valid when in a final function) */
3684  curperagg = aggstate->curperagg;
3685 
3686  if (curperagg)
3687  return aggstate->pertrans[curperagg->transno].aggshared;
3688 
3689  /* check curpertrans (valid when in a transition function) */
3690  curpertrans = aggstate->curpertrans;
3691 
3692  if (curpertrans)
3693  return curpertrans->aggshared;
3694  }
3695  return true;
3696 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
fmNodePtr context
Definition: fmgr.h:88
AggStatePerTrans pertrans
Definition: execnodes.h:2041
AggStatePerAgg curperagg
Definition: execnodes.h:2047
AggStatePerTrans curpertrans
Definition: execnodes.h:2049

◆ build_hash_table()

static void build_hash_table ( AggState aggstate)
static

Definition at line 1264 of file nodeAgg.c.

References AGG_HASHED, AGG_MIXED, AggStatePerHashData::aggnode, AggState::aggsplit, AggState::aggstrategy, Assert, BuildTupleHashTableExt(), DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_per_tuple_memory, AggStatePerHashData::eqfuncoids, EState::es_query_cxt, Agg::grpCollations, AggState::hashcontext, AggStatePerHashData::hashfunctions, AggStatePerHashData::hashGrpColIdxHash, AggStatePerHashData::hashslot, AggStatePerHashData::hashtable, i, AggState::num_hashes, AggStatePerHashData::numCols, Agg::numGroups, AggState::numtrans, AggState::perhash, ScanState::ps, ResetTupleHashTable(), AggState::ss, PlanState::state, AggState::tmpcontext, and TupleTableSlot::tts_tupleDescriptor.

Referenced by ExecInitAgg(), and ExecReScanAgg().

1265 {
1266  MemoryContext tmpmem = aggstate->tmpcontext->ecxt_per_tuple_memory;
1267  Size additionalsize;
1268  int i;
1269 
1270  Assert(aggstate->aggstrategy == AGG_HASHED || aggstate->aggstrategy == AGG_MIXED);
1271 
1272  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1273 
1274  for (i = 0; i < aggstate->num_hashes; ++i)
1275  {
1276  AggStatePerHash perhash = &aggstate->perhash[i];
1277 
1278  Assert(perhash->aggnode->numGroups > 0);
1279 
1280  if (perhash->hashtable)
1281  ResetTupleHashTable(perhash->hashtable);
1282  else
1283  perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
1284  perhash->hashslot->tts_tupleDescriptor,
1285  perhash->numCols,
1286  perhash->hashGrpColIdxHash,
1287  perhash->eqfuncoids,
1288  perhash->hashfunctions,
1289  perhash->aggnode->grpCollations,
1290  perhash->aggnode->numGroups,
1291  additionalsize,
1292  aggstate->ss.ps.state->es_query_cxt,
1294  tmpmem,
1295  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1296  }
1297 }
TupleHashTable BuildTupleHashTableExt(PlanState *parent, TupleDesc inputDesc, int numCols, AttrNumber *keyColIdx, const Oid *eqfuncoids, FmgrInfo *hashfunctions, Oid *collations, long nbuckets, Size additionalsize, MemoryContext metacxt, MemoryContext tablecxt, MemoryContext tempcxt, bool use_variable_hash_iv)
Definition: execGrouping.c:154
Oid * grpCollations
Definition: plannodes.h:814
ScanState ss
Definition: execnodes.h:2031
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:231
AggSplit aggsplit
Definition: execnodes.h:2036
EState * state
Definition: execnodes.h:941
int numtrans
Definition: execnodes.h:2034
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:282
ExprContext * tmpcontext
Definition: execnodes.h:2044
PlanState ps
Definition: execnodes.h:1326
MemoryContext es_query_cxt
Definition: execnodes.h:549
AggStrategy aggstrategy
Definition: execnodes.h:2035
struct AggStatePerGroupData AggStatePerGroupData
AggStatePerHash perhash
Definition: execnodes.h:2070
int num_hashes
Definition: execnodes.h:2069
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:303
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2042
FmgrInfo * hashfunctions
Definition: nodeAgg.h:297
#define Assert(condition)
Definition: c.h:739
size_t Size
Definition: c.h:467
long numGroups
Definition: plannodes.h:815
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:788
int i
TupleTableSlot * hashslot
Definition: nodeAgg.h:296
TupleHashTable hashtable
Definition: nodeAgg.h:294

◆ build_pertrans_for_aggref()

static void build_pertrans_for_aggref ( AggStatePerTrans  pertrans,
AggState aggstate,
EState estate,
Aggref aggref,
Oid  aggtransfn,
Oid  aggtranstype,
Oid  aggserialfn,
Oid  aggdeserialfn,
Datum  initValue,
bool  initValueIsNull,
Oid inputTypes,
int  numArguments 
)
static

Definition at line 2922 of file nodeAgg.c.

References AGG_HASHED, AGG_MIXED, AggStatePerTransData::aggCollation, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggkind, Aggref::aggorder, AggStatePerTransData::aggref, AggStatePerTransData::aggshared, AggState::aggsplit, AggState::aggstrategy, AggStatePerTransData::aggtranstype, Aggref::aggvariadic, Aggref::args, Assert, build_aggregate_combinefn_expr(), build_aggregate_deserialfn_expr(), build_aggregate_serialfn_expr(), build_aggregate_transfn_expr(), AggStatePerTransData::deserialfn, AggStatePerTransData::deserialfn_fcinfo, AggStatePerTransData::deserialfn_oid, DO_AGGSPLIT_COMBINE, AggStatePerTransData::equalfnMulti, AggStatePerTransData::equalfnOne, ereport, errcode(), errmsg(), ERROR, ExecInitExtraTupleSlot(), execTuplesMatchPrepare(), ExecTypeFromTL(), TargetEntry::expr, exprCollation(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_strict, format_type_be(), get_opcode(), get_sortgroupclause_tle(), get_typlenbyval(), i, InitFunctionCallInfoData, AggStatePerTransData::initValue, initValue(), AggStatePerTransData::initValueIsNull, Aggref::inputcollid, AggStatePerTransData::inputtypeByVal, AggStatePerTransData::inputtypeLen, InvalidOid, IsBinaryCoercible(), lfirst, list_length(), Max, AggState::maxsets, NIL, SortGroupClause::nulls_first, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numInputs, AggStatePerTransData::numSortCols, AggStatePerTransData::numTransInputs, OidIsValid, palloc(), palloc0(), pfree(), ScanState::ps, TargetEntry::resno, AggStatePerTransData::serialfn, AggStatePerTransData::serialfn_fcinfo, AggStatePerTransData::serialfn_oid, SizeForFunctionCallInfo, AggStatePerTransData::sortColIdx, AggStatePerTransData::sortCollations, AggStatePerTransData::sortdesc, AggStatePerTransData::sortNullsFirst, SortGroupClause::sortop, AggStatePerTransData::sortOperators, AggStatePerTransData::sortslot, AggStatePerTransData::sortstates, AggState::ss, AggStatePerTransData::transfn, AggStatePerTransData::transfn_fcinfo, AggStatePerTransData::transfn_oid, AggStatePerTransData::transtypeByVal, AggStatePerTransData::transtypeLen, TTSOpsMinimalTuple, and AggStatePerTransData::uniqslot.

Referenced by ExecInitAgg().

2929 {
2930  int numGroupingSets = Max(aggstate->maxsets, 1);
2931  Expr *serialfnexpr = NULL;
2932  Expr *deserialfnexpr = NULL;
2933  ListCell *lc;
2934  int numInputs;
2935  int numDirectArgs;
2936  List *sortlist;
2937  int numSortCols;
2938  int numDistinctCols;
2939  int i;
2940 
2941  /* Begin filling in the pertrans data */
2942  pertrans->aggref = aggref;
2943  pertrans->aggshared = false;
2944  pertrans->aggCollation = aggref->inputcollid;
2945  pertrans->transfn_oid = aggtransfn;
2946  pertrans->serialfn_oid = aggserialfn;
2947  pertrans->deserialfn_oid = aggdeserialfn;
2948  pertrans->initValue = initValue;
2949  pertrans->initValueIsNull = initValueIsNull;
2950 
2951  /* Count the "direct" arguments, if any */
2952  numDirectArgs = list_length(aggref->aggdirectargs);
2953 
2954  /* Count the number of aggregated input columns */
2955  pertrans->numInputs = numInputs = list_length(aggref->args);
2956 
2957  pertrans->aggtranstype = aggtranstype;
2958 
2959  /*
2960  * When combining states, we have no use at all for the aggregate
2961  * function's transfn. Instead we use the combinefn. In this case, the
2962  * transfn and transfn_oid fields of pertrans refer to the combine
2963  * function rather than the transition function.
2964  */
2965  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2966  {
2967  Expr *combinefnexpr;
2968  size_t numTransArgs;
2969 
2970  /*
2971  * When combining there's only one input, the to-be-combined added
2972  * transition value from below (this node's transition value is
2973  * counted separately).
2974  */
2975  pertrans->numTransInputs = 1;
2976 
2977  /* account for the current transition state */
2978  numTransArgs = pertrans->numTransInputs + 1;
2979 
2980  build_aggregate_combinefn_expr(aggtranstype,
2981  aggref->inputcollid,
2982  aggtransfn,
2983  &combinefnexpr);
2984  fmgr_info(aggtransfn, &pertrans->transfn);
2985  fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
2986 
2987  pertrans->transfn_fcinfo =
2990  &pertrans->transfn,
2991  numTransArgs,
2992  pertrans->aggCollation,
2993  (void *) aggstate, NULL);
2994 
2995  /*
2996  * Ensure that a combine function to combine INTERNAL states is not
2997  * strict. This should have been checked during CREATE AGGREGATE, but
2998  * the strict property could have been changed since then.
2999  */
3000  if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
3001  ereport(ERROR,
3002  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3003  errmsg("combine function with transition type %s must not be declared STRICT",
3004  format_type_be(aggtranstype))));
3005  }
3006  else
3007  {
3008  Expr *transfnexpr;
3009  size_t numTransArgs;
3010 
3011  /* Detect how many arguments to pass to the transfn */
3012  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3013  pertrans->numTransInputs = numInputs;
3014  else
3015  pertrans->numTransInputs = numArguments;
3016 
3017  /* account for the current transition state */
3018  numTransArgs = pertrans->numTransInputs + 1;
3019 
3020  /*
3021  * Set up infrastructure for calling the transfn. Note that
3022  * invtransfn is not needed here.
3023  */
3024  build_aggregate_transfn_expr(inputTypes,
3025  numArguments,
3026  numDirectArgs,
3027  aggref->aggvariadic,
3028  aggtranstype,
3029  aggref->inputcollid,
3030  aggtransfn,
3031  InvalidOid,
3032  &transfnexpr,
3033  NULL);
3034  fmgr_info(aggtransfn, &pertrans->transfn);
3035  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
3036 
3037  pertrans->transfn_fcinfo =
3040  &pertrans->transfn,
3041  numTransArgs,
3042  pertrans->aggCollation,
3043  (void *) aggstate, NULL);
3044 
3045  /*
3046  * If the transfn is strict and the initval is NULL, make sure input
3047  * type and transtype are the same (or at least binary-compatible), so
3048  * that it's OK to use the first aggregated input value as the initial
3049  * transValue. This should have been checked at agg definition time,
3050  * but we must check again in case the transfn's strictness property
3051  * has been changed.
3052  */
3053  if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
3054  {
3055  if (numArguments <= numDirectArgs ||
3056  !IsBinaryCoercible(inputTypes[numDirectArgs],
3057  aggtranstype))
3058  ereport(ERROR,
3059  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3060  errmsg("aggregate %u needs to have compatible input type and transition type",
3061  aggref->aggfnoid)));
3062  }
3063  }
3064 
3065  /* get info about the state value's datatype */
3066  get_typlenbyval(aggtranstype,
3067  &pertrans->transtypeLen,
3068  &pertrans->transtypeByVal);
3069 
3070  if (OidIsValid(aggserialfn))
3071  {
3072  build_aggregate_serialfn_expr(aggserialfn,
3073  &serialfnexpr);
3074  fmgr_info(aggserialfn, &pertrans->serialfn);
3075  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
3076 
3077  pertrans->serialfn_fcinfo =
3080  &pertrans->serialfn,
3081  1,
3082  InvalidOid,
3083  (void *) aggstate, NULL);
3084  }
3085 
3086  if (OidIsValid(aggdeserialfn))
3087  {
3088  build_aggregate_deserialfn_expr(aggdeserialfn,
3089  &deserialfnexpr);
3090  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
3091  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
3092 
3093  pertrans->deserialfn_fcinfo =
3096  &pertrans->deserialfn,
3097  2,
3098  InvalidOid,
3099  (void *) aggstate, NULL);
3100 
3101  }
3102 
3103  /*
3104  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
3105  * have a list of SortGroupClause nodes; fish out the data in them and
3106  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
3107  * however; the agg's transfn and finalfn are responsible for that.
3108  *
3109  * Note that by construction, if there is a DISTINCT clause then the ORDER
3110  * BY clause is a prefix of it (see transformDistinctClause).
3111  */
3112  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3113  {
3114  sortlist = NIL;
3115  numSortCols = numDistinctCols = 0;
3116  }
3117  else if (aggref->aggdistinct)
3118  {
3119  sortlist = aggref->aggdistinct;
3120  numSortCols = numDistinctCols = list_length(sortlist);
3121  Assert(numSortCols >= list_length(aggref->aggorder));
3122  }
3123  else
3124  {
3125  sortlist = aggref->aggorder;
3126  numSortCols = list_length(sortlist);
3127  numDistinctCols = 0;
3128  }
3129 
3130  pertrans->numSortCols = numSortCols;
3131  pertrans->numDistinctCols = numDistinctCols;
3132 
3133  /*
3134  * If we have either sorting or filtering to do, create a tupledesc and
3135  * slot corresponding to the aggregated inputs (including sort
3136  * expressions) of the agg.
3137  */
3138  if (numSortCols > 0 || aggref->aggfilter)
3139  {
3140  pertrans->sortdesc = ExecTypeFromTL(aggref->args);
3141  pertrans->sortslot =
3142  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
3144  }
3145 
3146  if (numSortCols > 0)
3147  {
3148  /*
3149  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
3150  * (yet)
3151  */
3152  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
3153 
3154  /* If we have only one input, we need its len/byval info. */
3155  if (numInputs == 1)
3156  {
3157  get_typlenbyval(inputTypes[numDirectArgs],
3158  &pertrans->inputtypeLen,
3159  &pertrans->inputtypeByVal);
3160  }
3161  else if (numDistinctCols > 0)
3162  {
3163  /* we will need an extra slot to store prior values */
3164  pertrans->uniqslot =
3165  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
3167  }
3168 
3169  /* Extract the sort information for use later */
3170  pertrans->sortColIdx =
3171  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
3172  pertrans->sortOperators =
3173  (Oid *) palloc(numSortCols * sizeof(Oid));
3174  pertrans->sortCollations =
3175  (Oid *) palloc(numSortCols * sizeof(Oid));
3176  pertrans->sortNullsFirst =
3177  (bool *) palloc(numSortCols * sizeof(bool));
3178 
3179  i = 0;
3180  foreach(lc, sortlist)
3181  {
3182  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
3183  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
3184 
3185  /* the parser should have made sure of this */
3186  Assert(OidIsValid(sortcl->sortop));
3187 
3188  pertrans->sortColIdx[i] = tle->resno;
3189  pertrans->sortOperators[i] = sortcl->sortop;
3190  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
3191  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
3192  i++;
3193  }
3194  Assert(i == numSortCols);
3195  }
3196 
3197  if (aggref->aggdistinct)
3198  {
3199  Oid *ops;
3200 
3201  Assert(numArguments > 0);
3202  Assert(list_length(aggref->aggdistinct) == numDistinctCols);
3203 
3204  ops = palloc(numDistinctCols * sizeof(Oid));
3205 
3206  i = 0;
3207  foreach(lc, aggref->aggdistinct)
3208  ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
3209 
3210  /* lookup / build the necessary comparators */
3211  if (numDistinctCols == 1)
3212  fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
3213  else
3214  pertrans->equalfnMulti =
3215  execTuplesMatchPrepare(pertrans->sortdesc,
3216  numDistinctCols,
3217  pertrans->sortColIdx,
3218  ops,
3219  pertrans->sortCollations,
3220  &aggstate->ss.ps);
3221  pfree(ops);
3222  }
3223 
3224  pertrans->sortstates = (Tuplesortstate **)
3225  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
3226 }
List * aggdistinct
Definition: primnodes.h:307
#define NIL
Definition: pg_list.h:65
bool aggvariadic
Definition: primnodes.h:310
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:389
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
ScanState ss
Definition: execnodes.h:2031
FmgrInfo equalfnOne
Definition: nodeAgg.h:109
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
Oid inputcollid
Definition: primnodes.h:301
Definition: nodes.h:525
AggSplit aggsplit
Definition: execnodes.h:2036
int errcode(int sqlerrcode)
Definition: elog.c:608
List * args
Definition: primnodes.h:305
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
void build_aggregate_deserialfn_expr(Oid deserialfn_oid, Expr **deserialfnexpr)
Definition: parse_agg.c:2013
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:787
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:161
TupleDesc sortdesc
Definition: nodeAgg.h:137
FmgrInfo transfn
Definition: nodeAgg.h:80
Aggref * aggref
Definition: nodeAgg.h:43
PlanState ps
Definition: execnodes.h:1326
int maxsets
Definition: execnodes.h:2058
void pfree(void *pointer)
Definition: mcxt.c:1056
AggStrategy aggstrategy
Definition: execnodes.h:2035
#define ERROR
Definition: elog.h:43
bool fn_strict
Definition: fmgr.h:61
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:124
ExprState * equalfnMulti
Definition: nodeAgg.h:110
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
static int initValue(long lng_val)
Definition: informix.c:677
List * aggorder
Definition: primnodes.h:306
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
AttrNumber resno
Definition: primnodes.h:1394
List * aggdirectargs
Definition: primnodes.h:304
AttrNumber * sortColIdx
Definition: nodeAgg.h:99
#define ereport(elevel, rest)
Definition: elog.h:141
void build_aggregate_combinefn_expr(Oid agg_state_type, Oid agg_input_collation, Oid combinefn_oid, Expr **combinefnexpr)
Definition: parse_agg.c:1961
bool IsBinaryCoercible(Oid srctype, Oid targettype)
void * palloc0(Size size)
Definition: mcxt.c:980
struct FunctionCallInfoBaseData * FunctionCallInfo
Definition: fmgr.h:38
FmgrInfo deserialfn
Definition: nodeAgg.h:86
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1092
Oid aggfnoid
Definition: primnodes.h:298
#define Max(x, y)
Definition: c.h:905
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
FmgrInfo serialfn
Definition: nodeAgg.h:83
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:166
void build_aggregate_serialfn_expr(Oid serialfn_oid, Expr **serialfnexpr)
Definition: parse_agg.c:1990
Expr * expr
Definition: primnodes.h:1393
void build_aggregate_transfn_expr(Oid *agg_input_types, int agg_num_inputs, int agg_num_direct_inputs, bool agg_variadic, Oid agg_state_type, Oid agg_input_collation, Oid transfn_oid, Oid invtransfn_oid, Expr **transfnexpr, Expr **invtransfnexpr)
Definition: parse_agg.c:1900
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
FunctionCallInfo serialfn_fcinfo
Definition: nodeAgg.h:164
static int list_length(const List *l)
Definition: pg_list.h:169
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:719
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2029
Expr * aggfilter
Definition: primnodes.h:308
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1908
TupleTableSlot * uniqslot
Definition: nodeAgg.h:136
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
char aggkind
Definition: primnodes.h:312
TupleTableSlot * sortslot
Definition: nodeAgg.h:135
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
bool * sortNullsFirst
Definition: nodeAgg.h:102

◆ ExecAgg()

static TupleTableSlot* ExecAgg ( PlanState pstate)
static

Definition at line 1551 of file nodeAgg.c.

References AggState::agg_done, agg_fill_hash_table(), AGG_HASHED, AGG_MIXED, AGG_PLAIN, agg_retrieve_direct(), agg_retrieve_hash_table(), AGG_SORTED, AggStatePerPhaseData::aggstrategy, castNode, CHECK_FOR_INTERRUPTS, AggState::phase, AggState::table_filled, and TupIsNull.

Referenced by ExecInitAgg().

1552 {
1553  AggState *node = castNode(AggState, pstate);
1554  TupleTableSlot *result = NULL;
1555 
1557 
1558  if (!node->agg_done)
1559  {
1560  /* Dispatch based on strategy */
1561  switch (node->phase->aggstrategy)
1562  {
1563  case AGG_HASHED:
1564  if (!node->table_filled)
1565  agg_fill_hash_table(node);
1566  /* FALLTHROUGH */
1567  case AGG_MIXED:
1568  result = agg_retrieve_hash_table(node);
1569  break;
1570  case AGG_PLAIN:
1571  case AGG_SORTED:
1572  result = agg_retrieve_direct(node);
1573  break;
1574  }
1575 
1576  if (!TupIsNull(result))
1577  return result;
1578  }
1579 
1580  return NULL;
1581 }
static void agg_fill_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1927
bool agg_done
Definition: execnodes.h:2051
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
bool table_filled
Definition: execnodes.h:2068
static TupleTableSlot * agg_retrieve_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1969
static TupleTableSlot * agg_retrieve_direct(AggState *aggstate)
Definition: nodeAgg.c:1587
#define TupIsNull(slot)
Definition: tuptable.h:292
AggStrategy aggstrategy
Definition: nodeAgg.h:273
AggStatePerPhase phase
Definition: execnodes.h:2037
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

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

3388 {
3390  int transno;
3391  int numGroupingSets = Max(node->maxsets, 1);
3392  int setno;
3393 
3394  /* Make sure we have closed any open tuplesorts */
3395 
3396  if (node->sort_in)
3397  tuplesort_end(node->sort_in);
3398  if (node->sort_out)
3399  tuplesort_end(node->sort_out);
3400 
3401  for (transno = 0; transno < node->numtrans; transno++)
3402  {
3403  AggStatePerTrans pertrans = &node->pertrans[transno];
3404 
3405  for (setno = 0; setno < numGroupingSets; setno++)
3406  {
3407  if (pertrans->sortstates[setno])
3408  tuplesort_end(pertrans->sortstates[setno]);
3409  }
3410  }
3411 
3412  /* And ensure any agg shutdown callbacks have been called */
3413  for (setno = 0; setno < numGroupingSets; setno++)
3414  ReScanExprContext(node->aggcontexts[setno]);
3415  if (node->hashcontext)
3417 
3418  /*
3419  * We don't actually free any ExprContexts here (see comment in
3420  * ExecFreeExprContext), just unlinking the output one from the plan node
3421  * suffices.
3422  */
3423  ExecFreeExprContext(&node->ss.ps);
3424 
3425  /* clean up tuple table */
3427 
3428  outerPlan = outerPlanState(node);
3429  ExecEndNode(outerPlan);
3430 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:537
Tuplesortstate * sort_out
Definition: execnodes.h:2061
ScanState ss
Definition: execnodes.h:2031
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1329
AggStatePerTrans pertrans
Definition: execnodes.h:2041
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:614
int numtrans
Definition: execnodes.h:2034
PlanState ps
Definition: execnodes.h:1326
int maxsets
Definition: execnodes.h:2058
Tuplesortstate * sort_in
Definition: execnodes.h:2060
#define outerPlanState(node)
Definition: execnodes.h:1033
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
#define outerPlan(node)
Definition: plannodes.h:172
ExprContext * hashcontext
Definition: execnodes.h:2042
#define Max(x, y)
Definition: c.h:905
ExprContext ** aggcontexts
Definition: execnodes.h:2043
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:402
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236

◆ ExecInitAgg()

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

Definition at line 2096 of file nodeAgg.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, AggState::agg_done, AGG_HASHED, AGG_MIXED, AGG_PLAIN, AGG_SORTED, AggState::aggcontexts, AggStatePerAggData::aggdirectargs, Aggref::aggdirectargs, AGGFNOID, Aggref::aggfnoid, Aggref::agglevelsup, AggrefExprState::aggno, AggStatePerPhaseData::aggnode, AggStatePerHashData::aggnode, AggStatePerAggData::aggref, AggrefExprState::aggref, AggState::aggs, AggStatePerTransData::aggshared, Aggref::aggsplit, Agg::aggsplit, AggState::aggsplit, AggStatePerPhaseData::aggstrategy, Agg::aggstrategy, AggState::aggstrategy, Aggref::aggtranstype, Aggref::aggtype, Assert, bms_add_member(), bms_add_members(), bms_next_member(), build_aggregate_finalfn_expr(), build_hash_table(), build_pertrans_for_aggref(), castNode, Agg::chain, AggState::curperagg, AggState::curpertrans, AggState::current_set, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_DESERIALIZE, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, elog, AggStatePerPhaseData::eqfunctions, ereport, errcode(), errmsg(), ERROR, AggStatePerPhaseData::evaltrans, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, EXEC_FLAG_REWIND, ExecAgg(), ExecAssignExprContext(), ExecAssignProjectionInfo(), ExecBuildAggTrans(), ExecCreateScanSlotFromOuterPlan(), ExecGetResultSlotOps(), ExecInitExprList(), ExecInitExtraTupleSlot(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), PlanState::ExecProcNode, execTuplesMatchPrepare(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, find_compatible_peragg(), find_compatible_pertrans(), find_hash_columns(), fmgr_info(), fmgr_info_set_expr, FUNC_MAX_ARGS, get_aggregate_argtypes(), get_func_name(), get_typlenbyval(), GetAggInitVal(), GETSTRUCT, GetUserId(), AggStatePerPhaseData::grouped_cols, Agg::groupingSets, AggState::grp_firstTuple, Agg::grpColIdx, Agg::grpCollations, Agg::grpOperators, AggStatePerPhaseData::gset_lengths, AggState::hashcontext, HeapTupleIsValid, i, initialize_phase(), initValue(), AggState::input_done, Aggref::inputcollid, InvalidOid, InvokeFunctionExecuteHook, lcons_int(), Plan::lefttree, lfirst, list_length(), list_nth_node, makeNode, Max, AggState::maxsets, NIL, AggState::numaggs, AggStatePerHashData::numCols, Agg::numCols, AggStatePerAggData::numFinalArgs, AggState::numphases, AggStatePerPhaseData::numsets, AggState::numtrans, OBJECT_AGGREGATE, OBJECT_FUNCTION, ObjectIdGetDatum, OidIsValid, PlanState::outerops, PlanState::outeropsfixed, PlanState::outeropsset, outerPlan, outerPlanState, palloc(), palloc0(), AggState::peragg, AggState::pergroups, AggState::pertrans, pg_proc_aclcheck(), Agg::plan, PlanState::plan, PROCOID, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, Plan::qual, PlanState::qual, ReleaseSysCache(), AggStatePerAggData::resulttypeByVal, AggStatePerAggData::resulttypeLen, SearchSysCache1(), select_current_set(), AggStatePerAggData::shareable, AggState::sort_in, AggState::sort_out, AggState::sort_slot, AggStatePerPhaseData::sortnode, AggState::ss, ScanState::ss_ScanTupleSlot, PlanState::state, SysCacheGetAttr(), AggState::tmpcontext, AggStatePerAggData::transno, TupleTableSlot::tts_tupleDescriptor, TTSOpsMinimalTuple, and TTSOpsVirtual.

Referenced by ExecInitNode().

2097 {
2098  AggState *aggstate;
2099  AggStatePerAgg peraggs;
2100  AggStatePerTrans pertransstates;
2101  AggStatePerGroup *pergroups;
2102  Plan *outerPlan;
2103  ExprContext *econtext;
2104  TupleDesc scanDesc;
2105  int numaggs,
2106  transno,
2107  aggno;
2108  int phase;
2109  int phaseidx;
2110  ListCell *l;
2111  Bitmapset *all_grouped_cols = NULL;
2112  int numGroupingSets = 1;
2113  int numPhases;
2114  int numHashes;
2115  int i = 0;
2116  int j = 0;
2117  bool use_hashing = (node->aggstrategy == AGG_HASHED ||
2118  node->aggstrategy == AGG_MIXED);
2119 
2120  /* check for unsupported flags */
2121  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
2122 
2123  /*
2124  * create state structure
2125  */
2126  aggstate = makeNode(AggState);
2127  aggstate->ss.ps.plan = (Plan *) node;
2128  aggstate->ss.ps.state = estate;
2129  aggstate->ss.ps.ExecProcNode = ExecAgg;
2130 
2131  aggstate->aggs = NIL;
2132  aggstate->numaggs = 0;
2133  aggstate->numtrans = 0;
2134  aggstate->aggstrategy = node->aggstrategy;
2135  aggstate->aggsplit = node->aggsplit;
2136  aggstate->maxsets = 0;
2137  aggstate->projected_set = -1;
2138  aggstate->current_set = 0;
2139  aggstate->peragg = NULL;
2140  aggstate->pertrans = NULL;
2141  aggstate->curperagg = NULL;
2142  aggstate->curpertrans = NULL;
2143  aggstate->input_done = false;
2144  aggstate->agg_done = false;
2145  aggstate->pergroups = NULL;
2146  aggstate->grp_firstTuple = NULL;
2147  aggstate->sort_in = NULL;
2148  aggstate->sort_out = NULL;
2149 
2150  /*
2151  * phases[0] always exists, but is dummy in sorted/plain mode
2152  */
2153  numPhases = (use_hashing ? 1 : 2);
2154  numHashes = (use_hashing ? 1 : 0);
2155 
2156  /*
2157  * Calculate the maximum number of grouping sets in any phase; this
2158  * determines the size of some allocations. Also calculate the number of
2159  * phases, since all hashed/mixed nodes contribute to only a single phase.
2160  */
2161  if (node->groupingSets)
2162  {
2163  numGroupingSets = list_length(node->groupingSets);
2164 
2165  foreach(l, node->chain)
2166  {
2167  Agg *agg = lfirst(l);
2168 
2169  numGroupingSets = Max(numGroupingSets,
2170  list_length(agg->groupingSets));
2171 
2172  /*
2173  * additional AGG_HASHED aggs become part of phase 0, but all
2174  * others add an extra phase.
2175  */
2176  if (agg->aggstrategy != AGG_HASHED)
2177  ++numPhases;
2178  else
2179  ++numHashes;
2180  }
2181  }
2182 
2183  aggstate->maxsets = numGroupingSets;
2184  aggstate->numphases = numPhases;
2185 
2186  aggstate->aggcontexts = (ExprContext **)
2187  palloc0(sizeof(ExprContext *) * numGroupingSets);
2188 
2189  /*
2190  * Create expression contexts. We need three or more, one for
2191  * per-input-tuple processing, one for per-output-tuple processing, one
2192  * for all the hashtables, and one for each grouping set. The per-tuple
2193  * memory context of the per-grouping-set ExprContexts (aggcontexts)
2194  * replaces the standalone memory context formerly used to hold transition
2195  * values. We cheat a little by using ExecAssignExprContext() to build
2196  * all of them.
2197  *
2198  * NOTE: the details of what is stored in aggcontexts and what is stored
2199  * in the regular per-query memory context are driven by a simple
2200  * decision: we want to reset the aggcontext at group boundaries (if not
2201  * hashing) and in ExecReScanAgg to recover no-longer-wanted space.
2202  */
2203  ExecAssignExprContext(estate, &aggstate->ss.ps);
2204  aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
2205 
2206  for (i = 0; i < numGroupingSets; ++i)
2207  {
2208  ExecAssignExprContext(estate, &aggstate->ss.ps);
2209  aggstate->aggcontexts[i] = aggstate->ss.ps.ps_ExprContext;
2210  }
2211 
2212  if (use_hashing)
2213  {
2214  ExecAssignExprContext(estate, &aggstate->ss.ps);
2215  aggstate->hashcontext = aggstate->ss.ps.ps_ExprContext;
2216  }
2217 
2218  ExecAssignExprContext(estate, &aggstate->ss.ps);
2219 
2220  /*
2221  * Initialize child nodes.
2222  *
2223  * If we are doing a hashed aggregation then the child plan does not need
2224  * to handle REWIND efficiently; see ExecReScanAgg.
2225  */
2226  if (node->aggstrategy == AGG_HASHED)
2227  eflags &= ~EXEC_FLAG_REWIND;
2228  outerPlan = outerPlan(node);
2229  outerPlanState(aggstate) = ExecInitNode(outerPlan, estate, eflags);
2230 
2231  /*
2232  * initialize source tuple type.
2233  */
2234  aggstate->ss.ps.outerops =
2236  &aggstate->ss.ps.outeropsfixed);
2237  aggstate->ss.ps.outeropsset = true;
2238 
2239  ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
2240  aggstate->ss.ps.outerops);
2241  scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
2242 
2243  /*
2244  * If there are more than two phases (including a potential dummy phase
2245  * 0), input will be resorted using tuplesort. Need a slot for that.
2246  */
2247  if (numPhases > 2)
2248  {
2249  aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
2251 
2252  /*
2253  * The output of the tuplesort, and the output from the outer child
2254  * might not use the same type of slot. In most cases the child will
2255  * be a Sort, and thus return a TTSOpsMinimalTuple type slot - but the
2256  * input can also be be presorted due an index, in which case it could
2257  * be a different type of slot.
2258  *
2259  * XXX: For efficiency it would be good to instead/additionally
2260  * generate expressions with corresponding settings of outerops* for
2261  * the individual phases - deforming is often a bottleneck for
2262  * aggregations with lots of rows per group. If there's multiple
2263  * sorts, we know that all but the first use TTSOpsMinimalTuple (via
2264  * the nodeAgg.c internal tuplesort).
2265  */
2266  if (aggstate->ss.ps.outeropsfixed &&
2267  aggstate->ss.ps.outerops != &TTSOpsMinimalTuple)
2268  aggstate->ss.ps.outeropsfixed = false;
2269  }
2270 
2271  /*
2272  * Initialize result type, slot and projection.
2273  */
2275  ExecAssignProjectionInfo(&aggstate->ss.ps, NULL);
2276 
2277  /*
2278  * initialize child expressions
2279  *
2280  * We expect the parser to have checked that no aggs contain other agg
2281  * calls in their arguments (and just to be sure, we verify it again while
2282  * initializing the plan node). This would make no sense under SQL
2283  * semantics, and it's forbidden by the spec. Because it is true, we
2284  * don't need to worry about evaluating the aggs in any particular order.
2285  *
2286  * Note: execExpr.c finds Aggrefs for us, and adds their AggrefExprState
2287  * nodes to aggstate->aggs. Aggrefs in the qual are found here; Aggrefs
2288  * in the targetlist are found during ExecAssignProjectionInfo, below.
2289  */
2290  aggstate->ss.ps.qual =
2291  ExecInitQual(node->plan.qual, (PlanState *) aggstate);
2292 
2293  /*
2294  * We should now have found all Aggrefs in the targetlist and quals.
2295  */
2296  numaggs = aggstate->numaggs;
2297  Assert(numaggs == list_length(aggstate->aggs));
2298 
2299  /*
2300  * For each phase, prepare grouping set data and fmgr lookup data for
2301  * compare functions. Accumulate all_grouped_cols in passing.
2302  */
2303  aggstate->phases = palloc0(numPhases * sizeof(AggStatePerPhaseData));
2304 
2305  aggstate->num_hashes = numHashes;
2306  if (numHashes)
2307  {
2308  aggstate->perhash = palloc0(sizeof(AggStatePerHashData) * numHashes);
2309  aggstate->phases[0].numsets = 0;
2310  aggstate->phases[0].gset_lengths = palloc(numHashes * sizeof(int));
2311  aggstate->phases[0].grouped_cols = palloc(numHashes * sizeof(Bitmapset *));
2312  }
2313 
2314  phase = 0;
2315  for (phaseidx = 0; phaseidx <= list_length(node->chain); ++phaseidx)
2316  {
2317  Agg *aggnode;
2318  Sort *sortnode;
2319 
2320  if (phaseidx > 0)
2321  {
2322  aggnode = list_nth_node(Agg, node->chain, phaseidx - 1);
2323  sortnode = castNode(Sort, aggnode->plan.lefttree);
2324  }
2325  else
2326  {
2327  aggnode = node;
2328  sortnode = NULL;
2329  }
2330 
2331  Assert(phase <= 1 || sortnode);
2332 
2333  if (aggnode->aggstrategy == AGG_HASHED
2334  || aggnode->aggstrategy == AGG_MIXED)
2335  {
2336  AggStatePerPhase phasedata = &aggstate->phases[0];
2337  AggStatePerHash perhash;
2338  Bitmapset *cols = NULL;
2339 
2340  Assert(phase == 0);
2341  i = phasedata->numsets++;
2342  perhash = &aggstate->perhash[i];
2343 
2344  /* phase 0 always points to the "real" Agg in the hash case */
2345  phasedata->aggnode = node;
2346  phasedata->aggstrategy = node->aggstrategy;
2347 
2348  /* but the actual Agg node representing this hash is saved here */
2349  perhash->aggnode = aggnode;
2350 
2351  phasedata->gset_lengths[i] = perhash->numCols = aggnode->numCols;
2352 
2353  for (j = 0; j < aggnode->numCols; ++j)
2354  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
2355 
2356  phasedata->grouped_cols[i] = cols;
2357 
2358  all_grouped_cols = bms_add_members(all_grouped_cols, cols);
2359  continue;
2360  }
2361  else
2362  {
2363  AggStatePerPhase phasedata = &aggstate->phases[++phase];
2364  int num_sets;
2365 
2366  phasedata->numsets = num_sets = list_length(aggnode->groupingSets);
2367 
2368  if (num_sets)
2369  {
2370  phasedata->gset_lengths = palloc(num_sets * sizeof(int));
2371  phasedata->grouped_cols = palloc(num_sets * sizeof(Bitmapset *));
2372 
2373  i = 0;
2374  foreach(l, aggnode->groupingSets)
2375  {
2376  int current_length = list_length(lfirst(l));
2377  Bitmapset *cols = NULL;
2378 
2379  /* planner forces this to be correct */
2380  for (j = 0; j < current_length; ++j)
2381  cols = bms_add_member(cols, aggnode->grpColIdx[j]);
2382 
2383  phasedata->grouped_cols[i] = cols;
2384  phasedata->gset_lengths[i] = current_length;
2385 
2386  ++i;
2387  }
2388 
2389  all_grouped_cols = bms_add_members(all_grouped_cols,
2390  phasedata->grouped_cols[0]);
2391  }
2392  else
2393  {
2394  Assert(phaseidx == 0);
2395 
2396  phasedata->gset_lengths = NULL;
2397  phasedata->grouped_cols = NULL;
2398  }
2399 
2400  /*
2401  * If we are grouping, precompute fmgr lookup data for inner loop.
2402  */
2403  if (aggnode->aggstrategy == AGG_SORTED)
2404  {
2405  int i = 0;
2406 
2407  Assert(aggnode->numCols > 0);
2408 
2409  /*
2410  * Build a separate function for each subset of columns that
2411  * need to be compared.
2412  */
2413  phasedata->eqfunctions =
2414  (ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *));
2415 
2416  /* for each grouping set */
2417  for (i = 0; i < phasedata->numsets; i++)
2418  {
2419  int length = phasedata->gset_lengths[i];
2420 
2421  if (phasedata->eqfunctions[length - 1] != NULL)
2422  continue;
2423 
2424  phasedata->eqfunctions[length - 1] =
2425  execTuplesMatchPrepare(scanDesc,
2426  length,
2427  aggnode->grpColIdx,
2428  aggnode->grpOperators,
2429  aggnode->grpCollations,
2430  (PlanState *) aggstate);
2431  }
2432 
2433  /* and for all grouped columns, unless already computed */
2434  if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL)
2435  {
2436  phasedata->eqfunctions[aggnode->numCols - 1] =
2437  execTuplesMatchPrepare(scanDesc,
2438  aggnode->numCols,
2439  aggnode->grpColIdx,
2440  aggnode->grpOperators,
2441  aggnode->grpCollations,
2442  (PlanState *) aggstate);
2443  }
2444  }
2445 
2446  phasedata->aggnode = aggnode;
2447  phasedata->aggstrategy = aggnode->aggstrategy;
2448  phasedata->sortnode = sortnode;
2449  }
2450  }
2451 
2452  /*
2453  * Convert all_grouped_cols to a descending-order list.
2454  */
2455  i = -1;
2456  while ((i = bms_next_member(all_grouped_cols, i)) >= 0)
2457  aggstate->all_grouped_cols = lcons_int(i, aggstate->all_grouped_cols);
2458 
2459  /*
2460  * Set up aggregate-result storage in the output expr context, and also
2461  * allocate my private per-agg working storage
2462  */
2463  econtext = aggstate->ss.ps.ps_ExprContext;
2464  econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
2465  econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
2466 
2467  peraggs = (AggStatePerAgg) palloc0(sizeof(AggStatePerAggData) * numaggs);
2468  pertransstates = (AggStatePerTrans) palloc0(sizeof(AggStatePerTransData) * numaggs);
2469 
2470  aggstate->peragg = peraggs;
2471  aggstate->pertrans = pertransstates;
2472 
2473 
2474  aggstate->all_pergroups =
2476  * (numGroupingSets + numHashes));
2477  pergroups = aggstate->all_pergroups;
2478 
2479  if (node->aggstrategy != AGG_HASHED)
2480  {
2481  for (i = 0; i < numGroupingSets; i++)
2482  {
2483  pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
2484  * numaggs);
2485  }
2486 
2487  aggstate->pergroups = pergroups;
2488  pergroups += numGroupingSets;
2489  }
2490 
2491  /*
2492  * Hashing can only appear in the initial phase.
2493  */
2494  if (use_hashing)
2495  {
2496  /* this is an array of pointers, not structures */
2497  aggstate->hash_pergroup = pergroups;
2498 
2499  find_hash_columns(aggstate);
2500  build_hash_table(aggstate);
2501  aggstate->table_filled = false;
2502  }
2503 
2504  /*
2505  * Initialize current phase-dependent values to initial phase. The initial
2506  * phase is 1 (first sort pass) for all strategies that use sorting (if
2507  * hashing is being done too, then phase 0 is processed last); but if only
2508  * hashing is being done, then phase 0 is all there is.
2509  */
2510  if (node->aggstrategy == AGG_HASHED)
2511  {
2512  aggstate->current_phase = 0;
2513  initialize_phase(aggstate, 0);
2514  select_current_set(aggstate, 0, true);
2515  }
2516  else
2517  {
2518  aggstate->current_phase = 1;
2519  initialize_phase(aggstate, 1);
2520  select_current_set(aggstate, 0, false);
2521  }
2522 
2523  /* -----------------
2524  * Perform lookups of aggregate function info, and initialize the
2525  * unchanging fields of the per-agg and per-trans data.
2526  *
2527  * We try to optimize by detecting duplicate aggregate functions so that
2528  * their state and final values are re-used, rather than needlessly being
2529  * re-calculated independently. We also detect aggregates that are not
2530  * the same, but which can share the same transition state.
2531  *
2532  * Scenarios:
2533  *
2534  * 1. Identical aggregate function calls appear in the query:
2535  *
2536  * SELECT SUM(x) FROM ... HAVING SUM(x) > 0
2537  *
2538  * Since these aggregates are identical, we only need to calculate
2539  * the value once. Both aggregates will share the same 'aggno' value.
2540  *
2541  * 2. Two different aggregate functions appear in the query, but the
2542  * aggregates have the same arguments, transition functions and
2543  * initial values (and, presumably, different final functions):
2544  *
2545  * SELECT AVG(x), STDDEV(x) FROM ...
2546  *
2547  * In this case we must create a new peragg for the varying aggregate,
2548  * and we need to call the final functions separately, but we need
2549  * only run the transition function once. (This requires that the
2550  * final functions be nondestructive of the transition state, but
2551  * that's required anyway for other reasons.)
2552  *
2553  * For either of these optimizations to be valid, all aggregate properties
2554  * used in the transition phase must be the same, including any modifiers
2555  * such as ORDER BY, DISTINCT and FILTER, and the arguments mustn't
2556  * contain any volatile functions.
2557  * -----------------
2558  */
2559  aggno = -1;
2560  transno = -1;
2561  foreach(l, aggstate->aggs)
2562  {
2563  AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l);
2564  Aggref *aggref = aggrefstate->aggref;
2565  AggStatePerAgg peragg;
2566  AggStatePerTrans pertrans;
2567  int existing_aggno;
2568  int existing_transno;
2569  List *same_input_transnos;
2570  Oid inputTypes[FUNC_MAX_ARGS];
2571  int numArguments;
2572  int numDirectArgs;
2573  HeapTuple aggTuple;
2574  Form_pg_aggregate aggform;
2575  AclResult aclresult;
2576  Oid transfn_oid,
2577  finalfn_oid;
2578  bool shareable;
2579  Oid serialfn_oid,
2580  deserialfn_oid;
2581  Expr *finalfnexpr;
2582  Oid aggtranstype;
2583  Datum textInitVal;
2584  Datum initValue;
2585  bool initValueIsNull;
2586 
2587  /* Planner should have assigned aggregate to correct level */
2588  Assert(aggref->agglevelsup == 0);
2589  /* ... and the split mode should match */
2590  Assert(aggref->aggsplit == aggstate->aggsplit);
2591 
2592  /* 1. Check for already processed aggs which can be re-used */
2593  existing_aggno = find_compatible_peragg(aggref, aggstate, aggno,
2594  &same_input_transnos);
2595  if (existing_aggno != -1)
2596  {
2597  /*
2598  * Existing compatible agg found. so just point the Aggref to the
2599  * same per-agg struct.
2600  */
2601  aggrefstate->aggno = existing_aggno;
2602  continue;
2603  }
2604 
2605  /* Mark Aggref state node with assigned index in the result array */
2606  peragg = &peraggs[++aggno];
2607  peragg->aggref = aggref;
2608  aggrefstate->aggno = aggno;
2609 
2610  /* Fetch the pg_aggregate row */
2611  aggTuple = SearchSysCache1(AGGFNOID,
2612  ObjectIdGetDatum(aggref->aggfnoid));
2613  if (!HeapTupleIsValid(aggTuple))
2614  elog(ERROR, "cache lookup failed for aggregate %u",
2615  aggref->aggfnoid);
2616  aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
2617 
2618  /* Check permission to call aggregate function */
2619  aclresult = pg_proc_aclcheck(aggref->aggfnoid, GetUserId(),
2620  ACL_EXECUTE);
2621  if (aclresult != ACLCHECK_OK)
2622  aclcheck_error(aclresult, OBJECT_AGGREGATE,
2623  get_func_name(aggref->aggfnoid));
2625 
2626  /* planner recorded transition state type in the Aggref itself */
2627  aggtranstype = aggref->aggtranstype;
2628  Assert(OidIsValid(aggtranstype));
2629 
2630  /*
2631  * If this aggregation is performing state combines, then instead of
2632  * using the transition function, we'll use the combine function
2633  */
2634  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2635  {
2636  transfn_oid = aggform->aggcombinefn;
2637 
2638  /* If not set then the planner messed up */
2639  if (!OidIsValid(transfn_oid))
2640  elog(ERROR, "combinefn not set for aggregate function");
2641  }
2642  else
2643  transfn_oid = aggform->aggtransfn;
2644 
2645  /* Final function only required if we're finalizing the aggregates */
2646  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
2647  peragg->finalfn_oid = finalfn_oid = InvalidOid;
2648  else
2649  peragg->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
2650 
2651  /*
2652  * If finalfn is marked read-write, we can't share transition states;
2653  * but it is okay to share states for AGGMODIFY_SHAREABLE aggs. Also,
2654  * if we're not executing the finalfn here, we can share regardless.
2655  */
2656  shareable = (aggform->aggfinalmodify != AGGMODIFY_READ_WRITE) ||
2657  (finalfn_oid == InvalidOid);
2658  peragg->shareable = shareable;
2659 
2660  serialfn_oid = InvalidOid;
2661  deserialfn_oid = InvalidOid;
2662 
2663  /*
2664  * Check if serialization/deserialization is required. We only do it
2665  * for aggregates that have transtype INTERNAL.
2666  */
2667  if (aggtranstype == INTERNALOID)
2668  {
2669  /*
2670  * The planner should only have generated a serialize agg node if
2671  * every aggregate with an INTERNAL state has a serialization
2672  * function. Verify that.
2673  */
2674  if (DO_AGGSPLIT_SERIALIZE(aggstate->aggsplit))
2675  {
2676  /* serialization only valid when not running finalfn */
2678 
2679  if (!OidIsValid(aggform->aggserialfn))
2680  elog(ERROR, "serialfunc not provided for serialization aggregation");
2681  serialfn_oid = aggform->aggserialfn;
2682  }
2683 
2684  /* Likewise for deserialization functions */
2685  if (DO_AGGSPLIT_DESERIALIZE(aggstate->aggsplit))
2686  {
2687  /* deserialization only valid when combining states */
2688  Assert(DO_AGGSPLIT_COMBINE(aggstate->aggsplit));
2689 
2690  if (!OidIsValid(aggform->aggdeserialfn))
2691  elog(ERROR, "deserialfunc not provided for deserialization aggregation");
2692  deserialfn_oid = aggform->aggdeserialfn;
2693  }
2694  }
2695 
2696  /* Check that aggregate owner has permission to call component fns */
2697  {
2698  HeapTuple procTuple;
2699  Oid aggOwner;
2700 
2701  procTuple = SearchSysCache1(PROCOID,
2702  ObjectIdGetDatum(aggref->aggfnoid));
2703  if (!HeapTupleIsValid(procTuple))
2704  elog(ERROR, "cache lookup failed for function %u",
2705  aggref->aggfnoid);
2706  aggOwner = ((Form_pg_proc) GETSTRUCT(procTuple))->proowner;
2707  ReleaseSysCache(procTuple);
2708 
2709  aclresult = pg_proc_aclcheck(transfn_oid, aggOwner,
2710  ACL_EXECUTE);
2711  if (aclresult != ACLCHECK_OK)
2712  aclcheck_error(aclresult, OBJECT_FUNCTION,
2713  get_func_name(transfn_oid));
2714  InvokeFunctionExecuteHook(transfn_oid);
2715  if (OidIsValid(finalfn_oid))
2716  {
2717  aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
2718  ACL_EXECUTE);
2719  if (aclresult != ACLCHECK_OK)
2720  aclcheck_error(aclresult, OBJECT_FUNCTION,
2721  get_func_name(finalfn_oid));
2722  InvokeFunctionExecuteHook(finalfn_oid);
2723  }
2724  if (OidIsValid(serialfn_oid))
2725  {
2726  aclresult = pg_proc_aclcheck(serialfn_oid, aggOwner,
2727  ACL_EXECUTE);
2728  if (aclresult != ACLCHECK_OK)
2729  aclcheck_error(aclresult, OBJECT_FUNCTION,
2730  get_func_name(serialfn_oid));
2731  InvokeFunctionExecuteHook(serialfn_oid);
2732  }
2733  if (OidIsValid(deserialfn_oid))
2734  {
2735  aclresult = pg_proc_aclcheck(deserialfn_oid, aggOwner,
2736  ACL_EXECUTE);
2737  if (aclresult != ACLCHECK_OK)
2738  aclcheck_error(aclresult, OBJECT_FUNCTION,
2739  get_func_name(deserialfn_oid));
2740  InvokeFunctionExecuteHook(deserialfn_oid);
2741  }
2742  }
2743 
2744  /*
2745  * Get actual datatypes of the (nominal) aggregate inputs. These
2746  * could be different from the agg's declared input types, when the
2747  * agg accepts ANY or a polymorphic type.
2748  */
2749  numArguments = get_aggregate_argtypes(aggref, inputTypes);
2750 
2751  /* Count the "direct" arguments, if any */
2752  numDirectArgs = list_length(aggref->aggdirectargs);
2753 
2754  /* Detect how many arguments to pass to the finalfn */
2755  if (aggform->aggfinalextra)
2756  peragg->numFinalArgs = numArguments + 1;
2757  else
2758  peragg->numFinalArgs = numDirectArgs + 1;
2759 
2760  /* Initialize any direct-argument expressions */
2761  peragg->aggdirectargs = ExecInitExprList(aggref->aggdirectargs,
2762  (PlanState *) aggstate);
2763 
2764  /*
2765  * build expression trees using actual argument & result types for the
2766  * finalfn, if it exists and is required.
2767  */
2768  if (OidIsValid(finalfn_oid))
2769  {
2770  build_aggregate_finalfn_expr(inputTypes,
2771  peragg->numFinalArgs,
2772  aggtranstype,
2773  aggref->aggtype,
2774  aggref->inputcollid,
2775  finalfn_oid,
2776  &finalfnexpr);
2777  fmgr_info(finalfn_oid, &peragg->finalfn);
2778  fmgr_info_set_expr((Node *) finalfnexpr, &peragg->finalfn);
2779  }
2780 
2781  /* get info about the output value's datatype */
2782  get_typlenbyval(aggref->aggtype,
2783  &peragg->resulttypeLen,
2784  &peragg->resulttypeByVal);
2785 
2786  /*
2787  * initval is potentially null, so don't try to access it as a struct
2788  * field. Must do it the hard way with SysCacheGetAttr.
2789  */
2790  textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
2791  Anum_pg_aggregate_agginitval,
2792  &initValueIsNull);
2793  if (initValueIsNull)
2794  initValue = (Datum) 0;
2795  else
2796  initValue = GetAggInitVal(textInitVal, aggtranstype);
2797 
2798  /*
2799  * 2. Build working state for invoking the transition function, or
2800  * look up previously initialized working state, if we can share it.
2801  *
2802  * find_compatible_peragg() already collected a list of shareable
2803  * per-Trans's with the same inputs. Check if any of them have the
2804  * same transition function and initial value.
2805  */
2806  existing_transno = find_compatible_pertrans(aggstate, aggref,
2807  shareable,
2808  transfn_oid, aggtranstype,
2809  serialfn_oid, deserialfn_oid,
2810  initValue, initValueIsNull,
2811  same_input_transnos);
2812  if (existing_transno != -1)
2813  {
2814  /*
2815  * Existing compatible trans found, so just point the 'peragg' to
2816  * the same per-trans struct, and mark the trans state as shared.
2817  */
2818  pertrans = &pertransstates[existing_transno];
2819  pertrans->aggshared = true;
2820  peragg->transno = existing_transno;
2821  }
2822  else
2823  {
2824  pertrans = &pertransstates[++transno];
2825  build_pertrans_for_aggref(pertrans, aggstate, estate,
2826  aggref, transfn_oid, aggtranstype,
2827  serialfn_oid, deserialfn_oid,
2828  initValue, initValueIsNull,
2829  inputTypes, numArguments);
2830  peragg->transno = transno;
2831  }
2832  ReleaseSysCache(aggTuple);
2833  }
2834 
2835  /*
2836  * Update aggstate->numaggs to be the number of unique aggregates found.
2837  * Also set numstates to the number of unique transition states found.
2838  */
2839  aggstate->numaggs = aggno + 1;
2840  aggstate->numtrans = transno + 1;
2841 
2842  /*
2843  * Last, check whether any more aggregates got added onto the node while
2844  * we processed the expressions for the aggregate arguments (including not
2845  * only the regular arguments and FILTER expressions handled immediately
2846  * above, but any direct arguments we might've handled earlier). If so,
2847  * we have nested aggregate functions, which is semantically nonsensical,
2848  * so complain. (This should have been caught by the parser, so we don't
2849  * need to work hard on a helpful error message; but we defend against it
2850  * here anyway, just to be sure.)
2851  */
2852  if (numaggs != list_length(aggstate->aggs))
2853  ereport(ERROR,
2854  (errcode(ERRCODE_GROUPING_ERROR),
2855  errmsg("aggregate function calls cannot be nested")));
2856 
2857  /*
2858  * Build expressions doing all the transition work at once. We build a
2859  * different one for each phase, as the number of transition function
2860  * invocation can differ between phases. Note this'll work both for
2861  * transition and combination functions (although there'll only be one
2862  * phase in the latter case).
2863  */
2864  for (phaseidx = 0; phaseidx < aggstate->numphases; phaseidx++)
2865  {
2866  AggStatePerPhase phase = &aggstate->phases[phaseidx];
2867  bool dohash = false;
2868  bool dosort = false;
2869 
2870  /* phase 0 doesn't necessarily exist */
2871  if (!phase->aggnode)
2872  continue;
2873 
2874  if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 1)
2875  {
2876  /*
2877  * Phase one, and only phase one, in a mixed agg performs both
2878  * sorting and aggregation.
2879  */
2880  dohash = true;
2881  dosort = true;
2882  }
2883  else if (aggstate->aggstrategy == AGG_MIXED && phaseidx == 0)
2884  {
2885  /*
2886  * No need to compute a transition function for an AGG_MIXED phase
2887  * 0 - the contents of the hashtables will have been computed
2888  * during phase 1.
2889  */
2890  continue;
2891  }
2892  else if (phase->aggstrategy == AGG_PLAIN ||
2893  phase->aggstrategy == AGG_SORTED)
2894  {
2895  dohash = false;
2896  dosort = true;
2897  }
2898  else if (phase->aggstrategy == AGG_HASHED)
2899  {
2900  dohash = true;
2901  dosort = false;
2902  }
2903  else
2904  Assert(false);
2905 
2906  phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash);
2907 
2908  }
2909 
2910  return aggstate;
2911 }
struct AggStatePerTransData * AggStatePerTrans
Definition: execnodes.h:2024
ExprState ** eqfunctions
Definition: nodeAgg.h:277
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2071
#define NIL
Definition: pg_list.h:65
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2025
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:302
int numCols
Definition: plannodes.h:811
List * qual
Definition: plannodes.h:143
AggStatePerPhase phases
Definition: execnodes.h:2059
Datum * ecxt_aggvalues
Definition: execnodes.h:242
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1801
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
AttrNumber * grpColIdx
Definition: plannodes.h:812
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:463
List * lcons_int(int datum, List *list)
Definition: list.c:472
int numaggs
Definition: execnodes.h:2033
Oid GetUserId(void)
Definition: miscinit.c:380
bool agg_done
Definition: execnodes.h:2051
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
Oid * grpCollations
Definition: plannodes.h:814
ExprState * ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash)
Definition: execExpr.c:2929
TupleTableSlot * sort_slot
Definition: execnodes.h:2062
List * all_grouped_cols
Definition: execnodes.h:2056
Tuplesortstate * sort_out
Definition: execnodes.h:2061
ScanState ss
Definition: execnodes.h:2031
ExprContext * ps_ExprContext
Definition: execnodes.h:978
ExprState * evaltrans
Definition: nodeAgg.h:282
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1043
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
Oid inputcollid
Definition: primnodes.h:301
int current_phase
Definition: execnodes.h:2039
Definition: nodes.h:525
AggSplit aggsplit
Definition: execnodes.h:2036
static TupleTableSlot * ExecAgg(PlanState *pstate)
Definition: nodeAgg.c:1551
int errcode(int sqlerrcode)
Definition: elog.c:608
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1329
void build_aggregate_finalfn_expr(Oid *agg_input_types, int num_finalfn_inputs, Oid agg_state_type, Oid agg_result_type, Oid agg_input_collation, Oid finalfn_oid, Expr **finalfnexpr)
Definition: parse_agg.c:2037
static int find_compatible_pertrans(AggState *aggstate, Aggref *newagg, bool shareable, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, List *transnos)
Definition: nodeAgg.c:3336
AggStatePerTrans pertrans
Definition: execnodes.h:2041
EState * state
Definition: execnodes.h:941
int projected_set
Definition: execnodes.h:2052
unsigned int Oid
Definition: postgres_ext.h:31
HeapTuple grp_firstTuple
Definition: execnodes.h:2066
Aggref * aggref
Definition: nodeAgg.h:186
int current_set
Definition: execnodes.h:2054
#define OidIsValid(objectId)
Definition: c.h:645
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:787
int numtrans
Definition: execnodes.h:2034
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:207
ExprContext * tmpcontext
Definition: execnodes.h:2044
#define FUNC_MAX_ARGS
Bitmapset ** grouped_cols
Definition: nodeAgg.h:276
PlanState ps
Definition: execnodes.h:1326
int maxsets
Definition: execnodes.h:2058
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:789
AggStrategy aggstrategy
Definition: plannodes.h:809
bool table_filled
Definition: execnodes.h:2068
AggStrategy aggstrategy
Definition: execnodes.h:2035
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1410
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:124
static void find_hash_columns(AggState *aggstate)
Definition: nodeAgg.c:1325
Tuplesortstate * sort_in
Definition: execnodes.h:2060
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define outerPlanState(node)
Definition: execnodes.h:1033
Aggref * aggref
Definition: execnodes.h:746
#define list_nth_node(type, list, n)
Definition: pg_list.h:305
static int initValue(long lng_val)
Definition: informix.c:677
void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc)
Definition: execUtils.c:499
static void build_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1264
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:316
Index agglevelsup
Definition: primnodes.h:313
List * aggdirectargs
Definition: primnodes.h:304
static Datum GetAggInitVal(Datum textInitVal, Oid transtype)
Definition: nodeAgg.c:3230
AggStatePerAgg curperagg
Definition: execnodes.h:2047
AggStatePerHash perhash
Definition: execnodes.h:2070
bool outeropsset
Definition: execnodes.h:1020
AggStrategy aggstrategy
Definition: nodeAgg.h:273
#define EXEC_FLAG_REWIND
Definition: executor.h:57
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:191
#define outerPlan(node)
Definition: plannodes.h:172
int num_hashes
Definition: execnodes.h:2069
Plan plan
Definition: plannodes.h:808
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
bool input_done
Definition: execnodes.h:2050
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:2042
bool * ecxt_aggnulls
Definition: execnodes.h:244
static int find_compatible_peragg(Aggref *newagg, AggState *aggstate, int lastaggno, List **same_input_transnos)
Definition: nodeAgg.c:3258
void * palloc0(Size size)
Definition: mcxt.c:980
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:945
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
List * groupingSets
Definition: plannodes.h:818
int16 resulttypeLen
Definition: nodeAgg.h:215
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:321
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:133
Plan * plan
Definition: execnodes.h:939
#define InvalidOid
Definition: postgres_ext.h:36
Oid aggfnoid
Definition: primnodes.h:298
#define Max(x, y)
Definition: c.h:905
ExprContext ** aggcontexts
Definition: execnodes.h:2043
#define makeNode(_type_)
Definition: nodes.h:573
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
ExprState * execTuplesMatchPrepare(TupleDesc desc, int numCols, const AttrNumber *keyColIdx, const Oid *eqOperators, const Oid *collations, PlanState *parent)
Definition: execGrouping.c:59
#define EXEC_FLAG_MARK
Definition: executor.h:59
AggSplit aggsplit
Definition: plannodes.h:810
struct AggStatePerAggData * AggStatePerAgg
Definition: execnodes.h:2023
FormData_pg_aggregate * Form_pg_aggregate
Definition: pg_aggregate.h:109
AggSplit aggsplit
Definition: primnodes.h:314
AggStatePerGroup * pergroups
Definition: execnodes.h:2064
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:444
static int list_length(const List *l)
Definition: pg_list.h:169
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:788
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2029
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1769
bool outeropsfixed
Definition: execnodes.h:1016
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:790
struct Plan * lefttree
Definition: plannodes.h:144
int numphases
Definition: execnodes.h:2038
ExprState * qual
Definition: execnodes.h:960
Oid * grpOperators
Definition: plannodes.h:813
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
List * chain
Definition: plannodes.h:819
AggStatePerAgg peragg
Definition: execnodes.h:2040
#define ACL_EXECUTE
Definition: parsenodes.h:81
#define elog(elevel,...)
Definition: elog.h:228
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4653
int i
List * aggdirectargs
Definition: nodeAgg.h:209
Oid aggtranstype
Definition: primnodes.h:302
AggStatePerTrans curpertrans
Definition: execnodes.h:2049
Oid aggtype
Definition: primnodes.h:299
bool resulttypeByVal
Definition: nodeAgg.h:216
Definition: plannodes.h:806
List * aggs
Definition: execnodes.h:2032
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:646
int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes)
Definition: parse_agg.c:1819
static void build_pertrans_for_aggref(AggStatePerTrans pertrans, AggState *aggstate, EState *estate, Aggref *aggref, Oid aggtransfn, Oid aggtranstype, Oid aggserialfn, Oid aggdeserialfn, Datum initValue, bool initValueIsNull, Oid *inputTypes, int numArguments)
Definition: nodeAgg.c:2922
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:138
Definition: pg_list.h:50
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
FmgrInfo finalfn
Definition: nodeAgg.h:198
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:793
const TupleTableSlotOps * outerops
Definition: execnodes.h:1012
AggStatePerGroup * all_pergroups
Definition: execnodes.h:2076

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

Definition at line 3433 of file nodeAgg.c.

References AggState::agg_done, AGG_HASHED, AGG_MIXED, AggState::aggcontexts, Agg::aggParams, AggState::aggstrategy, bms_overlap(), build_hash_table(), PlanState::chgParam, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExecClearTuple(), ExecReScan(), AggState::grp_firstTuple, AggState::hashcontext, AggStatePerHashData::hashiter, AggStatePerHashData::hashtable, heap_freetuple(), initialize_phase(), AggState::input_done, Max, AggState::maxsets, MemSet, AggState::numaggs, AggState::numtrans, outerPlan, outerPlanState, AggState::pergroups, AggState::perhash, AggState::pertrans, PlanState::plan, AggState::projected_set, ScanState::ps, PlanState::ps_ExprContext, ReScanExprContext(), ResetTupleHashIterator, select_current_set(), AggStatePerTransData::sortstates, AggState::ss, ScanState::ss_ScanTupleSlot, AggState::table_filled, and tuplesort_end().

Referenced by ExecReScan().

3434 {
3435  ExprContext *econtext = node->ss.ps.ps_ExprContext;
3437  Agg *aggnode = (Agg *) node->ss.ps.plan;
3438  int transno;
3439  int numGroupingSets = Max(node->maxsets, 1);
3440  int setno;
3441 
3442  node->agg_done = false;
3443 
3444  if (node->aggstrategy == AGG_HASHED)
3445  {
3446  /*
3447  * In the hashed case, if we haven't yet built the hash table then we
3448  * can just return; nothing done yet, so nothing to undo. If subnode's
3449  * chgParam is not NULL then it will be re-scanned by ExecProcNode,
3450  * else no reason to re-scan it at all.
3451  */
3452  if (!node->table_filled)
3453  return;
3454 
3455  /*
3456  * If we do have the hash table, and the subplan does not have any
3457  * parameter changes, and none of our own parameter changes affect
3458  * input expressions of the aggregated functions, then we can just
3459  * rescan the existing hash table; no need to build it again.
3460  */
3461  if (outerPlan->chgParam == NULL &&
3462  !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams))
3463  {
3465  &node->perhash[0].hashiter);
3466  select_current_set(node, 0, true);
3467  return;
3468  }
3469  }
3470 
3471  /* Make sure we have closed any open tuplesorts */
3472  for (transno = 0; transno < node->numtrans; transno++)
3473  {
3474  for (setno = 0; setno < numGroupingSets; setno++)
3475  {
3476  AggStatePerTrans pertrans = &node->pertrans[transno];
3477 
3478  if (pertrans->sortstates[setno])
3479  {
3480  tuplesort_end(pertrans->sortstates[setno]);
3481  pertrans->sortstates[setno] = NULL;
3482  }
3483  }
3484  }
3485 
3486  /*
3487  * We don't need to ReScanExprContext the output tuple context here;
3488  * ExecReScan already did it. But we do need to reset our per-grouping-set
3489  * contexts, which may have transvalues stored in them. (We use rescan
3490  * rather than just reset because transfns may have registered callbacks
3491  * that need to be run now.) For the AGG_HASHED case, see below.
3492  */
3493 
3494  for (setno = 0; setno < numGroupingSets; setno++)
3495  {
3496  ReScanExprContext(node->aggcontexts[setno]);
3497  }
3498 
3499  /* Release first tuple of group, if we have made a copy */
3500  if (node->grp_firstTuple != NULL)
3501  {
3503  node->grp_firstTuple = NULL;
3504  }
3506 
3507  /* Forget current agg values */
3508  MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
3509  MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
3510 
3511  /*
3512  * With AGG_HASHED/MIXED, the hash table is allocated in a sub-context of
3513  * the hashcontext. This used to be an issue, but now, resetting a context
3514  * automatically deletes sub-contexts too.
3515  */
3516  if (node->aggstrategy == AGG_HASHED || node->aggstrategy == AGG_MIXED)
3517  {
3519  /* Rebuild an empty hash table */
3520  build_hash_table(node);
3521  node->table_filled = false;
3522  /* iterator will be reset when the table is filled */
3523  }
3524 
3525  if (node->aggstrategy != AGG_HASHED)
3526  {
3527  /*
3528  * Reset the per-group state (in particular, mark transvalues null)
3529  */
3530  for (setno = 0; setno < numGroupingSets; setno++)
3531  {
3532  MemSet(node->pergroups[setno], 0,
3533  sizeof(AggStatePerGroupData) * node->numaggs);
3534  }
3535 
3536  /* reset to phase 1 */
3537  initialize_phase(node, 1);
3538 
3539  node->input_done = false;
3540  node->projected_set = -1;
3541  }
3542 
3543  if (outerPlan->chgParam == NULL)
3544  ExecReScan(outerPlan);
3545 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:302
Datum * ecxt_aggvalues
Definition: execnodes.h:242
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
int numaggs
Definition: execnodes.h:2033
bool agg_done
Definition: execnodes.h:2051
ScanState ss
Definition: execnodes.h:2031
ExprContext * ps_ExprContext
Definition: execnodes.h:978
void ExecReScan(PlanState *node)
Definition: execAmi.c:75
#define MemSet(start, val, len)
Definition: c.h:962
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1329
AggStatePerTrans pertrans
Definition: execnodes.h:2041
int projected_set
Definition: execnodes.h:2052
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple grp_firstTuple
Definition: execnodes.h:2066
int numtrans
Definition: execnodes.h:2034
PlanState ps
Definition: execnodes.h:1326
int maxsets
Definition: execnodes.h:2058
bool table_filled
Definition: execnodes.h:2068
AggStrategy aggstrategy
Definition: execnodes.h:2035
#define outerPlanState(node)
Definition: execnodes.h:1033
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
Bitmapset * aggParams
Definition: plannodes.h:816
static void build_hash_table(AggState *aggstate)
Definition: nodeAgg.c:1264
AggStatePerHash perhash
Definition: execnodes.h:2070
Bitmapset * chgParam
Definition: execnodes.h:971
#define outerPlan(node)
Definition: plannodes.h:172
TupleHashIterator hashiter
Definition: nodeAgg.h:295
bool input_done
Definition: execnodes.h:2050
ExprContext * hashcontext
Definition: execnodes.h:2042
bool * ecxt_aggnulls
Definition: execnodes.h:244
uintptr_t Datum
Definition: postgres.h:367
static void initialize_phase(AggState *aggstate, int newphase)
Definition: nodeAgg.c:321
Plan * plan
Definition: execnodes.h:939
#define ResetTupleHashIterator(htable, iter)
Definition: execnodes.h:721
#define Max(x, y)
Definition: c.h:905
ExprContext ** aggcontexts
Definition: execnodes.h:2043
AggStatePerGroup * pergroups
Definition: execnodes.h:2064
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:402
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:494
Definition: plannodes.h:806
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236
TupleHashTable hashtable
Definition: nodeAgg.h:294

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

Definition at line 391 of file nodeAgg.c.

References CHECK_FOR_INTERRUPTS, ExecProcNode(), outerPlanState, AggState::sort_in, AggState::sort_out, AggState::sort_slot, TupIsNull, tuplesort_gettupleslot(), and tuplesort_puttupleslot().

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

392 {
393  TupleTableSlot *slot;
394 
395  if (aggstate->sort_in)
396  {
397  /* make sure we check for interrupts in either path through here */
399  if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
400  aggstate->sort_slot, NULL))
401  return NULL;
402  slot = aggstate->sort_slot;
403  }
404  else
405  slot = ExecProcNode(outerPlanState(aggstate));
406 
407  if (!TupIsNull(slot) && aggstate->sort_out)
408  tuplesort_puttupleslot(aggstate->sort_out, slot);
409 
410  return slot;
411 }
TupleTableSlot * sort_slot
Definition: execnodes.h:2062
Tuplesortstate * sort_out
Definition: execnodes.h:2061
Tuplesortstate * sort_in
Definition: execnodes.h:2060
#define outerPlanState(node)
Definition: execnodes.h:1033
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2159
#define TupIsNull(slot)
Definition: tuptable.h:292
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:235
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
void tuplesort_puttupleslot(Tuplesortstate *state, TupleTableSlot *slot)
Definition: tuplesort.c:1435

◆ finalize_aggregate()

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

Definition at line 893 of file nodeAgg.c.

References AggStatePerTransData::aggCollation, AggStatePerAggData::aggdirectargs, AggState::curperagg, CurrentMemoryContext, datumCopy(), DatumGetPointer, ExprContext::ecxt_per_tuple_memory, ExecEvalExpr(), AggStatePerAggData::finalfn, AggStatePerAggData::finalfn_oid, FUNC_MAX_ARGS, FunctionCallInvoke, i, InitFunctionCallInfoData, lfirst, LOCAL_FCINFO, MakeExpandedObjectReadOnly, MemoryContextContains(), MemoryContextSwitchTo(), AggStatePerAggData::numFinalArgs, OidIsValid, AggState::pertrans, ScanState::ps, PlanState::ps_ExprContext, AggStatePerAggData::resulttypeByVal, AggStatePerAggData::resulttypeLen, AggState::ss, AggStatePerAggData::transno, AggStatePerTransData::transtypeLen, AggStatePerGroupData::transValue, and AggStatePerGroupData::transValueIsNull.

Referenced by finalize_aggregates().

897 {
898  LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
899  bool anynull = false;
900  MemoryContext oldContext;
901  int i;
902  ListCell *lc;
903  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
904 
906 
907  /*
908  * Evaluate any direct arguments. We do this even if there's no finalfn
909  * (which is unlikely anyway), so that side-effects happen as expected.
910  * The direct arguments go into arg positions 1 and up, leaving position 0
911  * for the transition state value.
912  */
913  i = 1;
914  foreach(lc, peragg->aggdirectargs)
915  {
916  ExprState *expr = (ExprState *) lfirst(lc);
917 
918  fcinfo->args[i].value = ExecEvalExpr(expr,
919  aggstate->ss.ps.ps_ExprContext,
920  &fcinfo->args[i].isnull);
921  anynull |= fcinfo->args[i].isnull;
922  i++;
923  }
924 
925  /*
926  * Apply the agg's finalfn if one is provided, else return transValue.
927  */
928  if (OidIsValid(peragg->finalfn_oid))
929  {
930  int numFinalArgs = peragg->numFinalArgs;
931 
932  /* set up aggstate->curperagg for AggGetAggref() */
933  aggstate->curperagg = peragg;
934 
935  InitFunctionCallInfoData(*fcinfo, &peragg->finalfn,
936  numFinalArgs,
937  pertrans->aggCollation,
938  (void *) aggstate, NULL);
939 
940  /* Fill in the transition state value */
941  fcinfo->args[0].value =
942  MakeExpandedObjectReadOnly(pergroupstate->transValue,
943  pergroupstate->transValueIsNull,
944  pertrans->transtypeLen);
945  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
946  anynull |= pergroupstate->transValueIsNull;
947 
948  /* Fill any remaining argument positions with nulls */
949  for (; i < numFinalArgs; i++)
950  {
951  fcinfo->args[i].value = (Datum) 0;
952  fcinfo->args[i].isnull = true;
953  anynull = true;
954  }
955 
956  if (fcinfo->flinfo->fn_strict && anynull)
957  {
958  /* don't call a strict function with NULL inputs */
959  *resultVal = (Datum) 0;
960  *resultIsNull = true;
961  }
962  else
963  {
964  *resultVal = FunctionCallInvoke(fcinfo);
965  *resultIsNull = fcinfo->isnull;
966  }
967  aggstate->curperagg = NULL;
968  }
969  else
970  {
971  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
972  *resultVal = pergroupstate->transValue;
973  *resultIsNull = pergroupstate->transValueIsNull;
974  }
975 
976  /*
977  * If result is pass-by-ref, make sure it is in the right context.
978  */
979  if (!peragg->resulttypeByVal && !*resultIsNull &&
981  DatumGetPointer(*resultVal)))
982  *resultVal = datumCopy(*resultVal,
983  peragg->resulttypeByVal,
984  peragg->resulttypeLen);
985 
986  MemoryContextSwitchTo(oldContext);
987 }
ScanState ss
Definition: execnodes.h:2031
ExprContext * ps_ExprContext
Definition: execnodes.h:978
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:231
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:2041
#define OidIsValid(objectId)
Definition: c.h:645
#define FUNC_MAX_ARGS
PlanState ps
Definition: execnodes.h:1326
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:167
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:285
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
AggStatePerAgg curperagg
Definition: execnodes.h:2047
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
uintptr_t Datum
Definition: postgres.h:367
int16 resulttypeLen
Definition: nodeAgg.h:215
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define lfirst(lc)
Definition: pg_list.h:190
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:691
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define DatumGetPointer(X)
Definition: postgres.h:549
int i
List * aggdirectargs
Definition: nodeAgg.h:209
bool resulttypeByVal
Definition: nodeAgg.h:216
FmgrInfo finalfn
Definition: nodeAgg.h:198

◆ finalize_aggregates()

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

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

1123 {
1124  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1125  Datum *aggvalues = econtext->ecxt_aggvalues;
1126  bool *aggnulls = econtext->ecxt_aggnulls;
1127  int aggno;
1128  int transno;
1129 
1130  /*
1131  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1132  * inputs and run the transition functions.
1133  */
1134  for (transno = 0; transno < aggstate->numtrans; transno++)
1135  {
1136  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1137  AggStatePerGroup pergroupstate;
1138 
1139  pergroupstate = &pergroup[transno];
1140 
1141  if (pertrans->numSortCols > 0)
1142  {
1143  Assert(aggstate->aggstrategy != AGG_HASHED &&
1144  aggstate->aggstrategy != AGG_MIXED);
1145 
1146  if (pertrans->numInputs == 1)
1148  pertrans,
1149  pergroupstate);
1150  else
1152  pertrans,
1153  pergroupstate);
1154  }
1155  }
1156 
1157  /*
1158  * Run the final functions.
1159  */
1160  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1161  {
1162  AggStatePerAgg peragg = &peraggs[aggno];
1163  int transno = peragg->transno;
1164  AggStatePerGroup pergroupstate;
1165 
1166  pergroupstate = &pergroup[transno];
1167 
1168  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1169  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1170  &aggvalues[aggno], &aggnulls[aggno]);
1171  else
1172  finalize_aggregate(aggstate, peragg, pergroupstate,
1173  &aggvalues[aggno], &aggnulls[aggno]);
1174  }
1175 }
Datum * ecxt_aggvalues
Definition: execnodes.h:242
int numaggs
Definition: execnodes.h:2033
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:996
ScanState ss
Definition: execnodes.h:2031
ExprContext * ps_ExprContext
Definition: execnodes.h:978
AggSplit aggsplit
Definition: execnodes.h:2036
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:893
AggStatePerTrans pertrans
Definition: execnodes.h:2041
int numtrans
Definition: execnodes.h:2034
PlanState ps
Definition: execnodes.h:1326
AggStrategy aggstrategy
Definition: execnodes.h:2035
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:799
bool * ecxt_aggnulls
Definition: execnodes.h:244
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:739
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:788
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:707

◆ finalize_partialaggregate()

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

Definition at line 996 of file nodeAgg.c.

References FunctionCallInfoBaseData::args, CurrentMemoryContext, datumCopy(), DatumGetPointer, ExprContext::ecxt_per_tuple_memory, FmgrInfo::fn_strict, FunctionCallInvoke, FunctionCallInfoBaseData::isnull, NullableDatum::isnull, MakeExpandedObjectReadOnly, MemoryContextContains(), MemoryContextSwitchTo(), OidIsValid, AggState::pertrans, ScanState::ps, PlanState::ps_ExprContext, AggStatePerAggData::resulttypeByVal, AggStatePerAggData::resulttypeLen, AggStatePerTransData::serialfn, AggStatePerTransData::serialfn_fcinfo, AggStatePerTransData::serialfn_oid, AggState::ss, AggStatePerAggData::transno, AggStatePerTransData::transtypeLen, AggStatePerGroupData::transValue, AggStatePerGroupData::transValueIsNull, and NullableDatum::value.

Referenced by finalize_aggregates().

1000 {
1001  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1002  MemoryContext oldContext;
1003 
1005 
1006  /*
1007  * serialfn_oid will be set if we must serialize the transvalue before
1008  * returning it
1009  */
1010  if (OidIsValid(pertrans->serialfn_oid))
1011  {
1012  /* Don't call a strict serialization function with NULL input. */
1013  if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
1014  {
1015  *resultVal = (Datum) 0;
1016  *resultIsNull = true;
1017  }
1018  else
1019  {
1020  FunctionCallInfo fcinfo = pertrans->serialfn_fcinfo;
1021 
1022  fcinfo->args[0].value =
1023  MakeExpandedObjectReadOnly(pergroupstate->transValue,
1024  pergroupstate->transValueIsNull,
1025  pertrans->transtypeLen);
1026  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
1027 
1028  *resultVal = FunctionCallInvoke(fcinfo);
1029  *resultIsNull = fcinfo->isnull;
1030  }
1031  }
1032  else
1033  {
1034  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1035  *resultVal = pergroupstate->transValue;
1036  *resultIsNull = pergroupstate->transValueIsNull;
1037  }
1038 
1039  /* If result is pass-by-ref, make sure it is in the right context. */
1040  if (!peragg->resulttypeByVal && !*resultIsNull &&
1042  DatumGetPointer(*resultVal)))
1043  *resultVal = datumCopy(*resultVal,
1044  peragg->resulttypeByVal,
1045  peragg->resulttypeLen);
1046 
1047  MemoryContextSwitchTo(oldContext);
1048 }
ScanState ss
Definition: execnodes.h:2031
ExprContext * ps_ExprContext
Definition: execnodes.h:978
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:231
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:2041
#define OidIsValid(objectId)
Definition: c.h:645
PlanState ps
Definition: execnodes.h:1326
bool fn_strict
Definition: fmgr.h:61
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:167
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
Datum value
Definition: postgres.h:378
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
uintptr_t Datum
Definition: postgres.h:367
int16 resulttypeLen
Definition: nodeAgg.h:215
FmgrInfo serialfn
Definition: nodeAgg.h:83
bool MemoryContextContains(MemoryContext context, void *pointer)
Definition: mcxt.c:691
FunctionCallInfo serialfn_fcinfo
Definition: nodeAgg.h:164
#define DatumGetPointer(X)
Definition: postgres.h:549
bool resulttypeByVal
Definition: nodeAgg.h:216

◆ find_compatible_peragg()

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

Definition at line 3258 of file nodeAgg.c.

References Aggref::aggcollid, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggfnoid, Aggref::aggkind, Aggref::aggorder, AggStatePerAggData::aggref, Aggref::aggstar, Aggref::aggtranstype, Aggref::aggtype, Aggref::aggvariadic, Aggref::args, contain_volatile_functions(), equal(), Aggref::inputcollid, lappend_int(), list_free(), NIL, AggState::peragg, AggStatePerAggData::shareable, and AggStatePerAggData::transno.

Referenced by ExecInitAgg().

3260 {
3261  int aggno;
3262  AggStatePerAgg peraggs;
3263 
3264  *same_input_transnos = NIL;
3265 
3266  /* we mustn't reuse the aggref if it contains volatile function calls */
3267  if (contain_volatile_functions((Node *) newagg))
3268  return -1;
3269 
3270  peraggs = aggstate->peragg;
3271 
3272  /*
3273  * Search through the list of already seen aggregates. If we find an
3274  * existing identical aggregate call, then we can re-use that one. While
3275  * searching, we'll also collect a list of Aggrefs with the same input
3276  * parameters. If no matching Aggref is found, the caller can potentially
3277  * still re-use the transition state of one of them. (At this stage we
3278  * just compare the parsetrees; whether different aggregates share the
3279  * same transition function will be checked later.)
3280  */
3281  for (aggno = 0; aggno <= lastaggno; aggno++)
3282  {
3283  AggStatePerAgg peragg;
3284  Aggref *existingRef;
3285 
3286  peragg = &peraggs[aggno];
3287  existingRef = peragg->aggref;
3288 
3289  /* all of the following must be the same or it's no match */
3290  if (newagg->inputcollid != existingRef->inputcollid ||
3291  newagg->aggtranstype != existingRef->aggtranstype ||
3292  newagg->aggstar != existingRef->aggstar ||
3293  newagg->aggvariadic != existingRef->aggvariadic ||
3294  newagg->aggkind != existingRef->aggkind ||
3295  !equal(newagg->args, existingRef->args) ||
3296  !equal(newagg->aggorder, existingRef->aggorder) ||
3297  !equal(newagg->aggdistinct, existingRef->aggdistinct) ||
3298  !equal(newagg->aggfilter, existingRef->aggfilter))
3299  continue;
3300 
3301  /* if it's the same aggregate function then report exact match */
3302  if (newagg->aggfnoid == existingRef->aggfnoid &&
3303  newagg->aggtype == existingRef->aggtype &&
3304  newagg->aggcollid == existingRef->aggcollid &&
3305  equal(newagg->aggdirectargs, existingRef->aggdirectargs))
3306  {
3307  list_free(*same_input_transnos);
3308  *same_input_transnos = NIL;
3309  return aggno;
3310  }
3311 
3312  /*
3313  * Not identical, but it had the same inputs. If the final function
3314  * permits sharing, return its transno to the caller, in case we can
3315  * re-use its per-trans state. (If there's already sharing going on,
3316  * we might report a transno more than once. find_compatible_pertrans
3317  * is cheap enough that it's not worth spending cycles to avoid that.)
3318  */
3319  if (peragg->shareable)
3320  *same_input_transnos = lappend_int(*same_input_transnos,
3321  peragg->transno);
3322  }
3323 
3324  return -1;
3325 }
List * aggdistinct
Definition: primnodes.h:307
#define NIL
Definition: pg_list.h:65
bool aggvariadic
Definition: primnodes.h:310
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3011
Oid inputcollid
Definition: primnodes.h:301
Definition: nodes.h:525
List * args
Definition: primnodes.h:305
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:724
bool aggstar
Definition: primnodes.h:309
Aggref * aggref
Definition: nodeAgg.h:186
List * aggorder
Definition: primnodes.h:306
List * aggdirectargs
Definition: primnodes.h:304
List * lappend_int(List *list, int datum)
Definition: list.c:340
Oid aggfnoid
Definition: primnodes.h:298
Expr * aggfilter
Definition: primnodes.h:308
Oid aggcollid
Definition: primnodes.h:300
AggStatePerAgg peragg
Definition: execnodes.h:2040
void list_free(List *list)
Definition: list.c:1377
Oid aggtranstype
Definition: primnodes.h:302
Oid aggtype
Definition: primnodes.h:299
char aggkind
Definition: primnodes.h:312

◆ find_compatible_pertrans()

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

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

3341 {
3342  ListCell *lc;
3343 
3344  /* If this aggregate can't share transition states, give up */
3345  if (!shareable)
3346  return -1;
3347 
3348  foreach(lc, transnos)
3349  {
3350  int transno = lfirst_int(lc);
3351  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3352 
3353  /*
3354  * if the transfns or transition state types are not the same then the
3355  * state can't be shared.
3356  */
3357  if (aggtransfn != pertrans->transfn_oid ||
3358  aggtranstype != pertrans->aggtranstype)
3359  continue;
3360 
3361  /*
3362  * The serialization and deserialization functions must match, if
3363  * present, as we're unable to share the trans state for aggregates
3364  * which will serialize or deserialize into different formats.
3365  * Remember that these will be InvalidOid if they're not required for
3366  * this agg node.
3367  */
3368  if (aggserialfn != pertrans->serialfn_oid ||
3369  aggdeserialfn != pertrans->deserialfn_oid)
3370  continue;
3371 
3372  /*
3373  * Check that the initial condition matches, too.
3374  */
3375  if (initValueIsNull && pertrans->initValueIsNull)
3376  return transno;
3377 
3378  if (!initValueIsNull && !pertrans->initValueIsNull &&
3379  datumIsEqual(initValue, pertrans->initValue,
3380  pertrans->transtypeByVal, pertrans->transtypeLen))
3381  return transno;
3382  }
3383  return -1;
3384 }
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:221
AggStatePerTrans pertrans
Definition: execnodes.h:2041
#define lfirst_int(lc)
Definition: pg_list.h:191
static int initValue(long lng_val)
Definition: informix.c:677

◆ find_hash_columns()

static void find_hash_columns ( AggState aggstate)
static

Definition at line 1325 of file nodeAgg.c.

References AggStatePerHashData::aggnode, AggState::all_grouped_cols, attnum, bms_add_member(), bms_copy(), bms_del_member(), bms_first_member(), bms_free(), bms_is_member(), bms_num_members(), AggStatePerHashData::eqfuncoids, EState::es_tupleTable, ExecAllocTableSlot(), execTuplesHashPrepare(), ExecTypeFromTL(), find_unaggregated_cols(), AggStatePerPhaseData::grouped_cols, Agg::grpColIdx, Agg::grpOperators, AggStatePerHashData::hashfunctions, AggStatePerHashData::hashGrpColIdxHash, AggStatePerHashData::hashGrpColIdxInput, AggStatePerHashData::hashslot, i, lappend(), AggStatePerHashData::largestGrpColIdx, lfirst_int, list_free(), list_nth(), Max, NIL, AggState::num_hashes, AggStatePerHashData::numCols, AggStatePerHashData::numhashGrpCols, outerPlanState, palloc(), AggState::perhash, AggState::phases, ScanState::ps, AggState::ss, PlanState::state, and TTSOpsMinimalTuple.

Referenced by ExecInitAgg().

1326 {
1327  Bitmapset *base_colnos;
1328  List *outerTlist = outerPlanState(aggstate)->plan->targetlist;
1329  int numHashes = aggstate->num_hashes;
1330  EState *estate = aggstate->ss.ps.state;
1331  int j;
1332 
1333  /* Find Vars that will be needed in tlist and qual */
1334  base_colnos = find_unaggregated_cols(aggstate);
1335 
1336  for (j = 0; j < numHashes; ++j)
1337  {
1338  AggStatePerHash perhash = &aggstate->perhash[j];
1339  Bitmapset *colnos = bms_copy(base_colnos);
1340  AttrNumber *grpColIdx = perhash->aggnode->grpColIdx;
1341  List *hashTlist = NIL;
1342  TupleDesc hashDesc;
1343  int maxCols;
1344  int i;
1345 
1346  perhash->largestGrpColIdx = 0;
1347 
1348  /*
1349  * If we're doing grouping sets, then some Vars might be referenced in
1350  * tlist/qual for the benefit of other grouping sets, but not needed
1351  * when hashing; i.e. prepare_projection_slot will null them out, so
1352  * there'd be no point storing them. Use prepare_projection_slot's
1353  * logic to determine which.
1354  */
1355  if (aggstate->phases[0].grouped_cols)
1356  {
1357  Bitmapset *grouped_cols = aggstate->phases[0].grouped_cols[j];
1358  ListCell *lc;
1359 
1360  foreach(lc, aggstate->all_grouped_cols)
1361  {
1362  int attnum = lfirst_int(lc);
1363 
1364  if (!bms_is_member(attnum, grouped_cols))
1365  colnos = bms_del_member(colnos, attnum);
1366  }
1367  }
1368 
1369  /*
1370  * Compute maximum number of input columns accounting for possible
1371  * duplications in the grpColIdx array, which can happen in some edge
1372  * cases where HashAggregate was generated as part of a semijoin or a
1373  * DISTINCT.
1374  */
1375  maxCols = bms_num_members(colnos) + perhash->numCols;
1376 
1377  perhash->hashGrpColIdxInput =
1378  palloc(maxCols * sizeof(AttrNumber));
1379  perhash->hashGrpColIdxHash =
1380  palloc(perhash->numCols * sizeof(AttrNumber));
1381 
1382  /* Add all the grouping columns to colnos */
1383  for (i = 0; i < perhash->numCols; i++)
1384  colnos = bms_add_member(colnos, grpColIdx[i]);
1385 
1386  /*
1387  * First build mapping for columns directly hashed. These are the
1388  * first, because they'll be accessed when computing hash values and
1389  * comparing tuples for exact matches. We also build simple mapping
1390  * for execGrouping, so it knows where to find the to-be-hashed /
1391  * compared columns in the input.
1392  */
1393  for (i = 0; i < perhash->numCols; i++)
1394  {
1395  perhash->hashGrpColIdxInput[i] = grpColIdx[i];
1396  perhash->hashGrpColIdxHash[i] = i + 1;
1397  perhash->numhashGrpCols++;
1398  /* delete already mapped columns */
1399  bms_del_member(colnos, grpColIdx[i]);
1400  }
1401 
1402  /* and add the remaining columns */
1403  while ((i = bms_first_member(colnos)) >= 0)
1404  {
1405  perhash->hashGrpColIdxInput[perhash->numhashGrpCols] = i;
1406  perhash->numhashGrpCols++;
1407  }
1408 
1409  /* and build a tuple descriptor for the hashtable */
1410  for (i = 0; i < perhash->numhashGrpCols; i++)
1411  {
1412  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
1413 
1414  hashTlist = lappend(hashTlist, list_nth(outerTlist, varNumber));
1415  perhash->largestGrpColIdx =
1416  Max(varNumber + 1, perhash->largestGrpColIdx);
1417  }
1418 
1419  hashDesc = ExecTypeFromTL(hashTlist);
1420 
1421  execTuplesHashPrepare(perhash->numCols,
1422  perhash->aggnode->grpOperators,
1423  &perhash->eqfuncoids,
1424  &perhash->hashfunctions);
1425  perhash->hashslot =
1426  ExecAllocTableSlot(&estate->es_tupleTable, hashDesc,
1428 
1429  list_free(hashTlist);
1430  bms_free(colnos);
1431  }
1432 
1433  bms_free(base_colnos);
1434 }
#define NIL
Definition: pg_list.h:65
int bms_first_member(Bitmapset *a)
Definition: bitmapset.c:996
AggStatePerPhase phases
Definition: execnodes.h:2059
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.h:302
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
AttrNumber * grpColIdx
Definition: plannodes.h:812
List * all_grouped_cols
Definition: execnodes.h:2056
ScanState ss
Definition: execnodes.h:2031
EState * state
Definition: execnodes.h:941
void execTuplesHashPrepare(int numCols, const Oid *eqOperators, Oid **eqFuncOids, FmgrInfo **hashFunctions)
Definition: execGrouping.c:96
Bitmapset ** grouped_cols
Definition: nodeAgg.h:276
PlanState ps
Definition: execnodes.h:1326
#define lfirst_int(lc)
Definition: pg_list.h:191
static void * list_nth(const List *list, int n)
Definition: pg_list.h:277
#define outerPlanState(node)
Definition: execnodes.h:1033
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:646
AggStatePerHash perhash
Definition: execnodes.h:2070
TupleTableSlot * ExecAllocTableSlot(List **tupleTable, TupleDesc desc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1141
List * lappend(List *list, void *datum)
Definition: list.c:322
int num_hashes
Definition: execnodes.h:2069
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:303
List * es_tupleTable
Definition: execnodes.h:551
int16 attnum
Definition: pg_attribute.h:79
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define Max(x, y)
Definition: c.h:905
FmgrInfo * hashfunctions
Definition: nodeAgg.h:297
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1908
static Bitmapset * find_unaggregated_cols(AggState *aggstate)
Definition: nodeAgg.c:1210
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
Oid * grpOperators
Definition: plannodes.h:813
void * palloc(Size size)
Definition: mcxt.c:949
void list_free(List *list)
Definition: list.c:1377
int i
TupleTableSlot * hashslot
Definition: nodeAgg.h:296
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:773
Definition: pg_list.h:50
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427
int16 AttrNumber
Definition: attnum.h:21
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85

◆ find_unaggregated_cols()

static Bitmapset * find_unaggregated_cols ( AggState aggstate)
static

Definition at line 1210 of file nodeAgg.c.

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

Referenced by find_hash_columns().

1211 {
1212  Agg *node = (Agg *) aggstate->ss.ps.plan;
1213  Bitmapset *colnos;
1214 
1215  colnos = NULL;
1217  &colnos);
1218  (void) find_unaggregated_cols_walker((Node *) node->plan.qual,
1219  &colnos);
1220  return colnos;
1221 }
List * qual
Definition: plannodes.h:143
ScanState ss
Definition: execnodes.h:2031
Definition: nodes.h:525
PlanState ps
Definition: execnodes.h:1326
static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
Definition: nodeAgg.c:1224
Plan plan
Definition: plannodes.h:808
Plan * plan
Definition: execnodes.h:939
List * targetlist
Definition: plannodes.h:142
Definition: plannodes.h:806

◆ find_unaggregated_cols_walker()

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

Definition at line 1224 of file nodeAgg.c.

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

Referenced by find_unaggregated_cols().

1225 {
1226  if (node == NULL)
1227  return false;
1228  if (IsA(node, Var))
1229  {
1230  Var *var = (Var *) node;
1231 
1232  /* setrefs.c should have set the varno to OUTER_VAR */
1233  Assert(var->varno == OUTER_VAR);
1234  Assert(var->varlevelsup == 0);
1235  *colnos = bms_add_member(*colnos, var->varattno);
1236  return false;
1237  }
1238  if (IsA(node, Aggref) ||IsA(node, GroupingFunc))
1239  {
1240  /* do not descend into aggregate exprs */
1241  return false;
1242  }
1244  (void *) colnos);
1245 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Index varlevelsup
Definition: primnodes.h:177
AttrNumber varattno
Definition: primnodes.h:172
Definition: primnodes.h:167
static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
Definition: nodeAgg.c:1224
Index varno
Definition: primnodes.h:170
#define Assert(condition)
Definition: c.h:739
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
#define OUTER_VAR
Definition: primnodes.h:158

◆ GetAggInitVal()

static Datum GetAggInitVal ( Datum  textInitVal,
Oid  transtype 
)
static

Definition at line 3230 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

3231 {
3232  Oid typinput,
3233  typioparam;
3234  char *strInitVal;
3235  Datum initVal;
3236 
3237  getTypeInputInfo(transtype, &typinput, &typioparam);
3238  strInitVal = TextDatumGetCString(textInitVal);
3239  initVal = OidInputFunctionCall(typinput, strInitVal,
3240  typioparam, -1);
3241  pfree(strInitVal);
3242  return initVal;
3243 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:1056
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2641
#define TextDatumGetCString(d)
Definition: builtins.h:84
uintptr_t Datum
Definition: postgres.h:367
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1646

◆ hash_agg_entry_size()

Size hash_agg_entry_size ( int  numAggs)

Definition at line 1445 of file nodeAgg.c.

References MAXALIGN.

Referenced by create_distinct_paths(), and estimate_hashagg_tablesize().

1446 {
1447  Size entrysize;
1448 
1449  /* This must match build_hash_table */
1450  entrysize = sizeof(TupleHashEntryData) +
1451  numAggs * sizeof(AggStatePerGroupData);
1452  entrysize = MAXALIGN(entrysize);
1453 
1454  return entrysize;
1455 }
struct TupleHashEntryData TupleHashEntryData
size_t Size
Definition: c.h:467
#define MAXALIGN(LEN)
Definition: c.h:692

◆ initialize_aggregate()

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

Definition at line 422 of file nodeAgg.c.

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

Referenced by initialize_aggregates(), and lookup_hash_entry().

424 {
425  /*
426  * Start a fresh sort operation for each DISTINCT/ORDER BY aggregate.
427  */
428  if (pertrans->numSortCols > 0)
429  {
430  /*
431  * In case of rescan, maybe there could be an uncompleted sort
432  * operation? Clean it up if so.
433  */
434  if (pertrans->sortstates[aggstate->current_set])
435  tuplesort_end(pertrans->sortstates[aggstate->current_set]);
436 
437 
438  /*
439  * We use a plain Datum sorter when there's a single input column;
440  * otherwise sort the full tuple. (See comments for
441  * process_ordered_aggregate_single.)
442  */
443  if (pertrans->numInputs == 1)
444  {
445  Form_pg_attribute attr = TupleDescAttr(pertrans->sortdesc, 0);
446 
447  pertrans->sortstates[aggstate->current_set] =
448  tuplesort_begin_datum(attr->atttypid,
449  pertrans->sortOperators[0],
450  pertrans->sortCollations[0],
451  pertrans->sortNullsFirst[0],
452  work_mem, NULL, false);
453  }
454  else
455  pertrans->sortstates[aggstate->current_set] =
456  tuplesort_begin_heap(pertrans->sortdesc,
457  pertrans->numSortCols,
458  pertrans->sortColIdx,
459  pertrans->sortOperators,
460  pertrans->sortCollations,
461  pertrans->sortNullsFirst,
462  work_mem, NULL, false);
463  }
464 
465  /*
466  * (Re)set transValue to the initial value.
467  *
468  * Note that when the initial value is pass-by-ref, we must copy it (into
469  * the aggcontext) since we will pfree the transValue later.
470  */
471  if (pertrans->initValueIsNull)
472  pergroupstate->transValue = pertrans->initValue;
473  else
474  {
475  MemoryContext oldContext;
476 
477  oldContext = MemoryContextSwitchTo(
479  pergroupstate->transValue = datumCopy(pertrans->initValue,
480  pertrans->transtypeByVal,
481  pertrans->transtypeLen);
482  MemoryContextSwitchTo(oldContext);
483  }
484  pergroupstate->transValueIsNull = pertrans->initValueIsNull;
485 
486  /*
487  * If the initial value for the transition state doesn't exist in the
488  * pg_aggregate table then we will let the first non-NULL value returned
489  * from the outer procNode become the initial value. (This is useful for
490  * aggregates like max() and min().) The noTransValue flag signals that we
491  * still need to do this.
492  */
493  pergroupstate->noTransValue = pertrans->initValueIsNull;
494 }
Tuplesortstate * tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation, bool nullsFirstFlag, int workMem, SortCoordinate coordinate, bool randomAccess)
Definition: tuplesort.c:1099
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:231
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int current_set
Definition: execnodes.h:2054
TupleDesc sortdesc
Definition: nodeAgg.h:137
Tuplesortstate * tuplesort_begin_heap(TupleDesc tupDesc, int nkeys, AttrNumber *attNums, Oid *sortOperators, Oid *sortCollations, bool *nullsFirstFlags, int workMem, SortCoordinate coordinate, bool randomAccess)
Definition: tuplesort.c:806
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
AttrNumber * sortColIdx
Definition: nodeAgg.h:99
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
ExprContext * curaggcontext
Definition: execnodes.h:2046
int work_mem
Definition: globals.c:121
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236
bool * sortNullsFirst
Definition: nodeAgg.h:102

◆ initialize_aggregates()

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

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

513 {
514  int transno;
515  int numGroupingSets = Max(aggstate->phase->numsets, 1);
516  int setno = 0;
517  int numTrans = aggstate->numtrans;
518  AggStatePerTrans transstates = aggstate->pertrans;
519 
520  if (numReset == 0)
521  numReset = numGroupingSets;
522 
523  for (setno = 0; setno < numReset; setno++)
524  {
525  AggStatePerGroup pergroup = pergroups[setno];
526 
527  select_current_set(aggstate, setno, false);
528 
529  for (transno = 0; transno < numTrans; transno++)
530  {
531  AggStatePerTrans pertrans = &transstates[transno];
532  AggStatePerGroup pergroupstate = &pergroup[transno];
533 
534  initialize_aggregate(aggstate, pertrans, pergroupstate);
535  }
536  }
537 }
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:302
AggStatePerTrans pertrans
Definition: execnodes.h:2041
int numtrans
Definition: execnodes.h:2034
static void initialize_aggregate(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:422
AggStatePerPhase phase
Definition: execnodes.h:2037
#define Max(x, y)
Definition: c.h:905

◆ initialize_phase()

static void initialize_phase ( AggState aggstate,
int  newphase 
)
static

Definition at line 321 of file nodeAgg.c.

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

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

322 {
323  Assert(newphase <= 1 || newphase == aggstate->current_phase + 1);
324 
325  /*
326  * Whatever the previous state, we're now done with whatever input
327  * tuplesort was in use.
328  */
329  if (aggstate->sort_in)
330  {
331  tuplesort_end(aggstate->sort_in);
332  aggstate->sort_in = NULL;
333  }
334 
335  if (newphase <= 1)
336  {
337  /*
338  * Discard any existing output tuplesort.
339  */
340  if (aggstate->sort_out)
341  {
342  tuplesort_end(aggstate->sort_out);
343  aggstate->sort_out = NULL;
344  }
345  }
346  else
347  {
348  /*
349  * The old output tuplesort becomes the new input one, and this is the
350  * right time to actually sort it.
351  */
352  aggstate->sort_in = aggstate->sort_out;
353  aggstate->sort_out = NULL;
354  Assert(aggstate->sort_in);
355  tuplesort_performsort(aggstate->sort_in);
356  }
357 
358  /*
359  * If this isn't the last phase, we need to sort appropriately for the
360  * next phase in sequence.
361  */
362  if (newphase > 0 && newphase < aggstate->numphases - 1)
363  {
364  Sort *sortnode = aggstate->phases[newphase + 1].sortnode;
365  PlanState *outerNode = outerPlanState(aggstate);
366  TupleDesc tupDesc = ExecGetResultType(outerNode);
367 
368  aggstate->sort_out = tuplesort_begin_heap(tupDesc,
369  sortnode->numCols,
370  sortnode->sortColIdx,
371  sortnode->sortOperators,
372  sortnode->collations,
373  sortnode->nullsFirst,
374  work_mem,
375  NULL, false);
376  }
377 
378  aggstate->current_phase = newphase;
379  aggstate->phase = &aggstate->phases[newphase];
380 }
AggStatePerPhase phases
Definition: execnodes.h:2059
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1791
Tuplesortstate * sort_out
Definition: execnodes.h:2061
int current_phase
Definition: execnodes.h:2039
bool * nullsFirst
Definition: plannodes.h:774
Oid * sortOperators
Definition: plannodes.h:772
Tuplesortstate * tuplesort_begin_heap(TupleDesc tupDesc, int nkeys, AttrNumber *attNums, Oid *sortOperators, Oid *sortCollations, bool *nullsFirstFlags, int workMem, SortCoordinate coordinate, bool randomAccess)
Definition: tuplesort.c:806
Tuplesortstate * sort_in
Definition: execnodes.h:2060
#define outerPlanState(node)
Definition: execnodes.h:1033
int numCols
Definition: plannodes.h:770
AggStatePerPhase phase
Definition: execnodes.h:2037
int work_mem
Definition: globals.c:121
#define Assert(condition)
Definition: c.h:739
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:454
AttrNumber * sortColIdx
Definition: plannodes.h:771
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236
Oid * collations
Definition: plannodes.h:773

◆ lookup_hash_entries()

static void lookup_hash_entries ( AggState aggstate)
static

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

1525 {
1526  int numHashes = aggstate->num_hashes;
1527  AggStatePerGroup *pergroup = aggstate->hash_pergroup;
1528  int setno;
1529 
1530  for (setno = 0; setno < numHashes; setno++)
1531  {
1532  select_current_set(aggstate, setno, true);
1533  pergroup[setno] = lookup_hash_entry(aggstate)->additional;
1534  }
1535 }
AggStatePerGroup * hash_pergroup
Definition: execnodes.h:2071
static void select_current_set(AggState *aggstate, int setno, bool is_hash)
Definition: nodeAgg.c:302
static TupleHashEntryData * lookup_hash_entry(AggState *aggstate)
Definition: nodeAgg.c:1466
int num_hashes
Definition: execnodes.h:2069

◆ lookup_hash_entry()

static TupleHashEntryData * lookup_hash_entry ( AggState aggstate)
static

Definition at line 1466 of file nodeAgg.c.

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

Referenced by lookup_hash_entries().

1467 {
1468  TupleTableSlot *inputslot = aggstate->tmpcontext->ecxt_outertuple;
1469  AggStatePerHash perhash = &aggstate->perhash[aggstate->current_set];
1470  TupleTableSlot *hashslot = perhash->hashslot;
1471  TupleHashEntryData *entry;
1472  bool isnew;
1473  int i;
1474 
1475  /* transfer just the needed columns into hashslot */
1476  slot_getsomeattrs(inputslot, perhash->largestGrpColIdx);
1477  ExecClearTuple(hashslot);
1478 
1479  for (i = 0; i < perhash->numhashGrpCols; i++)
1480  {
1481  int varNumber = perhash->hashGrpColIdxInput[i] - 1;
1482 
1483  hashslot->tts_values[i] = inputslot->tts_values[varNumber];
1484  hashslot->tts_isnull[i] = inputslot->tts_isnull[varNumber];
1485  }
1486  ExecStoreVirtualTuple(hashslot);
1487 
1488  /* find or create the hashtable entry using the filtered tuple */
1489  entry = LookupTupleHashEntry(perhash->hashtable, hashslot, &isnew);
1490 
1491  if (isnew)
1492  {
1493  AggStatePerGroup pergroup;
1494  int transno;
1495 
1496  pergroup = (AggStatePerGroup)
1498  sizeof(AggStatePerGroupData) * aggstate->numtrans);
1499  entry->additional = pergroup;
1500 
1501  /*
1502  * Initialize aggregates for new tuple group, lookup_hash_entries()
1503  * already has selected the relevant grouping set.
1504  */
1505  for (transno = 0; transno < aggstate->numtrans; transno++)
1506  {
1507  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1508  AggStatePerGroup pergroupstate = &pergroup[transno];
1509 
1510  initialize_aggregate(aggstate, pertrans, pergroupstate);
1511  }
1512  }
1513 
1514  return entry;
1515 }
struct AggStatePerGroupData * AggStatePerGroup
Definition: execnodes.h:2025
AttrNumber * hashGrpColIdxInput
Definition: nodeAgg.h:302
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
static void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:341
Datum * tts_values
Definition: tuptable.h:126
AggStatePerTrans pertrans
Definition: execnodes.h:2041
int current_set
Definition: execnodes.h:2054
int numtrans
Definition: execnodes.h:2034
ExprContext * tmpcontext
Definition: execnodes.h:2044
MemoryContext tablecxt
Definition: execnodes.h:698
bool * tts_isnull
Definition: tuptable.h:128
AggStatePerHash perhash
Definition: execnodes.h:2070
TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew)
Definition: execGrouping.c:300
static void initialize_aggregate(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:422
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:227
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
int i
TupleTableSlot * hashslot
Definition: nodeAgg.h:296
TupleHashTable hashtable
Definition: nodeAgg.h:294
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522

◆ prepare_projection_slot()

static void prepare_projection_slot ( AggState aggstate,
TupleTableSlot slot,
int  currentSet 
)
static

Definition at line 1075 of file nodeAgg.c.

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

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table().

1076 {
1077  if (aggstate->phase->grouped_cols)
1078  {
1079  Bitmapset *grouped_cols = aggstate->phase->grouped_cols[currentSet];
1080 
1081  aggstate->grouped_cols = grouped_cols;
1082 
1083  if (TTS_EMPTY(slot))
1084  {
1085  /*
1086  * Force all values to be NULL if working on an empty input tuple
1087  * (i.e. an empty grouping set for which no input rows were
1088  * supplied).
1089  */
1090  ExecStoreAllNullTuple(slot);
1091  }
1092  else if (aggstate->all_grouped_cols)
1093  {
1094  ListCell *lc;
1095 
1096  /* all_grouped_cols is arranged in desc order */
1098 
1099  foreach(lc, aggstate->all_grouped_cols)
1100  {
1101  int attnum = lfirst_int(lc);
1102 
1103  if (!bms_is_member(attnum, grouped_cols))
1104  slot->tts_isnull[attnum - 1] = true;
1105  }
1106  }
1107  }
1108 }
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
Definition: execTuples.c:1546
#define TTS_EMPTY(slot)
Definition: tuptable.h:97
List * all_grouped_cols
Definition: execnodes.h:2056
static void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:341
#define linitial_int(l)
Definition: pg_list.h:196
Bitmapset ** grouped_cols
Definition: nodeAgg.h:276
#define lfirst_int(lc)
Definition: pg_list.h:191
bool * tts_isnull
Definition: tuptable.h:128
Bitmapset * grouped_cols
Definition: execnodes.h:2055
AggStatePerPhase phase
Definition: execnodes.h:2037
int16 attnum
Definition: pg_attribute.h:79
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427

◆ process_ordered_aggregate_multi()

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

Definition at line 799 of file nodeAgg.c.

References advance_transition_function(), FunctionCallInfoBaseData::args, CHECK_FOR_INTERRUPTS, AggState::current_set, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, AggStatePerTransData::equalfnMulti, ExecClearTuple(), ExecQual(), i, NullableDatum::isnull, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numTransInputs, ResetExprContext, slot_getsomeattrs(), AggStatePerTransData::sortslot, AggStatePerTransData::sortstates, AggState::tmpcontext, AggStatePerTransData::transfn_fcinfo, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, tuplesort_end(), tuplesort_gettupleslot(), tuplesort_performsort(), AggStatePerTransData::uniqslot, and NullableDatum::value.

Referenced by finalize_aggregates().

802 {
803  ExprContext *tmpcontext = aggstate->tmpcontext;
804  FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
805  TupleTableSlot *slot1 = pertrans->sortslot;
806  TupleTableSlot *slot2 = pertrans->uniqslot;
807  int numTransInputs = pertrans->numTransInputs;
808  int numDistinctCols = pertrans->numDistinctCols;
809  Datum newAbbrevVal = (Datum) 0;
810  Datum oldAbbrevVal = (Datum) 0;
811  bool haveOldValue = false;
812  TupleTableSlot *save = aggstate->tmpcontext->ecxt_outertuple;
813  int i;
814 
815  tuplesort_performsort(pertrans->sortstates[aggstate->current_set]);
816 
817  ExecClearTuple(slot1);
818  if (slot2)
819  ExecClearTuple(slot2);
820 
821  while (tuplesort_gettupleslot(pertrans->sortstates[aggstate->current_set],
822  true, true, slot1, &newAbbrevVal))
823  {
825 
826  tmpcontext->ecxt_outertuple = slot1;
827  tmpcontext->ecxt_innertuple = slot2;
828 
829  if (numDistinctCols == 0 ||
830  !haveOldValue ||
831  newAbbrevVal != oldAbbrevVal ||
832  !ExecQual(pertrans->equalfnMulti, tmpcontext))
833  {
834  /*
835  * Extract the first numTransInputs columns as datums to pass to
836  * the transfn.
837  */
838  slot_getsomeattrs(slot1, numTransInputs);
839 
840  /* Load values into fcinfo */
841  /* Start from 1, since the 0th arg will be the transition value */
842  for (i = 0; i < numTransInputs; i++)
843  {
844  fcinfo->args[i + 1].value = slot1->tts_values[i];
845  fcinfo->args[i + 1].isnull = slot1->tts_isnull[i];
846  }
847 
848  advance_transition_function(aggstate, pertrans, pergroupstate);
849 
850  if (numDistinctCols > 0)
851  {
852  /* swap the slot pointers to retain the current tuple */
853  TupleTableSlot *tmpslot = slot2;
854 
855  slot2 = slot1;
856  slot1 = tmpslot;
857  /* avoid ExecQual() calls by reusing abbreviated keys */
858  oldAbbrevVal = newAbbrevVal;
859  haveOldValue = true;
860  }
861  }
862 
863  /* Reset context each time */
864  ResetExprContext(tmpcontext);
865 
866  ExecClearTuple(slot1);
867  }
868 
869  if (slot2)
870  ExecClearTuple(slot2);
871 
872  tuplesort_end(pertrans->sortstates[aggstate->current_set]);
873  pertrans->sortstates[aggstate->current_set] = NULL;
874 
875  /* restore previous slot, potentially in use for grouping sets */
876  tmpcontext->ecxt_outertuple = save;
877 }
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1791
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
static void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:341
Datum * tts_values
Definition: tuptable.h:126
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:365
int current_set
Definition: execnodes.h:2054
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:161
ExprContext * tmpcontext
Definition: execnodes.h:2044
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
ExprState * equalfnMulti
Definition: nodeAgg.h:110
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2159
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
bool * tts_isnull
Definition: tuptable.h:128
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:225
Datum value
Definition: postgres.h:378
uintptr_t Datum
Definition: postgres.h:367
static void advance_transition_function(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:551
TupleTableSlot * ecxt_outertuple
Definition: execnodes.h:227
TupleTableSlot * uniqslot
Definition: nodeAgg.h:136
int i
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
TupleTableSlot * sortslot
Definition: nodeAgg.h:135
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236
#define ResetExprContext(econtext)
Definition: executor.h:495

◆ process_ordered_aggregate_single()

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

Definition at line 707 of file nodeAgg.c.

References advance_transition_function(), AggStatePerTransData::aggCollation, FunctionCallInfoBaseData::args, Assert, AggState::current_set, DatumGetBool, DatumGetPointer, ExprContext::ecxt_per_tuple_memory, AggStatePerTransData::equalfnOne, FunctionCall2Coll(), AggStatePerTransData::inputtypeByVal, NullableDatum::isnull, MemoryContextReset(), MemoryContextSwitchTo(), AggStatePerTransData::numDistinctCols, pfree(), AggStatePerTransData::sortstates, AggState::tmpcontext, AggStatePerTransData::transfn_fcinfo, tuplesort_end(), tuplesort_getdatum(), tuplesort_performsort(), and NullableDatum::value.

Referenced by finalize_aggregates().

710 {
711  Datum oldVal = (Datum) 0;
712  bool oldIsNull = true;
713  bool haveOldVal = false;
714  MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory;
715  MemoryContext oldContext;
716  bool isDistinct = (pertrans->numDistinctCols > 0);
717  Datum newAbbrevVal = (Datum) 0;
718  Datum oldAbbrevVal = (Datum) 0;
719  FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
720  Datum *newVal;
721  bool *isNull;
722 
723  Assert(pertrans->numDistinctCols < 2);
724 
725  tuplesort_performsort(pertrans->sortstates[aggstate->current_set]);
726 
727  /* Load the column into argument 1 (arg 0 will be transition value) */
728  newVal = &fcinfo->args[1].value;
729  isNull = &fcinfo->args[1].isnull;
730 
731  /*
732  * Note: if input type is pass-by-ref, the datums returned by the sort are
733  * freshly palloc'd in the per-query context, so we must be careful to
734  * pfree them when they are no longer needed.
735  */
736 
737  while (tuplesort_getdatum(pertrans->sortstates[aggstate->current_set],
738  true, newVal, isNull, &newAbbrevVal))
739  {
740  /*
741  * Clear and select the working context for evaluation of the equality
742  * function and transition function.
743  */
744  MemoryContextReset(workcontext);
745  oldContext = MemoryContextSwitchTo(workcontext);
746 
747  /*
748  * If DISTINCT mode, and not distinct from prior, skip it.
749  */
750  if (isDistinct &&
751  haveOldVal &&
752  ((oldIsNull && *isNull) ||
753  (!oldIsNull && !*isNull &&
754  oldAbbrevVal == newAbbrevVal &&
756  pertrans->aggCollation,
757  oldVal, *newVal)))))
758  {
759  /* equal to prior, so forget this one */
760  if (!pertrans->inputtypeByVal && !*isNull)
761  pfree(DatumGetPointer(*newVal));
762  }
763  else
764  {
765  advance_transition_function(aggstate, pertrans, pergroupstate);
766  /* forget the old value, if any */
767  if (!oldIsNull && !pertrans->inputtypeByVal)
768  pfree(DatumGetPointer(oldVal));
769  /* and remember the new one for subsequent equality checks */
770  oldVal = *newVal;
771  oldAbbrevVal = newAbbrevVal;
772  oldIsNull = *isNull;
773  haveOldVal = true;
774  }
775 
776  MemoryContextSwitchTo(oldContext);
777  }
778 
779  if (!oldIsNull && !pertrans->inputtypeByVal)
780  pfree(DatumGetPointer(oldVal));
781 
782  tuplesort_end(pertrans->sortstates[aggstate->current_set]);
783  pertrans->sortstates[aggstate->current_set] = NULL;
784 }
bool tuplesort_getdatum(Tuplesortstate *state, bool forward, Datum *val, bool *isNull, Datum *abbrev)
Definition: tuplesort.c:2245
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:1791
FmgrInfo equalfnOne
Definition: nodeAgg.h:109
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:231
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
int current_set
Definition: execnodes.h:2054
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:161
ExprContext * tmpcontext
Definition: execnodes.h:2044
void pfree(void *pointer)
Definition: mcxt.c:1056
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
#define DatumGetBool(X)
Definition: postgres.h:393
Datum value
Definition: postgres.h:378
uintptr_t Datum
Definition: postgres.h:367
static void advance_transition_function(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:551
#define Assert(condition)
Definition: c.h:739
#define DatumGetPointer(X)
Definition: postgres.h:549
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1236

◆ project_aggregates()

static TupleTableSlot * project_aggregates ( AggState aggstate)
static

Definition at line 1183 of file nodeAgg.c.

References ExecProject(), ExecQual(), InstrCountFiltered1, ScanState::ps, PlanState::ps_ExprContext, PlanState::ps_ProjInfo, PlanState::qual, and AggState::ss.

Referenced by agg_retrieve_direct(), and agg_retrieve_hash_table().

1184 {
1185  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1186 
1187  /*
1188  * Check the qual (HAVING clause); if the group does not match, ignore it.
1189  */
1190  if (ExecQual(aggstate->ss.ps.qual, econtext))
1191  {
1192  /*
1193  * Form and return projection tuple using the aggregate results and
1194  * the representative input tuple.
1195  */
1196  return ExecProject(aggstate->ss.ps.ps_ProjInfo);
1197  }
1198  else
1199  InstrCountFiltered1(aggstate, 1);
1200 
1201  return NULL;
1202 }
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:979
ScanState ss
Definition: execnodes.h:2031
ExprContext * ps_ExprContext
Definition: execnodes.h:978
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:365
PlanState ps
Definition: execnodes.h:1326
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:1041
ExprState * qual
Definition: execnodes.h:960
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:328

◆ select_current_set()

static void select_current_set ( AggState aggstate,
int  setno,
bool  is_hash 
)
static

Definition at line 302 of file nodeAgg.c.

References AggState::aggcontexts, AggState::curaggcontext, AggState::current_set, and AggState::hashcontext.

Referenced by agg_fill_hash_table(), agg_retrieve_direct(), agg_retrieve_hash_table(), ExecInitAgg(), ExecReScanAgg(), initialize_aggregates(), and lookup_hash_entries().

303 {
304  /* when changing this, also adapt ExecInterpExpr() and friends */
305  if (is_hash)
306  aggstate->curaggcontext = aggstate->hashcontext;
307  else
308  aggstate->curaggcontext = aggstate->aggcontexts[setno];
309 
310  aggstate->current_set = setno;
311 }
int current_set
Definition: execnodes.h:2054
ExprContext * curaggcontext
Definition: execnodes.h:2046
ExprContext * hashcontext
Definition: execnodes.h:2042
ExprContext ** aggcontexts
Definition: execnodes.h:2043