Re: Improving avg performance for numeric
Hi,
I've reviewed the v6 of the "numeric optimize" patch
(/messages/by-id/CAFj8pRDQhG7Pqmf8XqXY0PnHfakkPQLPHnoRLJ_=EKFSbOAWeA@mail.gmail.com),
as Pavel did some hacking on the patch and asked me to do the review.
The patch seems fine to me, the following comments are mostly nitpicking:
1) Applies cleanly to the HEAD (although only by "patch" and not "git
apply").
2) I think we should use "estimate" instead of "approximation" in the
docs, it seems more correct / natural to me (but maybe I'm wrong on this
one).
3) state_data_size does not make much sense to me - it should be
state_size. This probably comes from the state_data_type, but that's
('state' + 'data type') and by replacing the second part with 'size'
you'll get state_size.
4) currently the state size may be specified for all data types, no
matter if their size is fixed or variable. Wouldn't it be safer to allow
this option only for variable-length data types? Right now you can
specify stype=int and sspace=200 which does not make much sense to me.
We can always relax the restrictions if needed, the opposite is much
more difficult.
5) in numeric.c, there are no comments for
- fields of the NumericAggState (some are obvious, some are not)
- multiple functions are missing the initial comments (e.g.
numeric_accum, do_numeric_accum)
6) I think the "first" variable in do_numeric_accum is rather useless,
it's trivial to remove it - just use the state->first instead and move
the assignment to the proper branch (ok, this is nitpicking).
7) I think the error message in makeNumericAggState should be something
like "This must not be called in non-aggregate context!" or something
like that.
8) The records in pg_aggregate.c are using either 0 (for fixed-length)
or 128. This seems slightly excessive to me. What is the reasoning
behind this? Is that because of the two NumericVar fields?
regards
Tomas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hello
2013/9/22 Tomas Vondra <tv@fuzzy.cz>
Hi,
I've reviewed the v6 of the "numeric optimize" patch
(http://www.postgresql.org/**message-id/**CAFj8pRDQhG7Pqmf8XqXY0PnHfakkP**
QLPHnoRLJ_=EKFSbOAWeA@mail.**gmail.com</messages/by-id/CAFj8pRDQhG7Pqmf8XqXY0PnHfakkPQLPHnoRLJ_=EKFSbOAWeA@mail.gmail.com>
),
as Pavel did some hacking on the patch and asked me to do the review.The patch seems fine to me, the following comments are mostly nitpicking:
1) Applies cleanly to the HEAD (although only by "patch" and not "git
apply").2) I think we should use "estimate" instead of "approximation" in the
docs, it seems more correct / natural to me (but maybe I'm wrong on this
one).3) state_data_size does not make much sense to me - it should be
state_size. This probably comes from the state_data_type, but that's
('state' + 'data type') and by replacing the second part with 'size'
you'll get state_size.
This name is consistent with previous field state_data_type - I expected so
this mean 'state data' + 'type'. I am not native speaker, so my position is
not strong, but in this moment I am thinking so state_data_size has a
sense. In this case both variant has sense - 'state data' + type or
'state' + 'data type'.
4) currently the state size may be specified for all data types, no
matter if their size is fixed or variable. Wouldn't it be safer to allow
this option only for variable-length data types? Right now you can
specify stype=int and sspace=200 which does not make much sense to me.
We can always relax the restrictions if needed, the opposite is much
more difficult.
good idea
5) in numeric.c, there are no comments for
- fields of the NumericAggState (some are obvious, some are not)
- multiple functions are missing the initial comments (e.g.
numeric_accum, do_numeric_accum)
ok
6) I think the "first" variable in do_numeric_accum is rather useless,
it's trivial to remove it - just use the state->first instead and move
the assignment to the proper branch (ok, this is nitpicking).
ok
7) I think the error message in makeNumericAggState should be something
like "This must not be called in non-aggregate context!" or something like
that.
I used a "a numeric aggregate function called in non-aggregate context" -
it is similar to other related messages
8) The records in pg_aggregate.c are using either 0 (for fixed-length) or
128. This seems slightly excessive to me. What is the reasoning behind
this? Is that because of the two NumericVar fields?
NumericAggState has 96 bytes - but you have to add a space for digits of
included numeric values (inclued in NumericVar) -- so it is others 16 + 16
= 128. I am not able to specify how much digits will be used exactly - 16
bytes is just good enough estimation - it is not used for memory
allocation, it is used for some planner magic.
Show quoted text
regards
Tomas--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/**mailpref/pgsql-hackers<http://www.postgresql.org/mailpref/pgsql-hackers>
Attachments:
numeric-optimize-v7.patchapplication/octet-stream; name=numeric-optimize-v7.patchDownload
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 373,378 ****
--- 373,384 ----
<entry>Data type of the aggregate function's internal transition (state) data</entry>
</row>
<row>
+ <entry><structfield>aggtransspace</structfield></entry>
+ <entry><type>int4</type></entry>
+ <entry></entry>
+ <entry>Approximation for the average size of the aggregate function's internal transition (state) data</entry>
+ </row>
+ <row>
<entry><structfield>agginitval</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
*** a/doc/src/sgml/ref/create_aggregate.sgml
--- b/doc/src/sgml/ref/create_aggregate.sgml
***************
*** 24,29 **** PostgreSQL documentation
--- 24,30 ----
CREATE AGGREGATE <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">arg_name</replaceable> ] <replaceable class="parameter">arg_data_type</replaceable> [ , ... ] ) (
SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
+ [ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
[ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
***************
*** 35,40 **** CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
--- 36,42 ----
BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
+ [ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
[ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
***************
*** 265,270 **** SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
--- 267,284 ----
</varlistentry>
<varlistentry>
+ <term><replaceable class="PARAMETER">state_data_size</replaceable></term>
+ <listitem>
+ <para>
+ Approximate average size (in bytes) of aggregate's state value.
+ Planner uses this value to approximate the memory required for
+ the aggregation. If this value is not provided, a default value is
+ used based on state_data_type.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><replaceable class="PARAMETER">ffunc</replaceable></term>
<listitem>
<para>
*** a/src/backend/catalog/pg_aggregate.c
--- b/src/backend/catalog/pg_aggregate.c
***************
*** 55,60 **** AggregateCreate(const char *aggName,
--- 55,61 ----
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
+ int32 aggTransSpace,
const char *agginitval)
{
Relation aggdesc;
***************
*** 195,200 **** AggregateCreate(const char *aggName,
--- 196,211 ----
errmsg("unsafe use of pseudo-type \"internal\""),
errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
+ /*
+ * Allow non zerro aggTransSpace only for INTERNALOID aggTransType
+ * Other types has known size.
+ */
+ if (aggTransType != INTERNALOID && aggTransSpace > 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("SSPACE can be used only for \"internal\" transition type"),
+ errdetail("SSPACE can be defined only together with a \"internal\" transition type.")));
+
/* handle sortop, if supplied */
if (aggsortopName)
{
***************
*** 273,278 **** AggregateCreate(const char *aggName,
--- 284,290 ----
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
+ values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
if (agginitval)
values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
else
*** a/src/backend/commands/aggregatecmds.c
--- b/src/backend/commands/aggregatecmds.c
***************
*** 68,73 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
--- 68,74 ----
ArrayType *parameterNames;
List *parameterDefaults;
Oid transTypeId;
+ int32 transSpace = 0;
char transTypeType;
ListCell *pl;
***************
*** 102,107 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
--- 103,110 ----
transType = defGetTypeName(defel);
else if (pg_strcasecmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
+ else if (pg_strcasecmp(defel->defname, "sspace") == 0)
+ transSpace = defGetInt32(defel);
else if (pg_strcasecmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
***************
*** 248,252 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
--- 251,256 ----
finalfuncName, /* final function name */
sortoperatorName, /* sort operator name */
transTypeId, /* transition data type */
+ transSpace, /* transition space */
initval); /* initial condition */
}
*** a/src/backend/commands/define.c
--- b/src/backend/commands/define.c
***************
*** 165,170 **** defGetBoolean(DefElem *def)
--- 165,194 ----
}
/*
+ * Extract an int32 value from a DefElem.
+ */
+ int32
+ defGetInt32(DefElem *def)
+ {
+ if (def->arg == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires an integer value",
+ def->defname)));
+ switch (nodeTag(def->arg))
+ {
+ case T_Integer:
+ return (int32) intVal(def->arg);
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires an integer value",
+ def->defname)));
+ }
+ return 0; /* keep compiler quiet */
+ }
+
+ /*
* Extract an int64 value from a DefElem.
*/
int64
*** a/src/backend/optimizer/util/clauses.c
--- b/src/backend/optimizer/util/clauses.c
***************
*** 461,466 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
--- 461,467 ----
Oid aggtransfn;
Oid aggfinalfn;
Oid aggtranstype;
+ int32 aggtransspace;
QualCost argcosts;
Oid *inputTypes;
int numArguments;
***************
*** 478,483 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
--- 479,485 ----
aggtransfn = aggform->aggtransfn;
aggfinalfn = aggform->aggfinalfn;
aggtranstype = aggform->aggtranstype;
+ aggtransspace = aggform->aggtransspace;
ReleaseSysCache(aggTuple);
/* count it */
***************
*** 533,545 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
pfree(declaredArgTypes);
}
/*
* If the transition type is pass-by-value then it doesn't add
* anything to the required size of the hashtable. If it is
* pass-by-reference then we have to add the estimated size of the
* value itself, plus palloc overhead.
*/
! if (!get_typbyval(aggtranstype))
{
int32 aggtranstypmod;
int32 avgwidth;
--- 535,555 ----
pfree(declaredArgTypes);
}
+ /*
+ * If approximate average space used by aggregate transition value is
+ * specified in pg_aggregate, then use it for transitionSpace.
+ */
+ if (aggtransspace > 0)
+ {
+ costs->transitionSpace += aggtransspace;
+ }
/*
* If the transition type is pass-by-value then it doesn't add
* anything to the required size of the hashtable. If it is
* pass-by-reference then we have to add the estimated size of the
* value itself, plus palloc overhead.
*/
! else if (!get_typbyval(aggtranstype))
{
int32 aggtranstypmod;
int32 avgwidth;
*** a/src/backend/utils/adt/numeric.c
--- b/src/backend/utils/adt/numeric.c
***************
*** 2464,2571 **** numeric_float4(PG_FUNCTION_ARGS)
*
* Aggregate functions
*
! * The transition datatype for all these aggregates is a 3-element array
! * of Numeric, holding the values N, sum(X), sum(X*X) in that order.
! *
! * We represent N as a numeric mainly to avoid having to build a special
! * datatype; it's unlikely it'd overflow an int4, but ...
*
* ----------------------------------------------------------------------
*/
! static ArrayType *
! do_numeric_accum(ArrayType *transarray, Numeric newval)
{
! Datum *transdatums;
! int ndatums;
! Datum N,
! sumX,
! sumX2;
! ArrayType *result;
!
! /* We assume the input is array of numeric */
! deconstruct_array(transarray,
! NUMERICOID, -1, false, 'i',
! &transdatums, NULL, &ndatums);
! if (ndatums != 3)
! elog(ERROR, "expected 3-element numeric array");
! N = transdatums[0];
! sumX = transdatums[1];
! sumX2 = transdatums[2];
!
! N = DirectFunctionCall1(numeric_inc, N);
! sumX = DirectFunctionCall2(numeric_add, sumX,
! NumericGetDatum(newval));
! sumX2 = DirectFunctionCall2(numeric_add, sumX2,
! DirectFunctionCall2(numeric_mul,
! NumericGetDatum(newval),
! NumericGetDatum(newval)));
!
! transdatums[0] = N;
! transdatums[1] = sumX;
! transdatums[2] = sumX2;
!
! result = construct_array(transdatums, 3,
! NUMERICOID, -1, false, 'i');
! return result;
}
/*
! * Improve avg performance by not caclulating sum(X*X).
*/
! static ArrayType *
! do_numeric_avg_accum(ArrayType *transarray, Numeric newval)
{
! Datum *transdatums;
! int ndatums;
! Datum N,
! sumX;
! ArrayType *result;
!
! /* We assume the input is array of numeric */
! deconstruct_array(transarray,
! NUMERICOID, -1, false, 'i',
! &transdatums, NULL, &ndatums);
! if (ndatums != 2)
! elog(ERROR, "expected 2-element numeric array");
! N = transdatums[0];
! sumX = transdatums[1];
!
! N = DirectFunctionCall1(numeric_inc, N);
! sumX = DirectFunctionCall2(numeric_add, sumX,
! NumericGetDatum(newval));
!
! transdatums[0] = N;
! transdatums[1] = sumX;
!
! result = construct_array(transdatums, 2,
! NUMERICOID, -1, false, 'i');
! return result;
}
Datum
numeric_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Numeric newval = PG_GETARG_NUMERIC(1);
! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
/*
! * Optimized case for average of numeric.
*/
Datum
numeric_avg_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Numeric newval = PG_GETARG_NUMERIC(1);
! PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
}
/*
* Integer data types all use Numeric accumulators to share code and
* avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
--- 2464,2632 ----
*
* Aggregate functions
*
! * The transition datatype for all these aggregates is a pointer to
! * a struct NumericAggState allocated in the aggregate context.
*
* ----------------------------------------------------------------------
*/
! typedef struct NumericAggState
{
! bool isNaN; /* true, when some processed number is NaN */
! uint64 N; /* count of processed numbers */
! NumericVar sumX; /* sum of processed numbers */
! NumericVar sumX2; /* sum of square of processed numbers */
! bool calcSumX2; /* when is true, then sumX2 is calculated */
! MemoryContext agg_context;
! } NumericAggState;
!
! /*
! * Prepare state data for Numeric aggregate function that needs to know a sum, count
! * and sometimes sum of square (when calcSumX2 is true).
! */
!
! static NumericAggState *
! makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
! {
! NumericAggState *state;
! MemoryContext agg_context;
! MemoryContext old_context;
!
! if (!AggCheckCallContext(fcinfo, &agg_context))
! elog(ERROR, "a numeric aggregate function called in non-aggregate context");
!
! old_context = MemoryContextSwitchTo(agg_context);
!
! state = palloc0(sizeof(NumericAggState));
! state->calcSumX2 = calcSumX2;
! state->agg_context = agg_context;
!
! MemoryContextSwitchTo(old_context);
!
! return state;
}
+
/*
! * a workhorse for numeric accum functions. A different behave (controlled by calcSumX2)
! * is specified when NumericAggState is initiated. This accum function is used for numeric
! * sum too due minimize overhead related to packing and unpacking Numeric value.
! *
*/
!
! static void
! do_numeric_accum(NumericAggState *state, Numeric newval)
{
! NumericVar X;
! NumericVar X2;
! MemoryContext old_context;
! /* result is NaN, when some processed number is NaN */
! if (state->isNaN || NUMERIC_IS_NAN(newval))
! {
! state->isNaN = true;
! return;
! }
!
! /* load processed number */
! init_var_from_num(newval, &X);
!
! if (state->calcSumX2)
! {
! init_var(&X2);
! mul_var(&X, &X, &X2, X.dscale * 2);
! }
!
! old_context = MemoryContextSwitchTo(state->agg_context);
!
! if (state->N++ > 0)
! {
! NumericVar preSumX;
!
! /* increase counters */
! memcpy(&preSumX, &(state->sumX), sizeof(NumericVar));
! init_var(&(state->sumX));
! add_var(&X, &preSumX, &(state->sumX));
! free_var(&preSumX);
!
! if (state->calcSumX2)
! {
! NumericVar preSumX2;
!
! memcpy(&preSumX2, &(state->sumX2), sizeof(NumericVar));
! init_var(&(state->sumX2));
! add_var(&X2, &preSumX2, &(state->sumX2));
! free_var(&preSumX2);
! }
! }
! else
! {
! /* initialize counters */
! set_var_from_var(&X, &(state->sumX));
!
! if (state->calcSumX2)
! set_var_from_var(&X2, &(state->sumX2));
! }
!
! MemoryContextSwitchTo(old_context);
}
+ /*
+ * Generic accum function for Numeric aggregates. It initialize NumericAggState
+ * with calcSumX2 is true - it ensure a sumX2 calcualtion.
+ */
+
Datum
numeric_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
!
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
! if (!PG_ARGISNULL(1))
! {
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, true);
!
! do_numeric_accum(state, PG_GETARG_NUMERIC(1));
! }
!
! if (state == NULL)
! PG_RETURN_NULL();
! else
! PG_RETURN_POINTER(state);
}
+
/*
! * Optimized accum function for average and sum aggregate function. Doesn't calculate sumX2.
*/
+
Datum
numeric_avg_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
!
! if (!PG_ARGISNULL(1))
! {
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, false);
!
! do_numeric_accum(state, PG_GETARG_NUMERIC(1));
! }
!
! if (state == NULL)
! PG_RETURN_NULL();
! else
! PG_RETURN_POINTER(state);
}
+
/*
* Integer data types all use Numeric accumulators to share code and
* avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
***************
*** 2578,2664 **** numeric_avg_accum(PG_FUNCTION_ARGS)
Datum
int2_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Datum newval2 = PG_GETARG_DATUM(1);
! Numeric newval;
! newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
Datum
int4_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Datum newval4 = PG_GETARG_DATUM(1);
! Numeric newval;
! newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
Datum
int8_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Datum newval8 = PG_GETARG_DATUM(1);
! Numeric newval;
! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
/*
* Optimized case for average of int8.
*/
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Datum newval8 = PG_GETARG_DATUM(1);
! Numeric newval;
!
! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
! PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
}
Datum
numeric_avg(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Datum *transdatums;
! int ndatums;
! Numeric N,
! sumX;
!
! /* We assume the input is array of numeric */
! deconstruct_array(transarray,
! NUMERICOID, -1, false, 'i',
! &transdatums, NULL, &ndatums);
! if (ndatums != 2)
! elog(ERROR, "expected 2-element numeric array");
! N = DatumGetNumeric(transdatums[0]);
! sumX = DatumGetNumeric(transdatums[1]);
! /* SQL defines AVG of no values to be NULL */
! /* N is zero iff no digits (cf. numeric_uminus) */
! if (NUMERIC_NDIGITS(N) == 0)
PG_RETURN_NULL();
! PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
! NumericGetDatum(sumX),
! NumericGetDatum(N)));
}
/*
* Workhorse routine for the standard deviance and variance
! * aggregates. 'transarray' is the aggregate's transition
! * array. 'variance' specifies whether we should calculate the
* variance or the standard deviation. 'sample' indicates whether the
* caller is interested in the sample or the population
* variance/stddev.
--- 2639,2788 ----
Datum
int2_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
!
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
! if (!PG_ARGISNULL(1))
! {
! Datum newval2 = PG_GETARG_DATUM(1);
! Numeric newval;
!
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, true);
!
! newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
! do_numeric_accum(state, newval);
! }
! if (state == NULL)
! PG_RETURN_NULL();
! else
! PG_RETURN_POINTER(state);
}
+
Datum
int4_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
! if (!PG_ARGISNULL(1))
! {
! Datum newval4 = PG_GETARG_DATUM(1);
! Numeric newval;
!
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, true);
!
! newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
! do_numeric_accum(state, newval);
! }
!
! if (state == NULL)
! PG_RETURN_NULL();
! else
! PG_RETURN_POINTER(state);
}
+
Datum
int8_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
! if (!PG_ARGISNULL(1))
! {
! Datum newval8 = PG_GETARG_DATUM(1);
! Numeric newval;
!
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, true);
!
! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
! do_numeric_accum(state, newval);
! }
!
! if (state == NULL)
! PG_RETURN_NULL();
! else
! PG_RETURN_POINTER(state);
}
+
/*
* Optimized case for average of int8.
*/
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
! if (!PG_ARGISNULL(1))
! {
! Datum newval8 = PG_GETARG_DATUM(1);
! Numeric newval;
!
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, false);
!
! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
! do_numeric_accum(state, newval);
! }
!
! if (state == NULL)
! PG_RETURN_NULL();
! else
! PG_RETURN_POINTER(state);
}
Datum
numeric_avg(PG_FUNCTION_ARGS)
{
! Datum N_datum;
! Datum sumX_datum;
! NumericAggState *state;
! if (PG_ARGISNULL(0))
! PG_RETURN_NULL();
!
! state = (NumericAggState *) PG_GETARG_POINTER(0);
!
! N_datum = DirectFunctionCall1(int8_numeric, Int64GetDatum(state->N));
! sumX_datum = NumericGetDatum(make_result(&state->sumX));
!
! PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumX_datum, N_datum));
! }
!
!
! Datum
! numeric_sum(PG_FUNCTION_ARGS)
! {
! NumericAggState *state;
!
! if (PG_ARGISNULL(0))
PG_RETURN_NULL();
+
+ state = (NumericAggState *) PG_GETARG_POINTER(0);
! PG_RETURN_NUMERIC(make_result(&(state->sumX)));
}
+
/*
* Workhorse routine for the standard deviance and variance
! * aggregates. 'state' is aggregate's transition state.
! * 'variance' specifies whether we should calculate the
* variance or the standard deviation. 'sample' indicates whether the
* caller is interested in the sample or the population
* variance/stddev.
***************
*** 2667,2682 **** numeric_avg(PG_FUNCTION_ARGS)
* *is_null is set to true and NULL is returned.
*/
static Numeric
! numeric_stddev_internal(ArrayType *transarray,
bool variance, bool sample,
bool *is_null)
{
! Datum *transdatums;
! int ndatums;
! Numeric N,
! sumX,
! sumX2,
! res;
NumericVar vN,
vsumX,
vsumX2,
--- 2791,2801 ----
* *is_null is set to true and NULL is returned.
*/
static Numeric
! numeric_stddev_internal(NumericAggState *state,
bool variance, bool sample,
bool *is_null)
{
! Numeric res;
NumericVar vN,
vsumX,
vsumX2,
***************
*** 2684,2705 **** numeric_stddev_internal(ArrayType *transarray,
NumericVar *comp;
int rscale;
*is_null = false;
! /* We assume the input is array of numeric */
! deconstruct_array(transarray,
! NUMERICOID, -1, false, 'i',
! &transdatums, NULL, &ndatums);
! if (ndatums != 3)
! elog(ERROR, "expected 3-element numeric array");
! N = DatumGetNumeric(transdatums[0]);
! sumX = DatumGetNumeric(transdatums[1]);
! sumX2 = DatumGetNumeric(transdatums[2]);
!
! if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))
return make_result(&const_nan);
! init_var_from_num(N, &vN);
/*
* Sample stddev and variance are undefined when N <= 1; population stddev
--- 2803,2826 ----
NumericVar *comp;
int rscale;
+ if (state == NULL)
+ {
+ *is_null = true;
+ return NULL;
+ }
+
*is_null = false;
! if (state->isNaN)
return make_result(&const_nan);
! init_var(&vN);
! init_var(&vsumX);
! init_var(&vsumX2);
!
! int8_to_numericvar(state->N, &vN);
! set_var_from_var(&(state->sumX), &vsumX);
! set_var_from_var(&(state->sumX2), &vsumX2);
/*
* Sample stddev and variance are undefined when N <= 1; population stddev
***************
*** 2719,2726 **** numeric_stddev_internal(ArrayType *transarray,
init_var(&vNminus1);
sub_var(&vN, &const_one, &vNminus1);
! init_var_from_num(sumX, &vsumX);
! init_var_from_num(sumX2, &vsumX2);
/* compute rscale for mul_var calls */
rscale = vsumX.dscale * 2;
--- 2840,2847 ----
init_var(&vNminus1);
sub_var(&vN, &const_one, &vNminus1);
! set_var_from_var(&(state->sumX), &vsumX);
! set_var_from_var(&(state->sumX2), &vsumX2);
/* compute rscale for mul_var calls */
rscale = vsumX.dscale * 2;
***************
*** 2761,2767 **** numeric_var_samp(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
true, true, &is_null);
if (is_null)
--- 2882,2888 ----
Numeric res;
bool is_null;
! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
true, true, &is_null);
if (is_null)
***************
*** 2776,2782 **** numeric_stddev_samp(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
false, true, &is_null);
if (is_null)
--- 2897,2903 ----
Numeric res;
bool is_null;
! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
false, true, &is_null);
if (is_null)
***************
*** 2791,2797 **** numeric_var_pop(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
true, false, &is_null);
if (is_null)
--- 2912,2918 ----
Numeric res;
bool is_null;
! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
true, false, &is_null);
if (is_null)
***************
*** 2806,2812 **** numeric_stddev_pop(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
false, false, &is_null);
if (is_null)
--- 2927,2933 ----
Numeric res;
bool is_null;
! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
false, false, &is_null);
if (is_null)
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 11419,11430 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11419,11432 ----
int i_aggfinalfn;
int i_aggsortop;
int i_aggtranstype;
+ int i_aggtransspace;
int i_agginitval;
int i_convertok;
const char *aggtransfn;
const char *aggfinalfn;
const char *aggsortop;
const char *aggtranstype;
+ const char *aggtransspace;
const char *agginitval;
bool convertok;
***************
*** 11442,11453 **** dumpAgg(Archive *fout, AggInfo *agginfo)
selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
/* Get aggregate-specific details */
! if (fout->remoteVersion >= 80400)
{
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
! "agginitval, "
"'t'::boolean AS convertok, "
"pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
"pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
--- 11444,11469 ----
selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
/* Get aggregate-specific details */
! if (fout->remoteVersion >= 90300)
! {
! appendPQExpBuffer(query, "SELECT aggtransfn, "
! "aggfinalfn, aggtranstype::pg_catalog.regtype, "
! "aggsortop::pg_catalog.regoperator, "
! "aggtransspace, agginitval, "
! "'t'::boolean AS convertok, "
! "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
! "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
! "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
! "WHERE a.aggfnoid = p.oid "
! "AND p.oid = '%u'::pg_catalog.oid",
! agginfo->aggfn.dobj.catId.oid);
! }
! else if (fout->remoteVersion >= 80400)
{
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
! "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok, "
"pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
"pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
***************
*** 11461,11467 **** dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
! "agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
--- 11477,11483 ----
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
! "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
***************
*** 11473,11479 **** dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"0 AS aggsortop, "
! "agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
--- 11489,11495 ----
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"0 AS aggsortop, "
! "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
***************
*** 11485,11491 **** dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
"format_type(aggtranstype, NULL) AS aggtranstype, "
"0 AS aggsortop, "
! "agginitval, "
"'t'::boolean AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
--- 11501,11507 ----
appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
"format_type(aggtranstype, NULL) AS aggtranstype, "
"0 AS aggsortop, "
! "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
***************
*** 11497,11503 **** dumpAgg(Archive *fout, AggInfo *agginfo)
"aggfinalfn, "
"(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
"0 AS aggsortop, "
! "agginitval1 AS agginitval, "
"(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
--- 11513,11519 ----
"aggfinalfn, "
"(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
"0 AS aggsortop, "
! "0 AS aggtransspace, agginitval1 AS agginitval, "
"(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
***************
*** 11510,11515 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11526,11532 ----
i_aggfinalfn = PQfnumber(res, "aggfinalfn");
i_aggsortop = PQfnumber(res, "aggsortop");
i_aggtranstype = PQfnumber(res, "aggtranstype");
+ i_aggtransspace = PQfnumber(res, "aggtransspace");
i_agginitval = PQfnumber(res, "agginitval");
i_convertok = PQfnumber(res, "convertok");
***************
*** 11517,11522 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11534,11540 ----
aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
aggsortop = PQgetvalue(res, 0, i_aggsortop);
aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
+ aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
agginitval = PQgetvalue(res, 0, i_agginitval);
convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
***************
*** 11570,11575 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11588,11599 ----
fmtId(aggtranstype));
}
+ if (strcmp(aggfinalfn, "0") != 0)
+ {
+ appendPQExpBuffer(details, ",\n SSPACE = %s",
+ aggtransspace);
+ }
+
if (!PQgetisnull(res, 0, i_agginitval))
{
appendPQExpBuffer(details, ",\n INITCOND = ");
*** a/src/include/catalog/pg_aggregate.h
--- b/src/include/catalog/pg_aggregate.h
***************
*** 44,49 **** CATALOG(pg_aggregate,2600) BKI_WITHOUT_OIDS
--- 44,50 ----
regproc aggfinalfn;
Oid aggsortop;
Oid aggtranstype;
+ int32 aggtransspace;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
text agginitval;
***************
*** 62,74 **** typedef FormData_pg_aggregate *Form_pg_aggregate;
* ----------------
*/
! #define Natts_pg_aggregate 6
#define Anum_pg_aggregate_aggfnoid 1
#define Anum_pg_aggregate_aggtransfn 2
#define Anum_pg_aggregate_aggfinalfn 3
#define Anum_pg_aggregate_aggsortop 4
#define Anum_pg_aggregate_aggtranstype 5
! #define Anum_pg_aggregate_agginitval 6
/* ----------------
--- 63,76 ----
* ----------------
*/
! #define Natts_pg_aggregate 7
#define Anum_pg_aggregate_aggfnoid 1
#define Anum_pg_aggregate_aggtransfn 2
#define Anum_pg_aggregate_aggfinalfn 3
#define Anum_pg_aggregate_aggsortop 4
#define Anum_pg_aggregate_aggtranstype 5
! #define Anum_pg_aggregate_aggtransspace 6
! #define Anum_pg_aggregate_agginitval 7
/* ----------------
***************
*** 77,239 **** typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
! DATA(insert ( 2100 int8_avg_accum numeric_avg 0 1231 "{0,0}" ));
! DATA(insert ( 2101 int4_avg_accum int8_avg 0 1016 "{0,0}" ));
! DATA(insert ( 2102 int2_avg_accum int8_avg 0 1016 "{0,0}" ));
! DATA(insert ( 2103 numeric_avg_accum numeric_avg 0 1231 "{0,0}" ));
! DATA(insert ( 2104 float4_accum float8_avg 0 1022 "{0,0,0}" ));
! DATA(insert ( 2105 float8_accum float8_avg 0 1022 "{0,0,0}" ));
! DATA(insert ( 2106 interval_accum interval_avg 0 1187 "{0 second,0 second}" ));
/* sum */
! DATA(insert ( 2107 int8_sum - 0 1700 _null_ ));
! DATA(insert ( 2108 int4_sum - 0 20 _null_ ));
! DATA(insert ( 2109 int2_sum - 0 20 _null_ ));
! DATA(insert ( 2110 float4pl - 0 700 _null_ ));
! DATA(insert ( 2111 float8pl - 0 701 _null_ ));
! DATA(insert ( 2112 cash_pl - 0 790 _null_ ));
! DATA(insert ( 2113 interval_pl - 0 1186 _null_ ));
! DATA(insert ( 2114 numeric_add - 0 1700 _null_ ));
/* max */
! DATA(insert ( 2115 int8larger - 413 20 _null_ ));
! DATA(insert ( 2116 int4larger - 521 23 _null_ ));
! DATA(insert ( 2117 int2larger - 520 21 _null_ ));
! DATA(insert ( 2118 oidlarger - 610 26 _null_ ));
! DATA(insert ( 2119 float4larger - 623 700 _null_ ));
! DATA(insert ( 2120 float8larger - 674 701 _null_ ));
! DATA(insert ( 2121 int4larger - 563 702 _null_ ));
! DATA(insert ( 2122 date_larger - 1097 1082 _null_ ));
! DATA(insert ( 2123 time_larger - 1112 1083 _null_ ));
! DATA(insert ( 2124 timetz_larger - 1554 1266 _null_ ));
! DATA(insert ( 2125 cashlarger - 903 790 _null_ ));
! DATA(insert ( 2126 timestamp_larger - 2064 1114 _null_ ));
! DATA(insert ( 2127 timestamptz_larger - 1324 1184 _null_ ));
! DATA(insert ( 2128 interval_larger - 1334 1186 _null_ ));
! DATA(insert ( 2129 text_larger - 666 25 _null_ ));
! DATA(insert ( 2130 numeric_larger - 1756 1700 _null_ ));
! DATA(insert ( 2050 array_larger - 1073 2277 _null_ ));
! DATA(insert ( 2244 bpchar_larger - 1060 1042 _null_ ));
! DATA(insert ( 2797 tidlarger - 2800 27 _null_ ));
! DATA(insert ( 3526 enum_larger - 3519 3500 _null_ ));
/* min */
! DATA(insert ( 2131 int8smaller - 412 20 _null_ ));
! DATA(insert ( 2132 int4smaller - 97 23 _null_ ));
! DATA(insert ( 2133 int2smaller - 95 21 _null_ ));
! DATA(insert ( 2134 oidsmaller - 609 26 _null_ ));
! DATA(insert ( 2135 float4smaller - 622 700 _null_ ));
! DATA(insert ( 2136 float8smaller - 672 701 _null_ ));
! DATA(insert ( 2137 int4smaller - 562 702 _null_ ));
! DATA(insert ( 2138 date_smaller - 1095 1082 _null_ ));
! DATA(insert ( 2139 time_smaller - 1110 1083 _null_ ));
! DATA(insert ( 2140 timetz_smaller - 1552 1266 _null_ ));
! DATA(insert ( 2141 cashsmaller - 902 790 _null_ ));
! DATA(insert ( 2142 timestamp_smaller - 2062 1114 _null_ ));
! DATA(insert ( 2143 timestamptz_smaller - 1322 1184 _null_ ));
! DATA(insert ( 2144 interval_smaller - 1332 1186 _null_ ));
! DATA(insert ( 2145 text_smaller - 664 25 _null_ ));
! DATA(insert ( 2146 numeric_smaller - 1754 1700 _null_ ));
! DATA(insert ( 2051 array_smaller - 1072 2277 _null_ ));
! DATA(insert ( 2245 bpchar_smaller - 1058 1042 _null_ ));
! DATA(insert ( 2798 tidsmaller - 2799 27 _null_ ));
! DATA(insert ( 3527 enum_smaller - 3518 3500 _null_ ));
/* count */
! DATA(insert ( 2147 int8inc_any - 0 20 "0" ));
! DATA(insert ( 2803 int8inc - 0 20 "0" ));
/* var_pop */
! DATA(insert ( 2718 int8_accum numeric_var_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2719 int4_accum numeric_var_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2720 int2_accum numeric_var_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2721 float4_accum float8_var_pop 0 1022 "{0,0,0}" ));
! DATA(insert ( 2722 float8_accum float8_var_pop 0 1022 "{0,0,0}" ));
! DATA(insert ( 2723 numeric_accum numeric_var_pop 0 1231 "{0,0,0}" ));
/* var_samp */
! DATA(insert ( 2641 int8_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2642 int4_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2643 int2_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2644 float4_accum float8_var_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2645 float8_accum float8_var_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2646 numeric_accum numeric_var_samp 0 1231 "{0,0,0}" ));
/* variance: historical Postgres syntax for var_samp */
! DATA(insert ( 2148 int8_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2149 int4_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2150 int2_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2151 float4_accum float8_var_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2152 float8_accum float8_var_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2153 numeric_accum numeric_var_samp 0 1231 "{0,0,0}" ));
/* stddev_pop */
! DATA(insert ( 2724 int8_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2725 int4_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2726 int2_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2727 float4_accum float8_stddev_pop 0 1022 "{0,0,0}" ));
! DATA(insert ( 2728 float8_accum float8_stddev_pop 0 1022 "{0,0,0}" ));
! DATA(insert ( 2729 numeric_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
/* stddev_samp */
! DATA(insert ( 2712 int8_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2713 int4_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2714 int2_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2715 float4_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2716 float8_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2717 numeric_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
/* stddev: historical Postgres syntax for stddev_samp */
! DATA(insert ( 2154 int8_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2155 int4_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2156 int2_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2157 float4_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2158 float8_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2159 numeric_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
/* SQL2003 binary regression aggregates */
! DATA(insert ( 2818 int8inc_float8_float8 - 0 20 "0" ));
! DATA(insert ( 2819 float8_regr_accum float8_regr_sxx 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2820 float8_regr_accum float8_regr_syy 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2821 float8_regr_accum float8_regr_sxy 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2822 float8_regr_accum float8_regr_avgx 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2823 float8_regr_accum float8_regr_avgy 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2824 float8_regr_accum float8_regr_r2 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2825 float8_regr_accum float8_regr_slope 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2826 float8_regr_accum float8_regr_intercept 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2827 float8_regr_accum float8_covar_pop 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2828 float8_regr_accum float8_covar_samp 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2829 float8_regr_accum float8_corr 0 1022 "{0,0,0,0,0,0}" ));
/* boolean-and and boolean-or */
! DATA(insert ( 2517 booland_statefunc - 58 16 _null_ ));
! DATA(insert ( 2518 boolor_statefunc - 59 16 _null_ ));
! DATA(insert ( 2519 booland_statefunc - 58 16 _null_ ));
/* bitwise integer */
! DATA(insert ( 2236 int2and - 0 21 _null_ ));
! DATA(insert ( 2237 int2or - 0 21 _null_ ));
! DATA(insert ( 2238 int4and - 0 23 _null_ ));
! DATA(insert ( 2239 int4or - 0 23 _null_ ));
! DATA(insert ( 2240 int8and - 0 20 _null_ ));
! DATA(insert ( 2241 int8or - 0 20 _null_ ));
! DATA(insert ( 2242 bitand - 0 1560 _null_ ));
! DATA(insert ( 2243 bitor - 0 1560 _null_ ));
/* xml */
! DATA(insert ( 2901 xmlconcat2 - 0 142 _null_ ));
/* array */
! DATA(insert ( 2335 array_agg_transfn array_agg_finalfn 0 2281 _null_ ));
/* text */
! DATA(insert ( 3538 string_agg_transfn string_agg_finalfn 0 2281 _null_ ));
/* bytea */
! DATA(insert ( 3545 bytea_string_agg_transfn bytea_string_agg_finalfn 0 2281 _null_ ));
/* json */
! DATA(insert ( 3175 json_agg_transfn json_agg_finalfn 0 2281 _null_ ));
/*
* prototypes for functions in pg_aggregate.c
--- 79,241 ----
*/
/* avg */
! DATA(insert ( 2100 int8_avg_accum numeric_avg 0 2281 128 _null_ ));
! DATA(insert ( 2101 int4_avg_accum int8_avg 0 1016 0 "{0,0}" ));
! DATA(insert ( 2102 int2_avg_accum int8_avg 0 1016 0 "{0,0}" ));
! DATA(insert ( 2103 numeric_avg_accum numeric_avg 0 2281 128 _null_ ));
! DATA(insert ( 2104 float4_accum float8_avg 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2105 float8_accum float8_avg 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2106 interval_accum interval_avg 0 1187 0 "{0 second,0 second}" ));
/* sum */
! DATA(insert ( 2107 int8_avg_accum numeric_sum 0 2281 128 _null_ ));
! DATA(insert ( 2108 int4_sum - 0 20 0 _null_ ));
! DATA(insert ( 2109 int2_sum - 0 20 0 _null_ ));
! DATA(insert ( 2110 float4pl - 0 700 0 _null_ ));
! DATA(insert ( 2111 float8pl - 0 701 0 _null_ ));
! DATA(insert ( 2112 cash_pl - 0 790 0 _null_ ));
! DATA(insert ( 2113 interval_pl - 0 1186 0 _null_ ));
! DATA(insert ( 2114 numeric_avg_accum numeric_sum 0 2281 128 _null_ ));
/* max */
! DATA(insert ( 2115 int8larger - 413 20 0 _null_ ));
! DATA(insert ( 2116 int4larger - 521 23 0 _null_ ));
! DATA(insert ( 2117 int2larger - 520 21 0 _null_ ));
! DATA(insert ( 2118 oidlarger - 610 26 0 _null_ ));
! DATA(insert ( 2119 float4larger - 623 700 0 _null_ ));
! DATA(insert ( 2120 float8larger - 674 701 0 _null_ ));
! DATA(insert ( 2121 int4larger - 563 702 0 _null_ ));
! DATA(insert ( 2122 date_larger - 1097 1082 0 _null_ ));
! DATA(insert ( 2123 time_larger - 1112 1083 0 _null_ ));
! DATA(insert ( 2124 timetz_larger - 1554 1266 0 _null_ ));
! DATA(insert ( 2125 cashlarger - 903 790 0 _null_ ));
! DATA(insert ( 2126 timestamp_larger - 2064 1114 0 _null_ ));
! DATA(insert ( 2127 timestamptz_larger - 1324 1184 0 _null_ ));
! DATA(insert ( 2128 interval_larger - 1334 1186 0 _null_ ));
! DATA(insert ( 2129 text_larger - 666 25 0 _null_ ));
! DATA(insert ( 2130 numeric_larger - 1756 1700 0 _null_ ));
! DATA(insert ( 2050 array_larger - 1073 2277 0 _null_ ));
! DATA(insert ( 2244 bpchar_larger - 1060 1042 0 _null_ ));
! DATA(insert ( 2797 tidlarger - 2800 27 0 _null_ ));
! DATA(insert ( 3526 enum_larger - 3519 3500 0 _null_ ));
/* min */
! DATA(insert ( 2131 int8smaller - 412 20 0 _null_ ));
! DATA(insert ( 2132 int4smaller - 97 23 0 _null_ ));
! DATA(insert ( 2133 int2smaller - 95 21 0 _null_ ));
! DATA(insert ( 2134 oidsmaller - 609 26 0 _null_ ));
! DATA(insert ( 2135 float4smaller - 622 700 0 _null_ ));
! DATA(insert ( 2136 float8smaller - 672 701 0 _null_ ));
! DATA(insert ( 2137 int4smaller - 562 702 0 _null_ ));
! DATA(insert ( 2138 date_smaller - 1095 1082 0 _null_ ));
! DATA(insert ( 2139 time_smaller - 1110 1083 0 _null_ ));
! DATA(insert ( 2140 timetz_smaller - 1552 1266 0 _null_ ));
! DATA(insert ( 2141 cashsmaller - 902 790 0 _null_ ));
! DATA(insert ( 2142 timestamp_smaller - 2062 1114 0 _null_ ));
! DATA(insert ( 2143 timestamptz_smaller - 1322 1184 0 _null_ ));
! DATA(insert ( 2144 interval_smaller - 1332 1186 0 _null_ ));
! DATA(insert ( 2145 text_smaller - 664 25 0 _null_ ));
! DATA(insert ( 2146 numeric_smaller - 1754 1700 0 _null_ ));
! DATA(insert ( 2051 array_smaller - 1072 2277 0 _null_ ));
! DATA(insert ( 2245 bpchar_smaller - 1058 1042 0 _null_ ));
! DATA(insert ( 2798 tidsmaller - 2799 27 0 _null_ ));
! DATA(insert ( 3527 enum_smaller - 3518 3500 0 _null_ ));
/* count */
! DATA(insert ( 2147 int8inc_any - 0 20 0 "0" ));
! DATA(insert ( 2803 int8inc - 0 20 0 "0" ));
/* var_pop */
! DATA(insert ( 2718 int8_accum numeric_var_pop 0 2281 128 _null_ ));
! DATA(insert ( 2719 int4_accum numeric_var_pop 0 2281 128 _null_ ));
! DATA(insert ( 2720 int2_accum numeric_var_pop 0 2281 128 _null_ ));
! DATA(insert ( 2721 float4_accum float8_var_pop 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2722 float8_accum float8_var_pop 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2723 numeric_accum numeric_var_pop 0 2281 128 _null_ ));
/* var_samp */
! DATA(insert ( 2641 int8_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2642 int4_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2643 int2_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2644 float4_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2645 float8_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2646 numeric_accum numeric_var_samp 0 2281 128 _null_ ));
/* variance: historical Postgres syntax for var_samp */
! DATA(insert ( 2148 int8_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2149 int4_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2150 int2_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2151 float4_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2152 float8_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2153 numeric_accum numeric_var_samp 0 2281 128 _null_ ));
/* stddev_pop */
! DATA(insert ( 2724 int8_accum numeric_stddev_pop 0 2281 128 _null_ ));
! DATA(insert ( 2725 int4_accum numeric_stddev_pop 0 2281 128 _null_ ));
! DATA(insert ( 2726 int2_accum numeric_stddev_pop 0 2281 128 _null_ ));
! DATA(insert ( 2727 float4_accum float8_stddev_pop 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2728 float8_accum float8_stddev_pop 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2729 numeric_accum numeric_stddev_pop 0 2281 128 _null_ ));
/* stddev_samp */
! DATA(insert ( 2712 int8_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2713 int4_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2714 int2_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2715 float4_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2716 float8_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2717 numeric_accum numeric_stddev_samp 0 2281 128 _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
! DATA(insert ( 2154 int8_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2155 int4_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2156 int2_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2157 float4_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2158 float8_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2159 numeric_accum numeric_stddev_samp 0 2281 128 _null_ ));
/* SQL2003 binary regression aggregates */
! DATA(insert ( 2818 int8inc_float8_float8 - 0 20 0 "0" ));
! DATA(insert ( 2819 float8_regr_accum float8_regr_sxx 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2820 float8_regr_accum float8_regr_syy 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2821 float8_regr_accum float8_regr_sxy 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2822 float8_regr_accum float8_regr_avgx 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2823 float8_regr_accum float8_regr_avgy 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2824 float8_regr_accum float8_regr_r2 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2825 float8_regr_accum float8_regr_slope 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2826 float8_regr_accum float8_regr_intercept 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2827 float8_regr_accum float8_covar_pop 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2828 float8_regr_accum float8_covar_samp 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2829 float8_regr_accum float8_corr 0 1022 0 "{0,0,0,0,0,0}" ));
/* boolean-and and boolean-or */
! DATA(insert ( 2517 booland_statefunc - 58 16 0 _null_ ));
! DATA(insert ( 2518 boolor_statefunc - 59 16 0 _null_ ));
! DATA(insert ( 2519 booland_statefunc - 58 16 0 _null_ ));
/* bitwise integer */
! DATA(insert ( 2236 int2and - 0 21 0 _null_ ));
! DATA(insert ( 2237 int2or - 0 21 0 _null_ ));
! DATA(insert ( 2238 int4and - 0 23 0 _null_ ));
! DATA(insert ( 2239 int4or - 0 23 0 _null_ ));
! DATA(insert ( 2240 int8and - 0 20 0 _null_ ));
! DATA(insert ( 2241 int8or - 0 20 0 _null_ ));
! DATA(insert ( 2242 bitand - 0 1560 0 _null_ ));
! DATA(insert ( 2243 bitor - 0 1560 0 _null_ ));
/* xml */
! DATA(insert ( 2901 xmlconcat2 - 0 142 0 _null_ ));
/* array */
! DATA(insert ( 2335 array_agg_transfn array_agg_finalfn 0 2281 0 _null_ ));
/* text */
! DATA(insert ( 3538 string_agg_transfn string_agg_finalfn 0 2281 0 _null_ ));
/* bytea */
! DATA(insert ( 3545 bytea_string_agg_transfn bytea_string_agg_finalfn 0 2281 0 _null_ ));
/* json */
! DATA(insert ( 3175 json_agg_transfn json_agg_finalfn 0 2281 0 _null_ ));
/*
* prototypes for functions in pg_aggregate.c
***************
*** 250,255 **** extern Oid AggregateCreate(const char *aggName,
--- 252,258 ----
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
+ int32 aggTransSpace,
const char *agginitval);
#endif /* PG_AGGREGATE_H */
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 2381,2407 **** DATA(insert OID = 2513 ( float8_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f t f i
DESCR("aggregate final function");
DATA(insert OID = 1832 ( float8_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "1022" _null_ _null_ _null_ _null_ float8_stddev_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 1833 ( numeric_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 1700" _null_ _null_ _null_ _null_ numeric_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 2858 ( numeric_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 1700" _null_ _null_ _null_ _null_ numeric_avg_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1834 ( int2_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 21" _null_ _null_ _null_ _null_ int2_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1835 ( int4_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 23" _null_ _null_ _null_ _null_ int4_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1836 ( int8_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 20" _null_ _null_ _null_ _null_ int8_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 2746 ( int8_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 20" _null_ _null_ _null_ _null_ int8_avg_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1837 ( numeric_avg PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 2514 ( numeric_var_pop PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_var_pop _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 1838 ( numeric_var_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_var_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 2596 ( numeric_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_stddev_pop _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 1839 ( numeric_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_stddev_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 1840 ( int2_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 20 "20 21" _null_ _null_ _null_ _null_ int2_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
--- 2381,2409 ----
DESCR("aggregate final function");
DATA(insert OID = 1832 ( float8_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "1022" _null_ _null_ _null_ _null_ float8_stddev_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 1833 ( numeric_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 1700" _null_ _null_ _null_ _null_ numeric_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 2858 ( numeric_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 1700" _null_ _null_ _null_ _null_ numeric_avg_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1834 ( int2_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 21" _null_ _null_ _null_ _null_ int2_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1835 ( int4_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 23" _null_ _null_ _null_ _null_ int4_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1836 ( int8_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ int8_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 2746 ( int8_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ int8_avg_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1837 ( numeric_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 3179 ( numeric_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_sum _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 2514 ( numeric_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_var_pop _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 1838 ( numeric_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_var_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 2596 ( numeric_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_stddev_pop _null_ _null_ _null_ ));
! DESCR("aggregate final function");
! DATA(insert OID = 1839 ( numeric_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_stddev_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 1840 ( int2_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 20 "20 21" _null_ _null_ _null_ _null_ int2_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 133,138 **** extern Datum transformGenericOptions(Oid catalogId,
--- 133,139 ----
extern char *defGetString(DefElem *def);
extern double defGetNumeric(DefElem *def);
extern bool defGetBoolean(DefElem *def);
+ extern int32 defGetInt32(DefElem *def);
extern int64 defGetInt64(DefElem *def);
extern List *defGetQualifiedName(DefElem *def);
extern TypeName *defGetTypeName(DefElem *def);
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
***************
*** 982,987 **** extern Datum int4_accum(PG_FUNCTION_ARGS);
--- 982,988 ----
extern Datum int8_accum(PG_FUNCTION_ARGS);
extern Datum int8_avg_accum(PG_FUNCTION_ARGS);
extern Datum numeric_avg(PG_FUNCTION_ARGS);
+ extern Datum numeric_sum(PG_FUNCTION_ARGS);
extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
*** a/src/test/regress/expected/aggregates.out
--- b/src/test/regress/expected/aggregates.out
***************
*** 1262,1264 **** select least_agg(variadic array[q1,q2]) from int8_tbl;
--- 1262,1313 ----
-4567890123456789
(1 row)
+ -- verify correct calculations for null set
+ select sum(null::int4) from generate_series(1,1);
+ sum
+ -----
+
+ (1 row)
+
+ select sum(null::int8) from generate_series(1,1);
+ sum
+ -----
+
+ (1 row)
+
+ select sum(null::numeric) from generate_series(1,1);
+ sum
+ -----
+
+ (1 row)
+
+ select sum(null::float8) from generate_series(1,1);
+ sum
+ -----
+
+ (1 row)
+
+ select avg(null::int4) from generate_series(1,1);
+ avg
+ -----
+
+ (1 row)
+
+ select avg(null::int8) from generate_series(1,1);
+ avg
+ -----
+
+ (1 row)
+
+ select avg(null::numeric) from generate_series(1,1);
+ avg
+ -----
+
+ (1 row)
+
+ select avg(null::float8) from generate_series(1,1);
+ avg
+ -----
+
+ (1 row)
+
*** a/src/test/regress/expected/create_aggregate.out
--- b/src/test/regress/expected/create_aggregate.out
***************
*** 66,68 **** returns anyelement language sql as
--- 66,75 ----
create aggregate least_agg(variadic items anyarray) (
stype = anyelement, sfunc = least_accum
);
+ -- should not work, sspace is allowed only for stype internal
+ create aggregate aggfns(integer,integer,text) (
+ sfunc = aggfns_trans, stype = aggtype[], sspace = 200,
+ initcond = '{}'
+ );
+ ERROR: SSPACE can be used only for "internal" transition type
+ DETAIL: SSPACE can be defined only together with a "internal" transition type.
*** a/src/test/regress/sql/aggregates.sql
--- b/src/test/regress/sql/aggregates.sql
***************
*** 484,486 **** select aggfns(distinct a,b,c order by a,c using ~<~,b) filter (where a > 1)
--- 484,497 ----
-- variadic aggregates
select least_agg(q1,q2) from int8_tbl;
select least_agg(variadic array[q1,q2]) from int8_tbl;
+
+ -- verify correct calculations for null set
+ select sum(null::int4) from generate_series(1,1);
+ select sum(null::int8) from generate_series(1,1);
+ select sum(null::numeric) from generate_series(1,1);
+ select sum(null::float8) from generate_series(1,1);
+
+ select avg(null::int4) from generate_series(1,1);
+ select avg(null::int8) from generate_series(1,1);
+ select avg(null::numeric) from generate_series(1,1);
+ select avg(null::float8) from generate_series(1,1);
*** a/src/test/regress/sql/create_aggregate.sql
--- b/src/test/regress/sql/create_aggregate.sql
***************
*** 80,82 **** returns anyelement language sql as
--- 80,88 ----
create aggregate least_agg(variadic items anyarray) (
stype = anyelement, sfunc = least_accum
);
+
+ -- should not work, sspace is allowed only for stype internal
+ create aggregate aggfns(integer,integer,text) (
+ sfunc = aggfns_trans, stype = aggtype[], sspace = 200,
+ initcond = '{}'
+ );
On 23 Září 2013, 18:18, Pavel Stehule wrote:
Hello
2013/9/22 Tomas Vondra <tv@fuzzy.cz>
Hi,
I've reviewed the v6 of the "numeric optimize" patch
(http://www.postgresql.org/**message-id/**CAFj8pRDQhG7Pqmf8XqXY0PnHfakkP**
QLPHnoRLJ_=EKFSbOAWeA@mail.**gmail.com</messages/by-id/CAFj8pRDQhG7Pqmf8XqXY0PnHfakkPQLPHnoRLJ_=EKFSbOAWeA@mail.gmail.com>
),
as Pavel did some hacking on the patch and asked me to do the review.The patch seems fine to me, the following comments are mostly
nitpicking:1) Applies cleanly to the HEAD (although only by "patch" and not "git
apply").2) I think we should use "estimate" instead of "approximation" in the
docs, it seems more correct / natural to me (but maybe I'm wrong on this
one).3) state_data_size does not make much sense to me - it should be
state_size. This probably comes from the state_data_type, but that's
('state' + 'data type') and by replacing the second part with 'size'
you'll get state_size.This name is consistent with previous field state_data_type - I expected
so
this mean 'state data' + 'type'. I am not native speaker, so my position
is
not strong, but in this moment I am thinking so state_data_size has a
sense. In this case both variant has sense - 'state data' + type or
'state' + 'data type'.
OK, let's leave this up to a native speaker.
8) The records in pg_aggregate.c are using either 0 (for fixed-length)
or
128. This seems slightly excessive to me. What is the reasoning behind
this? Is that because of the two NumericVar fields?NumericAggState has 96 bytes - but you have to add a space for digits of
included numeric values (inclued in NumericVar) -- so it is others 16 + 16
= 128. I am not able to specify how much digits will be used exactly - 16
bytes is just good enough estimation - it is not used for memory
allocation, it is used for some planner magic.
OK, makes sense.
I've made some basic tests on a 40M table with random numerics, for
example this query:
select avg(val), sum(val), var_pop(val) from numeric_test ;
takes ~57 seconds on current master, but only ~26 seconds with the v7
patch. Granted, in practice the improvements won't be as good because of
I/O costs etc., but it's a nice gain.
Seems "ready for commiter" to me. I'll wait a few days for others to
comment, and then I'll update the commitfest page.
regards
Tomas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Sep 23, 2013 at 4:15 PM, Tomas Vondra <tv@fuzzy.cz> wrote:
Seems "ready for commiter" to me. I'll wait a few days for others to
comment, and then I'll update the commitfest page.
Some thoughts:
The documentation doesn't reflect the restriction to type internal.
On a related note, why restrict this to type internal?
Formatting fixes are needed:
+ if (aggtransspace > 0)
+ {
+ costs->transitionSpace += aggtransspace;
+ }
Project style is not to use curly-braces for single statements. Also,
the changes to numeric.c add blank lines before and after function
header comments, which is not the usual style.
! if (state == NULL)
! PG_RETURN_NULL();
! else
! PG_RETURN_POINTER(state);
I think this should just say PG_RETURN_POINTER(state). PG_RETURN_NULL
is for returning an SQL NULL, not (void *) 0. Is there some reason
why we need an SQL NULL here, rather than a NULL pointer?
On the whole this looks fairly solid on a first read-through.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2013/9/24 Robert Haas <robertmhaas@gmail.com>
On Mon, Sep 23, 2013 at 4:15 PM, Tomas Vondra <tv@fuzzy.cz> wrote:
Seems "ready for commiter" to me. I'll wait a few days for others to
comment, and then I'll update the commitfest page.Some thoughts:
The documentation doesn't reflect the restriction to type internal.
On a related note, why restrict this to type internal?
Now, for almost all types Postgres well estimate size of state value. Only
arrays with unknown size can be a different. When we enable this value for
all types, then users can specify some bad values for scalar buildin types.
Next argument is simply and bad - I don't see a good use case for
customization this value for other than types than internal type.
I have no strong position here - prefer joining with internal type due
little bit higher robustness.
Formatting fixes are needed:
+ if (aggtransspace > 0) + { + costs->transitionSpace += aggtransspace; + }
Project style is not to use curly-braces for single statements. Also,
the changes to numeric.c add blank lines before and after function
header comments, which is not the usual style.! if (state == NULL)
! PG_RETURN_NULL();
! else
! PG_RETURN_POINTER(state);I think this should just say PG_RETURN_POINTER(state). PG_RETURN_NULL
is for returning an SQL NULL, not (void *) 0. Is there some reason
why we need an SQL NULL here, rather than a NULL pointer?
fixed
On the whole this looks fairly solid on a first read-through.
Thank you
Pavel
Show quoted text
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Attachments:
numeric-optimize-v8.patchapplication/octet-stream; name=numeric-optimize-v8.patchDownload
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 373,378 ****
--- 373,384 ----
<entry>Data type of the aggregate function's internal transition (state) data</entry>
</row>
<row>
+ <entry><structfield>aggtransspace</structfield></entry>
+ <entry><type>int4</type></entry>
+ <entry></entry>
+ <entry>Approximation for the average size of the aggregate function's internal transition (state) data</entry>
+ </row>
+ <row>
<entry><structfield>agginitval</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
*** a/doc/src/sgml/ref/create_aggregate.sgml
--- b/doc/src/sgml/ref/create_aggregate.sgml
***************
*** 24,29 **** PostgreSQL documentation
--- 24,30 ----
CREATE AGGREGATE <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">arg_name</replaceable> ] <replaceable class="parameter">arg_data_type</replaceable> [ , ... ] ) (
SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
+ [ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
[ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
***************
*** 35,40 **** CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
--- 36,42 ----
BASETYPE = <replaceable class="PARAMETER">base_type</replaceable>,
SFUNC = <replaceable class="PARAMETER">sfunc</replaceable>,
STYPE = <replaceable class="PARAMETER">state_data_type</replaceable>
+ [ , SSPACE = <replaceable class="PARAMETER">state_data_size</replaceable> ]
[ , FINALFUNC = <replaceable class="PARAMETER">ffunc</replaceable> ]
[ , INITCOND = <replaceable class="PARAMETER">initial_condition</replaceable> ]
[ , SORTOP = <replaceable class="PARAMETER">sort_operator</replaceable> ]
***************
*** 265,270 **** SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
--- 267,288 ----
</varlistentry>
<varlistentry>
+ <term><replaceable class="PARAMETER">state_data_size</replaceable></term>
+ <listitem>
+ <para>
+ Approximate average size (in bytes) of aggregate's state value.
+ Planner uses this value to approximate the memory required for
+ the aggregation. If this value is not provided, a default value is
+ used based on state_data_type. This parameter is enabled only only for
+ aggregate function where <replaceable
+ class="PARAMETER">state_data_type</replaceable> is internal, where size
+ is unknown and planner uses a 8KB as default. Default value is usually
+ too high (that effective disable HashAgg) and should be specified better.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><replaceable class="PARAMETER">ffunc</replaceable></term>
<listitem>
<para>
*** a/src/backend/catalog/pg_aggregate.c
--- b/src/backend/catalog/pg_aggregate.c
***************
*** 55,60 **** AggregateCreate(const char *aggName,
--- 55,61 ----
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
+ int32 aggTransSpace,
const char *agginitval)
{
Relation aggdesc;
***************
*** 195,200 **** AggregateCreate(const char *aggName,
--- 196,211 ----
errmsg("unsafe use of pseudo-type \"internal\""),
errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));
+ /*
+ * Allow non zerro aggTransSpace only for INTERNALOID aggTransType
+ * Other types has known size.
+ */
+ if (aggTransType != INTERNALOID && aggTransSpace > 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("SSPACE can be used only for \"internal\" transition type"),
+ errdetail("SSPACE can be defined only together with a \"internal\" transition type.")));
+
/* handle sortop, if supplied */
if (aggsortopName)
{
***************
*** 273,278 **** AggregateCreate(const char *aggName,
--- 284,290 ----
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop);
values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
+ values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace);
if (agginitval)
values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval);
else
*** a/src/backend/commands/aggregatecmds.c
--- b/src/backend/commands/aggregatecmds.c
***************
*** 68,73 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
--- 68,74 ----
ArrayType *parameterNames;
List *parameterDefaults;
Oid transTypeId;
+ int32 transSpace = 0;
char transTypeType;
ListCell *pl;
***************
*** 102,107 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
--- 103,110 ----
transType = defGetTypeName(defel);
else if (pg_strcasecmp(defel->defname, "stype1") == 0)
transType = defGetTypeName(defel);
+ else if (pg_strcasecmp(defel->defname, "sspace") == 0)
+ transSpace = defGetInt32(defel);
else if (pg_strcasecmp(defel->defname, "initcond") == 0)
initval = defGetString(defel);
else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
***************
*** 248,252 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters,
--- 251,256 ----
finalfuncName, /* final function name */
sortoperatorName, /* sort operator name */
transTypeId, /* transition data type */
+ transSpace, /* transition space */
initval); /* initial condition */
}
*** a/src/backend/commands/define.c
--- b/src/backend/commands/define.c
***************
*** 165,170 **** defGetBoolean(DefElem *def)
--- 165,194 ----
}
/*
+ * Extract an int32 value from a DefElem.
+ */
+ int32
+ defGetInt32(DefElem *def)
+ {
+ if (def->arg == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires an integer value",
+ def->defname)));
+ switch (nodeTag(def->arg))
+ {
+ case T_Integer:
+ return (int32) intVal(def->arg);
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires an integer value",
+ def->defname)));
+ }
+ return 0; /* keep compiler quiet */
+ }
+
+ /*
* Extract an int64 value from a DefElem.
*/
int64
*** a/src/backend/optimizer/util/clauses.c
--- b/src/backend/optimizer/util/clauses.c
***************
*** 461,466 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
--- 461,467 ----
Oid aggtransfn;
Oid aggfinalfn;
Oid aggtranstype;
+ int32 aggtransspace;
QualCost argcosts;
Oid *inputTypes;
int numArguments;
***************
*** 478,483 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
--- 479,485 ----
aggtransfn = aggform->aggtransfn;
aggfinalfn = aggform->aggfinalfn;
aggtranstype = aggform->aggtranstype;
+ aggtransspace = aggform->aggtransspace;
ReleaseSysCache(aggTuple);
/* count it */
***************
*** 539,545 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
* pass-by-reference then we have to add the estimated size of the
* value itself, plus palloc overhead.
*/
! if (!get_typbyval(aggtranstype))
{
int32 aggtranstypmod;
int32 avgwidth;
--- 541,547 ----
* pass-by-reference then we have to add the estimated size of the
* value itself, plus palloc overhead.
*/
! else if (!get_typbyval(aggtranstype))
{
int32 aggtranstypmod;
int32 avgwidth;
***************
*** 564,575 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
/*
* INTERNAL transition type is a special case: although INTERNAL
* is pass-by-value, it's almost certainly being used as a pointer
! * to some large data structure. We assume usage of
! * ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
! * being kept in a private memory context, as is done by
! * array_agg() for instance.
*/
! costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE;
}
/*
--- 566,581 ----
/*
* INTERNAL transition type is a special case: although INTERNAL
* is pass-by-value, it's almost certainly being used as a pointer
! * to some large data structure. A size of this structure can be
! * specified by aggtransspace value. When it is unspecified, then
! * We assume usage of ALLOCSET_DEFAULT_INITSIZE, which is a good
! * guess if the data is being kept in a private memory context,
! * as is done by array_agg() for instance.
*/
! if (aggtransspace > 0)
! costs->transitionSpace += aggtransspace;
! else
! costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE;
}
/*
*** a/src/backend/utils/adt/numeric.c
--- b/src/backend/utils/adt/numeric.c
***************
*** 2464,2571 **** numeric_float4(PG_FUNCTION_ARGS)
*
* Aggregate functions
*
! * The transition datatype for all these aggregates is a 3-element array
! * of Numeric, holding the values N, sum(X), sum(X*X) in that order.
! *
! * We represent N as a numeric mainly to avoid having to build a special
! * datatype; it's unlikely it'd overflow an int4, but ...
*
* ----------------------------------------------------------------------
*/
! static ArrayType *
! do_numeric_accum(ArrayType *transarray, Numeric newval)
{
! Datum *transdatums;
! int ndatums;
! Datum N,
! sumX,
! sumX2;
! ArrayType *result;
!
! /* We assume the input is array of numeric */
! deconstruct_array(transarray,
! NUMERICOID, -1, false, 'i',
! &transdatums, NULL, &ndatums);
! if (ndatums != 3)
! elog(ERROR, "expected 3-element numeric array");
! N = transdatums[0];
! sumX = transdatums[1];
! sumX2 = transdatums[2];
!
! N = DirectFunctionCall1(numeric_inc, N);
! sumX = DirectFunctionCall2(numeric_add, sumX,
! NumericGetDatum(newval));
! sumX2 = DirectFunctionCall2(numeric_add, sumX2,
! DirectFunctionCall2(numeric_mul,
! NumericGetDatum(newval),
! NumericGetDatum(newval)));
!
! transdatums[0] = N;
! transdatums[1] = sumX;
! transdatums[2] = sumX2;
!
! result = construct_array(transdatums, 3,
! NUMERICOID, -1, false, 'i');
! return result;
}
/*
! * Improve avg performance by not caclulating sum(X*X).
*/
! static ArrayType *
! do_numeric_avg_accum(ArrayType *transarray, Numeric newval)
{
! Datum *transdatums;
! int ndatums;
! Datum N,
! sumX;
! ArrayType *result;
!
! /* We assume the input is array of numeric */
! deconstruct_array(transarray,
! NUMERICOID, -1, false, 'i',
! &transdatums, NULL, &ndatums);
! if (ndatums != 2)
! elog(ERROR, "expected 2-element numeric array");
! N = transdatums[0];
! sumX = transdatums[1];
!
! N = DirectFunctionCall1(numeric_inc, N);
! sumX = DirectFunctionCall2(numeric_add, sumX,
! NumericGetDatum(newval));
!
! transdatums[0] = N;
! transdatums[1] = sumX;
!
! result = construct_array(transdatums, 2,
! NUMERICOID, -1, false, 'i');
! return result;
}
Datum
numeric_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Numeric newval = PG_GETARG_NUMERIC(1);
! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
/*
! * Optimized case for average of numeric.
*/
Datum
numeric_avg_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Numeric newval = PG_GETARG_NUMERIC(1);
! PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
}
/*
* Integer data types all use Numeric accumulators to share code and
* avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
--- 2464,2623 ----
*
* Aggregate functions
*
! * The transition datatype for all these aggregates is a pointer to
! * a struct NumericAggState allocated in the aggregate context.
*
* ----------------------------------------------------------------------
*/
! typedef struct NumericAggState
{
! bool isNaN; /* true, when some processed number is NaN */
! uint64 N; /* count of processed numbers */
! NumericVar sumX; /* sum of processed numbers */
! NumericVar sumX2; /* sum of square of processed numbers */
! bool calcSumX2; /* when is true, then sumX2 is calculated */
! MemoryContext agg_context;
! } NumericAggState;
!
! /*
! * Prepare state data for Numeric aggregate function that needs to know a sum, count
! * and sometimes sum of square (when calcSumX2 is true).
! */
! static NumericAggState *
! makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
! {
! NumericAggState *state;
! MemoryContext agg_context;
! MemoryContext old_context;
!
! if (!AggCheckCallContext(fcinfo, &agg_context))
! elog(ERROR, "a numeric aggregate function called in non-aggregate context");
!
! old_context = MemoryContextSwitchTo(agg_context);
!
! state = palloc0(sizeof(NumericAggState));
! state->calcSumX2 = calcSumX2;
! state->agg_context = agg_context;
!
! MemoryContextSwitchTo(old_context);
!
! return state;
}
+
/*
! * a workhorse for numeric accum functions. A different behave (controlled by calcSumX2)
! * is specified when NumericAggState is initiated. This accum function is used for numeric
! * sum too due minimize overhead related to packing and unpacking Numeric value.
! *
*/
! static void
! do_numeric_accum(NumericAggState *state, Numeric newval)
{
! NumericVar X;
! NumericVar X2;
! MemoryContext old_context;
! /* result is NaN, when some processed number is NaN */
! if (state->isNaN || NUMERIC_IS_NAN(newval))
! {
! state->isNaN = true;
! return;
! }
!
! /* load processed number */
! init_var_from_num(newval, &X);
!
! if (state->calcSumX2)
! {
! init_var(&X2);
! mul_var(&X, &X, &X2, X.dscale * 2);
! }
!
! old_context = MemoryContextSwitchTo(state->agg_context);
!
! if (state->N++ > 0)
! {
! NumericVar preSumX;
!
! /* increase counters */
! memcpy(&preSumX, &(state->sumX), sizeof(NumericVar));
! init_var(&(state->sumX));
! add_var(&X, &preSumX, &(state->sumX));
! free_var(&preSumX);
!
! if (state->calcSumX2)
! {
! NumericVar preSumX2;
!
! memcpy(&preSumX2, &(state->sumX2), sizeof(NumericVar));
! init_var(&(state->sumX2));
! add_var(&X2, &preSumX2, &(state->sumX2));
! free_var(&preSumX2);
! }
! }
! else
! {
! /* initialize counters */
! set_var_from_var(&X, &(state->sumX));
!
! if (state->calcSumX2)
! set_var_from_var(&X2, &(state->sumX2));
! }
!
! MemoryContextSwitchTo(old_context);
}
+ /*
+ * Generic accum function for Numeric aggregates. It initialize NumericAggState
+ * with calcSumX2 is true - it ensure a sumX2 calcualtion.
+ */
Datum
numeric_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
!
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
! if (!PG_ARGISNULL(1))
! {
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, true);
!
! do_numeric_accum(state, PG_GETARG_NUMERIC(1));
! }
!
! PG_RETURN_POINTER(state);
}
+
/*
! * Optimized accum function for average and sum aggregate function.
! * Doesn't calculate sumX2.
*/
Datum
numeric_avg_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
!
! if (!PG_ARGISNULL(1))
! {
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, false);
!
! do_numeric_accum(state, PG_GETARG_NUMERIC(1));
! }
!
! PG_RETURN_POINTER(state);
}
+
/*
* Integer data types all use Numeric accumulators to share code and
* avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
***************
*** 2574,2664 **** numeric_avg_accum(PG_FUNCTION_ARGS)
* for stddev/variance --- there are faster special-purpose accumulator
* routines for SUM and AVG of these datatypes.
*/
-
Datum
int2_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Datum newval2 = PG_GETARG_DATUM(1);
! Numeric newval;
! newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
Datum
int4_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Datum newval4 = PG_GETARG_DATUM(1);
! Numeric newval;
! newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
Datum
int8_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Datum newval8 = PG_GETARG_DATUM(1);
! Numeric newval;
! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
/*
* Optimized case for average of int8.
*/
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Datum newval8 = PG_GETARG_DATUM(1);
! Numeric newval;
! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
!
! PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
}
Datum
numeric_avg(PG_FUNCTION_ARGS)
{
! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! Datum *transdatums;
! int ndatums;
! Numeric N,
! sumX;
!
! /* We assume the input is array of numeric */
! deconstruct_array(transarray,
! NUMERICOID, -1, false, 'i',
! &transdatums, NULL, &ndatums);
! if (ndatums != 2)
! elog(ERROR, "expected 2-element numeric array");
! N = DatumGetNumeric(transdatums[0]);
! sumX = DatumGetNumeric(transdatums[1]);
! /* SQL defines AVG of no values to be NULL */
! /* N is zero iff no digits (cf. numeric_uminus) */
! if (NUMERIC_NDIGITS(N) == 0)
PG_RETURN_NULL();
! PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
! NumericGetDatum(sumX),
! NumericGetDatum(N)));
}
/*
* Workhorse routine for the standard deviance and variance
! * aggregates. 'transarray' is the aggregate's transition
! * array. 'variance' specifies whether we should calculate the
* variance or the standard deviation. 'sample' indicates whether the
* caller is interested in the sample or the population
* variance/stddev.
--- 2626,2764 ----
* for stddev/variance --- there are faster special-purpose accumulator
* routines for SUM and AVG of these datatypes.
*/
Datum
int2_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
! if (!PG_ARGISNULL(1))
! {
! Datum newval2 = PG_GETARG_DATUM(1);
! Numeric newval;
!
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, true);
!
! newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
! do_numeric_accum(state, newval);
! }
!
! PG_RETURN_POINTER(state);
}
+
Datum
int4_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
!
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
! if (!PG_ARGISNULL(1))
! {
! Datum newval4 = PG_GETARG_DATUM(1);
! Numeric newval;
!
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, true);
!
! newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
! do_numeric_accum(state, newval);
! }
! PG_RETURN_POINTER(state);
}
+
Datum
int8_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
! if (!PG_ARGISNULL(1))
! {
! Datum newval8 = PG_GETARG_DATUM(1);
! Numeric newval;
!
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, true);
!
! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
! do_numeric_accum(state, newval);
! }
!
! PG_RETURN_POINTER(state);
}
+
/*
* Optimized case for average of int8.
*/
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
! NumericAggState *state;
! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
! if (!PG_ARGISNULL(1))
! {
! Datum newval8 = PG_GETARG_DATUM(1);
! Numeric newval;
!
! /* On the first time through, create the state variable. */
! if (state == NULL)
! state = makeNumericAggState(fcinfo, false);
!
! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
! do_numeric_accum(state, newval);
! }
!
! PG_RETURN_POINTER(state);
}
Datum
numeric_avg(PG_FUNCTION_ARGS)
{
! Datum N_datum;
! Datum sumX_datum;
! NumericAggState *state;
! state = (NumericAggState *) PG_GETARG_POINTER(0);
! if (state == NULL)
! PG_RETURN_NULL();
!
! N_datum = DirectFunctionCall1(int8_numeric, Int64GetDatum(state->N));
! sumX_datum = NumericGetDatum(make_result(&state->sumX));
!
! PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumX_datum, N_datum));
! }
!
!
! Datum
! numeric_sum(PG_FUNCTION_ARGS)
! {
! NumericAggState *state;
!
! state = (NumericAggState *) PG_GETARG_POINTER(0);
! if (state == NULL)
PG_RETURN_NULL();
! PG_RETURN_NUMERIC(make_result(&(state->sumX)));
}
+
/*
* Workhorse routine for the standard deviance and variance
! * aggregates. 'state' is aggregate's transition state.
! * 'variance' specifies whether we should calculate the
* variance or the standard deviation. 'sample' indicates whether the
* caller is interested in the sample or the population
* variance/stddev.
***************
*** 2667,2682 **** numeric_avg(PG_FUNCTION_ARGS)
* *is_null is set to true and NULL is returned.
*/
static Numeric
! numeric_stddev_internal(ArrayType *transarray,
bool variance, bool sample,
bool *is_null)
{
! Datum *transdatums;
! int ndatums;
! Numeric N,
! sumX,
! sumX2,
! res;
NumericVar vN,
vsumX,
vsumX2,
--- 2767,2777 ----
* *is_null is set to true and NULL is returned.
*/
static Numeric
! numeric_stddev_internal(NumericAggState *state,
bool variance, bool sample,
bool *is_null)
{
! Numeric res;
NumericVar vN,
vsumX,
vsumX2,
***************
*** 2684,2705 **** numeric_stddev_internal(ArrayType *transarray,
NumericVar *comp;
int rscale;
*is_null = false;
! /* We assume the input is array of numeric */
! deconstruct_array(transarray,
! NUMERICOID, -1, false, 'i',
! &transdatums, NULL, &ndatums);
! if (ndatums != 3)
! elog(ERROR, "expected 3-element numeric array");
! N = DatumGetNumeric(transdatums[0]);
! sumX = DatumGetNumeric(transdatums[1]);
! sumX2 = DatumGetNumeric(transdatums[2]);
!
! if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))
return make_result(&const_nan);
! init_var_from_num(N, &vN);
/*
* Sample stddev and variance are undefined when N <= 1; population stddev
--- 2779,2802 ----
NumericVar *comp;
int rscale;
+ if (state == NULL)
+ {
+ *is_null = true;
+ return NULL;
+ }
+
*is_null = false;
! if (state->isNaN)
return make_result(&const_nan);
! init_var(&vN);
! init_var(&vsumX);
! init_var(&vsumX2);
!
! int8_to_numericvar(state->N, &vN);
! set_var_from_var(&(state->sumX), &vsumX);
! set_var_from_var(&(state->sumX2), &vsumX2);
/*
* Sample stddev and variance are undefined when N <= 1; population stddev
***************
*** 2719,2726 **** numeric_stddev_internal(ArrayType *transarray,
init_var(&vNminus1);
sub_var(&vN, &const_one, &vNminus1);
! init_var_from_num(sumX, &vsumX);
! init_var_from_num(sumX2, &vsumX2);
/* compute rscale for mul_var calls */
rscale = vsumX.dscale * 2;
--- 2816,2823 ----
init_var(&vNminus1);
sub_var(&vN, &const_one, &vNminus1);
! set_var_from_var(&(state->sumX), &vsumX);
! set_var_from_var(&(state->sumX2), &vsumX2);
/* compute rscale for mul_var calls */
rscale = vsumX.dscale * 2;
***************
*** 2761,2767 **** numeric_var_samp(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
true, true, &is_null);
if (is_null)
--- 2858,2864 ----
Numeric res;
bool is_null;
! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
true, true, &is_null);
if (is_null)
***************
*** 2776,2782 **** numeric_stddev_samp(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
false, true, &is_null);
if (is_null)
--- 2873,2879 ----
Numeric res;
bool is_null;
! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
false, true, &is_null);
if (is_null)
***************
*** 2791,2797 **** numeric_var_pop(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
true, false, &is_null);
if (is_null)
--- 2888,2894 ----
Numeric res;
bool is_null;
! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
true, false, &is_null);
if (is_null)
***************
*** 2806,2812 **** numeric_stddev_pop(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
false, false, &is_null);
if (is_null)
--- 2903,2909 ----
Numeric res;
bool is_null;
! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
false, false, &is_null);
if (is_null)
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 11419,11430 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11419,11432 ----
int i_aggfinalfn;
int i_aggsortop;
int i_aggtranstype;
+ int i_aggtransspace;
int i_agginitval;
int i_convertok;
const char *aggtransfn;
const char *aggfinalfn;
const char *aggsortop;
const char *aggtranstype;
+ const char *aggtransspace;
const char *agginitval;
bool convertok;
***************
*** 11442,11453 **** dumpAgg(Archive *fout, AggInfo *agginfo)
selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
/* Get aggregate-specific details */
! if (fout->remoteVersion >= 80400)
{
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
! "agginitval, "
"'t'::boolean AS convertok, "
"pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
"pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
--- 11444,11469 ----
selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
/* Get aggregate-specific details */
! if (fout->remoteVersion >= 90300)
! {
! appendPQExpBuffer(query, "SELECT aggtransfn, "
! "aggfinalfn, aggtranstype::pg_catalog.regtype, "
! "aggsortop::pg_catalog.regoperator, "
! "aggtransspace, agginitval, "
! "'t'::boolean AS convertok, "
! "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
! "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
! "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
! "WHERE a.aggfnoid = p.oid "
! "AND p.oid = '%u'::pg_catalog.oid",
! agginfo->aggfn.dobj.catId.oid);
! }
! else if (fout->remoteVersion >= 80400)
{
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
! "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok, "
"pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
"pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
***************
*** 11461,11467 **** dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
! "agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
--- 11477,11483 ----
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
! "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
***************
*** 11473,11479 **** dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"0 AS aggsortop, "
! "agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
--- 11489,11495 ----
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"0 AS aggsortop, "
! "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
***************
*** 11485,11491 **** dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
"format_type(aggtranstype, NULL) AS aggtranstype, "
"0 AS aggsortop, "
! "agginitval, "
"'t'::boolean AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
--- 11501,11507 ----
appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
"format_type(aggtranstype, NULL) AS aggtranstype, "
"0 AS aggsortop, "
! "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
***************
*** 11497,11503 **** dumpAgg(Archive *fout, AggInfo *agginfo)
"aggfinalfn, "
"(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
"0 AS aggsortop, "
! "agginitval1 AS agginitval, "
"(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
--- 11513,11519 ----
"aggfinalfn, "
"(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
"0 AS aggsortop, "
! "0 AS aggtransspace, agginitval1 AS agginitval, "
"(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
***************
*** 11510,11515 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11526,11532 ----
i_aggfinalfn = PQfnumber(res, "aggfinalfn");
i_aggsortop = PQfnumber(res, "aggsortop");
i_aggtranstype = PQfnumber(res, "aggtranstype");
+ i_aggtransspace = PQfnumber(res, "aggtransspace");
i_agginitval = PQfnumber(res, "agginitval");
i_convertok = PQfnumber(res, "convertok");
***************
*** 11517,11522 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11534,11540 ----
aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
aggsortop = PQgetvalue(res, 0, i_aggsortop);
aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
+ aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
agginitval = PQgetvalue(res, 0, i_agginitval);
convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
***************
*** 11570,11575 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11588,11599 ----
fmtId(aggtranstype));
}
+ if (strcmp(aggfinalfn, "0") != 0)
+ {
+ appendPQExpBuffer(details, ",\n SSPACE = %s",
+ aggtransspace);
+ }
+
if (!PQgetisnull(res, 0, i_agginitval))
{
appendPQExpBuffer(details, ",\n INITCOND = ");
*** a/src/include/catalog/pg_aggregate.h
--- b/src/include/catalog/pg_aggregate.h
***************
*** 44,49 **** CATALOG(pg_aggregate,2600) BKI_WITHOUT_OIDS
--- 44,50 ----
regproc aggfinalfn;
Oid aggsortop;
Oid aggtranstype;
+ int32 aggtransspace;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
text agginitval;
***************
*** 62,74 **** typedef FormData_pg_aggregate *Form_pg_aggregate;
* ----------------
*/
! #define Natts_pg_aggregate 6
#define Anum_pg_aggregate_aggfnoid 1
#define Anum_pg_aggregate_aggtransfn 2
#define Anum_pg_aggregate_aggfinalfn 3
#define Anum_pg_aggregate_aggsortop 4
#define Anum_pg_aggregate_aggtranstype 5
! #define Anum_pg_aggregate_agginitval 6
/* ----------------
--- 63,76 ----
* ----------------
*/
! #define Natts_pg_aggregate 7
#define Anum_pg_aggregate_aggfnoid 1
#define Anum_pg_aggregate_aggtransfn 2
#define Anum_pg_aggregate_aggfinalfn 3
#define Anum_pg_aggregate_aggsortop 4
#define Anum_pg_aggregate_aggtranstype 5
! #define Anum_pg_aggregate_aggtransspace 6
! #define Anum_pg_aggregate_agginitval 7
/* ----------------
***************
*** 77,239 **** typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
! DATA(insert ( 2100 int8_avg_accum numeric_avg 0 1231 "{0,0}" ));
! DATA(insert ( 2101 int4_avg_accum int8_avg 0 1016 "{0,0}" ));
! DATA(insert ( 2102 int2_avg_accum int8_avg 0 1016 "{0,0}" ));
! DATA(insert ( 2103 numeric_avg_accum numeric_avg 0 1231 "{0,0}" ));
! DATA(insert ( 2104 float4_accum float8_avg 0 1022 "{0,0,0}" ));
! DATA(insert ( 2105 float8_accum float8_avg 0 1022 "{0,0,0}" ));
! DATA(insert ( 2106 interval_accum interval_avg 0 1187 "{0 second,0 second}" ));
/* sum */
! DATA(insert ( 2107 int8_sum - 0 1700 _null_ ));
! DATA(insert ( 2108 int4_sum - 0 20 _null_ ));
! DATA(insert ( 2109 int2_sum - 0 20 _null_ ));
! DATA(insert ( 2110 float4pl - 0 700 _null_ ));
! DATA(insert ( 2111 float8pl - 0 701 _null_ ));
! DATA(insert ( 2112 cash_pl - 0 790 _null_ ));
! DATA(insert ( 2113 interval_pl - 0 1186 _null_ ));
! DATA(insert ( 2114 numeric_add - 0 1700 _null_ ));
/* max */
! DATA(insert ( 2115 int8larger - 413 20 _null_ ));
! DATA(insert ( 2116 int4larger - 521 23 _null_ ));
! DATA(insert ( 2117 int2larger - 520 21 _null_ ));
! DATA(insert ( 2118 oidlarger - 610 26 _null_ ));
! DATA(insert ( 2119 float4larger - 623 700 _null_ ));
! DATA(insert ( 2120 float8larger - 674 701 _null_ ));
! DATA(insert ( 2121 int4larger - 563 702 _null_ ));
! DATA(insert ( 2122 date_larger - 1097 1082 _null_ ));
! DATA(insert ( 2123 time_larger - 1112 1083 _null_ ));
! DATA(insert ( 2124 timetz_larger - 1554 1266 _null_ ));
! DATA(insert ( 2125 cashlarger - 903 790 _null_ ));
! DATA(insert ( 2126 timestamp_larger - 2064 1114 _null_ ));
! DATA(insert ( 2127 timestamptz_larger - 1324 1184 _null_ ));
! DATA(insert ( 2128 interval_larger - 1334 1186 _null_ ));
! DATA(insert ( 2129 text_larger - 666 25 _null_ ));
! DATA(insert ( 2130 numeric_larger - 1756 1700 _null_ ));
! DATA(insert ( 2050 array_larger - 1073 2277 _null_ ));
! DATA(insert ( 2244 bpchar_larger - 1060 1042 _null_ ));
! DATA(insert ( 2797 tidlarger - 2800 27 _null_ ));
! DATA(insert ( 3526 enum_larger - 3519 3500 _null_ ));
/* min */
! DATA(insert ( 2131 int8smaller - 412 20 _null_ ));
! DATA(insert ( 2132 int4smaller - 97 23 _null_ ));
! DATA(insert ( 2133 int2smaller - 95 21 _null_ ));
! DATA(insert ( 2134 oidsmaller - 609 26 _null_ ));
! DATA(insert ( 2135 float4smaller - 622 700 _null_ ));
! DATA(insert ( 2136 float8smaller - 672 701 _null_ ));
! DATA(insert ( 2137 int4smaller - 562 702 _null_ ));
! DATA(insert ( 2138 date_smaller - 1095 1082 _null_ ));
! DATA(insert ( 2139 time_smaller - 1110 1083 _null_ ));
! DATA(insert ( 2140 timetz_smaller - 1552 1266 _null_ ));
! DATA(insert ( 2141 cashsmaller - 902 790 _null_ ));
! DATA(insert ( 2142 timestamp_smaller - 2062 1114 _null_ ));
! DATA(insert ( 2143 timestamptz_smaller - 1322 1184 _null_ ));
! DATA(insert ( 2144 interval_smaller - 1332 1186 _null_ ));
! DATA(insert ( 2145 text_smaller - 664 25 _null_ ));
! DATA(insert ( 2146 numeric_smaller - 1754 1700 _null_ ));
! DATA(insert ( 2051 array_smaller - 1072 2277 _null_ ));
! DATA(insert ( 2245 bpchar_smaller - 1058 1042 _null_ ));
! DATA(insert ( 2798 tidsmaller - 2799 27 _null_ ));
! DATA(insert ( 3527 enum_smaller - 3518 3500 _null_ ));
/* count */
! DATA(insert ( 2147 int8inc_any - 0 20 "0" ));
! DATA(insert ( 2803 int8inc - 0 20 "0" ));
/* var_pop */
! DATA(insert ( 2718 int8_accum numeric_var_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2719 int4_accum numeric_var_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2720 int2_accum numeric_var_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2721 float4_accum float8_var_pop 0 1022 "{0,0,0}" ));
! DATA(insert ( 2722 float8_accum float8_var_pop 0 1022 "{0,0,0}" ));
! DATA(insert ( 2723 numeric_accum numeric_var_pop 0 1231 "{0,0,0}" ));
/* var_samp */
! DATA(insert ( 2641 int8_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2642 int4_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2643 int2_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2644 float4_accum float8_var_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2645 float8_accum float8_var_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2646 numeric_accum numeric_var_samp 0 1231 "{0,0,0}" ));
/* variance: historical Postgres syntax for var_samp */
! DATA(insert ( 2148 int8_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2149 int4_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2150 int2_accum numeric_var_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2151 float4_accum float8_var_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2152 float8_accum float8_var_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2153 numeric_accum numeric_var_samp 0 1231 "{0,0,0}" ));
/* stddev_pop */
! DATA(insert ( 2724 int8_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2725 int4_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2726 int2_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
! DATA(insert ( 2727 float4_accum float8_stddev_pop 0 1022 "{0,0,0}" ));
! DATA(insert ( 2728 float8_accum float8_stddev_pop 0 1022 "{0,0,0}" ));
! DATA(insert ( 2729 numeric_accum numeric_stddev_pop 0 1231 "{0,0,0}" ));
/* stddev_samp */
! DATA(insert ( 2712 int8_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2713 int4_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2714 int2_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2715 float4_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2716 float8_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2717 numeric_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
/* stddev: historical Postgres syntax for stddev_samp */
! DATA(insert ( 2154 int8_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2155 int4_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2156 int2_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
! DATA(insert ( 2157 float4_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2158 float8_accum float8_stddev_samp 0 1022 "{0,0,0}" ));
! DATA(insert ( 2159 numeric_accum numeric_stddev_samp 0 1231 "{0,0,0}" ));
/* SQL2003 binary regression aggregates */
! DATA(insert ( 2818 int8inc_float8_float8 - 0 20 "0" ));
! DATA(insert ( 2819 float8_regr_accum float8_regr_sxx 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2820 float8_regr_accum float8_regr_syy 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2821 float8_regr_accum float8_regr_sxy 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2822 float8_regr_accum float8_regr_avgx 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2823 float8_regr_accum float8_regr_avgy 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2824 float8_regr_accum float8_regr_r2 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2825 float8_regr_accum float8_regr_slope 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2826 float8_regr_accum float8_regr_intercept 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2827 float8_regr_accum float8_covar_pop 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2828 float8_regr_accum float8_covar_samp 0 1022 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2829 float8_regr_accum float8_corr 0 1022 "{0,0,0,0,0,0}" ));
/* boolean-and and boolean-or */
! DATA(insert ( 2517 booland_statefunc - 58 16 _null_ ));
! DATA(insert ( 2518 boolor_statefunc - 59 16 _null_ ));
! DATA(insert ( 2519 booland_statefunc - 58 16 _null_ ));
/* bitwise integer */
! DATA(insert ( 2236 int2and - 0 21 _null_ ));
! DATA(insert ( 2237 int2or - 0 21 _null_ ));
! DATA(insert ( 2238 int4and - 0 23 _null_ ));
! DATA(insert ( 2239 int4or - 0 23 _null_ ));
! DATA(insert ( 2240 int8and - 0 20 _null_ ));
! DATA(insert ( 2241 int8or - 0 20 _null_ ));
! DATA(insert ( 2242 bitand - 0 1560 _null_ ));
! DATA(insert ( 2243 bitor - 0 1560 _null_ ));
/* xml */
! DATA(insert ( 2901 xmlconcat2 - 0 142 _null_ ));
/* array */
! DATA(insert ( 2335 array_agg_transfn array_agg_finalfn 0 2281 _null_ ));
/* text */
! DATA(insert ( 3538 string_agg_transfn string_agg_finalfn 0 2281 _null_ ));
/* bytea */
! DATA(insert ( 3545 bytea_string_agg_transfn bytea_string_agg_finalfn 0 2281 _null_ ));
/* json */
! DATA(insert ( 3175 json_agg_transfn json_agg_finalfn 0 2281 _null_ ));
/*
* prototypes for functions in pg_aggregate.c
--- 79,241 ----
*/
/* avg */
! DATA(insert ( 2100 int8_avg_accum numeric_avg 0 2281 128 _null_ ));
! DATA(insert ( 2101 int4_avg_accum int8_avg 0 1016 0 "{0,0}" ));
! DATA(insert ( 2102 int2_avg_accum int8_avg 0 1016 0 "{0,0}" ));
! DATA(insert ( 2103 numeric_avg_accum numeric_avg 0 2281 128 _null_ ));
! DATA(insert ( 2104 float4_accum float8_avg 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2105 float8_accum float8_avg 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2106 interval_accum interval_avg 0 1187 0 "{0 second,0 second}" ));
/* sum */
! DATA(insert ( 2107 int8_avg_accum numeric_sum 0 2281 128 _null_ ));
! DATA(insert ( 2108 int4_sum - 0 20 0 _null_ ));
! DATA(insert ( 2109 int2_sum - 0 20 0 _null_ ));
! DATA(insert ( 2110 float4pl - 0 700 0 _null_ ));
! DATA(insert ( 2111 float8pl - 0 701 0 _null_ ));
! DATA(insert ( 2112 cash_pl - 0 790 0 _null_ ));
! DATA(insert ( 2113 interval_pl - 0 1186 0 _null_ ));
! DATA(insert ( 2114 numeric_avg_accum numeric_sum 0 2281 128 _null_ ));
/* max */
! DATA(insert ( 2115 int8larger - 413 20 0 _null_ ));
! DATA(insert ( 2116 int4larger - 521 23 0 _null_ ));
! DATA(insert ( 2117 int2larger - 520 21 0 _null_ ));
! DATA(insert ( 2118 oidlarger - 610 26 0 _null_ ));
! DATA(insert ( 2119 float4larger - 623 700 0 _null_ ));
! DATA(insert ( 2120 float8larger - 674 701 0 _null_ ));
! DATA(insert ( 2121 int4larger - 563 702 0 _null_ ));
! DATA(insert ( 2122 date_larger - 1097 1082 0 _null_ ));
! DATA(insert ( 2123 time_larger - 1112 1083 0 _null_ ));
! DATA(insert ( 2124 timetz_larger - 1554 1266 0 _null_ ));
! DATA(insert ( 2125 cashlarger - 903 790 0 _null_ ));
! DATA(insert ( 2126 timestamp_larger - 2064 1114 0 _null_ ));
! DATA(insert ( 2127 timestamptz_larger - 1324 1184 0 _null_ ));
! DATA(insert ( 2128 interval_larger - 1334 1186 0 _null_ ));
! DATA(insert ( 2129 text_larger - 666 25 0 _null_ ));
! DATA(insert ( 2130 numeric_larger - 1756 1700 0 _null_ ));
! DATA(insert ( 2050 array_larger - 1073 2277 0 _null_ ));
! DATA(insert ( 2244 bpchar_larger - 1060 1042 0 _null_ ));
! DATA(insert ( 2797 tidlarger - 2800 27 0 _null_ ));
! DATA(insert ( 3526 enum_larger - 3519 3500 0 _null_ ));
/* min */
! DATA(insert ( 2131 int8smaller - 412 20 0 _null_ ));
! DATA(insert ( 2132 int4smaller - 97 23 0 _null_ ));
! DATA(insert ( 2133 int2smaller - 95 21 0 _null_ ));
! DATA(insert ( 2134 oidsmaller - 609 26 0 _null_ ));
! DATA(insert ( 2135 float4smaller - 622 700 0 _null_ ));
! DATA(insert ( 2136 float8smaller - 672 701 0 _null_ ));
! DATA(insert ( 2137 int4smaller - 562 702 0 _null_ ));
! DATA(insert ( 2138 date_smaller - 1095 1082 0 _null_ ));
! DATA(insert ( 2139 time_smaller - 1110 1083 0 _null_ ));
! DATA(insert ( 2140 timetz_smaller - 1552 1266 0 _null_ ));
! DATA(insert ( 2141 cashsmaller - 902 790 0 _null_ ));
! DATA(insert ( 2142 timestamp_smaller - 2062 1114 0 _null_ ));
! DATA(insert ( 2143 timestamptz_smaller - 1322 1184 0 _null_ ));
! DATA(insert ( 2144 interval_smaller - 1332 1186 0 _null_ ));
! DATA(insert ( 2145 text_smaller - 664 25 0 _null_ ));
! DATA(insert ( 2146 numeric_smaller - 1754 1700 0 _null_ ));
! DATA(insert ( 2051 array_smaller - 1072 2277 0 _null_ ));
! DATA(insert ( 2245 bpchar_smaller - 1058 1042 0 _null_ ));
! DATA(insert ( 2798 tidsmaller - 2799 27 0 _null_ ));
! DATA(insert ( 3527 enum_smaller - 3518 3500 0 _null_ ));
/* count */
! DATA(insert ( 2147 int8inc_any - 0 20 0 "0" ));
! DATA(insert ( 2803 int8inc - 0 20 0 "0" ));
/* var_pop */
! DATA(insert ( 2718 int8_accum numeric_var_pop 0 2281 128 _null_ ));
! DATA(insert ( 2719 int4_accum numeric_var_pop 0 2281 128 _null_ ));
! DATA(insert ( 2720 int2_accum numeric_var_pop 0 2281 128 _null_ ));
! DATA(insert ( 2721 float4_accum float8_var_pop 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2722 float8_accum float8_var_pop 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2723 numeric_accum numeric_var_pop 0 2281 128 _null_ ));
/* var_samp */
! DATA(insert ( 2641 int8_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2642 int4_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2643 int2_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2644 float4_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2645 float8_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2646 numeric_accum numeric_var_samp 0 2281 128 _null_ ));
/* variance: historical Postgres syntax for var_samp */
! DATA(insert ( 2148 int8_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2149 int4_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2150 int2_accum numeric_var_samp 0 2281 128 _null_ ));
! DATA(insert ( 2151 float4_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2152 float8_accum float8_var_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2153 numeric_accum numeric_var_samp 0 2281 128 _null_ ));
/* stddev_pop */
! DATA(insert ( 2724 int8_accum numeric_stddev_pop 0 2281 128 _null_ ));
! DATA(insert ( 2725 int4_accum numeric_stddev_pop 0 2281 128 _null_ ));
! DATA(insert ( 2726 int2_accum numeric_stddev_pop 0 2281 128 _null_ ));
! DATA(insert ( 2727 float4_accum float8_stddev_pop 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2728 float8_accum float8_stddev_pop 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2729 numeric_accum numeric_stddev_pop 0 2281 128 _null_ ));
/* stddev_samp */
! DATA(insert ( 2712 int8_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2713 int4_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2714 int2_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2715 float4_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2716 float8_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2717 numeric_accum numeric_stddev_samp 0 2281 128 _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
! DATA(insert ( 2154 int8_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2155 int4_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2156 int2_accum numeric_stddev_samp 0 2281 128 _null_ ));
! DATA(insert ( 2157 float4_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2158 float8_accum float8_stddev_samp 0 1022 0 "{0,0,0}" ));
! DATA(insert ( 2159 numeric_accum numeric_stddev_samp 0 2281 128 _null_ ));
/* SQL2003 binary regression aggregates */
! DATA(insert ( 2818 int8inc_float8_float8 - 0 20 0 "0" ));
! DATA(insert ( 2819 float8_regr_accum float8_regr_sxx 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2820 float8_regr_accum float8_regr_syy 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2821 float8_regr_accum float8_regr_sxy 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2822 float8_regr_accum float8_regr_avgx 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2823 float8_regr_accum float8_regr_avgy 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2824 float8_regr_accum float8_regr_r2 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2825 float8_regr_accum float8_regr_slope 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2826 float8_regr_accum float8_regr_intercept 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2827 float8_regr_accum float8_covar_pop 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2828 float8_regr_accum float8_covar_samp 0 1022 0 "{0,0,0,0,0,0}" ));
! DATA(insert ( 2829 float8_regr_accum float8_corr 0 1022 0 "{0,0,0,0,0,0}" ));
/* boolean-and and boolean-or */
! DATA(insert ( 2517 booland_statefunc - 58 16 0 _null_ ));
! DATA(insert ( 2518 boolor_statefunc - 59 16 0 _null_ ));
! DATA(insert ( 2519 booland_statefunc - 58 16 0 _null_ ));
/* bitwise integer */
! DATA(insert ( 2236 int2and - 0 21 0 _null_ ));
! DATA(insert ( 2237 int2or - 0 21 0 _null_ ));
! DATA(insert ( 2238 int4and - 0 23 0 _null_ ));
! DATA(insert ( 2239 int4or - 0 23 0 _null_ ));
! DATA(insert ( 2240 int8and - 0 20 0 _null_ ));
! DATA(insert ( 2241 int8or - 0 20 0 _null_ ));
! DATA(insert ( 2242 bitand - 0 1560 0 _null_ ));
! DATA(insert ( 2243 bitor - 0 1560 0 _null_ ));
/* xml */
! DATA(insert ( 2901 xmlconcat2 - 0 142 0 _null_ ));
/* array */
! DATA(insert ( 2335 array_agg_transfn array_agg_finalfn 0 2281 0 _null_ ));
/* text */
! DATA(insert ( 3538 string_agg_transfn string_agg_finalfn 0 2281 0 _null_ ));
/* bytea */
! DATA(insert ( 3545 bytea_string_agg_transfn bytea_string_agg_finalfn 0 2281 0 _null_ ));
/* json */
! DATA(insert ( 3175 json_agg_transfn json_agg_finalfn 0 2281 0 _null_ ));
/*
* prototypes for functions in pg_aggregate.c
***************
*** 250,255 **** extern Oid AggregateCreate(const char *aggName,
--- 252,258 ----
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
+ int32 aggTransSpace,
const char *agginitval);
#endif /* PG_AGGREGATE_H */
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 2381,2407 **** DATA(insert OID = 2513 ( float8_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f t f i
DESCR("aggregate final function");
DATA(insert OID = 1832 ( float8_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "1022" _null_ _null_ _null_ _null_ float8_stddev_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 1833 ( numeric_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 1700" _null_ _null_ _null_ _null_ numeric_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 2858 ( numeric_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 1700" _null_ _null_ _null_ _null_ numeric_avg_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1834 ( int2_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 21" _null_ _null_ _null_ _null_ int2_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1835 ( int4_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 23" _null_ _null_ _null_ _null_ int4_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1836 ( int8_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 20" _null_ _null_ _null_ _null_ int8_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 2746 ( int8_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 20" _null_ _null_ _null_ _null_ int8_avg_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1837 ( numeric_avg PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 2514 ( numeric_var_pop PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_var_pop _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 1838 ( numeric_var_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_var_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 2596 ( numeric_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_stddev_pop _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 1839 ( numeric_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_stddev_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 1840 ( int2_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 20 "20 21" _null_ _null_ _null_ _null_ int2_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
--- 2381,2409 ----
DESCR("aggregate final function");
DATA(insert OID = 1832 ( float8_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "1022" _null_ _null_ _null_ _null_ float8_stddev_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 1833 ( numeric_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 1700" _null_ _null_ _null_ _null_ numeric_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 2858 ( numeric_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 1700" _null_ _null_ _null_ _null_ numeric_avg_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1834 ( int2_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 21" _null_ _null_ _null_ _null_ int2_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1835 ( int4_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 23" _null_ _null_ _null_ _null_ int4_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1836 ( int8_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ int8_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 2746 ( int8_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ int8_avg_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
! DATA(insert OID = 1837 ( numeric_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 3179 ( numeric_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_sum _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 2514 ( numeric_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_var_pop _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 1838 ( numeric_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_var_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
! DATA(insert OID = 2596 ( numeric_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_stddev_pop _null_ _null_ _null_ ));
! DESCR("aggregate final function");
! DATA(insert OID = 1839 ( numeric_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_stddev_samp _null_ _null_ _null_ ));
DESCR("aggregate final function");
DATA(insert OID = 1840 ( int2_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 20 "20 21" _null_ _null_ _null_ _null_ int2_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 133,138 **** extern Datum transformGenericOptions(Oid catalogId,
--- 133,139 ----
extern char *defGetString(DefElem *def);
extern double defGetNumeric(DefElem *def);
extern bool defGetBoolean(DefElem *def);
+ extern int32 defGetInt32(DefElem *def);
extern int64 defGetInt64(DefElem *def);
extern List *defGetQualifiedName(DefElem *def);
extern TypeName *defGetTypeName(DefElem *def);
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
***************
*** 982,987 **** extern Datum int4_accum(PG_FUNCTION_ARGS);
--- 982,988 ----
extern Datum int8_accum(PG_FUNCTION_ARGS);
extern Datum int8_avg_accum(PG_FUNCTION_ARGS);
extern Datum numeric_avg(PG_FUNCTION_ARGS);
+ extern Datum numeric_sum(PG_FUNCTION_ARGS);
extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
*** a/src/test/regress/expected/aggregates.out
--- b/src/test/regress/expected/aggregates.out
***************
*** 1262,1264 **** select least_agg(variadic array[q1,q2]) from int8_tbl;
--- 1262,1313 ----
-4567890123456789
(1 row)
+ -- verify correct calculations for null set
+ select sum(null::int4) from generate_series(1,1);
+ sum
+ -----
+
+ (1 row)
+
+ select sum(null::int8) from generate_series(1,1);
+ sum
+ -----
+
+ (1 row)
+
+ select sum(null::numeric) from generate_series(1,1);
+ sum
+ -----
+
+ (1 row)
+
+ select sum(null::float8) from generate_series(1,1);
+ sum
+ -----
+
+ (1 row)
+
+ select avg(null::int4) from generate_series(1,1);
+ avg
+ -----
+
+ (1 row)
+
+ select avg(null::int8) from generate_series(1,1);
+ avg
+ -----
+
+ (1 row)
+
+ select avg(null::numeric) from generate_series(1,1);
+ avg
+ -----
+
+ (1 row)
+
+ select avg(null::float8) from generate_series(1,1);
+ avg
+ -----
+
+ (1 row)
+
*** a/src/test/regress/expected/create_aggregate.out
--- b/src/test/regress/expected/create_aggregate.out
***************
*** 66,68 **** returns anyelement language sql as
--- 66,75 ----
create aggregate least_agg(variadic items anyarray) (
stype = anyelement, sfunc = least_accum
);
+ -- should not work, sspace is allowed only for stype internal
+ create aggregate aggfns(integer,integer,text) (
+ sfunc = aggfns_trans, stype = aggtype[], sspace = 200,
+ initcond = '{}'
+ );
+ ERROR: SSPACE can be used only for "internal" transition type
+ DETAIL: SSPACE can be defined only together with a "internal" transition type.
*** a/src/test/regress/sql/aggregates.sql
--- b/src/test/regress/sql/aggregates.sql
***************
*** 484,486 **** select aggfns(distinct a,b,c order by a,c using ~<~,b) filter (where a > 1)
--- 484,497 ----
-- variadic aggregates
select least_agg(q1,q2) from int8_tbl;
select least_agg(variadic array[q1,q2]) from int8_tbl;
+
+ -- verify correct calculations for null set
+ select sum(null::int4) from generate_series(1,1);
+ select sum(null::int8) from generate_series(1,1);
+ select sum(null::numeric) from generate_series(1,1);
+ select sum(null::float8) from generate_series(1,1);
+
+ select avg(null::int4) from generate_series(1,1);
+ select avg(null::int8) from generate_series(1,1);
+ select avg(null::numeric) from generate_series(1,1);
+ select avg(null::float8) from generate_series(1,1);
*** a/src/test/regress/sql/create_aggregate.sql
--- b/src/test/regress/sql/create_aggregate.sql
***************
*** 80,82 **** returns anyelement language sql as
--- 80,88 ----
create aggregate least_agg(variadic items anyarray) (
stype = anyelement, sfunc = least_accum
);
+
+ -- should not work, sspace is allowed only for stype internal
+ create aggregate aggfns(integer,integer,text) (
+ sfunc = aggfns_trans, stype = aggtype[], sspace = 200,
+ initcond = '{}'
+ );
On 24.9.2013 17:57, Pavel Stehule wrote:
2013/9/24 Robert Haas <robertmhaas@gmail.com
<mailto:robertmhaas@gmail.com>>On Mon, Sep 23, 2013 at 4:15 PM, Tomas Vondra <tv@fuzzy.cz
<mailto:tv@fuzzy.cz>> wrote:Seems "ready for commiter" to me. I'll wait a few days for others
to comment, and then I'll update the commitfest page.Some thoughts:
The documentation doesn't reflect the restriction to type internal.
On a related note, why restrict this to type internal?Now, for almost all types Postgres well estimate size of state
value. Only arrays with unknown size can be a different. When we
enable this value for all types, then users can specify some bad
values for scalar buildin types. Next argument is simply and bad - I
don't see a good use case for customization this value for other than
types than internal type.I have no strong position here - prefer joining with internal type
due little bit higher robustness.
I share this oppinion. I was not able to come up with a single use case
benefiting from allowing this for types other than internal. Seems like
a footgun to me, with no potential benefit.
So +1 to keeping the patch 'type internal only' from me.
With the formatting issues now fixed, I believe the patch is ready for
committer (and someone already switched it to that state).
Tomas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Pavel Stehule <pavel.stehule@gmail.com> writes:
[ numeric-optimize-v8.patch ]
I've committed this with some adjustments. Aside from cosmetic
changes and documentation/comment improvements:
* I don't agree at all with the claim that aggtransspace is only useful
for INTERNAL transition data. There are lots of cases with regular
SQL types where the planner doesn't have a good idea of how large the
transition value will be, and with the current code it tends to guess
on the small side (frequently 32 bytes :-(). It seems to me to be
useful to give users a knob to twiddle there. Consider for example
an aggregate that uses an integer array as transition state; the author
of the aggregate might know that there are usually hundreds of entries
in the array, and wish to dial up aggtransspace to prevent the planner
from optimistically choosing hash aggregation.
As committed, I just took out the restriction in CREATE AGGREGATE
altogether; it will let you set SSPACE for any transition datatype.
The planner will ignore it for pass-by-value types, where the behavior
is known, but otherwise honor it. It's possible that we should put in
a restriction to INTERNAL plus pass-by-reference types, or even INTERNAL
plus pass-by-reference variable-length types, but I can't get excited
about that. The error message would be too confusing I think.
* There was a stray "else" added to clauses.c that disabled space
accounting for polymorphic aggregates.
* I simplified the summing code in do_numeric_accum; the copying and
reallocating it was doing was not only unnecessary but contained
unpleasant assumptions about what you can do with a NumericVar. This
probably makes the committed patch a bit faster than what was submitted,
but I didn't try to benchmark the change.
* I made sure all the functions accessed their input state pointer with
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
There were places that omitted the ARGISNULL test, and thus only happened
to work if the uninitialized Datum value they got was zero. While that
might chance to be true in the current state of the code, it's not an
assumption you're supposed to make.
* numeric sum/avg failed to check for NaN inputs.
* I fixed incorrect tests in the code added to pg_dump.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers