Improving avg performance for numeric
Revisiting:
/messages/by-id/45661BE7.4050205@paradise.net.nz
I think the reasons which the numeric average was slow were:
(1) Using Numeric for count, which is slower than int8 to increment,
(2) Constructing/deconstructing arrays at each transition step.
This is also discussed at:
http://www.citusdata.com/blog/53-postgres-performance-to-avg-or-to-sum-divided-by-count
So, I think we can improve the speed of numeric average by keeping the
transition state as an struct in the aggregate context, and just passing
the pointer to that struct from/to the aggregate transition function.
The attached patch uses this method.
I tested it using the data generated using:
CREATE TABLE avg_test AS SELECT (random() * 999)::decimal(5,2) as d FROM
generate_series(1, 10000000) s;
After applying this patch, run time of "SELECT avg(d) FROM avg_test;"
improves from 10.701 seconds to 5.204 seconds, which seems to be a huge
improvement.
I think we may also be able to use a similar method to improve performance
of some other numeric aggregates (like stddev). But I want to know your
feedback first.
Is this worth working on?
Thanks,
-- Hadi
Attachments:
numeric-avg-optimize.patchapplication/octet-stream; name=numeric-avg-optimize.patchDownload
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 229b408..6e1a6ae 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -259,6 +259,13 @@ typedef struct NumericVar
NumericDigit *digits; /* base-NBASE digits */
} NumericVar;
+/* Transition state for numeric average aggregate. */
+typedef struct AvgAggState
+{
+ Numeric sumX;
+ uint64 N;
+ size_t sumX_size;
+} AvgAggState;
/* ----------
* Some preinitialized constants
@@ -432,7 +439,7 @@ static void trunc_var(NumericVar *var, int rscale);
static void strip_var(NumericVar *var);
static void compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
NumericVar *count_var, NumericVar *result_var);
-
+static AvgAggState * makeAvgAggState(FunctionCallInfo fcinfo);
/* ----------------------------------------------------------------------
*
@@ -2511,38 +2518,28 @@ do_numeric_accum(ArrayType *transarray, Numeric newval)
return result;
}
-/*
- * Improve avg performance by not caclulating sum(X*X).
- */
-static ArrayType *
-do_numeric_avg_accum(ArrayType *transarray, Numeric newval)
+static void
+do_numeric_avg_accum(AvgAggState *state, Numeric newval)
{
- Datum *transdatums;
- int ndatums;
- Datum N,
- sumX;
- ArrayType *result;
+ Numeric newsumX;
+ size_t newsumX_size;
- /* 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];
+ /* Calculate the new value for sumX. */
+ newsumX = DatumGetNumeric(DirectFunctionCall2(numeric_add,
+ NumericGetDatum(state->sumX),
+ NumericGetDatum(newval)));
- 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');
+ /* Enlarge state->sumX to have enough space for the new sumX. */
+ newsumX_size = VARSIZE(newsumX);
+ if (newsumX_size > state->sumX_size)
+ {
+ state->sumX = repalloc(state->sumX, newsumX_size);
+ state->sumX_size = newsumX_size;
+ }
- return result;
+ /* Update state. */
+ memcpy(state->sumX, newsumX, newsumX_size);
+ state->N++;
}
Datum
@@ -2560,10 +2557,20 @@ numeric_accum(PG_FUNCTION_ARGS)
Datum
numeric_avg_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Numeric newval = PG_GETARG_NUMERIC(1);
+ AvgAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (AvgAggState *) PG_GETARG_POINTER(0);
+
+ if (!PG_ARGISNULL(1))
+ {
+ /* On the first time through, create the state variable. */
+ if (state == NULL)
+ state = makeAvgAggState(fcinfo);
+
+ do_numeric_avg_accum(state, PG_GETARG_NUMERIC(1));
+ }
- PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
+ PG_RETURN_POINTER(state);
}
/*
@@ -2617,42 +2624,43 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Datum newval8 = PG_GETARG_DATUM(1);
- Numeric newval;
+ AvgAggState *state;
- newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
+ state = PG_ARGISNULL(0) ? NULL : (AvgAggState *) PG_GETARG_POINTER(0);
- PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
-}
+ if (!PG_ARGISNULL(1))
+ {
+ Datum newval8;
+ Numeric newval;
+ /* On the first time through, create the state variable. */
+ if (state == NULL)
+ state = makeAvgAggState(fcinfo);
+
+ newval8 = PG_GETARG_DATUM(1);
+ newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
+
+ do_numeric_avg_accum(state, newval);
+ }
+
+ PG_RETURN_POINTER(state);
+}
Datum
numeric_avg(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Datum *transdatums;
- int ndatums;
- Numeric N,
- sumX;
+ Datum countd;
+ AvgAggState *state;
- /* 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]);
-
- /* SQL92 defines AVG of no values to be NULL */
- /* N is zero iff no digits (cf. numeric_uminus) */
- if (NUMERIC_NDIGITS(N) == 0)
+ if (PG_ARGISNULL(0))
PG_RETURN_NULL();
+ state = (AvgAggState *) PG_GETARG_POINTER(0);
+ countd = DirectFunctionCall1(int8_numeric, Int64GetDatum(state->N));
+
PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
- NumericGetDatum(sumX),
- NumericGetDatum(N)));
+ NumericGetDatum(state->sumX),
+ countd));
}
/*
@@ -6170,3 +6178,39 @@ strip_var(NumericVar *var)
var->digits = digits;
var->ndigits = ndigits;
}
+
+/*
+ * makeAvgAggState
+ *
+ * Initialize state for numeric avg aggregate in the aggregate context
+ */
+static AvgAggState *
+makeAvgAggState(FunctionCallInfo fcinfo)
+{
+ AvgAggState *state;
+ NumericVar *sumX_var;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ {
+ /* cannot be called directly because of internal-type argument */
+ elog(ERROR, "numeric_avg_accum called in non-aggregate context");
+ }
+
+ sumX_var = palloc0(sizeof(NumericVar));
+ zero_var(sumX_var);
+
+ /*
+ * Create state in aggregate context. It'll stay there across subsequent
+ * calls.
+ */
+ old_context = MemoryContextSwitchTo(agg_context);
+ state = palloc0(sizeof(AvgAggState));
+ state->sumX = make_result(sumX_var);
+ state->sumX_size = VARSIZE(state->sumX);
+ state->N = 0;
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..b34fedf 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -77,10 +77,10 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 int8_avg_accum numeric_avg 0 1231 "{0,0}" ));
+DATA(insert ( 2100 int8_avg_accum numeric_avg 0 2281 _null_ ));
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 ( 2103 numeric_avg_accum numeric_avg 0 2281 _null_ ));
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}" ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c97056e..f30a7a3 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2385,7 +2385,7 @@ DATA(insert OID = 1832 ( float8_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f
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_ ));
+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 t f i 2 0 1231 "1231 21" _null_ _null_ _null_ _null_ int2_accum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
@@ -2393,9 +2393,9 @@ DATA(insert OID = 1835 ( int4_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0
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_ ));
+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 t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ ));
+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 = 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");
Hello
2013/3/16 Hadi Moshayedi <hadi@moshayedi.net>:
Revisiting:
/messages/by-id/45661BE7.4050205@paradise.net.nzI think the reasons which the numeric average was slow were:
(1) Using Numeric for count, which is slower than int8 to increment,
(2) Constructing/deconstructing arrays at each transition step.This is also discussed at:
http://www.citusdata.com/blog/53-postgres-performance-to-avg-or-to-sum-divided-by-countSo, I think we can improve the speed of numeric average by keeping the
transition state as an struct in the aggregate context, and just passing the
pointer to that struct from/to the aggregate transition function.The attached patch uses this method.
I tested it using the data generated using:
CREATE TABLE avg_test AS SELECT (random() * 999)::decimal(5,2) as d FROM
generate_series(1, 10000000) s;After applying this patch, run time of "SELECT avg(d) FROM avg_test;"
improves from 10.701 seconds to 5.204 seconds, which seems to be a huge
improvement.I think we may also be able to use a similar method to improve performance
of some other numeric aggregates (like stddev). But I want to know your
feedback first.Is this worth working on?
nice
+1
Regards
Pavel
Thanks,
-- Hadi--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2013/3/16 Hadi Moshayedi <hadi@moshayedi.net>:
Revisiting:
/messages/by-id/45661BE7.4050205@paradise.net.nzI think the reasons which the numeric average was slow were:
(1) Using Numeric for count, which is slower than int8 to increment,
(2) Constructing/deconstructing arrays at each transition step.This is also discussed at:
http://www.citusdata.com/blog/53-postgres-performance-to-avg-or-to-sum-divided-by-countSo, I think we can improve the speed of numeric average by keeping the
transition state as an struct in the aggregate context, and just passing the
pointer to that struct from/to the aggregate transition function.The attached patch uses this method.
I tested it using the data generated using:
CREATE TABLE avg_test AS SELECT (random() * 999)::decimal(5,2) as d FROM
generate_series(1, 10000000) s;After applying this patch, run time of "SELECT avg(d) FROM avg_test;"
improves from 10.701 seconds to 5.204 seconds, which seems to be a huge
improvement.I think we may also be able to use a similar method to improve performance
of some other numeric aggregates (like stddev). But I want to know your
feedback first.Is this worth working on?
I checked this patch and it has a interesting speedup - and a price of
this methoud should not be limited to numeric type only
Pavel
Thanks,
-- Hadi--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi Pavel,
Thanks a lot for your feedback.
I'll work more on this patch this week, and will send a more complete patch
later this week.
I'll also try to see how much is the speed up of this method for other
types.
Thanks,
-- Hadi
On Mon, Mar 18, 2013 at 10:36 AM, Pavel Stehule <pavel.stehule@gmail.com>wrote:
Show quoted text
2013/3/16 Hadi Moshayedi <hadi@moshayedi.net>:
Revisiting:
/messages/by-id/45661BE7.4050205@paradise.net.nzI think the reasons which the numeric average was slow were:
(1) Using Numeric for count, which is slower than int8 to increment,
(2) Constructing/deconstructing arrays at each transition step.This is also discussed at:
http://www.citusdata.com/blog/53-postgres-performance-to-avg-or-to-sum-divided-by-count
So, I think we can improve the speed of numeric average by keeping the
transition state as an struct in the aggregate context, and just passingthe
pointer to that struct from/to the aggregate transition function.
The attached patch uses this method.
I tested it using the data generated using:
CREATE TABLE avg_test AS SELECT (random() * 999)::decimal(5,2) as d FROM
generate_series(1, 10000000) s;After applying this patch, run time of "SELECT avg(d) FROM avg_test;"
improves from 10.701 seconds to 5.204 seconds, which seems to be a huge
improvement.I think we may also be able to use a similar method to improve
performance
of some other numeric aggregates (like stddev). But I want to know your
feedback first.Is this worth working on?
I checked this patch and it has a interesting speedup - and a price of
this methoud should not be limited to numeric type onlyPavel
Thanks,
-- Hadi--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hello
I played with sum(numeric) optimization
Now it is based on generic numeric_add function - this code is
relative old - now we can design aggregates with internal transition
buffers, and probably we can do this work more effective.
I just removed useles palloc/free operations and I got a 30% better
performance! My patch is ugly - because I used a generic add_var
function. Because Sum, Avg and almost all aggregates functions is
limited by speed of sum calculation I thing so we need a new numeric
routines optimized for calculation "sum", that use a only preallocated
buffers. A speed of numeric is more important now, because there are
more and more warehouses, where CPU is botleneck.
Regards
Pavel
2013/3/18 Hadi Moshayedi <hadi@moshayedi.net>:
Show quoted text
Hi Pavel,
Thanks a lot for your feedback.
I'll work more on this patch this week, and will send a more complete patch
later this week.I'll also try to see how much is the speed up of this method for other
types.Thanks,
-- HadiOn Mon, Mar 18, 2013 at 10:36 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:2013/3/16 Hadi Moshayedi <hadi@moshayedi.net>:
Revisiting:
/messages/by-id/45661BE7.4050205@paradise.net.nzI think the reasons which the numeric average was slow were:
(1) Using Numeric for count, which is slower than int8 to increment,
(2) Constructing/deconstructing arrays at each transition step.This is also discussed at:
http://www.citusdata.com/blog/53-postgres-performance-to-avg-or-to-sum-divided-by-count
So, I think we can improve the speed of numeric average by keeping the
transition state as an struct in the aggregate context, and just passing
the
pointer to that struct from/to the aggregate transition function.The attached patch uses this method.
I tested it using the data generated using:
CREATE TABLE avg_test AS SELECT (random() * 999)::decimal(5,2) as d FROM
generate_series(1, 10000000) s;After applying this patch, run time of "SELECT avg(d) FROM avg_test;"
improves from 10.701 seconds to 5.204 seconds, which seems to be a huge
improvement.I think we may also be able to use a similar method to improve
performance
of some other numeric aggregates (like stddev). But I want to know your
feedback first.Is this worth working on?
I checked this patch and it has a interesting speedup - and a price of
this methoud should not be limited to numeric type onlyPavel
Thanks,
-- Hadi--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
numeric-sum-optimize.patchapplication/octet-stream; name=numeric-sum-optimize.patchDownload
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 229b408..cd43416 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -259,6 +259,13 @@ typedef struct NumericVar
NumericDigit *digits; /* base-NBASE digits */
} NumericVar;
+/* Transition state for numeric average aggregate. */
+typedef struct AvgAggState
+{
+ Numeric sumX;
+ uint64 N;
+ size_t sumX_size;
+} AvgAggState;
/* ----------
* Some preinitialized constants
@@ -432,7 +439,7 @@ static void trunc_var(NumericVar *var, int rscale);
static void strip_var(NumericVar *var);
static void compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
NumericVar *count_var, NumericVar *result_var);
-
+static AvgAggState * makeAvgAggState(FunctionCallInfo fcinfo);
/* ----------------------------------------------------------------------
*
@@ -1576,6 +1583,117 @@ numeric_add(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
+/*
+ * numeric_fadd() -
+ *
+ * fast sum aggregate
+ */
+typedef struct SumAggState
+{
+ NumericVar sumX;
+ MemoryContext agg_context;
+ bool isNaN;
+} SumAggState;
+
+static SumAggState *
+makeSumAggState(FunctionCallInfo fcinfo)
+{
+ SumAggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ {
+ elog(ERROR, "numeric_fadd is called in non-aggregate context");
+ }
+
+ old_context = MemoryContextSwitchTo(agg_context);
+ state = palloc0(sizeof(SumAggState));
+ state->agg_context = agg_context;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
+
+
+Datum
+numeric_fadd_accum(PG_FUNCTION_ARGS)
+{
+ SumAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (SumAggState *) PG_GETARG_POINTER(0);
+
+ if (!PG_ARGISNULL(1))
+ {
+ bool first = false;
+
+ if (state == NULL)
+ {
+ state = makeSumAggState(fcinfo);
+ first = true;
+ }
+
+ if (!state->isNaN)
+ {
+ Numeric par = PG_GETARG_NUMERIC(1);
+
+ if (NUMERIC_IS_NAN(par))
+ {
+ state->isNaN = true;
+ }
+ else
+ {
+ NumericVar numvar;
+ NumericVar tmp;
+ MemoryContext old_context;
+
+ init_var_from_num(par, &numvar);
+
+ old_context = MemoryContextSwitchTo(state->agg_context);
+
+ if (!first)
+ {
+ memcpy(&tmp, &(state->sumX), sizeof(NumericVar));
+ init_var(&(state->sumX));
+
+ add_var(&numvar, &tmp, &(state->sumX));
+ free_var(&tmp);
+ }
+ else
+ set_var_from_var(&numvar, &(state->sumX));
+
+ MemoryContextSwitchTo(old_context);
+
+
+ }
+ }
+ }
+
+ PG_RETURN_POINTER(state);
+}
+
+Datum
+numeric_fadd(PG_FUNCTION_ARGS)
+{
+ SumAggState *state;
+ Numeric res;
+
+ if (PG_ARGISNULL(0))
+ PG_RETURN_NULL();
+
+ state = (SumAggState *) PG_GETARG_POINTER(0);
+ if (state->isNaN)
+ {
+ pfree(state);
+ PG_RETURN_NUMERIC(make_result(&const_nan));
+ }
+
+ res = make_result(&(state->sumX));
+ pfree(state);
+
+ PG_RETURN_NUMERIC(res);
+}
/*
* numeric_sub() -
@@ -2511,38 +2629,28 @@ do_numeric_accum(ArrayType *transarray, Numeric newval)
return result;
}
-/*
- * Improve avg performance by not caclulating sum(X*X).
- */
-static ArrayType *
-do_numeric_avg_accum(ArrayType *transarray, Numeric newval)
+static void
+do_numeric_avg_accum(AvgAggState *state, 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));
+ Numeric newsumX;
+ size_t newsumX_size;
- transdatums[0] = N;
- transdatums[1] = sumX;
+ /* Calculate the new value for sumX. */
+ newsumX = DatumGetNumeric(DirectFunctionCall2(numeric_add,
+ NumericGetDatum(state->sumX),
+ NumericGetDatum(newval)));
- result = construct_array(transdatums, 2,
- NUMERICOID, -1, false, 'i');
+ /* Enlarge state->sumX to have enough space for the new sumX. */
+ newsumX_size = VARSIZE(newsumX);
+ if (newsumX_size > state->sumX_size)
+ {
+ state->sumX = repalloc(state->sumX, newsumX_size);
+ state->sumX_size = newsumX_size;
+ }
- return result;
+ /* Update state. */
+ memcpy(state->sumX, newsumX, newsumX_size);
+ state->N++;
}
Datum
@@ -2560,10 +2668,20 @@ numeric_accum(PG_FUNCTION_ARGS)
Datum
numeric_avg_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Numeric newval = PG_GETARG_NUMERIC(1);
+ AvgAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (AvgAggState *) PG_GETARG_POINTER(0);
- PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
+ if (!PG_ARGISNULL(1))
+ {
+ /* On the first time through, create the state variable. */
+ if (state == NULL)
+ state = makeAvgAggState(fcinfo);
+
+ do_numeric_avg_accum(state, PG_GETARG_NUMERIC(1));
+ }
+
+ PG_RETURN_POINTER(state);
}
/*
@@ -2617,42 +2735,43 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Datum newval8 = PG_GETARG_DATUM(1);
- Numeric newval;
+ AvgAggState *state;
- newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
+ state = PG_ARGISNULL(0) ? NULL : (AvgAggState *) PG_GETARG_POINTER(0);
- PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
-}
+ if (!PG_ARGISNULL(1))
+ {
+ Datum newval8;
+ Numeric newval;
+
+ /* On the first time through, create the state variable. */
+ if (state == NULL)
+ state = makeAvgAggState(fcinfo);
+
+ newval8 = PG_GETARG_DATUM(1);
+ newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
+
+ do_numeric_avg_accum(state, newval);
+ }
+ PG_RETURN_POINTER(state);
+}
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]);
+ Datum countd;
+ AvgAggState *state;
- /* SQL92 defines AVG of no values to be NULL */
- /* N is zero iff no digits (cf. numeric_uminus) */
- if (NUMERIC_NDIGITS(N) == 0)
+ if (PG_ARGISNULL(0))
PG_RETURN_NULL();
+ state = (AvgAggState *) PG_GETARG_POINTER(0);
+ countd = DirectFunctionCall1(int8_numeric, Int64GetDatum(state->N));
+
PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
- NumericGetDatum(sumX),
- NumericGetDatum(N)));
+ NumericGetDatum(state->sumX),
+ countd));
}
/*
@@ -6170,3 +6289,39 @@ strip_var(NumericVar *var)
var->digits = digits;
var->ndigits = ndigits;
}
+
+/*
+ * makeAvgAggState
+ *
+ * Initialize state for numeric avg aggregate in the aggregate context
+ */
+static AvgAggState *
+makeAvgAggState(FunctionCallInfo fcinfo)
+{
+ AvgAggState *state;
+ NumericVar *sumX_var;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ {
+ /* cannot be called directly because of internal-type argument */
+ elog(ERROR, "numeric_avg_accum called in non-aggregate context");
+ }
+
+ sumX_var = palloc0(sizeof(NumericVar));
+ zero_var(sumX_var);
+
+ /*
+ * Create state in aggregate context. It'll stay there across subsequent
+ * calls.
+ */
+ old_context = MemoryContextSwitchTo(agg_context);
+ state = palloc0(sizeof(AvgAggState));
+ state->sumX = make_result(sumX_var);
+ state->sumX_size = VARSIZE(state->sumX);
+ state->N = 0;
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..fb12637 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -77,13 +77,14 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 int8_avg_accum numeric_avg 0 1231 "{0,0}" ));
+DATA(insert ( 2100 int8_avg_accum numeric_avg 0 2281 _null_ ));
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 ( 2103 numeric_avg_accum numeric_avg 0 2281 _null_ ));
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}" ));
+DATA(insert ( 3179 numeric_fadd_accum numeric_fadd 0 2281 _null_ ));
/* sum */
DATA(insert ( 2107 int8_sum - 0 1700 _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c97056e..94e5d4e 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2385,18 +2385,22 @@ DATA(insert OID = 1832 ( float8_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f
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_ ));
+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 = 3177 ( numeric_fadd_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_fadd_accum _null_ _null_ _null_ ));
+DESCR("fast sum 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_ ));
+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 t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ ));
+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 = 3188 ( numeric_fadd PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_fadd _null_ _null_ _null_ ));
+DESCR("aggregate fast sum 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_ ));
@@ -3034,7 +3038,8 @@ DATA(insert OID = 2105 ( avg PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 701 "7
DESCR("the average (arithmetic mean) as float8 of all float8 values");
DATA(insert OID = 2106 ( avg PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 1186 "1186" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
DESCR("the average (arithmetic mean) as interval of all interval values");
-
+DATA(insert OID = 3179 ( fsum PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 1700 "1700" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
+DESCR("the sum as numeric of all numeric values");
DATA(insert OID = 2107 ( sum PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 1700 "20" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
DESCR("sum as numeric across all bigint input values");
DATA(insert OID = 2108 ( sum PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 20 "23" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index c0debe4..d680367 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -949,6 +949,8 @@ extern Datum numeric_lt(PG_FUNCTION_ARGS);
extern Datum numeric_le(PG_FUNCTION_ARGS);
extern Datum numeric_add(PG_FUNCTION_ARGS);
extern Datum numeric_sub(PG_FUNCTION_ARGS);
+extern Datum numeric_fadd_accum(PG_FUNCTION_ARGS);
+extern Datum numeric_fadd(PG_FUNCTION_ARGS);
extern Datum numeric_mul(PG_FUNCTION_ARGS);
extern Datum numeric_div(PG_FUNCTION_ARGS);
extern Datum numeric_div_trunc(PG_FUNCTION_ARGS);
Hello,
I updated the patch by taking ideas from your patch, and unifying the
transition struct and update function for different aggregates. The speed
of avg improved even more. It now has 60% better performance than the
current committed version.
This patch optimizes numeric/int8 sum, avg, stddev_pop, stddev_samp,
var_pop, var_samp.
I also noticed that this patch makes matview test fail. It seems that it
just changes the ordering of rows for queries like "SELECT * FROM tv;".
Does this seem like a bug in my patch, or should we add "ORDER BY" clauses
to this test to make it more deterministic?
I also agree with you that adding sum functions to use preallocated buffers
will make even more optimization. I'll try to see if I can find a simple
way to do this.
Thanks,
-- Hadi
On Mon, Mar 18, 2013 at 5:25 PM, Pavel Stehule <pavel.stehule@gmail.com>wrote:
Show quoted text
Hello
I played with sum(numeric) optimization
Now it is based on generic numeric_add function - this code is
relative old - now we can design aggregates with internal transition
buffers, and probably we can do this work more effective.I just removed useles palloc/free operations and I got a 30% better
performance! My patch is ugly - because I used a generic add_var
function. Because Sum, Avg and almost all aggregates functions is
limited by speed of sum calculation I thing so we need a new numeric
routines optimized for calculation "sum", that use a only preallocated
buffers. A speed of numeric is more important now, because there are
more and more warehouses, where CPU is botleneck.Regards
Pavel
2013/3/18 Hadi Moshayedi <hadi@moshayedi.net>:
Hi Pavel,
Thanks a lot for your feedback.
I'll work more on this patch this week, and will send a more complete
patch
later this week.
I'll also try to see how much is the speed up of this method for other
types.Thanks,
-- HadiOn Mon, Mar 18, 2013 at 10:36 AM, Pavel Stehule <pavel.stehule@gmail.com
wrote:
2013/3/16 Hadi Moshayedi <hadi@moshayedi.net>:
Revisiting:
/messages/by-id/45661BE7.4050205@paradise.net.nzI think the reasons which the numeric average was slow were:
(1) Using Numeric for count, which is slower than int8 to increment,
(2) Constructing/deconstructing arrays at each transition step.This is also discussed at:
http://www.citusdata.com/blog/53-postgres-performance-to-avg-or-to-sum-divided-by-count
So, I think we can improve the speed of numeric average by keeping the
transition state as an struct in the aggregate context, and justpassing
the
pointer to that struct from/to the aggregate transition function.The attached patch uses this method.
I tested it using the data generated using:
CREATE TABLE avg_test AS SELECT (random() * 999)::decimal(5,2) as dFROM
generate_series(1, 10000000) s;
After applying this patch, run time of "SELECT avg(d) FROM avg_test;"
improves from 10.701 seconds to 5.204 seconds, which seems to be ahuge
improvement.
I think we may also be able to use a similar method to improve
performance
of some other numeric aggregates (like stddev). But I want to knowyour
feedback first.
Is this worth working on?
I checked this patch and it has a interesting speedup - and a price of
this methoud should not be limited to numeric type onlyPavel
Thanks,
-- Hadi--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
numeric-optimize-v2.patchapplication/octet-stream; name=numeric-optimize-v2.patchDownload
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 229b408..e8294b6 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -2464,94 +2464,122 @@ 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 ...
+ * The transition datatype for all these aggregates is a pointer to
+ * a struct NumericAggState allocated in the aggregate context.
*
* ----------------------------------------------------------------------
*/
-static ArrayType *
-do_numeric_accum(ArrayType *transarray, Numeric newval)
+typedef struct NumericAggState
+{
+ bool first;
+ bool isNaN;
+ uint64 N;
+ NumericVar sumX;
+ NumericVar sumX2;
+ bool calcSumX2;
+ MemoryContext agg_context;
+} NumericAggState;
+
+static NumericAggState *
+makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
{
- 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');
+ NumericAggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
- return result;
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ {
+ elog(ERROR, "this is called in non-aggregate context");
+ }
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = palloc0(sizeof(NumericAggState));
+ state->first = true;
+ state->calcSumX2 = calcSumX2;
+ state->agg_context = agg_context;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
}
-/*
- * Improve avg performance by not caclulating sum(X*X).
- */
-static ArrayType *
-do_numeric_avg_accum(ArrayType *transarray, Numeric newval)
+static void
+do_numeric_accum(NumericAggState *state, 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');
+ NumericVar X;
+ NumericVar X2;
+ MemoryContext old_context;
+ bool first;
+
+ first = state->first;
+ state->first = false;
+ state->N++;
+
+ if (state->isNaN || NUMERIC_IS_NAN(newval))
+ {
+ state->isNaN = true;
+ return;
+ }
- return result;
+ 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 (!first)
+ {
+ NumericVar preSumX;
+
+ 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
+ {
+ set_var_from_var(&X, &(state->sumX));
+
+ if (state->calcSumX2)
+ set_var_from_var(&X2, &(state->sumX2));
+ }
+
+ MemoryContextSwitchTo(old_context);
}
Datum
numeric_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Numeric newval = PG_GETARG_NUMERIC(1);
+ 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_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+ PG_RETURN_POINTER(state);
}
/*
@@ -2560,10 +2588,20 @@ numeric_accum(PG_FUNCTION_ARGS)
Datum
numeric_avg_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Numeric newval = PG_GETARG_NUMERIC(1);
+ NumericAggState *state;
- PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
+ 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);
}
/*
@@ -2578,37 +2616,70 @@ 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;
+ NumericAggState *state;
- newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
+ 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_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+ PG_RETURN_POINTER(state);
}
Datum
int4_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Datum newval4 = PG_GETARG_DATUM(1);
- Numeric newval;
+ NumericAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
- newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
+ 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_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+ PG_RETURN_POINTER(state);
}
Datum
int8_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Datum newval8 = PG_GETARG_DATUM(1);
- Numeric newval;
+ NumericAggState *state;
- newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
+ state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
- PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+ 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);
}
/*
@@ -2617,48 +2688,61 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Datum newval8 = PG_GETARG_DATUM(1);
- Numeric newval;
+ NumericAggState *state;
- newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
+ state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
- PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
-}
+ 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)
{
- 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]);
+ Datum N_datum;
+ Datum sumX_datum;
+ NumericAggState *state;
- /* SQL92 defines AVG of no values to be NULL */
- /* N is zero iff no digits (cf. numeric_uminus) */
- if (NUMERIC_NDIGITS(N) == 0)
+ 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();
- PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
- NumericGetDatum(sumX),
- NumericGetDatum(N)));
+ state = (NumericAggState *) PG_GETARG_POINTER(0);
+
+ PG_RETURN_NUMERIC(make_result(&(state->sumX)));
}
/*
* Workhorse routine for the standard deviance and variance
- * aggregates. 'transarray' is the aggregate's transition
- * array. 'variance' specifies whether we should calculate the
+ * 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,16 +2751,11 @@ numeric_avg(PG_FUNCTION_ARGS)
* *is_null is set to true and NULL is returned.
*/
static Numeric
-numeric_stddev_internal(ArrayType *transarray,
+numeric_stddev_internal(NumericAggState *state,
bool variance, bool sample,
bool *is_null)
{
- Datum *transdatums;
- int ndatums;
- Numeric N,
- sumX,
- sumX2,
- res;
+ Numeric res;
NumericVar vN,
vsumX,
vsumX2,
@@ -2684,22 +2763,24 @@ numeric_stddev_internal(ArrayType *transarray,
NumericVar *comp;
int rscale;
+ if (state == NULL)
+ {
+ *is_null = true;
+ return NULL;
+ }
+
*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))
+ if (state->isNaN)
return make_result(&const_nan);
- init_var_from_num(N, &vN);
+ 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,8 +2800,8 @@ 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);
+ 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,7 +2842,7 @@ numeric_var_samp(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
- res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
+ res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
true, true, &is_null);
if (is_null)
@@ -2776,7 +2857,7 @@ numeric_stddev_samp(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
- res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
+ res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
false, true, &is_null);
if (is_null)
@@ -2791,7 +2872,7 @@ numeric_var_pop(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
- res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
+ res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
true, false, &is_null);
if (is_null)
@@ -2806,7 +2887,7 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
- res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
+ res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
false, false, &is_null);
if (is_null)
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..6f4090e 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -77,23 +77,23 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 int8_avg_accum numeric_avg 0 1231 "{0,0}" ));
+DATA(insert ( 2100 int8_avg_accum numeric_avg 0 2281 _null_ ));
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 ( 2103 numeric_avg_accum numeric_avg 0 2281 _null_ ));
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 ( 2107 int8_avg_accum numeric_sum 0 2281 _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_ ));
+DATA(insert ( 2114 numeric_avg_accum numeric_sum 0 2281 _null_ ));
/* max */
DATA(insert ( 2115 int8larger - 413 20 _null_ ));
@@ -144,52 +144,52 @@ 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 ( 2718 int8_accum numeric_var_pop 0 2281 _null_ ));
+DATA(insert ( 2719 int4_accum numeric_var_pop 0 2281 _null_ ));
+DATA(insert ( 2720 int2_accum numeric_var_pop 0 2281 _null_ ));
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}" ));
+DATA(insert ( 2723 numeric_accum numeric_var_pop 0 2281 _null_ ));
/* 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 ( 2641 int8_accum numeric_var_samp 0 2281 _null_ ));
+DATA(insert ( 2642 int4_accum numeric_var_samp 0 2281 _null_ ));
+DATA(insert ( 2643 int2_accum numeric_var_samp 0 2281 _null_ ));
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}" ));
+DATA(insert ( 2646 numeric_accum numeric_var_samp 0 2281 _null_ ));
/* 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 ( 2148 int8_accum numeric_var_samp 0 2281 _null_ ));
+DATA(insert ( 2149 int4_accum numeric_var_samp 0 2281 _null_ ));
+DATA(insert ( 2150 int2_accum numeric_var_samp 0 2281 _null_ ));
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}" ));
+DATA(insert ( 2153 numeric_accum numeric_var_samp 0 2281 _null_ ));
/* 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 ( 2724 int8_accum numeric_stddev_pop 0 2281 _null_ ));
+DATA(insert ( 2725 int4_accum numeric_stddev_pop 0 2281 _null_ ));
+DATA(insert ( 2726 int2_accum numeric_stddev_pop 0 2281 _null_ ));
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}" ));
+DATA(insert ( 2729 numeric_accum numeric_stddev_pop 0 2281 _null_ ));
/* 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 ( 2712 int8_accum numeric_stddev_samp 0 2281 _null_ ));
+DATA(insert ( 2713 int4_accum numeric_stddev_samp 0 2281 _null_ ));
+DATA(insert ( 2714 int2_accum numeric_stddev_samp 0 2281 _null_ ));
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}" ));
+DATA(insert ( 2717 numeric_accum numeric_stddev_samp 0 2281 _null_ ));
/* 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 ( 2154 int8_accum numeric_stddev_samp 0 2281 _null_ ));
+DATA(insert ( 2155 int4_accum numeric_stddev_samp 0 2281 _null_ ));
+DATA(insert ( 2156 int2_accum numeric_stddev_samp 0 2281 _null_ ));
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}" ));
+DATA(insert ( 2159 numeric_accum numeric_stddev_samp 0 2281 _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 int8inc_float8_float8 - 0 20 "0" ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c97056e..8541112 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2383,27 +2383,29 @@ 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_ ));
+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 t f i 2 0 1231 "1231 1700" _null_ _null_ _null_ _null_ numeric_avg_accum _null_ _null_ _null_ ));
+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 t f i 2 0 1231 "1231 21" _null_ _null_ _null_ _null_ int2_accum _null_ _null_ _null_ ));
+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 t f i 2 0 1231 "1231 23" _null_ _null_ _null_ _null_ int4_accum _null_ _null_ _null_ ));
+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 t f i 2 0 1231 "1231 20" _null_ _null_ _null_ _null_ int8_accum _null_ _null_ _null_ ));
+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 t f i 2 0 1231 "1231 20" _null_ _null_ _null_ _null_ int8_avg_accum _null_ _null_ _null_ ));
+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 t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ ));
+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 = 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_ ));
+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 = 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_ ));
+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 = 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_ ));
+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 = 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_ ));
+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");
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index c0debe4..fb8880f 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -980,6 +980,7 @@ extern Datum int4_accum(PG_FUNCTION_ARGS);
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);
Hadi Moshayedi <hadi@moshayedi.net> wrote:
I updated the patch by taking ideas from your patch, and unifying
the transition struct and update function for different
aggregates. The speed of avg improved even more. It now has 60%
better performance than the current committed version.
Outstanding!
I also noticed that this patch makes matview test fail. It seems
that it just changes the ordering of rows for queries like
"SELECT * FROM tv;". Does this seem like a bug in my patch, or
should we add "ORDER BY" clauses to this test to make it more
deterministic?
I added some ORDER BY clauses. That is probably a good thing
anyway for purposes of code coverage. Does that fix it for you?
--
Kevin Grittner
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/3/19 Kevin Grittner <kgrittn@ymail.com>:
Hadi Moshayedi <hadi@moshayedi.net> wrote:
I updated the patch by taking ideas from your patch, and unifying
the transition struct and update function for different
aggregates. The speed of avg improved even more. It now has 60%
better performance than the current committed version.Outstanding!
I did some tests ala OLAP queries and I am thinking so ~ 40% speedup
for queries with AVG is realistic. Depends on other conditions.
But there are lot of situation when data are in shared buffers or file
system memory and then this patch can carry significant speedup - and
probably can be better if some better algorithm for sum two numeric
numbers in aggregate.
Regards
Pavel
I also noticed that this patch makes matview test fail. It seems
that it just changes the ordering of rows for queries like
"SELECT * FROM tv;". Does this seem like a bug in my patch, or
should we add "ORDER BY" clauses to this test to make it more
deterministic?I added some ORDER BY clauses. That is probably a good thing
anyway for purposes of code coverage. Does that fix it for you?--
Kevin Grittner
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
Kevin Grittner <kgrittn@ymail.com> writes:
Hadi Moshayedi <hadi@moshayedi.net> wrote:
I also noticed that this patch makes matview test fail. It seems
that it just changes the ordering of rows for queries like
"SELECT * FROM tv;". Does this seem like a bug in my patch, or
should we add "ORDER BY" clauses to this test to make it more
deterministic?
I added some ORDER BY clauses.� That is probably a good thing
anyway for purposes of code coverage.� Does that fix it for you?
Uh, what? Fooling around with the implementation of avg() should surely
not change any planning decisions.
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
I am not sure how this works, but I also changed numeric sum(), and the
views in question had a numeric sum() column. Can that have any impact?
I am going to dig deeper to see why this happens.
On Tue, Mar 19, 2013 at 6:25 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Show quoted text
Kevin Grittner <kgrittn@ymail.com> writes:
Hadi Moshayedi <hadi@moshayedi.net> wrote:
I also noticed that this patch makes matview test fail. It seems
that it just changes the ordering of rows for queries like
"SELECT * FROM tv;". Does this seem like a bug in my patch, or
should we add "ORDER BY" clauses to this test to make it more
deterministic?I added some ORDER BY clauses. That is probably a good thing
anyway for purposes of code coverage. Does that fix it for you?Uh, what? Fooling around with the implementation of avg() should surely
not change any planning decisions.regards, tom lane
[ please do not top-reply ]
Hadi Moshayedi <hadi@moshayedi.net> writes:
On Tue, Mar 19, 2013 at 6:25 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Uh, what? Fooling around with the implementation of avg() should surely
not change any planning decisions.
I am not sure how this works, but I also changed numeric sum(), and the
views in question had a numeric sum() column. Can that have any impact?
[ looks at patch... ] Oh, I see what's affecting the plan: you changed
the aggtranstypes to internal for a bunch of aggregates. That's not
very good, because right now the planner takes that to mean that the
aggregate could eat a lot of space. We don't want that to happen for
these aggregates, I think.
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
I wrote:
[ looks at patch... ] Oh, I see what's affecting the plan: you changed
the aggtranstypes to internal for a bunch of aggregates. That's not
very good, because right now the planner takes that to mean that the
aggregate could eat a lot of space. We don't want that to happen for
these aggregates, I think.
After thinking about that for awhile: if we pursue this type of
optimization, what would probably be appropriate is to add an aggregate
property (stored in pg_aggregate) that allows direct specification of
the size that the planner should assume for the aggregate's transition
value. We were getting away with a hardwired assumption of 8K for
"internal" because the existing aggregates that used that transtype all
had similar properties, but it was always really a band-aid not a proper
solution. A per-aggregate override could be useful in other cases too.
This was looking like 9.4 material already, but adding such a property
would definitely put it over the top of what we could think about
squeezing into 9.3, IMO.
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
Hello
2013/3/19 Tom Lane <tgl@sss.pgh.pa.us>:
I wrote:
[ looks at patch... ] Oh, I see what's affecting the plan: you changed
the aggtranstypes to internal for a bunch of aggregates. That's not
very good, because right now the planner takes that to mean that the
aggregate could eat a lot of space. We don't want that to happen for
these aggregates, I think.After thinking about that for awhile: if we pursue this type of
optimization, what would probably be appropriate is to add an aggregate
property (stored in pg_aggregate) that allows direct specification of
the size that the planner should assume for the aggregate's transition
value. We were getting away with a hardwired assumption of 8K for
"internal" because the existing aggregates that used that transtype all
had similar properties, but it was always really a band-aid not a proper
solution. A per-aggregate override could be useful in other cases too.This was looking like 9.4 material already, but adding such a property
would definitely put it over the top of what we could think about
squeezing into 9.3, IMO.
Postgres is not a "in memory" OLAP database, but lot of companies use
it for OLAP queries due pg comfortable usage. This feature can be very
interesting for these users - and can introduce interesting speedup
with relative low price.
Regards
Pavel
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
Hi Tom,
Tom Lane <tgl@sss.pgh.pa.us> wrote:
After thinking about that for awhile: if we pursue this type of
optimization, what would probably be appropriate is to add an aggregate
property (stored in pg_aggregate) that allows direct specification of
the size that the planner should assume for the aggregate's transition
value. We were getting away with a hardwired assumption of 8K for
"internal" because the existing aggregates that used that transtype all
had similar properties, but it was always really a band-aid not a proper
solution. A per-aggregate override could be useful in other cases too.
Cool.
I created a patch which adds an aggregate property to pg_aggregate, so
the transition space is can be overridden. This patch doesn't contain
the numeric optimizations. It uses "0" (meaning not-set) for all
existing aggregates.
I manual-tested it a bit, by changing this value for aggregates and
observing the changes in plan. I also updated some docs and pg_dump.
Does this look like something along the lines of what you meant?
Thanks,
-- Hadi
Attachments:
aggregate-transspace.patchapplication/octet-stream; name=aggregate-transspace.patchDownload
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 6c0ef5b..4b752d6 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -373,6 +373,12 @@
<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><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></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>
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index d5e4e27..594d095 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -24,6 +24,7 @@ PostgreSQL documentation
CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_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,6 +36,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
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> ]
@@ -241,6 +243,18 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
</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>
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index e80b600..d08e14a 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -51,6 +51,7 @@ AggregateCreate(const char *aggName,
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
+ int32 aggTransSpace,
const char *agginitval)
{
Relation aggdesc;
@@ -269,6 +270,7 @@ AggregateCreate(const char *aggName,
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
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index d34a102..6e5446a 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -62,6 +62,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
Oid *aggArgTypes;
int numArgs;
Oid transTypeId;
+ int32 transSpace = 0;
char transTypeType;
ListCell *pl;
@@ -96,6 +97,8 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
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)
@@ -225,5 +228,6 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
finalfuncName, /* final function name */
sortoperatorName, /* sort operator name */
transTypeId, /* transition data type */
+ transSpace, /* transition space */
initval); /* initial condition */
}
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 9fa222f..75f77da 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -165,6 +165,30 @@ defGetBoolean(DefElem *def)
}
/*
+ * 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
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 657a18b..b5e2c01 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -461,6 +461,7 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
Oid aggtransfn;
Oid aggfinalfn;
Oid aggtranstype;
+ int32 aggtransspace;
QualCost argcosts;
Oid *inputTypes;
int numArguments;
@@ -478,6 +479,7 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
aggtransfn = aggform->aggtransfn;
aggfinalfn = aggform->aggfinalfn;
aggtranstype = aggform->aggtranstype;
+ aggtransspace = aggform->aggtransspace;
ReleaseSysCache(aggTuple);
/* count it */
@@ -524,13 +526,21 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
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.
*/
- if (!get_typbyval(aggtranstype))
+ else if (!get_typbyval(aggtranstype))
{
int32 aggtranstypmod;
int32 avgwidth;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 9458429..fd04c54 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -11268,12 +11268,14 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
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;
@@ -11291,12 +11293,24 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
/* Get aggregate-specific details */
- if (fout->remoteVersion >= 80100)
+ if (fout->remoteVersion >= 90300)
+ {
+ appendPQExpBuffer(query, "SELECT aggtransfn, "
+ "aggfinalfn, aggtranstype::pg_catalog.regtype, "
+ "aggsortop::pg_catalog.regoperator, "
+ "aggtransspace, agginitval, "
+ "'t'::boolean AS convertok "
+ "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 >= 80100)
{
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
- "agginitval, "
+ "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
@@ -11308,7 +11322,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"0 AS aggsortop, "
- "agginitval, "
+ "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
@@ -11320,7 +11334,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
"format_type(aggtranstype, NULL) AS aggtranstype, "
"0 AS aggsortop, "
- "agginitval, "
+ "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
@@ -11332,7 +11346,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
"aggfinalfn, "
"(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
"0 AS aggsortop, "
- "agginitval1 AS agginitval, "
+ "0 AS aggtransspace, agginitval1 AS agginitval, "
"(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
@@ -11345,6 +11359,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
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");
@@ -11352,6 +11367,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
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');
@@ -11388,6 +11404,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
fmtId(aggtranstype));
}
+ if (strcmp(aggtransspace, "0") != 0)
+ {
+ appendPQExpBuffer(details, ",\n SSPACE = %s",
+ aggtransspace);
+ }
+
if (!PQgetisnull(res, 0, i_agginitval))
{
appendPQExpBuffer(details, ",\n INITCOND = ");
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..65ab160 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -32,6 +32,7 @@
* aggfinalfn final function (0 if none)
* aggsortop associated sort operator (0 if none)
* aggtranstype type of aggregate's transition (state) data
+ * aggtransspace approximate size of aggregate transition state
* agginitval initial value for transition state (can be NULL)
* ----------------------------------------------------------------
*/
@@ -44,6 +45,7 @@ CATALOG(pg_aggregate,2600) BKI_WITHOUT_OIDS
regproc aggfinalfn;
Oid aggsortop;
Oid aggtranstype;
+ int32 aggtransspace;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
text agginitval;
@@ -62,13 +64,14 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
* ----------------
*/
-#define Natts_pg_aggregate 6
+#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_agginitval 6
+#define Anum_pg_aggregate_aggtransspace 6
+#define Anum_pg_aggregate_agginitval 7
/* ----------------
@@ -77,163 +80,163 @@ 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}" ));
+DATA(insert ( 2100 int8_avg_accum numeric_avg 0 1231 0 "{0,0}" ));
+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 1231 0 "{0,0}" ));
+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_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_ ));
+DATA(insert ( 2107 int8_sum - 0 1700 0 _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_add - 0 1700 0 _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_ ));
+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 _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_ ));
+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" ));
-DATA(insert ( 2803 int8inc - 0 20 "0" ));
+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 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}" ));
+DATA(insert ( 2718 int8_accum numeric_var_pop 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2719 int4_accum numeric_var_pop 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2720 int2_accum numeric_var_pop 0 1231 0 "{0,0,0}" ));
+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 1231 0 "{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}" ));
+DATA(insert ( 2641 int8_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2642 int4_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2643 int2_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
+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 1231 0 "{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}" ));
+DATA(insert ( 2148 int8_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2149 int4_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2150 int2_accum numeric_var_samp 0 1231 0 "{0,0,0}" ));
+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 1231 0 "{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}" ));
+DATA(insert ( 2724 int8_accum numeric_stddev_pop 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2725 int4_accum numeric_stddev_pop 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2726 int2_accum numeric_stddev_pop 0 1231 0 "{0,0,0}" ));
+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 1231 0 "{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}" ));
+DATA(insert ( 2712 int8_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2713 int4_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2714 int2_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
+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 1231 0 "{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}" ));
+DATA(insert ( 2154 int8_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2155 int4_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
+DATA(insert ( 2156 int2_accum numeric_stddev_samp 0 1231 0 "{0,0,0}" ));
+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 1231 0 "{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}" ));
+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 _null_ ));
-DATA(insert ( 2518 boolor_statefunc - 59 16 _null_ ));
-DATA(insert ( 2519 booland_statefunc - 58 16 _null_ ));
+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 _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_ ));
+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 _null_ ));
+DATA(insert ( 2901 xmlconcat2 - 0 142 0 _null_ ));
/* array */
-DATA(insert ( 2335 array_agg_transfn array_agg_finalfn 0 2281 _null_ ));
+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 _null_ ));
+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 _null_ ));
+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 _null_ ));
+DATA(insert ( 3175 json_agg_transfn json_agg_finalfn 0 2281 0 _null_ ));
/*
* prototypes for functions in pg_aggregate.c
@@ -246,6 +249,7 @@ extern Oid AggregateCreate(const char *aggName,
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
+ int32 aggTransSpace,
const char *agginitval);
#endif /* PG_AGGREGATE_H */
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 62515b2..3abc89b 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -122,6 +122,7 @@ extern Datum transformGenericOptions(Oid catalogId,
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);
Hello
2013/3/20 Hadi Moshayedi <hadi@moshayedi.net>:
Hi Tom,
Tom Lane <tgl@sss.pgh.pa.us> wrote:
After thinking about that for awhile: if we pursue this type of
optimization, what would probably be appropriate is to add an aggregate
property (stored in pg_aggregate) that allows direct specification of
the size that the planner should assume for the aggregate's transition
value. We were getting away with a hardwired assumption of 8K for
"internal" because the existing aggregates that used that transtype all
had similar properties, but it was always really a band-aid not a proper
solution. A per-aggregate override could be useful in other cases too.Cool.
I created a patch which adds an aggregate property to pg_aggregate, so
the transition space is can be overridden. This patch doesn't contain
the numeric optimizations. It uses "0" (meaning not-set) for all
existing aggregates.I manual-tested it a bit, by changing this value for aggregates and
observing the changes in plan. I also updated some docs and pg_dump.Does this look like something along the lines of what you meant?
please, can you subscribe your patch to next commitfest?
I tested this patch, and it increase performance about 20% what is
interesting. More - it allows more comfortable custom aggregates for
custom types with better hash agg support.
Regards
Pavel
Thanks,
-- Hadi
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
I am attaching the updated the patch, which also fixes a bug which
caused one of the regression tests failed.
I'll subscribe this patch to the commitfest in the next hour.
Can you please review the patch?
Thanks,
-- Hadi
Attachments:
numeric-optimize-v3.patchapplication/octet-stream; name=numeric-optimize-v3.patchDownload
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 6715782..1fae7db 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -373,6 +373,12 @@
<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>
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index d5e4e27..594d095 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -24,6 +24,7 @@ PostgreSQL documentation
CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> ( <replaceable class="PARAMETER">input_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,6 +36,7 @@ CREATE AGGREGATE <replaceable class="PARAMETER">name</replaceable> (
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> ]
@@ -241,6 +243,18 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
</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>
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index e80b600..d08e14a 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -51,6 +51,7 @@ AggregateCreate(const char *aggName,
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
+ int32 aggTransSpace,
const char *agginitval)
{
Relation aggdesc;
@@ -269,6 +270,7 @@ AggregateCreate(const char *aggName,
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
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4a03786..656bf7a 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -62,6 +62,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
Oid *aggArgTypes;
int numArgs;
Oid transTypeId;
+ int32 transSpace = 0;
char transTypeType;
ListCell *pl;
@@ -96,6 +97,8 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
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)
@@ -225,5 +228,6 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
finalfuncName, /* final function name */
sortoperatorName, /* sort operator name */
transTypeId, /* transition data type */
+ transSpace, /* transition space */
initval); /* initial condition */
}
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 9fa222f..75f77da 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -165,6 +165,30 @@ defGetBoolean(DefElem *def)
}
/*
+ * 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
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 6d5b204..5d8f56d 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -461,6 +461,7 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
Oid aggtransfn;
Oid aggfinalfn;
Oid aggtranstype;
+ int32 aggtransspace;
QualCost argcosts;
Oid *inputTypes;
int numArguments;
@@ -478,6 +479,7 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
aggtransfn = aggform->aggtransfn;
aggfinalfn = aggform->aggfinalfn;
aggtranstype = aggform->aggtranstype;
+ aggtransspace = aggform->aggtransspace;
ReleaseSysCache(aggTuple);
/* count it */
@@ -524,13 +526,21 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context)
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.
*/
- if (!get_typbyval(aggtranstype))
+ else if (!get_typbyval(aggtranstype))
{
int32 aggtranstypmod;
int32 avgwidth;
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index b4d6394..9a4706b 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -2464,108 +2464,157 @@ 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 ...
+ * The transition datatype for all these aggregates is a pointer to
+ * a struct NumericAggState allocated in the aggregate context.
*
* ----------------------------------------------------------------------
*/
-static ArrayType *
-do_numeric_accum(ArrayType *transarray, Numeric newval)
+typedef struct NumericAggState
+{
+ bool first;
+ bool isNaN;
+ uint64 N;
+ NumericVar sumX;
+ NumericVar sumX2;
+ bool calcSumX2;
+ MemoryContext agg_context;
+} NumericAggState;
+
+
+static NumericAggState *
+makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
{
- 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');
+ NumericAggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
- return result;
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ {
+ elog(ERROR, "this is called in non-aggregate context");
+ }
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = palloc0(sizeof(NumericAggState));
+ state->first = true;
+ state->calcSumX2 = calcSumX2;
+ state->agg_context = agg_context;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
}
-/*
- * Improve avg performance by not caclulating sum(X*X).
- */
-static ArrayType *
-do_numeric_avg_accum(ArrayType *transarray, Numeric newval)
+
+static void
+do_numeric_accum(NumericAggState *state, 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');
+ NumericVar X;
+ NumericVar X2;
+ MemoryContext old_context;
+ bool first;
+
+ first = state->first;
+ state->first = false;
+ state->N++;
+
+ if (state->isNaN || NUMERIC_IS_NAN(newval))
+ {
+ state->isNaN = true;
+ return;
+ }
- return result;
+ 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 (!first)
+ {
+ NumericVar preSumX;
+
+ 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
+ {
+ set_var_from_var(&X, &(state->sumX));
+
+ if (state->calcSumX2)
+ set_var_from_var(&X2, &(state->sumX2));
+ }
+
+ MemoryContextSwitchTo(old_context);
}
+
Datum
numeric_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Numeric newval = PG_GETARG_NUMERIC(1);
+ NumericAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
- PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+ 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 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);
+ NumericAggState *state;
- PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
+ 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,87 +2627,150 @@ 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;
+ NumericAggState *state;
- newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
+ state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
- PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+ 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)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Datum newval4 = PG_GETARG_DATUM(1);
- Numeric newval;
+ NumericAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
- newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
+ 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_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
+ if (state == NULL)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_POINTER(state);
}
+
Datum
int8_accum(PG_FUNCTION_ARGS)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Datum newval8 = PG_GETARG_DATUM(1);
- Numeric newval;
+ NumericAggState *state;
- newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
+ 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_ARRAYTYPE_P(do_numeric_accum(transarray, 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)
{
- ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- Datum newval8 = PG_GETARG_DATUM(1);
- Numeric newval;
-
- newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
+ NumericAggState *state;
+ state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
- PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
+ 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)
{
- 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]);
+ Datum N_datum;
+ Datum sumX_datum;
+ NumericAggState *state;
- /* SQL defines AVG of no values to be NULL */
- /* N is zero iff no digits (cf. numeric_uminus) */
- if (NUMERIC_NDIGITS(N) == 0)
+ if (PG_ARGISNULL(0))
PG_RETURN_NULL();
- PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
- NumericGetDatum(sumX),
- NumericGetDatum(N)));
+ 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. 'transarray' is the aggregate's transition
- * array. 'variance' specifies whether we should calculate the
+ * 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,16 +2779,11 @@ numeric_avg(PG_FUNCTION_ARGS)
* *is_null is set to true and NULL is returned.
*/
static Numeric
-numeric_stddev_internal(ArrayType *transarray,
+numeric_stddev_internal(NumericAggState *state,
bool variance, bool sample,
bool *is_null)
{
- Datum *transdatums;
- int ndatums;
- Numeric N,
- sumX,
- sumX2,
- res;
+ Numeric res;
NumericVar vN,
vsumX,
vsumX2,
@@ -2684,22 +2791,24 @@ numeric_stddev_internal(ArrayType *transarray,
NumericVar *comp;
int rscale;
+ if (state == NULL)
+ {
+ *is_null = true;
+ return NULL;
+ }
+
*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))
+ if (state->isNaN)
return make_result(&const_nan);
- init_var_from_num(N, &vN);
+ 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,8 +2828,8 @@ 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);
+ 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,7 +2870,7 @@ numeric_var_samp(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
- res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
+ res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
true, true, &is_null);
if (is_null)
@@ -2776,7 +2885,7 @@ numeric_stddev_samp(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
- res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
+ res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
false, true, &is_null);
if (is_null)
@@ -2791,7 +2900,7 @@ numeric_var_pop(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
- res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
+ res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
true, false, &is_null);
if (is_null)
@@ -2806,7 +2915,7 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
Numeric res;
bool is_null;
- res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
+ res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0),
false, false, &is_null);
if (is_null)
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index f40961f..ff71eca 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -11402,12 +11402,14 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
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;
@@ -11425,12 +11427,24 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
/* Get aggregate-specific details */
- if (fout->remoteVersion >= 80100)
+ if (fout->remoteVersion >= 90300)
+ {
+ appendPQExpBuffer(query, "SELECT aggtransfn, "
+ "aggfinalfn, aggtranstype::pg_catalog.regtype, "
+ "aggsortop::pg_catalog.regoperator, "
+ "aggtransspace, agginitval, "
+ "'t'::boolean AS convertok "
+ "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 >= 80100)
{
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"aggsortop::pg_catalog.regoperator, "
- "agginitval, "
+ "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
@@ -11442,7 +11456,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, "
"aggfinalfn, aggtranstype::pg_catalog.regtype, "
"0 AS aggsortop, "
- "agginitval, "
+ "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
"WHERE a.aggfnoid = p.oid "
@@ -11454,7 +11468,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
"format_type(aggtranstype, NULL) AS aggtranstype, "
"0 AS aggsortop, "
- "agginitval, "
+ "0 AS aggtransspace, agginitval, "
"'t'::boolean AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
@@ -11466,7 +11480,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
"aggfinalfn, "
"(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
"0 AS aggsortop, "
- "agginitval1 AS agginitval, "
+ "0 AS aggtransspace, agginitval1 AS agginitval, "
"(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
"FROM pg_aggregate "
"WHERE oid = '%u'::oid",
@@ -11479,6 +11493,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
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");
@@ -11486,6 +11501,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
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');
@@ -11522,6 +11538,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
fmtId(aggtranstype));
}
+ if (strcmp(aggtransspace, "0") != 0)
+ {
+ appendPQExpBuffer(details, ",\n SSPACE = %s",
+ aggtransspace);
+ }
+
if (!PQgetisnull(res, 0, i_agginitval))
{
appendPQExpBuffer(details, ",\n INITCOND = ");
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 6fb10a9..385c906 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -44,6 +44,7 @@ CATALOG(pg_aggregate,2600) BKI_WITHOUT_OIDS
regproc aggfinalfn;
Oid aggsortop;
Oid aggtranstype;
+ int32 aggtransspace;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
text agginitval;
@@ -62,13 +63,14 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
* ----------------
*/
-#define Natts_pg_aggregate 6
+#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_agginitval 6
+#define Anum_pg_aggregate_aggtransspace 6
+#define Anum_pg_aggregate_agginitval 7
/* ----------------
@@ -77,163 +79,163 @@ 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}" ));
+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_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_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_ ));
+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 _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_ ));
+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 _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_ ));
+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" ));
-DATA(insert ( 2803 int8inc - 0 20 "0" ));
+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 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}" ));
+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 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}" ));
+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 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}" ));
+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 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}" ));
+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 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}" ));
+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 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}" ));
+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" ));
-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}" ));
+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 _null_ ));
-DATA(insert ( 2518 boolor_statefunc - 59 16 _null_ ));
-DATA(insert ( 2519 booland_statefunc - 58 16 _null_ ));
+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 _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_ ));
+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 _null_ ));
+DATA(insert ( 2901 xmlconcat2 - 0 142 0 _null_ ));
/* array */
-DATA(insert ( 2335 array_agg_transfn array_agg_finalfn 0 2281 _null_ ));
+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 _null_ ));
+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 _null_ ));
+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 _null_ ));
+DATA(insert ( 3175 json_agg_transfn json_agg_finalfn 0 2281 0 _null_ ));
/*
* prototypes for functions in pg_aggregate.c
@@ -246,6 +248,7 @@ extern Oid AggregateCreate(const char *aggName,
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
+ int32 aggTransSpace,
const char *agginitval);
#endif /* PG_AGGREGATE_H */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 90aff3d..b413e60 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2381,27 +2381,29 @@ 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_ ));
+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 t f i 2 0 1231 "1231 1700" _null_ _null_ _null_ _null_ numeric_avg_accum _null_ _null_ _null_ ));
+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 t f i 2 0 1231 "1231 21" _null_ _null_ _null_ _null_ int2_accum _null_ _null_ _null_ ));
+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 t f i 2 0 1231 "1231 23" _null_ _null_ _null_ _null_ int4_accum _null_ _null_ _null_ ));
+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 t f i 2 0 1231 "1231 20" _null_ _null_ _null_ _null_ int8_accum _null_ _null_ _null_ ));
+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 t f i 2 0 1231 "1231 20" _null_ _null_ _null_ _null_ int8_avg_accum _null_ _null_ _null_ ));
+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 t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ ));
+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 = 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_ ));
+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 = 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_ ));
+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 = 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_ ));
+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 = 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_ ));
+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");
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index fa9f41f..7ccb656 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -122,6 +122,7 @@ extern Datum transformGenericOptions(Oid catalogId,
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);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 667c58b..9e3ef1c 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -981,6 +981,7 @@ extern Datum int4_accum(PG_FUNCTION_ARGS);
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);
2013/7/8 Hadi Moshayedi <hadi@moshayedi.net>:
I am attaching the updated the patch, which also fixes a bug which
caused one of the regression tests failed.I'll subscribe this patch to the commitfest in the next hour.
Can you please review the patch?
sure, :)
Pavel
Thanks,
-- Hadi
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hello
I am testing your code, and It increase speed of sum about 24% faster
then original implementation.
But I am surprise of AVG speed - it should have same speed like sum in
new implementation, but it is 2x slower, than sum - what signalize
some strange and there is used wrong transition function
I am sending fixed version
postgres=# create table bubu(a int, b float, c numeric);
CREATE TABLE
postgres=# insert into bubu select i, i+1, i+1.122 from
generate_series(1,1000000) g(i);
INSERT 0 1000000
After fixing a speed of sum and avg for numeric is similar
postgres=# select avg(c) from bubu;
avg
---------------------
500001.622000000000
(1 row)
Time: 228.483 ms
postgres=# select sum(c) from bubu;
sum
------------------
500001622000.000
(1 row)
Time: 222.791 ms
Regards
Pavel
2013/7/8 Hadi Moshayedi <hadi@moshayedi.net>:
Show quoted text
I am attaching the updated the patch, which also fixes a bug which
caused one of the regression tests failed.I'll subscribe this patch to the commitfest in the next hour.
Can you please review the patch?
Thanks,
-- Hadi
Attachments:
numeric-optimize-v4.patchapplication/octet-stream; name=numeric-optimize-v4.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">input_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> ]
***************
*** 241,246 **** SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
--- 243,260 ----
</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
***************
*** 51,56 **** AggregateCreate(const char *aggName,
--- 51,57 ----
List *aggfinalfnName,
List *aggsortopName,
Oid aggTransType,
+ int32 aggTransSpace,
const char *agginitval)
{
Relation aggdesc;
***************
*** 269,274 **** AggregateCreate(const char *aggName,
--- 270,276 ----
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
***************
*** 62,67 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
--- 62,68 ----
Oid *aggArgTypes;
int numArgs;
Oid transTypeId;
+ int32 transSpace = 0;
char transTypeType;
ListCell *pl;
***************
*** 96,101 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
--- 97,104 ----
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)
***************
*** 225,229 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
--- 228,233 ----
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 */
***************
*** 524,536 **** 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;
--- 526,546 ----
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,2620 ----
*
* 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 first;
! bool isNaN;
! uint64 N;
! NumericVar sumX;
! NumericVar sumX2;
! bool calcSumX2;
! MemoryContext agg_context;
! } NumericAggState;
!
!
! static NumericAggState *
! makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
{
! NumericAggState *state;
! MemoryContext agg_context;
! MemoryContext old_context;
! if (!AggCheckCallContext(fcinfo, &agg_context))
! {
! elog(ERROR, "this is called in non-aggregate context");
! }
!
! old_context = MemoryContextSwitchTo(agg_context);
!
! state = palloc0(sizeof(NumericAggState));
! state->first = true;
! state->calcSumX2 = calcSumX2;
! state->agg_context = agg_context;
!
! MemoryContextSwitchTo(old_context);
!
! return state;
}
!
! static void
! do_numeric_accum(NumericAggState *state, Numeric newval)
{
! NumericVar X;
! NumericVar X2;
! MemoryContext old_context;
! bool first;
!
! first = state->first;
! state->first = false;
! state->N++;
!
! if (state->isNaN || NUMERIC_IS_NAN(newval))
! {
! state->isNaN = true;
! return;
! }
! 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 (!first)
! {
! NumericVar preSumX;
!
! 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
! {
! set_var_from_var(&X, &(state->sumX));
!
! if (state->calcSumX2)
! set_var_from_var(&X2, &(state->sumX2));
! }
!
! MemoryContextSwitchTo(old_context);
}
+
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 case for average of numeric.
*/
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.
--- 2627,2776 ----
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,
--- 2779,2789 ----
* *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
--- 2791,2814 ----
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;
--- 2828,2835 ----
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)
--- 2870,2876 ----
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)
--- 2885,2891 ----
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)
--- 2900,2906 ----
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)
--- 2915,2921 ----
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
***************
*** 11402,11413 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11402,11415 ----
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;
***************
*** 11425,11436 **** dumpAgg(Archive *fout, AggInfo *agginfo)
selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
/* Get aggregate-specific details */
! if (fout->remoteVersion >= 80100)
{
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 "
--- 11427,11450 ----
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 "
! "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 >= 80100)
{
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 "
***************
*** 11442,11448 **** 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 "
--- 11456,11462 ----
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 "
***************
*** 11454,11460 **** 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",
--- 11468,11474 ----
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",
***************
*** 11466,11472 **** 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",
--- 11480,11486 ----
"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",
***************
*** 11479,11484 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11493,11499 ----
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");
***************
*** 11486,11491 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11501,11507 ----
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');
***************
*** 11522,11527 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 11538,11549 ----
fmtId(aggtranstype));
}
+ if (strcmp(aggtransspace, "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
***************
*** 246,251 **** extern Oid AggregateCreate(const char *aggName,
--- 248,254 ----
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
***************
*** 122,127 **** extern Datum transformGenericOptions(Oid catalogId,
--- 122,128 ----
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
***************
*** 981,986 **** extern Datum int4_accum(PG_FUNCTION_ARGS);
--- 981,987 ----
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);
On 07/07/2013 09:14 PM, Hadi Moshayedi wrote:
I am attaching the updated the patch, which also fixes a bug which
caused one of the regression tests failed.I'll subscribe this patch to the commitfest in the next hour.
Can you please review the patch?
I'm afraid that, since this patch wasn't included anywhere near the
first week of the CommitFest, I can't possibly include it in the June
commitfest now. Accordingly, I have moved it to the September
commitfest. Hopefully someone can look at it before then.
Sorry for missing this in my "patch sweep" at the beginning of the CF.
Searching email for patches is, at best, inexact.
--
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Import Notes
Reply to msg id not found: WMac14ad23339656fbe619daebddebd2097b5a10bd665e49f4e6c9f6433d7e38ff7bf21ca3f59c74535435bc1a7918fd38@asav-3.01.com
Hello
2013/7/8 Josh Berkus <josh@agliodbs.com>:
On 07/07/2013 09:14 PM, Hadi Moshayedi wrote:
I am attaching the updated the patch, which also fixes a bug which
caused one of the regression tests failed.I'll subscribe this patch to the commitfest in the next hour.
Can you please review the patch?
I'm afraid that, since this patch wasn't included anywhere near the
first week of the CommitFest, I can't possibly include it in the June
commitfest now. Accordingly, I have moved it to the September
commitfest. Hopefully someone can look at it before then.Sorry for missing this in my "patch sweep" at the beginning of the CF.
Searching email for patches is, at best, inexact.
sure, it should be in September CF. It is relative simple patch
without global impacts. But I like it, it increase speed for
sum(numeric) about 25% and avg(numeric) about 50%
Regards
Pavel
--
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Pavel,
sure, it should be in September CF. It is relative simple patch
without global impacts. But I like it, it increase speed for
sum(numeric) about 25% and avg(numeric) about 50%
Do you think you could give this a review after CF1 ends, but before
September? I hate to make Hadi wait just because I didn't see his patch.
--
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Import Notes
Reply to msg id not found: WM24c8624bee50309fb076fb289c76d889d8e050e14bb1847c9f22a51deaa89c8cfd764171e1e4ca8d63ec90d86dab84e6@asav-2.01.com
2013/7/8 Josh Berkus <josh@agliodbs.com>:
Pavel,
sure, it should be in September CF. It is relative simple patch
without global impacts. But I like it, it increase speed for
sum(numeric) about 25% and avg(numeric) about 50%Do you think you could give this a review after CF1 ends, but before
September? I hate to make Hadi wait just because I didn't see his patch.
yes, I can.
Regards
Pavel
--
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hello
here is a rebased patch. Hadi, please, can verify this version?
Regards
Pavel
p.s. Performance tests
postgres=# create table foo(a int, b float, c double precision, d numeric,
gr int);
CREATE TABLE
postgres=#
postgres=# insert into foo select 1, 2.0, 3.0, 3.14, random()*10000 from
generate_series(1,10000000);
postgres=# \d foo
Table "public.foo"
Column | Type | Modifiers
--------+------------------+-----------
a | integer |
b | double precision |
c | double precision |
d | numeric |
gr | integer |
set work_mem to '2MB';
postgres=# show debug_assertions;
debug_assertions
------------------
off
(1 row)
postgres=# explain (analyze, timing off) select sum(a) from foo;
QUERY
PLAN
---------------------------------------------------------------------------------------------------
Aggregate (cost=208332.23..208332.24 rows=1 width=4) (actual rows=1
loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=4) (actual
rows=10000000 loops=1)
Total runtime: 1210.321 ms (1195.117 ms) -- patched (original)
(3 rows)
Time: 1210.709 ms
postgres=# explain (analyze, timing off) select sum(a) from foo group by gr;
QUERY
PLAN
---------------------------------------------------------------------------------------------------
HashAggregate (cost=233331.87..233431.71 rows=9984 width=8) (actual
rows=10001 loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=8) (actual
rows=10000000 loops=1)
Total runtime: 2923.987 ms (2952.292 ms)
(3 rows)
Time: 2924.384 ms
postgres=# explain (analyze, timing off) select avg(a) from foo;
QUERY
PLAN
---------------------------------------------------------------------------------------------------
Aggregate (cost=208332.23..208332.24 rows=1 width=4) (actual rows=1
loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=4) (actual
rows=10000000 loops=1)
Total runtime: 1331.627 ms (1312.140 ms)
(3 rows)
postgres=# explain (analyze, timing off) select avg(a) from foo group by gr;
QUERY
PLAN
---------------------------------------------------------------------------------------------------
HashAggregate (cost=233331.87..233456.67 rows=9984 width=8) (actual
rows=10001 loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=8) (actual
rows=10000000 loops=1)
Total runtime: 3139.296 ms (3079.479 ms)
(3 rows)
postgres=# explain (analyze, timing off) select sum(b) from foo;
QUERY
PLAN
---------------------------------------------------------------------------------------------------
Aggregate (cost=208332.23..208332.24 rows=1 width=8) (actual rows=1
loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=8) (actual
rows=10000000 loops=1)
Total runtime: 1327.841 ms (1339.214 ms)
(3 rows)
postgres=# explain (analyze, timing off) select sum(b) from foo group by gr;
QUERY
PLAN
----------------------------------------------------------------------------------------------------
HashAggregate (cost=233331.87..233431.71 rows=9984 width=12) (actual
rows=10001 loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=12)
(actual rows=10000000 loops=1)
Total runtime: 3047.893 ms (3095.591 ms)
(3 rows)
postgres=# explain (analyze, timing off) select avg(b) from foo;
QUERY
PLAN
---------------------------------------------------------------------------------------------------
Aggregate (cost=208332.23..208332.24 rows=1 width=8) (actual rows=1
loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=8) (actual
rows=10000000 loops=1)
Total runtime: 1454.665 ms (1471.413 ms)
(3 rows)
postgres=# explain (analyze, timing off) select avg(b) from foo group by gr;
QUERY
PLAN
----------------------------------------------------------------------------------------------------
HashAggregate (cost=233331.87..233456.67 rows=9984 width=12) (actual
rows=10001 loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=12)
(actual rows=10000000 loops=1)
Total runtime: 3282.838 ms (3187.157 ms)
(3 rows)
postgres=# explain (analyze, timing off) select sum(c) from foo;
QUERY
PLAN
---------------------------------------------------------------------------------------------------
Aggregate (cost=208332.23..208332.24 rows=1 width=8) (actual rows=1
loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=8) (actual
rows=10000000 loops=1)
Total runtime: 1348.555 ms (1364.585 ms)
(3 rows)
postgres=# explain (analyze, timing off) select sum(c) from foo group by gr;
QUERY
PLAN
----------------------------------------------------------------------------------------------------
HashAggregate (cost=233331.87..233431.71 rows=9984 width=12) (actual
rows=10001 loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=12)
(actual rows=10000000 loops=1)
Total runtime: 3028.663 ms (3069.710 ms)
(3 rows)
postgres=# explain (analyze, timing off) select avg(c) from foo;
QUERY
PLAN
---------------------------------------------------------------------------------------------------
Aggregate (cost=208332.23..208332.24 rows=1 width=8) (actual rows=1
loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=8) (actual
rows=10000000 loops=1)
Total runtime: 1488.980 ms (1463.813 ms)
(3 rows)
postgres=# explain (analyze, timing off) select avg(c) from foo group by gr;
QUERY
PLAN
----------------------------------------------------------------------------------------------------
HashAggregate (cost=233331.87..233456.67 rows=9984 width=12) (actual
rows=10001 loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=12)
(actual rows=10000000 loops=1)
Total runtime: 3252.972 ms (3149.986 ms)
(3 rows)
postgres=# explain (analyze, timing off) select sum(d) from foo;
QUERY
PLAN
---------------------------------------------------------------------------------------------------
Aggregate (cost=208332.23..208332.24 rows=1 width=7) (actual rows=1
loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=7) (actual
rows=10000000 loops=1)
Total runtime: 2301.769 ms (2784.430 ms)
(3 rows)
postgres=# explain (analyze, timing off) select sum(d) from foo group by gr;
QUERY
PLAN
----------------------------------------------------------------------------------------------------
HashAggregate (cost=233331.87..233456.67 rows=9984 width=11) (actual
rows=10001 loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=11)
(actual rows=10000000 loops=1)
Total runtime: 4189.272 ms (4440.335 ms)
(3 rows)
postgres=# explain (analyze, timing off) select avg(d) from foo;
QUERY
PLAN
---------------------------------------------------------------------------------------------------
Aggregate (cost=208332.23..208332.24 rows=1 width=7) (actual rows=1
loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=7) (actual
rows=10000000 loops=1)
Total runtime: 2308.493 ms (5195.970 ms)
(3 rows)
postgres=# explain (analyze, timing off) select avg(d) from foo group by gr;
QUERY
PLAN
----------------------------------------------------------------------------------------------------
HashAggregate (cost=233331.87..233456.67 rows=9984 width=11) (actual
rows=10001 loops=1)
-> Seq Scan on foo (cost=0.00..183332.58 rows=9999858 width=11)
(actual rows=10000000 loops=1)
Total runtime: 4179.978 ms (6828.398 ms)
(3 rows)
int, float, double 26829 ms (26675 ms) -- 0.5% slower .. statistic error ..
cleaner code
numeric sum 6490 ms (7224 ms) -- 10% faster
numeric avg 6487 ms (12023 ms) -- 46% faster
2013/8/22 Hadi Moshayedi <hadi@moshayedi.net>
Show quoted text
Hello Pavel,
Do you think you could give this a review after CF1 ends, but before
September? I hate to make Hadi wait just because I didn't see hispatch.
yes, I can.
When do you think you will have time to review this patch?
Thanks,
-- Hadi
Attachments:
Import Notes
Reply to msg id not found: CAK1Wq2QuUsarGeq7U9gpzRaYSwxCDY5FwZmOr24TD-rcHyuQ@mail.gmail.com
Hello,
int, float, double 26829 ms (26675 ms) -- 0.5% slower .. statistic error ..
cleaner code
numeric sum 6490 ms (7224 ms) -- 10% faster
numeric avg 6487 ms (12023 ms) -- 46% faster
I also got very similar results.
On the other hand, initially I was receiving sigsegv's whenever I
wanted to try to run an aggregate function. gdb was telling that this
was happening somewhere in nodeAgg.c at ExecInitAgg. While trying to
find the reason, I had to reboot my computer at some point, after the
reboot the sigsegv's went away. I want to look into this and find the
reason, I think I have missed something here. Any thoughts about why
this would happen?
--Hadi
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
2013/8/29 Hadi Moshayedi <hadi@moshayedi.net>
Hello,
int, float, double 26829 ms (26675 ms) -- 0.5% slower .. statistic error
..
cleaner code
numeric sum 6490 ms (7224 ms) -- 10% faster
numeric avg 6487 ms (12023 ms) -- 46% fasterI also got very similar results.
On the other hand, initially I was receiving sigsegv's whenever I
wanted to try to run an aggregate function. gdb was telling that this
was happening somewhere in nodeAgg.c at ExecInitAgg. While trying to
find the reason, I had to reboot my computer at some point, after the
reboot the sigsegv's went away. I want to look into this and find the
reason, I think I have missed something here. Any thoughts about why
this would happen?
I found a few bugs, that I fixed. There was a issue with empty sets. Other
issues I didn't find.
Regards
Pavel
Show quoted text
--Hadi
On 7/8/13 10:05 AM, Pavel Stehule wrote:
I am testing your code, and It increase speed of sum about 24% faster
then original implementation.
This patch needs to be rebased (and/or the later version registered in
the commit fest).
--
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/4 Peter Eisentraut <peter_e@gmx.net>
On 7/8/13 10:05 AM, Pavel Stehule wrote:
I am testing your code, and It increase speed of sum about 24% faster
then original implementation.This patch needs to be rebased (and/or the later version registered in
the commit fest).
I updated a commit fest info
Regards
Pavel
On 9/4/13 2:26 PM, Pavel Stehule wrote:
2013/9/4 Peter Eisentraut <peter_e@gmx.net <mailto:peter_e@gmx.net>>
On 7/8/13 10:05 AM, Pavel Stehule wrote:
I am testing your code, and It increase speed of sum about 24% faster
then original implementation.This patch needs to be rebased (and/or the later version registered in
the commit fest).I updated a commit fest info
The new patch also needs to be rebased.
--
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/4 Peter Eisentraut <peter_e@gmx.net>
Show quoted text
On 9/4/13 2:26 PM, Pavel Stehule wrote:
2013/9/4 Peter Eisentraut <peter_e@gmx.net <mailto:peter_e@gmx.net>>
On 7/8/13 10:05 AM, Pavel Stehule wrote:
I am testing your code, and It increase speed of sum about 24%
faster
then original implementation.
This patch needs to be rebased (and/or the later version registered
in
the commit fest).
I updated a commit fest info
The new patch also needs to be rebased.
rebased
Attachments:
numeric-optimize-v6.patchapplication/octet-stream; name=numeric-optimize-v6.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;
***************
*** 273,278 **** AggregateCreate(const char *aggName,
--- 274,280 ----
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,2620 ----
*
* 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 first;
! bool isNaN;
! uint64 N;
! NumericVar sumX;
! NumericVar sumX2;
! bool calcSumX2;
! MemoryContext agg_context;
! } NumericAggState;
!
!
! static NumericAggState *
! makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
{
! NumericAggState *state;
! MemoryContext agg_context;
! MemoryContext old_context;
! if (!AggCheckCallContext(fcinfo, &agg_context))
! {
! elog(ERROR, "this is called in non-aggregate context");
! }
!
! old_context = MemoryContextSwitchTo(agg_context);
!
! state = palloc0(sizeof(NumericAggState));
! state->first = true;
! state->calcSumX2 = calcSumX2;
! state->agg_context = agg_context;
!
! MemoryContextSwitchTo(old_context);
!
! return state;
}
!
! static void
! do_numeric_accum(NumericAggState *state, Numeric newval)
{
! NumericVar X;
! NumericVar X2;
! MemoryContext old_context;
! bool first;
!
! first = state->first;
! state->first = false;
! state->N++;
!
! if (state->isNaN || NUMERIC_IS_NAN(newval))
! {
! state->isNaN = true;
! return;
! }
! 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 (!first)
! {
! NumericVar preSumX;
!
! 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
! {
! set_var_from_var(&X, &(state->sumX));
!
! if (state->calcSumX2)
! set_var_from_var(&X2, &(state->sumX2));
! }
!
! MemoryContextSwitchTo(old_context);
}
+
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 case for average of numeric.
*/
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.
--- 2627,2776 ----
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,
--- 2779,2789 ----
* *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
--- 2791,2814 ----
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;
--- 2828,2835 ----
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)
--- 2870,2876 ----
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)
--- 2885,2891 ----
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)
--- 2900,2906 ----
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)
--- 2915,2921 ----
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/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);