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/expandeddatum.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/tuplesort.h"
#include "utils/datum.h"
Include dependency graph for nodeAgg.c:

Go to the source code of this file.

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

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

Referenced by agg_fill_hash_table(), and agg_retrieve_direct().

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

◆ advance_transition_function()

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

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

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

◆ agg_fill_hash_table()

static void agg_fill_hash_table ( AggState aggstate)
static

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

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

◆ agg_retrieve_direct()

static TupleTableSlot * agg_retrieve_direct ( AggState aggstate)
static

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

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

◆ agg_retrieve_hash_table()

static TupleTableSlot * agg_retrieve_hash_table ( AggState aggstate)
static

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

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

◆ AggCheckCallContext()

int AggCheckCallContext ( FunctionCallInfo  fcinfo,
MemoryContext aggcontext 
)

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

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

◆ AggGetAggref()

Aggref* AggGetAggref ( FunctionCallInfo  fcinfo)

Definition at line 3616 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

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

◆ AggGetTempMemoryContext()

MemoryContext AggGetTempMemoryContext ( FunctionCallInfo  fcinfo)

Definition at line 3650 of file nodeAgg.c.

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

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

◆ aggregate_dummy()

Datum aggregate_dummy ( PG_FUNCTION_ARGS  )

Definition at line 3743 of file nodeAgg.c.

References elog, and ERROR.

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

◆ AggRegisterCallback()

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

Definition at line 3715 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

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

◆ AggStateIsShared()

bool AggStateIsShared ( FunctionCallInfo  fcinfo)

Definition at line 3676 of file nodeAgg.c.

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

Referenced by ordered_set_startup().

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

◆ build_hash_table()

static void build_hash_table ( AggState aggstate)
static

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

1266 {
1267  MemoryContext tmpmem = aggstate->tmpcontext->ecxt_per_tuple_memory;
1268  Size additionalsize;
1269  int i;
1270 
1271  Assert(aggstate->aggstrategy == AGG_HASHED || aggstate->aggstrategy == AGG_MIXED);
1272 
1273  additionalsize = aggstate->numtrans * sizeof(AggStatePerGroupData);
1274 
1275  for (i = 0; i < aggstate->num_hashes; ++i)
1276  {
1277  AggStatePerHash perhash = &aggstate->perhash[i];
1278 
1279  Assert(perhash->aggnode->numGroups > 0);
1280 
1281  if (perhash->hashtable)
1282  ResetTupleHashTable(perhash->hashtable);
1283  else
1284  perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
1285  perhash->hashslot->tts_tupleDescriptor,
1286  perhash->numCols,
1287  perhash->hashGrpColIdxHash,
1288  perhash->eqfuncoids,
1289  perhash->hashfunctions,
1290  perhash->aggnode->grpCollations,
1291  perhash->aggnode->numGroups,
1292  additionalsize,
1293  aggstate->ss.ps.state->es_query_cxt,
1295  tmpmem,
1296  DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit));
1297  }
1298 }
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:810
ScanState ss
Definition: execnodes.h:1985
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
AggSplit aggsplit
Definition: execnodes.h:1990
EState * state
Definition: execnodes.h:947
int numtrans
Definition: execnodes.h:1988
void ResetTupleHashTable(TupleHashTable hashtable)
Definition: execGrouping.c:271
ExprContext * tmpcontext
Definition: execnodes.h:1998
PlanState ps
Definition: execnodes.h:1280
MemoryContext es_query_cxt
Definition: execnodes.h:550
AggStrategy aggstrategy
Definition: execnodes.h:1989
struct AggStatePerGroupData AggStatePerGroupData
AggStatePerHash perhash
Definition: execnodes.h:2024
int num_hashes
Definition: execnodes.h:2023
AttrNumber * hashGrpColIdxHash
Definition: nodeAgg.h:303
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
ExprContext * hashcontext
Definition: execnodes.h:1996
FmgrInfo * hashfunctions
Definition: nodeAgg.h:297
#define Assert(condition)
Definition: c.h:732
size_t Size
Definition: c.h:466
long numGroups
Definition: plannodes.h:811
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:787
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 2923 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().

2930 {
2931  int numGroupingSets = Max(aggstate->maxsets, 1);
2932  Expr *serialfnexpr = NULL;
2933  Expr *deserialfnexpr = NULL;
2934  ListCell *lc;
2935  int numInputs;
2936  int numDirectArgs;
2937  List *sortlist;
2938  int numSortCols;
2939  int numDistinctCols;
2940  int i;
2941 
2942  /* Begin filling in the pertrans data */
2943  pertrans->aggref = aggref;
2944  pertrans->aggshared = false;
2945  pertrans->aggCollation = aggref->inputcollid;
2946  pertrans->transfn_oid = aggtransfn;
2947  pertrans->serialfn_oid = aggserialfn;
2948  pertrans->deserialfn_oid = aggdeserialfn;
2949  pertrans->initValue = initValue;
2950  pertrans->initValueIsNull = initValueIsNull;
2951 
2952  /* Count the "direct" arguments, if any */
2953  numDirectArgs = list_length(aggref->aggdirectargs);
2954 
2955  /* Count the number of aggregated input columns */
2956  pertrans->numInputs = numInputs = list_length(aggref->args);
2957 
2958  pertrans->aggtranstype = aggtranstype;
2959 
2960  /*
2961  * When combining states, we have no use at all for the aggregate
2962  * function's transfn. Instead we use the combinefn. In this case, the
2963  * transfn and transfn_oid fields of pertrans refer to the combine
2964  * function rather than the transition function.
2965  */
2966  if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2967  {
2968  Expr *combinefnexpr;
2969  size_t numTransArgs;
2970 
2971  /*
2972  * When combining there's only one input, the to-be-combined added
2973  * transition value from below (this node's transition value is
2974  * counted separately).
2975  */
2976  pertrans->numTransInputs = 1;
2977 
2978  /* account for the current transition state */
2979  numTransArgs = pertrans->numTransInputs + 1;
2980 
2981  build_aggregate_combinefn_expr(aggtranstype,
2982  aggref->inputcollid,
2983  aggtransfn,
2984  &combinefnexpr);
2985  fmgr_info(aggtransfn, &pertrans->transfn);
2986  fmgr_info_set_expr((Node *) combinefnexpr, &pertrans->transfn);
2987 
2988  pertrans->transfn_fcinfo =
2991  &pertrans->transfn,
2992  numTransArgs,
2993  pertrans->aggCollation,
2994  (void *) aggstate, NULL);
2995 
2996  /*
2997  * Ensure that a combine function to combine INTERNAL states is not
2998  * strict. This should have been checked during CREATE AGGREGATE, but
2999  * the strict property could have been changed since then.
3000  */
3001  if (pertrans->transfn.fn_strict && aggtranstype == INTERNALOID)
3002  ereport(ERROR,
3003  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3004  errmsg("combine function with transition type %s must not be declared STRICT",
3005  format_type_be(aggtranstype))));
3006  }
3007  else
3008  {
3009  Expr *transfnexpr;
3010  size_t numTransArgs;
3011 
3012  /* Detect how many arguments to pass to the transfn */
3013  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3014  pertrans->numTransInputs = numInputs;
3015  else
3016  pertrans->numTransInputs = numArguments;
3017 
3018  /* account for the current transition state */
3019  numTransArgs = pertrans->numTransInputs + 1;
3020 
3021  /*
3022  * Set up infrastructure for calling the transfn. Note that
3023  * invtransfn is not needed here.
3024  */
3025  build_aggregate_transfn_expr(inputTypes,
3026  numArguments,
3027  numDirectArgs,
3028  aggref->aggvariadic,
3029  aggtranstype,
3030  aggref->inputcollid,
3031  aggtransfn,
3032  InvalidOid,
3033  &transfnexpr,
3034  NULL);
3035  fmgr_info(aggtransfn, &pertrans->transfn);
3036  fmgr_info_set_expr((Node *) transfnexpr, &pertrans->transfn);
3037 
3038  pertrans->transfn_fcinfo =
3041  &pertrans->transfn,
3042  numTransArgs,
3043  pertrans->aggCollation,
3044  (void *) aggstate, NULL);
3045 
3046  /*
3047  * If the transfn is strict and the initval is NULL, make sure input
3048  * type and transtype are the same (or at least binary-compatible), so
3049  * that it's OK to use the first aggregated input value as the initial
3050  * transValue. This should have been checked at agg definition time,
3051  * but we must check again in case the transfn's strictness property
3052  * has been changed.
3053  */
3054  if (pertrans->transfn.fn_strict && pertrans->initValueIsNull)
3055  {
3056  if (numArguments <= numDirectArgs ||
3057  !IsBinaryCoercible(inputTypes[numDirectArgs],
3058  aggtranstype))
3059  ereport(ERROR,
3060  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
3061  errmsg("aggregate %u needs to have compatible input type and transition type",
3062  aggref->aggfnoid)));
3063  }
3064  }
3065 
3066  /* get info about the state value's datatype */
3067  get_typlenbyval(aggtranstype,
3068  &pertrans->transtypeLen,
3069  &pertrans->transtypeByVal);
3070 
3071  if (OidIsValid(aggserialfn))
3072  {
3073  build_aggregate_serialfn_expr(aggserialfn,
3074  &serialfnexpr);
3075  fmgr_info(aggserialfn, &pertrans->serialfn);
3076  fmgr_info_set_expr((Node *) serialfnexpr, &pertrans->serialfn);
3077 
3078  pertrans->serialfn_fcinfo =
3081  &pertrans->serialfn,
3082  1,
3083  InvalidOid,
3084  (void *) aggstate, NULL);
3085  }
3086 
3087  if (OidIsValid(aggdeserialfn))
3088  {
3089  build_aggregate_deserialfn_expr(aggdeserialfn,
3090  &deserialfnexpr);
3091  fmgr_info(aggdeserialfn, &pertrans->deserialfn);
3092  fmgr_info_set_expr((Node *) deserialfnexpr, &pertrans->deserialfn);
3093 
3094  pertrans->deserialfn_fcinfo =
3097  &pertrans->deserialfn,
3098  2,
3099  InvalidOid,
3100  (void *) aggstate, NULL);
3101 
3102  }
3103 
3104  /*
3105  * If we're doing either DISTINCT or ORDER BY for a plain agg, then we
3106  * have a list of SortGroupClause nodes; fish out the data in them and
3107  * stick them into arrays. We ignore ORDER BY for an ordered-set agg,
3108  * however; the agg's transfn and finalfn are responsible for that.
3109  *
3110  * Note that by construction, if there is a DISTINCT clause then the ORDER
3111  * BY clause is a prefix of it (see transformDistinctClause).
3112  */
3113  if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3114  {
3115  sortlist = NIL;
3116  numSortCols = numDistinctCols = 0;
3117  }
3118  else if (aggref->aggdistinct)
3119  {
3120  sortlist = aggref->aggdistinct;
3121  numSortCols = numDistinctCols = list_length(sortlist);
3122  Assert(numSortCols >= list_length(aggref->aggorder));
3123  }
3124  else
3125  {
3126  sortlist = aggref->aggorder;
3127  numSortCols = list_length(sortlist);
3128  numDistinctCols = 0;
3129  }
3130 
3131  pertrans->numSortCols = numSortCols;
3132  pertrans->numDistinctCols = numDistinctCols;
3133 
3134  /*
3135  * If we have either sorting or filtering to do, create a tupledesc and
3136  * slot corresponding to the aggregated inputs (including sort
3137  * expressions) of the agg.
3138  */
3139  if (numSortCols > 0 || aggref->aggfilter)
3140  {
3141  pertrans->sortdesc = ExecTypeFromTL(aggref->args);
3142  pertrans->sortslot =
3143  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
3145  }
3146 
3147  if (numSortCols > 0)
3148  {
3149  /*
3150  * We don't implement DISTINCT or ORDER BY aggs in the HASHED case
3151  * (yet)
3152  */
3153  Assert(aggstate->aggstrategy != AGG_HASHED && aggstate->aggstrategy != AGG_MIXED);
3154 
3155  /* If we have only one input, we need its len/byval info. */
3156  if (numInputs == 1)
3157  {
3158  get_typlenbyval(inputTypes[numDirectArgs],
3159  &pertrans->inputtypeLen,
3160  &pertrans->inputtypeByVal);
3161  }
3162  else if (numDistinctCols > 0)
3163  {
3164  /* we will need an extra slot to store prior values */
3165  pertrans->uniqslot =
3166  ExecInitExtraTupleSlot(estate, pertrans->sortdesc,
3168  }
3169 
3170  /* Extract the sort information for use later */
3171  pertrans->sortColIdx =
3172  (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber));
3173  pertrans->sortOperators =
3174  (Oid *) palloc(numSortCols * sizeof(Oid));
3175  pertrans->sortCollations =
3176  (Oid *) palloc(numSortCols * sizeof(Oid));
3177  pertrans->sortNullsFirst =
3178  (bool *) palloc(numSortCols * sizeof(bool));
3179 
3180  i = 0;
3181  foreach(lc, sortlist)
3182  {
3183  SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
3184  TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args);
3185 
3186  /* the parser should have made sure of this */
3187  Assert(OidIsValid(sortcl->sortop));
3188 
3189  pertrans->sortColIdx[i] = tle->resno;
3190  pertrans->sortOperators[i] = sortcl->sortop;
3191  pertrans->sortCollations[i] = exprCollation((Node *) tle->expr);
3192  pertrans->sortNullsFirst[i] = sortcl->nulls_first;
3193  i++;
3194  }
3195  Assert(i == numSortCols);
3196  }
3197 
3198  if (aggref->aggdistinct)
3199  {
3200  Oid *ops;
3201 
3202  Assert(numArguments > 0);
3203  Assert(list_length(aggref->aggdistinct) == numDistinctCols);
3204 
3205  ops = palloc(numDistinctCols * sizeof(Oid));
3206 
3207  i = 0;
3208  foreach(lc, aggref->aggdistinct)
3209  ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop;
3210 
3211  /* lookup / build the necessary comparators */
3212  if (numDistinctCols == 1)
3213  fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne);
3214  else
3215  pertrans->equalfnMulti =
3216  execTuplesMatchPrepare(pertrans->sortdesc,
3217  numDistinctCols,
3218  pertrans->sortColIdx,
3219  ops,
3220  pertrans->sortCollations,
3221  &aggstate->ss.ps);
3222  pfree(ops);
3223  }
3224 
3225  pertrans->sortstates = (Tuplesortstate **)
3226  palloc0(sizeof(Tuplesortstate *) * numGroupingSets);
3227 }
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:1796
ScanState ss
Definition: execnodes.h:1985
FmgrInfo equalfnOne
Definition: nodeAgg.h:109
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
Oid inputcollid
Definition: primnodes.h:301
Definition: nodes.h:524
AggSplit aggsplit
Definition: execnodes.h:1990
int errcode(int sqlerrcode)
Definition: elog.c:570
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:638
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:786
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:1280
int maxsets
Definition: execnodes.h:2012
void pfree(void *pointer)
Definition: mcxt.c:1031
AggStrategy aggstrategy
Definition: execnodes.h:1989
#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:697
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:955
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:898
#define Assert(condition)
Definition: c.h:732
#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:720
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:1904
TupleTableSlot * uniqslot
Definition: nodeAgg.h:136
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:784
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:86
bool * sortNullsFirst
Definition: nodeAgg.h:102

◆ ExecAgg()

static TupleTableSlot* ExecAgg ( PlanState pstate)
static

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

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

◆ ExecEndAgg()

void ExecEndAgg ( AggState node)

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

3389 {
3391  int transno;
3392  int numGroupingSets = Max(node->maxsets, 1);
3393  int setno;
3394 
3395  /* Make sure we have closed any open tuplesorts */
3396 
3397  if (node->sort_in)
3398  tuplesort_end(node->sort_in);
3399  if (node->sort_out)
3400  tuplesort_end(node->sort_out);
3401 
3402  for (transno = 0; transno < node->numtrans; transno++)
3403  {
3404  AggStatePerTrans pertrans = &node->pertrans[transno];
3405 
3406  for (setno = 0; setno < numGroupingSets; setno++)
3407  {
3408  if (pertrans->sortstates[setno])
3409  tuplesort_end(pertrans->sortstates[setno]);
3410  }
3411  }
3412 
3413  /* And ensure any agg shutdown callbacks have been called */
3414  for (setno = 0; setno < numGroupingSets; setno++)
3415  ReScanExprContext(node->aggcontexts[setno]);
3416  if (node->hashcontext)
3418 
3419  /*
3420  * We don't actually free any ExprContexts here (see comment in
3421  * ExecFreeExprContext), just unlinking the output one from the plan node
3422  * suffices.
3423  */
3424  ExecFreeExprContext(&node->ss.ps);
3425 
3426  /* clean up tuple table */
3428 
3429  outerPlan = outerPlanState(node);
3430  ExecEndNode(outerPlan);
3431 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:538
Tuplesortstate * sort_out
Definition: execnodes.h:2015
ScanState ss
Definition: execnodes.h:1985
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1283
AggStatePerTrans pertrans
Definition: execnodes.h:1995
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:616
int numtrans
Definition: execnodes.h:1988
PlanState ps
Definition: execnodes.h:1280
int maxsets
Definition: execnodes.h:2012
Tuplesortstate * sort_in
Definition: execnodes.h:2014
#define outerPlanState(node)
Definition: execnodes.h:1039
Tuplesortstate ** sortstates
Definition: nodeAgg.h:153
#define outerPlan(node)
Definition: plannodes.h:170
ExprContext * hashcontext
Definition: execnodes.h:1996
#define Max(x, y)
Definition: c.h:898
ExprContext ** aggcontexts
Definition: execnodes.h:1997
void ReScanExprContext(ExprContext *econtext)
Definition: execUtils.c:404
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1235

◆ ExecInitAgg()

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

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

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

◆ ExecReScanAgg()

void ExecReScanAgg ( AggState node)

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

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

◆ fetch_input_tuple()

static TupleTableSlot * fetch_input_tuple ( AggState aggstate)
static

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

393 {
394  TupleTableSlot *slot;
395 
396  if (aggstate->sort_in)
397  {
398  /* make sure we check for interrupts in either path through here */
400  if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
401  aggstate->sort_slot, NULL))
402  return NULL;
403  slot = aggstate->sort_slot;
404  }
405  else
406  slot = ExecProcNode(outerPlanState(aggstate));
407 
408  if (!TupIsNull(slot) && aggstate->sort_out)
409  tuplesort_puttupleslot(aggstate->sort_out, slot);
410 
411  return slot;
412 }
TupleTableSlot * sort_slot
Definition: execnodes.h:2016
Tuplesortstate * sort_out
Definition: execnodes.h:2015
Tuplesortstate * sort_in
Definition: execnodes.h:2014
#define outerPlanState(node)
Definition: execnodes.h:1039
bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy, TupleTableSlot *slot, Datum *abbrev)
Definition: tuplesort.c:2158
#define TupIsNull(slot)
Definition: tuptable.h:293
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:1434

◆ finalize_aggregate()

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

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

898 {
899  LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
900  bool anynull = false;
901  MemoryContext oldContext;
902  int i;
903  ListCell *lc;
904  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
905 
907 
908  /*
909  * Evaluate any direct arguments. We do this even if there's no finalfn
910  * (which is unlikely anyway), so that side-effects happen as expected.
911  * The direct arguments go into arg positions 1 and up, leaving position 0
912  * for the transition state value.
913  */
914  i = 1;
915  foreach(lc, peragg->aggdirectargs)
916  {
917  ExprState *expr = (ExprState *) lfirst(lc);
918 
919  fcinfo->args[i].value = ExecEvalExpr(expr,
920  aggstate->ss.ps.ps_ExprContext,
921  &fcinfo->args[i].isnull);
922  anynull |= fcinfo->args[i].isnull;
923  i++;
924  }
925 
926  /*
927  * Apply the agg's finalfn if one is provided, else return transValue.
928  */
929  if (OidIsValid(peragg->finalfn_oid))
930  {
931  int numFinalArgs = peragg->numFinalArgs;
932 
933  /* set up aggstate->curperagg for AggGetAggref() */
934  aggstate->curperagg = peragg;
935 
936  InitFunctionCallInfoData(*fcinfo, &peragg->finalfn,
937  numFinalArgs,
938  pertrans->aggCollation,
939  (void *) aggstate, NULL);
940 
941  /* Fill in the transition state value */
942  fcinfo->args[0].value =
943  MakeExpandedObjectReadOnly(pergroupstate->transValue,
944  pergroupstate->transValueIsNull,
945  pertrans->transtypeLen);
946  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
947  anynull |= pergroupstate->transValueIsNull;
948 
949  /* Fill any remaining argument positions with nulls */
950  for (; i < numFinalArgs; i++)
951  {
952  fcinfo->args[i].value = (Datum) 0;
953  fcinfo->args[i].isnull = true;
954  anynull = true;
955  }
956 
957  if (fcinfo->flinfo->fn_strict && anynull)
958  {
959  /* don't call a strict function with NULL inputs */
960  *resultVal = (Datum) 0;
961  *resultIsNull = true;
962  }
963  else
964  {
965  *resultVal = FunctionCallInvoke(fcinfo);
966  *resultIsNull = fcinfo->isnull;
967  }
968  aggstate->curperagg = NULL;
969  }
970  else
971  {
972  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
973  *resultVal = pergroupstate->transValue;
974  *resultIsNull = pergroupstate->transValueIsNull;
975  }
976 
977  /*
978  * If result is pass-by-ref, make sure it is in the right context.
979  */
980  if (!peragg->resulttypeByVal && !*resultIsNull &&
982  DatumGetPointer(*resultVal)))
983  *resultVal = datumCopy(*resultVal,
984  peragg->resulttypeByVal,
985  peragg->resulttypeLen);
986 
987  MemoryContextSwitchTo(oldContext);
988 }
ScanState ss
Definition: execnodes.h:1985
ExprContext * ps_ExprContext
Definition: execnodes.h:984
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:1995
#define OidIsValid(objectId)
Definition: c.h:638
#define FUNC_MAX_ARGS
PlanState ps
Definition: execnodes.h:1280
#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:2001
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:667
#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 1121 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().

1124 {
1125  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1126  Datum *aggvalues = econtext->ecxt_aggvalues;
1127  bool *aggnulls = econtext->ecxt_aggnulls;
1128  int aggno;
1129  int transno;
1130 
1131  /*
1132  * If there were any DISTINCT and/or ORDER BY aggregates, sort their
1133  * inputs and run the transition functions.
1134  */
1135  for (transno = 0; transno < aggstate->numtrans; transno++)
1136  {
1137  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
1138  AggStatePerGroup pergroupstate;
1139 
1140  pergroupstate = &pergroup[transno];
1141 
1142  if (pertrans->numSortCols > 0)
1143  {
1144  Assert(aggstate->aggstrategy != AGG_HASHED &&
1145  aggstate->aggstrategy != AGG_MIXED);
1146 
1147  if (pertrans->numInputs == 1)
1149  pertrans,
1150  pergroupstate);
1151  else
1153  pertrans,
1154  pergroupstate);
1155  }
1156  }
1157 
1158  /*
1159  * Run the final functions.
1160  */
1161  for (aggno = 0; aggno < aggstate->numaggs; aggno++)
1162  {
1163  AggStatePerAgg peragg = &peraggs[aggno];
1164  int transno = peragg->transno;
1165  AggStatePerGroup pergroupstate;
1166 
1167  pergroupstate = &pergroup[transno];
1168 
1169  if (DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit))
1170  finalize_partialaggregate(aggstate, peragg, pergroupstate,
1171  &aggvalues[aggno], &aggnulls[aggno]);
1172  else
1173  finalize_aggregate(aggstate, peragg, pergroupstate,
1174  &aggvalues[aggno], &aggnulls[aggno]);
1175  }
1176 }
Datum * ecxt_aggvalues
Definition: execnodes.h:243
int numaggs
Definition: execnodes.h:1987
static void finalize_partialaggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:997
ScanState ss
Definition: execnodes.h:1985
ExprContext * ps_ExprContext
Definition: execnodes.h:984
AggSplit aggsplit
Definition: execnodes.h:1990
static void finalize_aggregate(AggState *aggstate, AggStatePerAgg peragg, AggStatePerGroup pergroupstate, Datum *resultVal, bool *resultIsNull)
Definition: nodeAgg.c:894
AggStatePerTrans pertrans
Definition: execnodes.h:1995
int numtrans
Definition: execnodes.h:1988
PlanState ps
Definition: execnodes.h:1280
AggStrategy aggstrategy
Definition: execnodes.h:1989
static void process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:800
bool * ecxt_aggnulls
Definition: execnodes.h:245
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:732
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:787
static void process_ordered_aggregate_single(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate)
Definition: nodeAgg.c:708

◆ finalize_partialaggregate()

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

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

1001 {
1002  AggStatePerTrans pertrans = &aggstate->pertrans[peragg->transno];
1003  MemoryContext oldContext;
1004 
1006 
1007  /*
1008  * serialfn_oid will be set if we must serialize the transvalue before
1009  * returning it
1010  */
1011  if (OidIsValid(pertrans->serialfn_oid))
1012  {
1013  /* Don't call a strict serialization function with NULL input. */
1014  if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
1015  {
1016  *resultVal = (Datum) 0;
1017  *resultIsNull = true;
1018  }
1019  else
1020  {
1021  FunctionCallInfo fcinfo = pertrans->serialfn_fcinfo;
1022 
1023  fcinfo->args[0].value =
1024  MakeExpandedObjectReadOnly(pergroupstate->transValue,
1025  pergroupstate->transValueIsNull,
1026  pertrans->transtypeLen);
1027  fcinfo->args[0].isnull = pergroupstate->transValueIsNull;
1028 
1029  *resultVal = FunctionCallInvoke(fcinfo);
1030  *resultIsNull = fcinfo->isnull;
1031  }
1032  }
1033  else
1034  {
1035  /* Don't need MakeExpandedObjectReadOnly; datumCopy will copy it */
1036  *resultVal = pergroupstate->transValue;
1037  *resultIsNull = pergroupstate->transValueIsNull;
1038  }
1039 
1040  /* If result is pass-by-ref, make sure it is in the right context. */
1041  if (!peragg->resulttypeByVal && !*resultIsNull &&
1043  DatumGetPointer(*resultVal)))
1044  *resultVal = datumCopy(*resultVal,
1045  peragg->resulttypeByVal,
1046  peragg->resulttypeLen);
1047 
1048  MemoryContextSwitchTo(oldContext);
1049 }
ScanState ss
Definition: execnodes.h:1985
ExprContext * ps_ExprContext
Definition: execnodes.h:984
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:232
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
AggStatePerTrans pertrans
Definition: execnodes.h:1995
#define OidIsValid(objectId)
Definition: c.h:638
PlanState ps
Definition: execnodes.h:1280
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:667
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 3259 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().

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

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

◆ find_hash_columns()

static void find_hash_columns ( AggState aggstate)
static

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

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

◆ find_unaggregated_cols()

static Bitmapset * find_unaggregated_cols ( AggState aggstate)
static

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

1212 {
1213  Agg *node = (Agg *) aggstate->ss.ps.plan;
1214  Bitmapset *colnos;
1215 
1216  colnos = NULL;
1218  &colnos);
1219  (void) find_unaggregated_cols_walker((Node *) node->plan.qual,
1220  &colnos);
1221  return colnos;
1222 }
List * qual
Definition: plannodes.h:141
ScanState ss
Definition: execnodes.h:1985
Definition: nodes.h:524
PlanState ps
Definition: execnodes.h:1280
static bool find_unaggregated_cols_walker(Node *node, Bitmapset **colnos)
Definition: nodeAgg.c:1225
Plan plan
Definition: plannodes.h:804
Plan * plan
Definition: execnodes.h:945
List * targetlist
Definition: plannodes.h:140
Definition: plannodes.h:802

◆ find_unaggregated_cols_walker()

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

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

1226 {
1227  if (node == NULL)
1228  return false;
1229  if (IsA(node, Var))
1230  {
1231  Var *var = (Var *) node;
1232 
1233  /* setrefs.c should have set the varno to OUTER_VAR */
1234  Assert(var->varno == OUTER_VAR);
1235  Assert(var->varlevelsup == 0);
1236  *colnos = bms_add_member(*colnos, var->varattno);
1237  return false;
1238  }
1239  if (IsA(node, Aggref) ||IsA(node, GroupingFunc))
1240  {
1241  /* do not descend into aggregate exprs */
1242  return false;
1243  }
1245  (void *) colnos);
1246 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:575
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:1225
Index varno
Definition: primnodes.h:170
#define Assert(condition)
Definition: c.h:732
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1840
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 3231 of file nodeAgg.c.

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

Referenced by ExecInitAgg().

3232 {
3233  Oid typinput,
3234  typioparam;
3235  char *strInitVal;
3236  Datum initVal;
3237 
3238  getTypeInputInfo(transtype, &typinput, &typioparam);
3239  strInitVal = TextDatumGetCString(textInitVal);
3240  initVal = OidInputFunctionCall(typinput, strInitVal,
3241  typioparam, -1);
3242  pfree(strInitVal);
3243  return initVal;
3244 }
unsigned int Oid
Definition: postgres_ext.h:31
void pfree(void *pointer)
Definition: mcxt.c:1031
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 1446 of file nodeAgg.c.

References MAXALIGN.

Referenced by create_distinct_paths(), and estimate_hashagg_tablesize().

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

◆ initialize_aggregate()

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

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

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

◆ initialize_aggregates()

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

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

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

◆ initialize_phase()

static void initialize_phase ( AggState aggstate,
int  newphase 
)
static

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

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

◆ lookup_hash_entries()

static void lookup_hash_entries ( AggState aggstate)
static

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

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

◆ lookup_hash_entry()

static TupleHashEntryData * lookup_hash_entry ( AggState aggstate)
static

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

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

◆ prepare_projection_slot()

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

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

1077 {
1078  if (aggstate->phase->grouped_cols)
1079  {
1080  Bitmapset *grouped_cols = aggstate->phase->grouped_cols[currentSet];
1081 
1082  aggstate->grouped_cols = grouped_cols;
1083 
1084  if (TTS_EMPTY(slot))
1085  {
1086  /*
1087  * Force all values to be NULL if working on an empty input tuple
1088  * (i.e. an empty grouping set for which no input rows were
1089  * supplied).
1090  */
1091  ExecStoreAllNullTuple(slot);
1092  }
1093  else if (aggstate->all_grouped_cols)
1094  {
1095  ListCell *lc;
1096 
1097  /* all_grouped_cols is arranged in desc order */
1099 
1100  foreach(lc, aggstate->all_grouped_cols)
1101  {
1102  int attnum = lfirst_int(lc);
1103 
1104  if (!bms_is_member(attnum, grouped_cols))
1105  slot->tts_isnull[attnum - 1] = true;
1106  }
1107  }
1108  }
1109 }
TupleTableSlot * ExecStoreAllNullTuple(TupleTableSlot *slot)
Definition: execTuples.c:1541
#define TTS_EMPTY(slot)
Definition: tuptable.h:97
List * all_grouped_cols
Definition: execnodes.h:2010
static void slot_getsomeattrs(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:342
#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:2009
AggStatePerPhase phase
Definition: execnodes.h:1991
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 800 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().

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

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

◆ project_aggregates()

static TupleTableSlot * project_aggregates ( AggState aggstate)
static

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

1185 {
1186  ExprContext *econtext = aggstate->ss.ps.ps_ExprContext;
1187 
1188  /*
1189  * Check the qual (HAVING clause); if the group does not match, ignore it.
1190  */
1191  if (ExecQual(aggstate->ss.ps.qual, econtext))
1192  {
1193  /*
1194  * Form and return projection tuple using the aggregate results and
1195  * the representative input tuple.
1196  */
1197  return ExecProject(aggstate->ss.ps.ps_ProjInfo);
1198  }
1199  else
1200  InstrCountFiltered1(aggstate, 1);
1201 
1202  return NULL;
1203 }
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:985
ScanState ss
Definition: execnodes.h:1985
ExprContext * ps_ExprContext
Definition: execnodes.h:984
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:365
PlanState ps
Definition: execnodes.h:1280
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:1047
ExprState * qual
Definition: execnodes.h:966
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 303 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().

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