*** a/doc/src/sgml/catalogs.sgml --- b/doc/src/sgml/catalogs.sgml *************** *** 373,378 **** --- 373,384 ---- Data type of the aggregate function's internal transition (state) data + aggtransspace + int4 + + Approximation for the average size of the aggregate function's internal transition (state) data + + agginitval text *** a/doc/src/sgml/ref/create_aggregate.sgml --- b/doc/src/sgml/ref/create_aggregate.sgml *************** *** 24,29 **** PostgreSQL documentation --- 24,30 ---- CREATE AGGREGATE name ( [ argmode ] [ arg_name ] arg_data_type [ , ... ] ) ( SFUNC = sfunc, STYPE = state_data_type + [ , SSPACE = state_data_size ] [ , FINALFUNC = ffunc ] [ , INITCOND = initial_condition ] [ , SORTOP = sort_operator ] *************** *** 35,40 **** CREATE AGGREGATE name ( --- 36,42 ---- BASETYPE = base_type, SFUNC = sfunc, STYPE = state_data_type + [ , SSPACE = state_data_size ] [ , FINALFUNC = ffunc ] [ , INITCOND = initial_condition ] [ , SORTOP = sort_operator ] *************** *** 265,270 **** SELECT col FROM tab ORDER BY col USING sortop LIMIT 1; --- 267,288 ---- + state_data_size + + + Approximate average size (in bytes) of aggregate's state value. + Planner uses this value to approximate the memory required for + the aggregation. If this value is not provided, a default value is + used based on state_data_type. This parameter is enabled only only for + aggregate function where state_data_type is internal, where size + is unknown and planner uses a 8KB as default. Default value is usually + too high (that effective disable HashAgg) and should be specified better. + + + + + ffunc *** a/src/backend/catalog/pg_aggregate.c --- b/src/backend/catalog/pg_aggregate.c *************** *** 55,60 **** AggregateCreate(const char *aggName, --- 55,61 ---- List *aggfinalfnName, List *aggsortopName, Oid aggTransType, + int32 aggTransSpace, const char *agginitval) { Relation aggdesc; *************** *** 195,200 **** AggregateCreate(const char *aggName, --- 196,211 ---- errmsg("unsafe use of pseudo-type \"internal\""), errdetail("A function returning \"internal\" must have at least one \"internal\" argument."))); + /* + * Allow non zerro aggTransSpace only for INTERNALOID aggTransType + * Other types has known size. + */ + if (aggTransType != INTERNALOID && aggTransSpace > 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("SSPACE can be used only for \"internal\" transition type"), + errdetail("SSPACE can be defined only together with a \"internal\" transition type."))); + /* handle sortop, if supplied */ if (aggsortopName) { *************** *** 273,278 **** AggregateCreate(const char *aggName, --- 284,290 ---- values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn); values[Anum_pg_aggregate_aggsortop - 1] = ObjectIdGetDatum(sortop); values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType); + values[Anum_pg_aggregate_aggtransspace - 1] = Int32GetDatum(aggTransSpace); if (agginitval) values[Anum_pg_aggregate_agginitval - 1] = CStringGetTextDatum(agginitval); else *** a/src/backend/commands/aggregatecmds.c --- b/src/backend/commands/aggregatecmds.c *************** *** 68,73 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, --- 68,74 ---- ArrayType *parameterNames; List *parameterDefaults; Oid transTypeId; + int32 transSpace = 0; char transTypeType; ListCell *pl; *************** *** 102,107 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, --- 103,110 ---- transType = defGetTypeName(defel); else if (pg_strcasecmp(defel->defname, "stype1") == 0) transType = defGetTypeName(defel); + else if (pg_strcasecmp(defel->defname, "sspace") == 0) + transSpace = defGetInt32(defel); else if (pg_strcasecmp(defel->defname, "initcond") == 0) initval = defGetString(defel); else if (pg_strcasecmp(defel->defname, "initcond1") == 0) *************** *** 248,252 **** DefineAggregate(List *name, List *args, bool oldstyle, List *parameters, --- 251,256 ---- finalfuncName, /* final function name */ sortoperatorName, /* sort operator name */ transTypeId, /* transition data type */ + transSpace, /* transition space */ initval); /* initial condition */ } *** a/src/backend/commands/define.c --- b/src/backend/commands/define.c *************** *** 165,170 **** defGetBoolean(DefElem *def) --- 165,194 ---- } /* + * Extract an int32 value from a DefElem. + */ + int32 + defGetInt32(DefElem *def) + { + if (def->arg == NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("%s requires an integer value", + def->defname))); + switch (nodeTag(def->arg)) + { + case T_Integer: + return (int32) intVal(def->arg); + default: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("%s requires an integer value", + def->defname))); + } + return 0; /* keep compiler quiet */ + } + + /* * Extract an int64 value from a DefElem. */ int64 *** a/src/backend/optimizer/util/clauses.c --- b/src/backend/optimizer/util/clauses.c *************** *** 461,466 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context) --- 461,467 ---- Oid aggtransfn; Oid aggfinalfn; Oid aggtranstype; + int32 aggtransspace; QualCost argcosts; Oid *inputTypes; int numArguments; *************** *** 478,483 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context) --- 479,485 ---- aggtransfn = aggform->aggtransfn; aggfinalfn = aggform->aggfinalfn; aggtranstype = aggform->aggtranstype; + aggtransspace = aggform->aggtransspace; ReleaseSysCache(aggTuple); /* count it */ *************** *** 539,545 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context) * pass-by-reference then we have to add the estimated size of the * value itself, plus palloc overhead. */ ! if (!get_typbyval(aggtranstype)) { int32 aggtranstypmod; int32 avgwidth; --- 541,547 ---- * pass-by-reference then we have to add the estimated size of the * value itself, plus palloc overhead. */ ! else if (!get_typbyval(aggtranstype)) { int32 aggtranstypmod; int32 avgwidth; *************** *** 564,575 **** count_agg_clauses_walker(Node *node, count_agg_clauses_context *context) /* * INTERNAL transition type is a special case: although INTERNAL * is pass-by-value, it's almost certainly being used as a pointer ! * to some large data structure. We assume usage of ! * ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is ! * being kept in a private memory context, as is done by ! * array_agg() for instance. */ ! costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE; } /* --- 566,581 ---- /* * INTERNAL transition type is a special case: although INTERNAL * is pass-by-value, it's almost certainly being used as a pointer ! * to some large data structure. A size of this structure can be ! * specified by aggtransspace value. When it is unspecified, then ! * We assume usage of ALLOCSET_DEFAULT_INITSIZE, which is a good ! * guess if the data is being kept in a private memory context, ! * as is done by array_agg() for instance. */ ! if (aggtransspace > 0) ! costs->transitionSpace += aggtransspace; ! else ! costs->transitionSpace += ALLOCSET_DEFAULT_INITSIZE; } /* *** a/src/backend/utils/adt/numeric.c --- b/src/backend/utils/adt/numeric.c *************** *** 2464,2571 **** numeric_float4(PG_FUNCTION_ARGS) * * Aggregate functions * ! * The transition datatype for all these aggregates is a 3-element array ! * of Numeric, holding the values N, sum(X), sum(X*X) in that order. ! * ! * We represent N as a numeric mainly to avoid having to build a special ! * datatype; it's unlikely it'd overflow an int4, but ... * * ---------------------------------------------------------------------- */ ! static ArrayType * ! do_numeric_accum(ArrayType *transarray, Numeric newval) { ! Datum *transdatums; ! int ndatums; ! Datum N, ! sumX, ! sumX2; ! ArrayType *result; ! ! /* We assume the input is array of numeric */ ! deconstruct_array(transarray, ! NUMERICOID, -1, false, 'i', ! &transdatums, NULL, &ndatums); ! if (ndatums != 3) ! elog(ERROR, "expected 3-element numeric array"); ! N = transdatums[0]; ! sumX = transdatums[1]; ! sumX2 = transdatums[2]; ! ! N = DirectFunctionCall1(numeric_inc, N); ! sumX = DirectFunctionCall2(numeric_add, sumX, ! NumericGetDatum(newval)); ! sumX2 = DirectFunctionCall2(numeric_add, sumX2, ! DirectFunctionCall2(numeric_mul, ! NumericGetDatum(newval), ! NumericGetDatum(newval))); ! ! transdatums[0] = N; ! transdatums[1] = sumX; ! transdatums[2] = sumX2; ! ! result = construct_array(transdatums, 3, ! NUMERICOID, -1, false, 'i'); ! return result; } /* ! * Improve avg performance by not caclulating sum(X*X). */ ! static ArrayType * ! do_numeric_avg_accum(ArrayType *transarray, Numeric newval) { ! Datum *transdatums; ! int ndatums; ! Datum N, ! sumX; ! ArrayType *result; ! ! /* We assume the input is array of numeric */ ! deconstruct_array(transarray, ! NUMERICOID, -1, false, 'i', ! &transdatums, NULL, &ndatums); ! if (ndatums != 2) ! elog(ERROR, "expected 2-element numeric array"); ! N = transdatums[0]; ! sumX = transdatums[1]; ! ! N = DirectFunctionCall1(numeric_inc, N); ! sumX = DirectFunctionCall2(numeric_add, sumX, ! NumericGetDatum(newval)); ! ! transdatums[0] = N; ! transdatums[1] = sumX; ! ! result = construct_array(transdatums, 2, ! NUMERICOID, -1, false, 'i'); ! return result; } Datum numeric_accum(PG_FUNCTION_ARGS) { ! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); ! Numeric newval = PG_GETARG_NUMERIC(1); ! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval)); } /* ! * Optimized case for average of numeric. */ Datum numeric_avg_accum(PG_FUNCTION_ARGS) { ! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); ! Numeric newval = PG_GETARG_NUMERIC(1); ! PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval)); } /* * Integer data types all use Numeric accumulators to share code and * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation --- 2464,2623 ---- * * Aggregate functions * ! * The transition datatype for all these aggregates is a pointer to ! * a struct NumericAggState allocated in the aggregate context. * * ---------------------------------------------------------------------- */ ! typedef struct NumericAggState { ! bool isNaN; /* true, when some processed number is NaN */ ! uint64 N; /* count of processed numbers */ ! NumericVar sumX; /* sum of processed numbers */ ! NumericVar sumX2; /* sum of square of processed numbers */ ! bool calcSumX2; /* when is true, then sumX2 is calculated */ ! MemoryContext agg_context; ! } NumericAggState; ! ! /* ! * Prepare state data for Numeric aggregate function that needs to know a sum, count ! * and sometimes sum of square (when calcSumX2 is true). ! */ ! static NumericAggState * ! makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2) ! { ! NumericAggState *state; ! MemoryContext agg_context; ! MemoryContext old_context; ! ! if (!AggCheckCallContext(fcinfo, &agg_context)) ! elog(ERROR, "a numeric aggregate function called in non-aggregate context"); ! ! old_context = MemoryContextSwitchTo(agg_context); ! ! state = palloc0(sizeof(NumericAggState)); ! state->calcSumX2 = calcSumX2; ! state->agg_context = agg_context; ! ! MemoryContextSwitchTo(old_context); ! ! return state; } + /* ! * a workhorse for numeric accum functions. A different behave (controlled by calcSumX2) ! * is specified when NumericAggState is initiated. This accum function is used for numeric ! * sum too due minimize overhead related to packing and unpacking Numeric value. ! * */ ! static void ! do_numeric_accum(NumericAggState *state, Numeric newval) { ! NumericVar X; ! NumericVar X2; ! MemoryContext old_context; ! /* result is NaN, when some processed number is NaN */ ! if (state->isNaN || NUMERIC_IS_NAN(newval)) ! { ! state->isNaN = true; ! return; ! } ! ! /* load processed number */ ! init_var_from_num(newval, &X); ! ! if (state->calcSumX2) ! { ! init_var(&X2); ! mul_var(&X, &X, &X2, X.dscale * 2); ! } ! ! old_context = MemoryContextSwitchTo(state->agg_context); ! ! if (state->N++ > 0) ! { ! NumericVar preSumX; ! ! /* increase counters */ ! memcpy(&preSumX, &(state->sumX), sizeof(NumericVar)); ! init_var(&(state->sumX)); ! add_var(&X, &preSumX, &(state->sumX)); ! free_var(&preSumX); ! ! if (state->calcSumX2) ! { ! NumericVar preSumX2; ! ! memcpy(&preSumX2, &(state->sumX2), sizeof(NumericVar)); ! init_var(&(state->sumX2)); ! add_var(&X2, &preSumX2, &(state->sumX2)); ! free_var(&preSumX2); ! } ! } ! else ! { ! /* initialize counters */ ! set_var_from_var(&X, &(state->sumX)); ! ! if (state->calcSumX2) ! set_var_from_var(&X2, &(state->sumX2)); ! } ! ! MemoryContextSwitchTo(old_context); } + /* + * Generic accum function for Numeric aggregates. It initialize NumericAggState + * with calcSumX2 is true - it ensure a sumX2 calcualtion. + */ Datum numeric_accum(PG_FUNCTION_ARGS) { ! NumericAggState *state; ! ! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); ! if (!PG_ARGISNULL(1)) ! { ! /* On the first time through, create the state variable. */ ! if (state == NULL) ! state = makeNumericAggState(fcinfo, true); ! ! do_numeric_accum(state, PG_GETARG_NUMERIC(1)); ! } ! ! PG_RETURN_POINTER(state); } + /* ! * Optimized accum function for average and sum aggregate function. ! * Doesn't calculate sumX2. */ Datum numeric_avg_accum(PG_FUNCTION_ARGS) { ! NumericAggState *state; ! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); ! ! if (!PG_ARGISNULL(1)) ! { ! /* On the first time through, create the state variable. */ ! if (state == NULL) ! state = makeNumericAggState(fcinfo, false); ! ! do_numeric_accum(state, PG_GETARG_NUMERIC(1)); ! } ! ! PG_RETURN_POINTER(state); } + /* * Integer data types all use Numeric accumulators to share code and * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation *************** *** 2574,2664 **** numeric_avg_accum(PG_FUNCTION_ARGS) * for stddev/variance --- there are faster special-purpose accumulator * routines for SUM and AVG of these datatypes. */ - Datum int2_accum(PG_FUNCTION_ARGS) { ! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); ! Datum newval2 = PG_GETARG_DATUM(1); ! Numeric newval; ! newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2)); ! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval)); } Datum int4_accum(PG_FUNCTION_ARGS) { ! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); ! Datum newval4 = PG_GETARG_DATUM(1); ! Numeric newval; ! newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4)); ! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval)); } Datum int8_accum(PG_FUNCTION_ARGS) { ! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); ! Datum newval8 = PG_GETARG_DATUM(1); ! Numeric newval; ! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8)); ! PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval)); } /* * Optimized case for average of int8. */ Datum int8_avg_accum(PG_FUNCTION_ARGS) { ! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); ! Datum newval8 = PG_GETARG_DATUM(1); ! Numeric newval; ! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8)); ! ! PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval)); } Datum numeric_avg(PG_FUNCTION_ARGS) { ! ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); ! Datum *transdatums; ! int ndatums; ! Numeric N, ! sumX; ! ! /* We assume the input is array of numeric */ ! deconstruct_array(transarray, ! NUMERICOID, -1, false, 'i', ! &transdatums, NULL, &ndatums); ! if (ndatums != 2) ! elog(ERROR, "expected 2-element numeric array"); ! N = DatumGetNumeric(transdatums[0]); ! sumX = DatumGetNumeric(transdatums[1]); ! /* SQL defines AVG of no values to be NULL */ ! /* N is zero iff no digits (cf. numeric_uminus) */ ! if (NUMERIC_NDIGITS(N) == 0) PG_RETURN_NULL(); ! PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, ! NumericGetDatum(sumX), ! NumericGetDatum(N))); } /* * Workhorse routine for the standard deviance and variance ! * aggregates. 'transarray' is the aggregate's transition ! * array. 'variance' specifies whether we should calculate the * variance or the standard deviation. 'sample' indicates whether the * caller is interested in the sample or the population * variance/stddev. --- 2626,2764 ---- * for stddev/variance --- there are faster special-purpose accumulator * routines for SUM and AVG of these datatypes. */ Datum int2_accum(PG_FUNCTION_ARGS) { ! NumericAggState *state; ! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); ! if (!PG_ARGISNULL(1)) ! { ! Datum newval2 = PG_GETARG_DATUM(1); ! Numeric newval; ! ! /* On the first time through, create the state variable. */ ! if (state == NULL) ! state = makeNumericAggState(fcinfo, true); ! ! newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2)); ! do_numeric_accum(state, newval); ! } ! ! PG_RETURN_POINTER(state); } + Datum int4_accum(PG_FUNCTION_ARGS) { ! NumericAggState *state; ! ! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); ! if (!PG_ARGISNULL(1)) ! { ! Datum newval4 = PG_GETARG_DATUM(1); ! Numeric newval; ! ! /* On the first time through, create the state variable. */ ! if (state == NULL) ! state = makeNumericAggState(fcinfo, true); ! ! newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4)); ! do_numeric_accum(state, newval); ! } ! PG_RETURN_POINTER(state); } + Datum int8_accum(PG_FUNCTION_ARGS) { ! NumericAggState *state; ! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); ! if (!PG_ARGISNULL(1)) ! { ! Datum newval8 = PG_GETARG_DATUM(1); ! Numeric newval; ! ! /* On the first time through, create the state variable. */ ! if (state == NULL) ! state = makeNumericAggState(fcinfo, true); ! ! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8)); ! do_numeric_accum(state, newval); ! } ! ! PG_RETURN_POINTER(state); } + /* * Optimized case for average of int8. */ Datum int8_avg_accum(PG_FUNCTION_ARGS) { ! NumericAggState *state; ! state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); ! if (!PG_ARGISNULL(1)) ! { ! Datum newval8 = PG_GETARG_DATUM(1); ! Numeric newval; ! ! /* On the first time through, create the state variable. */ ! if (state == NULL) ! state = makeNumericAggState(fcinfo, false); ! ! newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8)); ! do_numeric_accum(state, newval); ! } ! ! PG_RETURN_POINTER(state); } Datum numeric_avg(PG_FUNCTION_ARGS) { ! Datum N_datum; ! Datum sumX_datum; ! NumericAggState *state; ! state = (NumericAggState *) PG_GETARG_POINTER(0); ! if (state == NULL) ! PG_RETURN_NULL(); ! ! N_datum = DirectFunctionCall1(int8_numeric, Int64GetDatum(state->N)); ! sumX_datum = NumericGetDatum(make_result(&state->sumX)); ! ! PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumX_datum, N_datum)); ! } ! ! ! Datum ! numeric_sum(PG_FUNCTION_ARGS) ! { ! NumericAggState *state; ! ! state = (NumericAggState *) PG_GETARG_POINTER(0); ! if (state == NULL) PG_RETURN_NULL(); ! PG_RETURN_NUMERIC(make_result(&(state->sumX))); } + /* * Workhorse routine for the standard deviance and variance ! * aggregates. 'state' is aggregate's transition state. ! * 'variance' specifies whether we should calculate the * variance or the standard deviation. 'sample' indicates whether the * caller is interested in the sample or the population * variance/stddev. *************** *** 2667,2682 **** numeric_avg(PG_FUNCTION_ARGS) * *is_null is set to true and NULL is returned. */ static Numeric ! numeric_stddev_internal(ArrayType *transarray, bool variance, bool sample, bool *is_null) { ! Datum *transdatums; ! int ndatums; ! Numeric N, ! sumX, ! sumX2, ! res; NumericVar vN, vsumX, vsumX2, --- 2767,2777 ---- * *is_null is set to true and NULL is returned. */ static Numeric ! numeric_stddev_internal(NumericAggState *state, bool variance, bool sample, bool *is_null) { ! Numeric res; NumericVar vN, vsumX, vsumX2, *************** *** 2684,2705 **** numeric_stddev_internal(ArrayType *transarray, NumericVar *comp; int rscale; *is_null = false; ! /* We assume the input is array of numeric */ ! deconstruct_array(transarray, ! NUMERICOID, -1, false, 'i', ! &transdatums, NULL, &ndatums); ! if (ndatums != 3) ! elog(ERROR, "expected 3-element numeric array"); ! N = DatumGetNumeric(transdatums[0]); ! sumX = DatumGetNumeric(transdatums[1]); ! sumX2 = DatumGetNumeric(transdatums[2]); ! ! if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2)) return make_result(&const_nan); ! init_var_from_num(N, &vN); /* * Sample stddev and variance are undefined when N <= 1; population stddev --- 2779,2802 ---- NumericVar *comp; int rscale; + if (state == NULL) + { + *is_null = true; + return NULL; + } + *is_null = false; ! if (state->isNaN) return make_result(&const_nan); ! init_var(&vN); ! init_var(&vsumX); ! init_var(&vsumX2); ! ! int8_to_numericvar(state->N, &vN); ! set_var_from_var(&(state->sumX), &vsumX); ! set_var_from_var(&(state->sumX2), &vsumX2); /* * Sample stddev and variance are undefined when N <= 1; population stddev *************** *** 2719,2726 **** numeric_stddev_internal(ArrayType *transarray, init_var(&vNminus1); sub_var(&vN, &const_one, &vNminus1); ! init_var_from_num(sumX, &vsumX); ! init_var_from_num(sumX2, &vsumX2); /* compute rscale for mul_var calls */ rscale = vsumX.dscale * 2; --- 2816,2823 ---- init_var(&vNminus1); sub_var(&vN, &const_one, &vNminus1); ! set_var_from_var(&(state->sumX), &vsumX); ! set_var_from_var(&(state->sumX2), &vsumX2); /* compute rscale for mul_var calls */ rscale = vsumX.dscale * 2; *************** *** 2761,2767 **** numeric_var_samp(PG_FUNCTION_ARGS) Numeric res; bool is_null; ! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0), true, true, &is_null); if (is_null) --- 2858,2864 ---- Numeric res; bool is_null; ! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0), true, true, &is_null); if (is_null) *************** *** 2776,2782 **** numeric_stddev_samp(PG_FUNCTION_ARGS) Numeric res; bool is_null; ! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0), false, true, &is_null); if (is_null) --- 2873,2879 ---- Numeric res; bool is_null; ! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0), false, true, &is_null); if (is_null) *************** *** 2791,2797 **** numeric_var_pop(PG_FUNCTION_ARGS) Numeric res; bool is_null; ! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0), true, false, &is_null); if (is_null) --- 2888,2894 ---- Numeric res; bool is_null; ! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0), true, false, &is_null); if (is_null) *************** *** 2806,2812 **** numeric_stddev_pop(PG_FUNCTION_ARGS) Numeric res; bool is_null; ! res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0), false, false, &is_null); if (is_null) --- 2903,2909 ---- Numeric res; bool is_null; ! res = numeric_stddev_internal((NumericAggState *) PG_GETARG_POINTER(0), false, false, &is_null); if (is_null) *** a/src/bin/pg_dump/pg_dump.c --- b/src/bin/pg_dump/pg_dump.c *************** *** 11419,11430 **** dumpAgg(Archive *fout, AggInfo *agginfo) --- 11419,11432 ---- int i_aggfinalfn; int i_aggsortop; int i_aggtranstype; + int i_aggtransspace; int i_agginitval; int i_convertok; const char *aggtransfn; const char *aggfinalfn; const char *aggsortop; const char *aggtranstype; + const char *aggtransspace; const char *agginitval; bool convertok; *************** *** 11442,11453 **** dumpAgg(Archive *fout, AggInfo *agginfo) selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name); /* Get aggregate-specific details */ ! if (fout->remoteVersion >= 80400) { appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " "aggsortop::pg_catalog.regoperator, " ! "agginitval, " "'t'::boolean AS convertok, " "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, " "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs " --- 11444,11469 ---- selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name); /* Get aggregate-specific details */ ! if (fout->remoteVersion >= 90300) ! { ! appendPQExpBuffer(query, "SELECT aggtransfn, " ! "aggfinalfn, aggtranstype::pg_catalog.regtype, " ! "aggsortop::pg_catalog.regoperator, " ! "aggtransspace, agginitval, " ! "'t'::boolean AS convertok, " ! "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, " ! "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs " ! "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " ! "WHERE a.aggfnoid = p.oid " ! "AND p.oid = '%u'::pg_catalog.oid", ! agginfo->aggfn.dobj.catId.oid); ! } ! else if (fout->remoteVersion >= 80400) { appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " "aggsortop::pg_catalog.regoperator, " ! "0 AS aggtransspace, agginitval, " "'t'::boolean AS convertok, " "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, " "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs " *************** *** 11461,11467 **** dumpAgg(Archive *fout, AggInfo *agginfo) appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " "aggsortop::pg_catalog.regoperator, " ! "agginitval, " "'t'::boolean AS convertok " "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " "WHERE a.aggfnoid = p.oid " --- 11477,11483 ---- appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " "aggsortop::pg_catalog.regoperator, " ! "0 AS aggtransspace, agginitval, " "'t'::boolean AS convertok " "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " "WHERE a.aggfnoid = p.oid " *************** *** 11473,11479 **** dumpAgg(Archive *fout, AggInfo *agginfo) appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " "0 AS aggsortop, " ! "agginitval, " "'t'::boolean AS convertok " "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " "WHERE a.aggfnoid = p.oid " --- 11489,11495 ---- appendPQExpBuffer(query, "SELECT aggtransfn, " "aggfinalfn, aggtranstype::pg_catalog.regtype, " "0 AS aggsortop, " ! "0 AS aggtransspace, agginitval, " "'t'::boolean AS convertok " "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p " "WHERE a.aggfnoid = p.oid " *************** *** 11485,11491 **** dumpAgg(Archive *fout, AggInfo *agginfo) appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, " "format_type(aggtranstype, NULL) AS aggtranstype, " "0 AS aggsortop, " ! "agginitval, " "'t'::boolean AS convertok " "FROM pg_aggregate " "WHERE oid = '%u'::oid", --- 11501,11507 ---- appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, " "format_type(aggtranstype, NULL) AS aggtranstype, " "0 AS aggsortop, " ! "0 AS aggtransspace, agginitval, " "'t'::boolean AS convertok " "FROM pg_aggregate " "WHERE oid = '%u'::oid", *************** *** 11497,11503 **** dumpAgg(Archive *fout, AggInfo *agginfo) "aggfinalfn, " "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, " "0 AS aggsortop, " ! "agginitval1 AS agginitval, " "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok " "FROM pg_aggregate " "WHERE oid = '%u'::oid", --- 11513,11519 ---- "aggfinalfn, " "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, " "0 AS aggsortop, " ! "0 AS aggtransspace, agginitval1 AS agginitval, " "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok " "FROM pg_aggregate " "WHERE oid = '%u'::oid", *************** *** 11510,11515 **** dumpAgg(Archive *fout, AggInfo *agginfo) --- 11526,11532 ---- i_aggfinalfn = PQfnumber(res, "aggfinalfn"); i_aggsortop = PQfnumber(res, "aggsortop"); i_aggtranstype = PQfnumber(res, "aggtranstype"); + i_aggtransspace = PQfnumber(res, "aggtransspace"); i_agginitval = PQfnumber(res, "agginitval"); i_convertok = PQfnumber(res, "convertok"); *************** *** 11517,11522 **** dumpAgg(Archive *fout, AggInfo *agginfo) --- 11534,11540 ---- aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn); aggsortop = PQgetvalue(res, 0, i_aggsortop); aggtranstype = PQgetvalue(res, 0, i_aggtranstype); + aggtransspace = PQgetvalue(res, 0, i_aggtransspace); agginitval = PQgetvalue(res, 0, i_agginitval); convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't'); *************** *** 11570,11575 **** dumpAgg(Archive *fout, AggInfo *agginfo) --- 11588,11599 ---- fmtId(aggtranstype)); } + if (strcmp(aggfinalfn, "0") != 0) + { + appendPQExpBuffer(details, ",\n SSPACE = %s", + aggtransspace); + } + if (!PQgetisnull(res, 0, i_agginitval)) { appendPQExpBuffer(details, ",\n INITCOND = "); *** a/src/include/catalog/pg_aggregate.h --- b/src/include/catalog/pg_aggregate.h *************** *** 44,49 **** CATALOG(pg_aggregate,2600) BKI_WITHOUT_OIDS --- 44,50 ---- regproc aggfinalfn; Oid aggsortop; Oid aggtranstype; + int32 aggtransspace; #ifdef CATALOG_VARLEN /* variable-length fields start here */ text agginitval; *************** *** 62,74 **** typedef FormData_pg_aggregate *Form_pg_aggregate; * ---------------- */ ! #define Natts_pg_aggregate 6 #define Anum_pg_aggregate_aggfnoid 1 #define Anum_pg_aggregate_aggtransfn 2 #define Anum_pg_aggregate_aggfinalfn 3 #define Anum_pg_aggregate_aggsortop 4 #define Anum_pg_aggregate_aggtranstype 5 ! #define Anum_pg_aggregate_agginitval 6 /* ---------------- --- 63,76 ---- * ---------------- */ ! #define Natts_pg_aggregate 7 #define Anum_pg_aggregate_aggfnoid 1 #define Anum_pg_aggregate_aggtransfn 2 #define Anum_pg_aggregate_aggfinalfn 3 #define Anum_pg_aggregate_aggsortop 4 #define Anum_pg_aggregate_aggtranstype 5 ! #define Anum_pg_aggregate_aggtransspace 6 ! #define Anum_pg_aggregate_agginitval 7 /* ---------------- *************** *** 77,239 **** typedef FormData_pg_aggregate *Form_pg_aggregate; */ /* avg */ ! DATA(insert ( 2100 int8_avg_accum numeric_avg 0 1231 "{0,0}" )); ! DATA(insert ( 2101 int4_avg_accum int8_avg 0 1016 "{0,0}" )); ! DATA(insert ( 2102 int2_avg_accum int8_avg 0 1016 "{0,0}" )); ! DATA(insert ( 2103 numeric_avg_accum numeric_avg 0 1231 "{0,0}" )); ! DATA(insert ( 2104 float4_accum float8_avg 0 1022 "{0,0,0}" )); ! DATA(insert ( 2105 float8_accum float8_avg 0 1022 "{0,0,0}" )); ! DATA(insert ( 2106 interval_accum interval_avg 0 1187 "{0 second,0 second}" )); /* sum */ ! DATA(insert ( 2107 int8_sum - 0 1700 _null_ )); ! DATA(insert ( 2108 int4_sum - 0 20 _null_ )); ! DATA(insert ( 2109 int2_sum - 0 20 _null_ )); ! DATA(insert ( 2110 float4pl - 0 700 _null_ )); ! DATA(insert ( 2111 float8pl - 0 701 _null_ )); ! DATA(insert ( 2112 cash_pl - 0 790 _null_ )); ! DATA(insert ( 2113 interval_pl - 0 1186 _null_ )); ! DATA(insert ( 2114 numeric_add - 0 1700 _null_ )); /* max */ ! DATA(insert ( 2115 int8larger - 413 20 _null_ )); ! DATA(insert ( 2116 int4larger - 521 23 _null_ )); ! DATA(insert ( 2117 int2larger - 520 21 _null_ )); ! DATA(insert ( 2118 oidlarger - 610 26 _null_ )); ! DATA(insert ( 2119 float4larger - 623 700 _null_ )); ! DATA(insert ( 2120 float8larger - 674 701 _null_ )); ! DATA(insert ( 2121 int4larger - 563 702 _null_ )); ! DATA(insert ( 2122 date_larger - 1097 1082 _null_ )); ! DATA(insert ( 2123 time_larger - 1112 1083 _null_ )); ! DATA(insert ( 2124 timetz_larger - 1554 1266 _null_ )); ! DATA(insert ( 2125 cashlarger - 903 790 _null_ )); ! DATA(insert ( 2126 timestamp_larger - 2064 1114 _null_ )); ! DATA(insert ( 2127 timestamptz_larger - 1324 1184 _null_ )); ! DATA(insert ( 2128 interval_larger - 1334 1186 _null_ )); ! DATA(insert ( 2129 text_larger - 666 25 _null_ )); ! DATA(insert ( 2130 numeric_larger - 1756 1700 _null_ )); ! DATA(insert ( 2050 array_larger - 1073 2277 _null_ )); ! DATA(insert ( 2244 bpchar_larger - 1060 1042 _null_ )); ! DATA(insert ( 2797 tidlarger - 2800 27 _null_ )); ! DATA(insert ( 3526 enum_larger - 3519 3500 _null_ )); /* min */ ! DATA(insert ( 2131 int8smaller - 412 20 _null_ )); ! DATA(insert ( 2132 int4smaller - 97 23 _null_ )); ! DATA(insert ( 2133 int2smaller - 95 21 _null_ )); ! DATA(insert ( 2134 oidsmaller - 609 26 _null_ )); ! DATA(insert ( 2135 float4smaller - 622 700 _null_ )); ! DATA(insert ( 2136 float8smaller - 672 701 _null_ )); ! DATA(insert ( 2137 int4smaller - 562 702 _null_ )); ! DATA(insert ( 2138 date_smaller - 1095 1082 _null_ )); ! DATA(insert ( 2139 time_smaller - 1110 1083 _null_ )); ! DATA(insert ( 2140 timetz_smaller - 1552 1266 _null_ )); ! DATA(insert ( 2141 cashsmaller - 902 790 _null_ )); ! DATA(insert ( 2142 timestamp_smaller - 2062 1114 _null_ )); ! DATA(insert ( 2143 timestamptz_smaller - 1322 1184 _null_ )); ! DATA(insert ( 2144 interval_smaller - 1332 1186 _null_ )); ! DATA(insert ( 2145 text_smaller - 664 25 _null_ )); ! DATA(insert ( 2146 numeric_smaller - 1754 1700 _null_ )); ! DATA(insert ( 2051 array_smaller - 1072 2277 _null_ )); ! DATA(insert ( 2245 bpchar_smaller - 1058 1042 _null_ )); ! DATA(insert ( 2798 tidsmaller - 2799 27 _null_ )); ! DATA(insert ( 3527 enum_smaller - 3518 3500 _null_ )); /* count */ ! DATA(insert ( 2147 int8inc_any - 0 20 "0" )); ! DATA(insert ( 2803 int8inc - 0 20 "0" )); /* var_pop */ ! DATA(insert ( 2718 int8_accum numeric_var_pop 0 1231 "{0,0,0}" )); ! DATA(insert ( 2719 int4_accum numeric_var_pop 0 1231 "{0,0,0}" )); ! DATA(insert ( 2720 int2_accum numeric_var_pop 0 1231 "{0,0,0}" )); ! DATA(insert ( 2721 float4_accum float8_var_pop 0 1022 "{0,0,0}" )); ! DATA(insert ( 2722 float8_accum float8_var_pop 0 1022 "{0,0,0}" )); ! DATA(insert ( 2723 numeric_accum numeric_var_pop 0 1231 "{0,0,0}" )); /* var_samp */ ! DATA(insert ( 2641 int8_accum numeric_var_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2642 int4_accum numeric_var_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2643 int2_accum numeric_var_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2644 float4_accum float8_var_samp 0 1022 "{0,0,0}" )); ! DATA(insert ( 2645 float8_accum float8_var_samp 0 1022 "{0,0,0}" )); ! DATA(insert ( 2646 numeric_accum numeric_var_samp 0 1231 "{0,0,0}" )); /* variance: historical Postgres syntax for var_samp */ ! DATA(insert ( 2148 int8_accum numeric_var_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2149 int4_accum numeric_var_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2150 int2_accum numeric_var_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2151 float4_accum float8_var_samp 0 1022 "{0,0,0}" )); ! DATA(insert ( 2152 float8_accum float8_var_samp 0 1022 "{0,0,0}" )); ! DATA(insert ( 2153 numeric_accum numeric_var_samp 0 1231 "{0,0,0}" )); /* stddev_pop */ ! DATA(insert ( 2724 int8_accum numeric_stddev_pop 0 1231 "{0,0,0}" )); ! DATA(insert ( 2725 int4_accum numeric_stddev_pop 0 1231 "{0,0,0}" )); ! DATA(insert ( 2726 int2_accum numeric_stddev_pop 0 1231 "{0,0,0}" )); ! DATA(insert ( 2727 float4_accum float8_stddev_pop 0 1022 "{0,0,0}" )); ! DATA(insert ( 2728 float8_accum float8_stddev_pop 0 1022 "{0,0,0}" )); ! DATA(insert ( 2729 numeric_accum numeric_stddev_pop 0 1231 "{0,0,0}" )); /* stddev_samp */ ! DATA(insert ( 2712 int8_accum numeric_stddev_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2713 int4_accum numeric_stddev_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2714 int2_accum numeric_stddev_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2715 float4_accum float8_stddev_samp 0 1022 "{0,0,0}" )); ! DATA(insert ( 2716 float8_accum float8_stddev_samp 0 1022 "{0,0,0}" )); ! DATA(insert ( 2717 numeric_accum numeric_stddev_samp 0 1231 "{0,0,0}" )); /* stddev: historical Postgres syntax for stddev_samp */ ! DATA(insert ( 2154 int8_accum numeric_stddev_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2155 int4_accum numeric_stddev_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2156 int2_accum numeric_stddev_samp 0 1231 "{0,0,0}" )); ! DATA(insert ( 2157 float4_accum float8_stddev_samp 0 1022 "{0,0,0}" )); ! DATA(insert ( 2158 float8_accum float8_stddev_samp 0 1022 "{0,0,0}" )); ! DATA(insert ( 2159 numeric_accum numeric_stddev_samp 0 1231 "{0,0,0}" )); /* SQL2003 binary regression aggregates */ ! DATA(insert ( 2818 int8inc_float8_float8 - 0 20 "0" )); ! DATA(insert ( 2819 float8_regr_accum float8_regr_sxx 0 1022 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2820 float8_regr_accum float8_regr_syy 0 1022 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2821 float8_regr_accum float8_regr_sxy 0 1022 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2822 float8_regr_accum float8_regr_avgx 0 1022 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2823 float8_regr_accum float8_regr_avgy 0 1022 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2824 float8_regr_accum float8_regr_r2 0 1022 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2825 float8_regr_accum float8_regr_slope 0 1022 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2826 float8_regr_accum float8_regr_intercept 0 1022 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2827 float8_regr_accum float8_covar_pop 0 1022 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2828 float8_regr_accum float8_covar_samp 0 1022 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2829 float8_regr_accum float8_corr 0 1022 "{0,0,0,0,0,0}" )); /* boolean-and and boolean-or */ ! DATA(insert ( 2517 booland_statefunc - 58 16 _null_ )); ! DATA(insert ( 2518 boolor_statefunc - 59 16 _null_ )); ! DATA(insert ( 2519 booland_statefunc - 58 16 _null_ )); /* bitwise integer */ ! DATA(insert ( 2236 int2and - 0 21 _null_ )); ! DATA(insert ( 2237 int2or - 0 21 _null_ )); ! DATA(insert ( 2238 int4and - 0 23 _null_ )); ! DATA(insert ( 2239 int4or - 0 23 _null_ )); ! DATA(insert ( 2240 int8and - 0 20 _null_ )); ! DATA(insert ( 2241 int8or - 0 20 _null_ )); ! DATA(insert ( 2242 bitand - 0 1560 _null_ )); ! DATA(insert ( 2243 bitor - 0 1560 _null_ )); /* xml */ ! DATA(insert ( 2901 xmlconcat2 - 0 142 _null_ )); /* array */ ! DATA(insert ( 2335 array_agg_transfn array_agg_finalfn 0 2281 _null_ )); /* text */ ! DATA(insert ( 3538 string_agg_transfn string_agg_finalfn 0 2281 _null_ )); /* bytea */ ! DATA(insert ( 3545 bytea_string_agg_transfn bytea_string_agg_finalfn 0 2281 _null_ )); /* json */ ! DATA(insert ( 3175 json_agg_transfn json_agg_finalfn 0 2281 _null_ )); /* * prototypes for functions in pg_aggregate.c --- 79,241 ---- */ /* avg */ ! DATA(insert ( 2100 int8_avg_accum numeric_avg 0 2281 128 _null_ )); ! DATA(insert ( 2101 int4_avg_accum int8_avg 0 1016 0 "{0,0}" )); ! DATA(insert ( 2102 int2_avg_accum int8_avg 0 1016 0 "{0,0}" )); ! DATA(insert ( 2103 numeric_avg_accum numeric_avg 0 2281 128 _null_ )); ! DATA(insert ( 2104 float4_accum float8_avg 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2105 float8_accum float8_avg 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2106 interval_accum interval_avg 0 1187 0 "{0 second,0 second}" )); /* sum */ ! DATA(insert ( 2107 int8_avg_accum numeric_sum 0 2281 128 _null_ )); ! DATA(insert ( 2108 int4_sum - 0 20 0 _null_ )); ! DATA(insert ( 2109 int2_sum - 0 20 0 _null_ )); ! DATA(insert ( 2110 float4pl - 0 700 0 _null_ )); ! DATA(insert ( 2111 float8pl - 0 701 0 _null_ )); ! DATA(insert ( 2112 cash_pl - 0 790 0 _null_ )); ! DATA(insert ( 2113 interval_pl - 0 1186 0 _null_ )); ! DATA(insert ( 2114 numeric_avg_accum numeric_sum 0 2281 128 _null_ )); /* max */ ! DATA(insert ( 2115 int8larger - 413 20 0 _null_ )); ! DATA(insert ( 2116 int4larger - 521 23 0 _null_ )); ! DATA(insert ( 2117 int2larger - 520 21 0 _null_ )); ! DATA(insert ( 2118 oidlarger - 610 26 0 _null_ )); ! DATA(insert ( 2119 float4larger - 623 700 0 _null_ )); ! DATA(insert ( 2120 float8larger - 674 701 0 _null_ )); ! DATA(insert ( 2121 int4larger - 563 702 0 _null_ )); ! DATA(insert ( 2122 date_larger - 1097 1082 0 _null_ )); ! DATA(insert ( 2123 time_larger - 1112 1083 0 _null_ )); ! DATA(insert ( 2124 timetz_larger - 1554 1266 0 _null_ )); ! DATA(insert ( 2125 cashlarger - 903 790 0 _null_ )); ! DATA(insert ( 2126 timestamp_larger - 2064 1114 0 _null_ )); ! DATA(insert ( 2127 timestamptz_larger - 1324 1184 0 _null_ )); ! DATA(insert ( 2128 interval_larger - 1334 1186 0 _null_ )); ! DATA(insert ( 2129 text_larger - 666 25 0 _null_ )); ! DATA(insert ( 2130 numeric_larger - 1756 1700 0 _null_ )); ! DATA(insert ( 2050 array_larger - 1073 2277 0 _null_ )); ! DATA(insert ( 2244 bpchar_larger - 1060 1042 0 _null_ )); ! DATA(insert ( 2797 tidlarger - 2800 27 0 _null_ )); ! DATA(insert ( 3526 enum_larger - 3519 3500 0 _null_ )); /* min */ ! DATA(insert ( 2131 int8smaller - 412 20 0 _null_ )); ! DATA(insert ( 2132 int4smaller - 97 23 0 _null_ )); ! DATA(insert ( 2133 int2smaller - 95 21 0 _null_ )); ! DATA(insert ( 2134 oidsmaller - 609 26 0 _null_ )); ! DATA(insert ( 2135 float4smaller - 622 700 0 _null_ )); ! DATA(insert ( 2136 float8smaller - 672 701 0 _null_ )); ! DATA(insert ( 2137 int4smaller - 562 702 0 _null_ )); ! DATA(insert ( 2138 date_smaller - 1095 1082 0 _null_ )); ! DATA(insert ( 2139 time_smaller - 1110 1083 0 _null_ )); ! DATA(insert ( 2140 timetz_smaller - 1552 1266 0 _null_ )); ! DATA(insert ( 2141 cashsmaller - 902 790 0 _null_ )); ! DATA(insert ( 2142 timestamp_smaller - 2062 1114 0 _null_ )); ! DATA(insert ( 2143 timestamptz_smaller - 1322 1184 0 _null_ )); ! DATA(insert ( 2144 interval_smaller - 1332 1186 0 _null_ )); ! DATA(insert ( 2145 text_smaller - 664 25 0 _null_ )); ! DATA(insert ( 2146 numeric_smaller - 1754 1700 0 _null_ )); ! DATA(insert ( 2051 array_smaller - 1072 2277 0 _null_ )); ! DATA(insert ( 2245 bpchar_smaller - 1058 1042 0 _null_ )); ! DATA(insert ( 2798 tidsmaller - 2799 27 0 _null_ )); ! DATA(insert ( 3527 enum_smaller - 3518 3500 0 _null_ )); /* count */ ! DATA(insert ( 2147 int8inc_any - 0 20 0 "0" )); ! DATA(insert ( 2803 int8inc - 0 20 0 "0" )); /* var_pop */ ! DATA(insert ( 2718 int8_accum numeric_var_pop 0 2281 128 _null_ )); ! DATA(insert ( 2719 int4_accum numeric_var_pop 0 2281 128 _null_ )); ! DATA(insert ( 2720 int2_accum numeric_var_pop 0 2281 128 _null_ )); ! DATA(insert ( 2721 float4_accum float8_var_pop 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2722 float8_accum float8_var_pop 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2723 numeric_accum numeric_var_pop 0 2281 128 _null_ )); /* var_samp */ ! DATA(insert ( 2641 int8_accum numeric_var_samp 0 2281 128 _null_ )); ! DATA(insert ( 2642 int4_accum numeric_var_samp 0 2281 128 _null_ )); ! DATA(insert ( 2643 int2_accum numeric_var_samp 0 2281 128 _null_ )); ! DATA(insert ( 2644 float4_accum float8_var_samp 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2645 float8_accum float8_var_samp 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2646 numeric_accum numeric_var_samp 0 2281 128 _null_ )); /* variance: historical Postgres syntax for var_samp */ ! DATA(insert ( 2148 int8_accum numeric_var_samp 0 2281 128 _null_ )); ! DATA(insert ( 2149 int4_accum numeric_var_samp 0 2281 128 _null_ )); ! DATA(insert ( 2150 int2_accum numeric_var_samp 0 2281 128 _null_ )); ! DATA(insert ( 2151 float4_accum float8_var_samp 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2152 float8_accum float8_var_samp 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2153 numeric_accum numeric_var_samp 0 2281 128 _null_ )); /* stddev_pop */ ! DATA(insert ( 2724 int8_accum numeric_stddev_pop 0 2281 128 _null_ )); ! DATA(insert ( 2725 int4_accum numeric_stddev_pop 0 2281 128 _null_ )); ! DATA(insert ( 2726 int2_accum numeric_stddev_pop 0 2281 128 _null_ )); ! DATA(insert ( 2727 float4_accum float8_stddev_pop 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2728 float8_accum float8_stddev_pop 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2729 numeric_accum numeric_stddev_pop 0 2281 128 _null_ )); /* stddev_samp */ ! DATA(insert ( 2712 int8_accum numeric_stddev_samp 0 2281 128 _null_ )); ! DATA(insert ( 2713 int4_accum numeric_stddev_samp 0 2281 128 _null_ )); ! DATA(insert ( 2714 int2_accum numeric_stddev_samp 0 2281 128 _null_ )); ! DATA(insert ( 2715 float4_accum float8_stddev_samp 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2716 float8_accum float8_stddev_samp 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2717 numeric_accum numeric_stddev_samp 0 2281 128 _null_ )); /* stddev: historical Postgres syntax for stddev_samp */ ! DATA(insert ( 2154 int8_accum numeric_stddev_samp 0 2281 128 _null_ )); ! DATA(insert ( 2155 int4_accum numeric_stddev_samp 0 2281 128 _null_ )); ! DATA(insert ( 2156 int2_accum numeric_stddev_samp 0 2281 128 _null_ )); ! DATA(insert ( 2157 float4_accum float8_stddev_samp 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2158 float8_accum float8_stddev_samp 0 1022 0 "{0,0,0}" )); ! DATA(insert ( 2159 numeric_accum numeric_stddev_samp 0 2281 128 _null_ )); /* SQL2003 binary regression aggregates */ ! DATA(insert ( 2818 int8inc_float8_float8 - 0 20 0 "0" )); ! DATA(insert ( 2819 float8_regr_accum float8_regr_sxx 0 1022 0 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2820 float8_regr_accum float8_regr_syy 0 1022 0 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2821 float8_regr_accum float8_regr_sxy 0 1022 0 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2822 float8_regr_accum float8_regr_avgx 0 1022 0 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2823 float8_regr_accum float8_regr_avgy 0 1022 0 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2824 float8_regr_accum float8_regr_r2 0 1022 0 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2825 float8_regr_accum float8_regr_slope 0 1022 0 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2826 float8_regr_accum float8_regr_intercept 0 1022 0 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2827 float8_regr_accum float8_covar_pop 0 1022 0 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2828 float8_regr_accum float8_covar_samp 0 1022 0 "{0,0,0,0,0,0}" )); ! DATA(insert ( 2829 float8_regr_accum float8_corr 0 1022 0 "{0,0,0,0,0,0}" )); /* boolean-and and boolean-or */ ! DATA(insert ( 2517 booland_statefunc - 58 16 0 _null_ )); ! DATA(insert ( 2518 boolor_statefunc - 59 16 0 _null_ )); ! DATA(insert ( 2519 booland_statefunc - 58 16 0 _null_ )); /* bitwise integer */ ! DATA(insert ( 2236 int2and - 0 21 0 _null_ )); ! DATA(insert ( 2237 int2or - 0 21 0 _null_ )); ! DATA(insert ( 2238 int4and - 0 23 0 _null_ )); ! DATA(insert ( 2239 int4or - 0 23 0 _null_ )); ! DATA(insert ( 2240 int8and - 0 20 0 _null_ )); ! DATA(insert ( 2241 int8or - 0 20 0 _null_ )); ! DATA(insert ( 2242 bitand - 0 1560 0 _null_ )); ! DATA(insert ( 2243 bitor - 0 1560 0 _null_ )); /* xml */ ! DATA(insert ( 2901 xmlconcat2 - 0 142 0 _null_ )); /* array */ ! DATA(insert ( 2335 array_agg_transfn array_agg_finalfn 0 2281 0 _null_ )); /* text */ ! DATA(insert ( 3538 string_agg_transfn string_agg_finalfn 0 2281 0 _null_ )); /* bytea */ ! DATA(insert ( 3545 bytea_string_agg_transfn bytea_string_agg_finalfn 0 2281 0 _null_ )); /* json */ ! DATA(insert ( 3175 json_agg_transfn json_agg_finalfn 0 2281 0 _null_ )); /* * prototypes for functions in pg_aggregate.c *************** *** 250,255 **** extern Oid AggregateCreate(const char *aggName, --- 252,258 ---- List *aggfinalfnName, List *aggsortopName, Oid aggTransType, + int32 aggTransSpace, const char *agginitval); #endif /* PG_AGGREGATE_H */ *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** *** 2381,2407 **** DATA(insert OID = 2513 ( float8_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f t f i DESCR("aggregate final function"); DATA(insert OID = 1832 ( float8_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "1022" _null_ _null_ _null_ _null_ float8_stddev_samp _null_ _null_ _null_ )); DESCR("aggregate final function"); ! DATA(insert OID = 1833 ( numeric_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 1700" _null_ _null_ _null_ _null_ numeric_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 2858 ( numeric_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 1700" _null_ _null_ _null_ _null_ numeric_avg_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 1834 ( int2_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 21" _null_ _null_ _null_ _null_ int2_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 1835 ( int4_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 23" _null_ _null_ _null_ _null_ int4_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 1836 ( int8_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 20" _null_ _null_ _null_ _null_ int8_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 2746 ( int8_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1231 "1231 20" _null_ _null_ _null_ _null_ int8_avg_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 1837 ( numeric_avg PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ )); DESCR("aggregate final function"); ! DATA(insert OID = 2514 ( numeric_var_pop PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_var_pop _null_ _null_ _null_ )); DESCR("aggregate final function"); ! DATA(insert OID = 1838 ( numeric_var_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_var_samp _null_ _null_ _null_ )); DESCR("aggregate final function"); ! DATA(insert OID = 2596 ( numeric_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_stddev_pop _null_ _null_ _null_ )); DESCR("aggregate final function"); ! DATA(insert OID = 1839 ( numeric_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1231" _null_ _null_ _null_ _null_ numeric_stddev_samp _null_ _null_ _null_ )); DESCR("aggregate final function"); DATA(insert OID = 1840 ( int2_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 20 "20 21" _null_ _null_ _null_ _null_ int2_sum _null_ _null_ _null_ )); DESCR("aggregate transition function"); --- 2381,2409 ---- DESCR("aggregate final function"); DATA(insert OID = 1832 ( float8_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 701 "1022" _null_ _null_ _null_ _null_ float8_stddev_samp _null_ _null_ _null_ )); DESCR("aggregate final function"); ! DATA(insert OID = 1833 ( numeric_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 1700" _null_ _null_ _null_ _null_ numeric_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 2858 ( numeric_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 1700" _null_ _null_ _null_ _null_ numeric_avg_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 1834 ( int2_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 21" _null_ _null_ _null_ _null_ int2_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 1835 ( int4_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 23" _null_ _null_ _null_ _null_ int4_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 1836 ( int8_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ int8_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 2746 ( int8_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 20" _null_ _null_ _null_ _null_ int8_avg_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); ! DATA(insert OID = 1837 ( numeric_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_avg _null_ _null_ _null_ )); DESCR("aggregate final function"); ! DATA(insert OID = 3179 ( numeric_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_sum _null_ _null_ _null_ )); DESCR("aggregate final function"); ! DATA(insert OID = 2514 ( numeric_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_var_pop _null_ _null_ _null_ )); DESCR("aggregate final function"); ! DATA(insert OID = 1838 ( numeric_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_var_samp _null_ _null_ _null_ )); DESCR("aggregate final function"); ! DATA(insert OID = 2596 ( numeric_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_stddev_pop _null_ _null_ _null_ )); ! DESCR("aggregate final function"); ! DATA(insert OID = 1839 ( numeric_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_stddev_samp _null_ _null_ _null_ )); DESCR("aggregate final function"); DATA(insert OID = 1840 ( int2_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 20 "20 21" _null_ _null_ _null_ _null_ int2_sum _null_ _null_ _null_ )); DESCR("aggregate transition function"); *** a/src/include/commands/defrem.h --- b/src/include/commands/defrem.h *************** *** 133,138 **** extern Datum transformGenericOptions(Oid catalogId, --- 133,139 ---- extern char *defGetString(DefElem *def); extern double defGetNumeric(DefElem *def); extern bool defGetBoolean(DefElem *def); + extern int32 defGetInt32(DefElem *def); extern int64 defGetInt64(DefElem *def); extern List *defGetQualifiedName(DefElem *def); extern TypeName *defGetTypeName(DefElem *def); *** a/src/include/utils/builtins.h --- b/src/include/utils/builtins.h *************** *** 982,987 **** extern Datum int4_accum(PG_FUNCTION_ARGS); --- 982,988 ---- extern Datum int8_accum(PG_FUNCTION_ARGS); extern Datum int8_avg_accum(PG_FUNCTION_ARGS); extern Datum numeric_avg(PG_FUNCTION_ARGS); + extern Datum numeric_sum(PG_FUNCTION_ARGS); extern Datum numeric_var_pop(PG_FUNCTION_ARGS); extern Datum numeric_var_samp(PG_FUNCTION_ARGS); extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS); *** a/src/test/regress/expected/aggregates.out --- b/src/test/regress/expected/aggregates.out *************** *** 1262,1264 **** select least_agg(variadic array[q1,q2]) from int8_tbl; --- 1262,1313 ---- -4567890123456789 (1 row) + -- verify correct calculations for null set + select sum(null::int4) from generate_series(1,1); + sum + ----- + + (1 row) + + select sum(null::int8) from generate_series(1,1); + sum + ----- + + (1 row) + + select sum(null::numeric) from generate_series(1,1); + sum + ----- + + (1 row) + + select sum(null::float8) from generate_series(1,1); + sum + ----- + + (1 row) + + select avg(null::int4) from generate_series(1,1); + avg + ----- + + (1 row) + + select avg(null::int8) from generate_series(1,1); + avg + ----- + + (1 row) + + select avg(null::numeric) from generate_series(1,1); + avg + ----- + + (1 row) + + select avg(null::float8) from generate_series(1,1); + avg + ----- + + (1 row) + *** a/src/test/regress/expected/create_aggregate.out --- b/src/test/regress/expected/create_aggregate.out *************** *** 66,68 **** returns anyelement language sql as --- 66,75 ---- create aggregate least_agg(variadic items anyarray) ( stype = anyelement, sfunc = least_accum ); + -- should not work, sspace is allowed only for stype internal + create aggregate aggfns(integer,integer,text) ( + sfunc = aggfns_trans, stype = aggtype[], sspace = 200, + initcond = '{}' + ); + ERROR: SSPACE can be used only for "internal" transition type + DETAIL: SSPACE can be defined only together with a "internal" transition type. *** a/src/test/regress/sql/aggregates.sql --- b/src/test/regress/sql/aggregates.sql *************** *** 484,486 **** select aggfns(distinct a,b,c order by a,c using ~<~,b) filter (where a > 1) --- 484,497 ---- -- variadic aggregates select least_agg(q1,q2) from int8_tbl; select least_agg(variadic array[q1,q2]) from int8_tbl; + + -- verify correct calculations for null set + select sum(null::int4) from generate_series(1,1); + select sum(null::int8) from generate_series(1,1); + select sum(null::numeric) from generate_series(1,1); + select sum(null::float8) from generate_series(1,1); + + select avg(null::int4) from generate_series(1,1); + select avg(null::int8) from generate_series(1,1); + select avg(null::numeric) from generate_series(1,1); + select avg(null::float8) from generate_series(1,1); *** a/src/test/regress/sql/create_aggregate.sql --- b/src/test/regress/sql/create_aggregate.sql *************** *** 80,82 **** returns anyelement language sql as --- 80,88 ---- create aggregate least_agg(variadic items anyarray) ( stype = anyelement, sfunc = least_accum ); + + -- should not work, sspace is allowed only for stype internal + create aggregate aggfns(integer,integer,text) ( + sfunc = aggfns_trans, stype = aggtype[], sspace = 200, + initcond = '{}' + );