mirror of
https://github.com/postgres/postgres.git
synced 2025-06-30 21:42:05 +03:00
Ye-old pgindent run. Same 4-space tabs.
This commit is contained in:
@ -15,7 +15,7 @@
|
||||
* value1 = finalfunc(value1, value2)
|
||||
*
|
||||
* If initcond1 is NULL then the first non-NULL input_value is
|
||||
* assigned directly to value1. sfunc1 isn't applied until value1
|
||||
* assigned directly to value1. sfunc1 isn't applied until value1
|
||||
* is non-NULL.
|
||||
*
|
||||
* sfunc1 is never applied when the current tuple's input_value is NULL.
|
||||
@ -24,7 +24,7 @@
|
||||
* (usenulls was formerly used for COUNT(*), but is no longer needed for
|
||||
* that purpose; as of 10/1999 the support for usenulls is dead code.
|
||||
* I have not removed it because it seems like a potentially useful
|
||||
* feature for user-defined aggregates. We'd just need to add a
|
||||
* feature for user-defined aggregates. We'd just need to add a
|
||||
* flag column to pg_aggregate and a parameter to CREATE AGGREGATE...)
|
||||
*
|
||||
*
|
||||
@ -32,7 +32,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.62 2000/01/26 05:56:22 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.63 2000/04/12 17:15:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -56,6 +56,7 @@
|
||||
*/
|
||||
typedef struct AggStatePerAggData
|
||||
{
|
||||
|
||||
/*
|
||||
* These values are set up during ExecInitAgg() and do not change
|
||||
* thereafter:
|
||||
@ -68,6 +69,7 @@ typedef struct AggStatePerAggData
|
||||
Oid xfn1_oid;
|
||||
Oid xfn2_oid;
|
||||
Oid finalfn_oid;
|
||||
|
||||
/*
|
||||
* fmgr lookup data for transfer functions --- only valid when
|
||||
* corresponding oid is not InvalidOid
|
||||
@ -75,18 +77,21 @@ typedef struct AggStatePerAggData
|
||||
FmgrInfo xfn1;
|
||||
FmgrInfo xfn2;
|
||||
FmgrInfo finalfn;
|
||||
|
||||
/*
|
||||
* Type of input data and Oid of sort operator to use for it;
|
||||
* only set/used when aggregate has DISTINCT flag. (These are not
|
||||
* used directly by nodeAgg, but must be passed to the Tuplesort object.)
|
||||
* Type of input data and Oid of sort operator to use for it; only
|
||||
* set/used when aggregate has DISTINCT flag. (These are not used
|
||||
* directly by nodeAgg, but must be passed to the Tuplesort object.)
|
||||
*/
|
||||
Oid inputType;
|
||||
Oid sortOperator;
|
||||
|
||||
/*
|
||||
* fmgr lookup data for input type's equality operator --- only set/used
|
||||
* when aggregate has DISTINCT flag.
|
||||
* fmgr lookup data for input type's equality operator --- only
|
||||
* set/used when aggregate has DISTINCT flag.
|
||||
*/
|
||||
FmgrInfo equalfn;
|
||||
|
||||
/*
|
||||
* initial values from pg_aggregate entry
|
||||
*/
|
||||
@ -94,6 +99,7 @@ typedef struct AggStatePerAggData
|
||||
Datum initValue2; /* for transtype2 */
|
||||
bool initValue1IsNull,
|
||||
initValue2IsNull;
|
||||
|
||||
/*
|
||||
* We need the len and byval info for the agg's input and transition
|
||||
* data types in order to know how to copy/delete values.
|
||||
@ -106,14 +112,14 @@ typedef struct AggStatePerAggData
|
||||
transtype2ByVal;
|
||||
|
||||
/*
|
||||
* These values are working state that is initialized at the start
|
||||
* of an input tuple group and updated for each input tuple.
|
||||
* These values are working state that is initialized at the start of
|
||||
* an input tuple group and updated for each input tuple.
|
||||
*
|
||||
* For a simple (non DISTINCT) aggregate, we just feed the input values
|
||||
* straight to the transition functions. If it's DISTINCT, we pass the
|
||||
* input values into a Tuplesort object; then at completion of the input
|
||||
* tuple group, we scan the sorted values, eliminate duplicates, and run
|
||||
* the transition functions on the rest.
|
||||
* straight to the transition functions. If it's DISTINCT, we pass
|
||||
* the input values into a Tuplesort object; then at completion of the
|
||||
* input tuple group, we scan the sorted values, eliminate duplicates,
|
||||
* and run the transition functions on the rest.
|
||||
*/
|
||||
|
||||
Tuplesortstate *sortstate; /* sort object, if a DISTINCT agg */
|
||||
@ -123,20 +129,22 @@ typedef struct AggStatePerAggData
|
||||
bool value1IsNull,
|
||||
value2IsNull;
|
||||
bool noInitValue; /* true if value1 not set yet */
|
||||
|
||||
/*
|
||||
* Note: right now, noInitValue always has the same value as value1IsNull.
|
||||
* But we should keep them separate because once the fmgr interface is
|
||||
* fixed, we'll need to distinguish a null returned by transfn1 from
|
||||
* a null we haven't yet replaced with an input value.
|
||||
* Note: right now, noInitValue always has the same value as
|
||||
* value1IsNull. But we should keep them separate because once the
|
||||
* fmgr interface is fixed, we'll need to distinguish a null returned
|
||||
* by transfn1 from a null we haven't yet replaced with an input
|
||||
* value.
|
||||
*/
|
||||
} AggStatePerAggData;
|
||||
|
||||
|
||||
static void initialize_aggregate (AggStatePerAgg peraggstate);
|
||||
static void advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
Datum newVal, bool isNull);
|
||||
static void finalize_aggregate (AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull);
|
||||
static void initialize_aggregate(AggStatePerAgg peraggstate);
|
||||
static void advance_transition_functions(AggStatePerAgg peraggstate,
|
||||
Datum newVal, bool isNull);
|
||||
static void finalize_aggregate(AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull);
|
||||
static Datum copyDatum(Datum val, int typLen, bool typByVal);
|
||||
|
||||
|
||||
@ -144,17 +152,19 @@ static Datum copyDatum(Datum val, int typLen, bool typByVal);
|
||||
* Initialize one aggregate for a new set of input values.
|
||||
*/
|
||||
static void
|
||||
initialize_aggregate (AggStatePerAgg peraggstate)
|
||||
initialize_aggregate(AggStatePerAgg peraggstate)
|
||||
{
|
||||
Aggref *aggref = peraggstate->aggref;
|
||||
Aggref *aggref = peraggstate->aggref;
|
||||
|
||||
/*
|
||||
* Start a fresh sort operation for each DISTINCT aggregate.
|
||||
*/
|
||||
if (aggref->aggdistinct)
|
||||
{
|
||||
/* In case of rescan, maybe there could be an uncompleted
|
||||
* sort operation? Clean it up if so.
|
||||
|
||||
/*
|
||||
* In case of rescan, maybe there could be an uncompleted sort
|
||||
* operation? Clean it up if so.
|
||||
*/
|
||||
if (peraggstate->sortstate)
|
||||
tuplesort_end(peraggstate->sortstate);
|
||||
@ -169,8 +179,8 @@ initialize_aggregate (AggStatePerAgg peraggstate)
|
||||
* (Re)set value1 and value2 to their initial values.
|
||||
*/
|
||||
if (OidIsValid(peraggstate->xfn1_oid) &&
|
||||
! peraggstate->initValue1IsNull)
|
||||
peraggstate->value1 = copyDatum(peraggstate->initValue1,
|
||||
!peraggstate->initValue1IsNull)
|
||||
peraggstate->value1 = copyDatum(peraggstate->initValue1,
|
||||
peraggstate->transtype1Len,
|
||||
peraggstate->transtype1ByVal);
|
||||
else
|
||||
@ -178,8 +188,8 @@ initialize_aggregate (AggStatePerAgg peraggstate)
|
||||
peraggstate->value1IsNull = peraggstate->initValue1IsNull;
|
||||
|
||||
if (OidIsValid(peraggstate->xfn2_oid) &&
|
||||
! peraggstate->initValue2IsNull)
|
||||
peraggstate->value2 = copyDatum(peraggstate->initValue2,
|
||||
!peraggstate->initValue2IsNull)
|
||||
peraggstate->value2 = copyDatum(peraggstate->initValue2,
|
||||
peraggstate->transtype2Len,
|
||||
peraggstate->transtype2ByVal);
|
||||
else
|
||||
@ -205,8 +215,8 @@ initialize_aggregate (AggStatePerAgg peraggstate)
|
||||
* out before reaching here.
|
||||
*/
|
||||
static void
|
||||
advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
Datum newVal, bool isNull)
|
||||
advance_transition_functions(AggStatePerAgg peraggstate,
|
||||
Datum newVal, bool isNull)
|
||||
{
|
||||
Datum args[2];
|
||||
|
||||
@ -214,6 +224,7 @@ advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
{
|
||||
if (peraggstate->noInitValue)
|
||||
{
|
||||
|
||||
/*
|
||||
* value1 has not been initialized. This is the first non-NULL
|
||||
* input value. We use it as the initial value for value1.
|
||||
@ -238,7 +249,7 @@ advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
newVal = (Datum) fmgr_c(&peraggstate->xfn1,
|
||||
(FmgrValues *) args,
|
||||
&isNull);
|
||||
if (! peraggstate->transtype1ByVal)
|
||||
if (!peraggstate->transtype1ByVal)
|
||||
pfree(peraggstate->value1);
|
||||
peraggstate->value1 = newVal;
|
||||
}
|
||||
@ -252,7 +263,7 @@ advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
newVal = (Datum) fmgr_c(&peraggstate->xfn2,
|
||||
(FmgrValues *) args,
|
||||
&isNull);
|
||||
if (! peraggstate->transtype2ByVal)
|
||||
if (!peraggstate->transtype2ByVal)
|
||||
pfree(peraggstate->value2);
|
||||
peraggstate->value2 = newVal;
|
||||
}
|
||||
@ -262,17 +273,18 @@ advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
* Compute the final value of one aggregate.
|
||||
*/
|
||||
static void
|
||||
finalize_aggregate (AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull)
|
||||
finalize_aggregate(AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull)
|
||||
{
|
||||
Aggref *aggref = peraggstate->aggref;
|
||||
char *args[2];
|
||||
|
||||
/*
|
||||
* If it's a DISTINCT aggregate, all we've done so far is to stuff the
|
||||
* input values into the sort object. Complete the sort, then run
|
||||
* the transition functions on the non-duplicate values. Note that
|
||||
* DISTINCT always suppresses nulls, per SQL spec, regardless of usenulls.
|
||||
* input values into the sort object. Complete the sort, then run the
|
||||
* transition functions on the non-duplicate values. Note that
|
||||
* DISTINCT always suppresses nulls, per SQL spec, regardless of
|
||||
* usenulls.
|
||||
*/
|
||||
if (aggref->aggdistinct)
|
||||
{
|
||||
@ -289,41 +301,41 @@ finalize_aggregate (AggStatePerAgg peraggstate,
|
||||
continue;
|
||||
if (haveOldVal)
|
||||
{
|
||||
Datum equal;
|
||||
Datum equal;
|
||||
|
||||
equal = (Datum) (*fmgr_faddr(&peraggstate->equalfn)) (oldVal,
|
||||
newVal);
|
||||
newVal);
|
||||
if (DatumGetInt32(equal) != 0)
|
||||
{
|
||||
if (! peraggstate->inputtypeByVal)
|
||||
if (!peraggstate->inputtypeByVal)
|
||||
pfree(DatumGetPointer(newVal));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
advance_transition_functions(peraggstate, newVal, false);
|
||||
if (haveOldVal && ! peraggstate->inputtypeByVal)
|
||||
if (haveOldVal && !peraggstate->inputtypeByVal)
|
||||
pfree(DatumGetPointer(oldVal));
|
||||
oldVal = newVal;
|
||||
haveOldVal = true;
|
||||
}
|
||||
if (haveOldVal && ! peraggstate->inputtypeByVal)
|
||||
if (haveOldVal && !peraggstate->inputtypeByVal)
|
||||
pfree(DatumGetPointer(oldVal));
|
||||
tuplesort_end(peraggstate->sortstate);
|
||||
peraggstate->sortstate = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now apply the agg's finalfn, or substitute the appropriate transition
|
||||
* value if there is no finalfn.
|
||||
* Now apply the agg's finalfn, or substitute the appropriate
|
||||
* transition value if there is no finalfn.
|
||||
*
|
||||
* XXX For now, only apply finalfn if we got at least one
|
||||
* non-null input value. This prevents zero divide in AVG().
|
||||
* If we had cleaner handling of null inputs/results in functions,
|
||||
* we could probably take out this hack and define the result
|
||||
* for no inputs as whatever finalfn returns for null input.
|
||||
* XXX For now, only apply finalfn if we got at least one non-null input
|
||||
* value. This prevents zero divide in AVG(). If we had cleaner
|
||||
* handling of null inputs/results in functions, we could probably
|
||||
* take out this hack and define the result for no inputs as whatever
|
||||
* finalfn returns for null input.
|
||||
*/
|
||||
if (OidIsValid(peraggstate->finalfn_oid) &&
|
||||
! peraggstate->noInitValue)
|
||||
!peraggstate->noInitValue)
|
||||
{
|
||||
if (peraggstate->finalfn.fn_nargs > 1)
|
||||
{
|
||||
@ -361,17 +373,17 @@ finalize_aggregate (AggStatePerAgg peraggstate,
|
||||
elog(ERROR, "ExecAgg: no valid transition functions??");
|
||||
|
||||
/*
|
||||
* Release any per-group working storage, unless we're passing
|
||||
* it back as the result of the aggregate.
|
||||
* Release any per-group working storage, unless we're passing it back
|
||||
* as the result of the aggregate.
|
||||
*/
|
||||
if (OidIsValid(peraggstate->xfn1_oid) &&
|
||||
! peraggstate->value1IsNull &&
|
||||
! peraggstate->transtype1ByVal)
|
||||
!peraggstate->value1IsNull &&
|
||||
!peraggstate->transtype1ByVal)
|
||||
pfree(peraggstate->value1);
|
||||
|
||||
|
||||
if (OidIsValid(peraggstate->xfn2_oid) &&
|
||||
! peraggstate->value2IsNull &&
|
||||
! peraggstate->transtype2ByVal)
|
||||
!peraggstate->value2IsNull &&
|
||||
!peraggstate->transtype2ByVal)
|
||||
pfree(peraggstate->value2);
|
||||
}
|
||||
|
||||
@ -383,8 +395,8 @@ finalize_aggregate (AggStatePerAgg peraggstate,
|
||||
* the appropriate attribute for each aggregate function use (Aggref
|
||||
* node) appearing in the targetlist or qual of the node. The number
|
||||
* of tuples to aggregate over depends on whether a GROUP BY clause is
|
||||
* present. We can produce an aggregate result row per group, or just
|
||||
* one for the whole query. The value of each aggregate is stored in
|
||||
* present. We can produce an aggregate result row per group, or just
|
||||
* one for the whole query. The value of each aggregate is stored in
|
||||
* the expression context to be used when ExecProject evaluates the
|
||||
* result tuple.
|
||||
*
|
||||
@ -403,7 +415,7 @@ ExecAgg(Agg *node)
|
||||
ProjectionInfo *projInfo;
|
||||
Datum *aggvalues;
|
||||
bool *aggnulls;
|
||||
AggStatePerAgg peragg;
|
||||
AggStatePerAgg peragg;
|
||||
TupleTableSlot *resultSlot;
|
||||
HeapTuple inputTuple;
|
||||
int aggno;
|
||||
@ -437,7 +449,7 @@ ExecAgg(Agg *node)
|
||||
*/
|
||||
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
|
||||
{
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
|
||||
initialize_aggregate(peraggstate);
|
||||
}
|
||||
@ -459,9 +471,9 @@ ExecAgg(Agg *node)
|
||||
|
||||
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
|
||||
{
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
Aggref *aggref = peraggstate->aggref;
|
||||
Datum newVal;
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
Aggref *aggref = peraggstate->aggref;
|
||||
Datum newVal;
|
||||
|
||||
newVal = ExecEvalExpr(aggref->target, econtext,
|
||||
&isNull, &isDone);
|
||||
@ -479,37 +491,37 @@ ExecAgg(Agg *node)
|
||||
|
||||
/*
|
||||
* Keep a copy of the first input tuple for the projection.
|
||||
* (We only need one since only the GROUP BY columns in it
|
||||
* can be referenced, and these will be the same for all
|
||||
* tuples aggregated over.)
|
||||
* (We only need one since only the GROUP BY columns in it can
|
||||
* be referenced, and these will be the same for all tuples
|
||||
* aggregated over.)
|
||||
*/
|
||||
if (!inputTuple)
|
||||
inputTuple = heap_copytuple(outerslot->val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Done scanning input tuple group.
|
||||
* Finalize each aggregate calculation.
|
||||
* Done scanning input tuple group. Finalize each aggregate
|
||||
* calculation.
|
||||
*/
|
||||
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
|
||||
{
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
|
||||
finalize_aggregate(peraggstate,
|
||||
& aggvalues[aggno], & aggnulls[aggno]);
|
||||
&aggvalues[aggno], &aggnulls[aggno]);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the outerPlan is a Group node, we will reach here after each
|
||||
* group. We are not done unless the Group node is done (a little
|
||||
* ugliness here while we reach into the Group's state to find out).
|
||||
* Furthermore, when grouping we return nothing at all unless we
|
||||
* had some input tuple(s). By the nature of Group, there are
|
||||
* no empty groups, so if we get here with no input the whole scan
|
||||
* is empty.
|
||||
* ugliness here while we reach into the Group's state to find
|
||||
* out). Furthermore, when grouping we return nothing at all
|
||||
* unless we had some input tuple(s). By the nature of Group,
|
||||
* there are no empty groups, so if we get here with no input the
|
||||
* whole scan is empty.
|
||||
*
|
||||
* If the outerPlan isn't a Group, we are done when we get here,
|
||||
* and we will emit a (single) tuple even if there were no input
|
||||
* If the outerPlan isn't a Group, we are done when we get here, and
|
||||
* we will emit a (single) tuple even if there were no input
|
||||
* tuples.
|
||||
*/
|
||||
if (IsA(outerPlan, Group))
|
||||
@ -523,17 +535,18 @@ ExecAgg(Agg *node)
|
||||
else
|
||||
{
|
||||
aggstate->agg_done = true;
|
||||
|
||||
/*
|
||||
* If inputtuple==NULL (ie, the outerPlan didn't return anything),
|
||||
* create a dummy all-nulls input tuple for use by execProject.
|
||||
* 99.44% of the time this is a waste of cycles, because
|
||||
* ordinarily the projected output tuple's targetlist cannot
|
||||
* contain any direct (non-aggregated) references to input
|
||||
* columns, so the dummy tuple will not be referenced. However
|
||||
* there are special cases where this isn't so --- in particular
|
||||
* an UPDATE involving an aggregate will have a targetlist
|
||||
* reference to ctid. We need to return a null for ctid in that
|
||||
* situation, not coredump.
|
||||
* If inputtuple==NULL (ie, the outerPlan didn't return
|
||||
* anything), create a dummy all-nulls input tuple for use by
|
||||
* execProject. 99.44% of the time this is a waste of cycles,
|
||||
* because ordinarily the projected output tuple's targetlist
|
||||
* cannot contain any direct (non-aggregated) references to
|
||||
* input columns, so the dummy tuple will not be referenced.
|
||||
* However there are special cases where this isn't so --- in
|
||||
* particular an UPDATE involving an aggregate will have a
|
||||
* targetlist reference to ctid. We need to return a null for
|
||||
* ctid in that situation, not coredump.
|
||||
*
|
||||
* The values returned for the aggregates will be the initial
|
||||
* values of the transition functions.
|
||||
@ -550,7 +563,7 @@ ExecAgg(Agg *node)
|
||||
/* watch out for null input tuples, though... */
|
||||
if (tupType && tupValue)
|
||||
{
|
||||
null_array = (char *) palloc(sizeof(char)*tupType->natts);
|
||||
null_array = (char *) palloc(sizeof(char) * tupType->natts);
|
||||
for (attnum = 0; attnum < tupType->natts; attnum++)
|
||||
null_array[attnum] = 'n';
|
||||
inputTuple = heap_formtuple(tupType, tupValue, null_array);
|
||||
@ -571,17 +584,17 @@ ExecAgg(Agg *node)
|
||||
|
||||
/*
|
||||
* Form a projection tuple using the aggregate results and the
|
||||
* representative input tuple. Store it in the result tuple slot.
|
||||
* representative input tuple. Store it in the result tuple slot.
|
||||
*/
|
||||
resultSlot = ExecProject(projInfo, &isDone);
|
||||
|
||||
/*
|
||||
* If the completed tuple does not match the qualifications,
|
||||
* it is ignored and we loop back to try to process another group.
|
||||
* If the completed tuple does not match the qualifications, it is
|
||||
* ignored and we loop back to try to process another group.
|
||||
* Otherwise, return the tuple.
|
||||
*/
|
||||
}
|
||||
while (! ExecQual(node->plan.qual, econtext, false));
|
||||
while (!ExecQual(node->plan.qual, econtext, false));
|
||||
|
||||
return resultSlot;
|
||||
}
|
||||
@ -596,13 +609,13 @@ ExecAgg(Agg *node)
|
||||
bool
|
||||
ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
{
|
||||
AggState *aggstate;
|
||||
AggStatePerAgg peragg;
|
||||
Plan *outerPlan;
|
||||
ExprContext *econtext;
|
||||
int numaggs,
|
||||
aggno;
|
||||
List *alist;
|
||||
AggState *aggstate;
|
||||
AggStatePerAgg peragg;
|
||||
Plan *outerPlan;
|
||||
ExprContext *econtext;
|
||||
int numaggs,
|
||||
aggno;
|
||||
List *alist;
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
@ -620,21 +633,23 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
* find aggregates in targetlist and quals
|
||||
*
|
||||
* Note: pull_agg_clauses also checks that no aggs contain other agg
|
||||
* calls in their arguments. This would make no sense under SQL semantics
|
||||
* anyway (and it's forbidden by the spec). Because that is true, we
|
||||
* don't need to worry about evaluating the aggs in any particular order.
|
||||
* calls in their arguments. This would make no sense under SQL
|
||||
* semantics anyway (and it's forbidden by the spec). Because that is
|
||||
* true, we don't need to worry about evaluating the aggs in any
|
||||
* particular order.
|
||||
*/
|
||||
aggstate->aggs = nconc(pull_agg_clause((Node *) node->plan.targetlist),
|
||||
pull_agg_clause((Node *) node->plan.qual));
|
||||
aggstate->numaggs = numaggs = length(aggstate->aggs);
|
||||
if (numaggs <= 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* This used to be treated as an error, but we can't do that anymore
|
||||
* because constant-expression simplification could optimize away
|
||||
* all of the Aggrefs in the targetlist and qual. So, just make a
|
||||
* debug note, and force numaggs positive so that palloc()s below
|
||||
* don't choke.
|
||||
* This used to be treated as an error, but we can't do that
|
||||
* anymore because constant-expression simplification could
|
||||
* optimize away all of the Aggrefs in the targetlist and qual.
|
||||
* So, just make a debug note, and force numaggs positive so that
|
||||
* palloc()s below don't choke.
|
||||
*/
|
||||
elog(DEBUG, "ExecInitAgg: could not find any aggregate functions");
|
||||
numaggs = 1;
|
||||
@ -655,8 +670,8 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
|
||||
|
||||
/*
|
||||
* Set up aggregate-result storage in the expr context,
|
||||
* and also allocate my private per-agg working storage
|
||||
* Set up aggregate-result storage in the expr context, and also
|
||||
* allocate my private per-agg working storage
|
||||
*/
|
||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
||||
econtext->ecxt_aggvalues = (Datum *) palloc(sizeof(Datum) * numaggs);
|
||||
@ -693,15 +708,15 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
aggno = -1;
|
||||
foreach(alist, aggstate->aggs)
|
||||
{
|
||||
Aggref *aggref = (Aggref *) lfirst(alist);
|
||||
AggStatePerAgg peraggstate = &peragg[++aggno];
|
||||
char *aggname = aggref->aggname;
|
||||
HeapTuple aggTuple;
|
||||
Aggref *aggref = (Aggref *) lfirst(alist);
|
||||
AggStatePerAgg peraggstate = &peragg[++aggno];
|
||||
char *aggname = aggref->aggname;
|
||||
HeapTuple aggTuple;
|
||||
Form_pg_aggregate aggform;
|
||||
Type typeInfo;
|
||||
Oid xfn1_oid,
|
||||
xfn2_oid,
|
||||
finalfn_oid;
|
||||
Type typeInfo;
|
||||
Oid xfn1_oid,
|
||||
xfn2_oid,
|
||||
finalfn_oid;
|
||||
|
||||
/* Mark Aggref node with its associated index in the result array */
|
||||
aggref->aggno = aggno;
|
||||
@ -762,9 +777,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
}
|
||||
|
||||
if (OidIsValid(finalfn_oid))
|
||||
{
|
||||
fmgr_info(finalfn_oid, &peraggstate->finalfn);
|
||||
}
|
||||
|
||||
if (aggref->aggdistinct)
|
||||
{
|
||||
@ -848,7 +861,7 @@ copyDatum(Datum val, int typLen, bool typByVal)
|
||||
return val;
|
||||
else
|
||||
{
|
||||
char *newVal;
|
||||
char *newVal;
|
||||
|
||||
if (typLen == -1) /* variable length type? */
|
||||
typLen = VARSIZE((struct varlena *) DatumGetPointer(val));
|
||||
|
Reference in New Issue
Block a user