From 9d229f399e87d2ae7132c2e8feef317ce1479728 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 12 Apr 2014 20:33:09 -0400 Subject: [PATCH] Provide moving-aggregate support for a bunch of numerical aggregates. First installment of the promised moving-aggregate support in built-in aggregates: count(), sum(), avg(), stddev() and variance() for assorted datatypes, though not for float4/float8. In passing, remove a 2001-vintage kluge in interval_accum(): interval array elements have been properly aligned since around 2003, but nobody remembered to take out this workaround. Also, fix a thinko in the opr_sanity tests for moving-aggregate catalog entries. David Rowley and Florian Pflug, reviewed by Dean Rasheed --- src/backend/utils/adt/int8.c | 63 ++- src/backend/utils/adt/numeric.c | 383 +++++++++++++++--- src/backend/utils/adt/timestamp.c | 72 ++-- src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_aggregate.h | 266 ++++++------- src/include/catalog/pg_proc.h | 20 + src/include/utils/builtins.h | 7 + src/include/utils/int8.h | 2 + src/include/utils/timestamp.h | 1 + src/test/regress/expected/opr_sanity.out | 12 +- src/test/regress/expected/window.out | 475 +++++++++++++++++++++++ src/test/regress/sql/opr_sanity.sql | 12 +- src/test/regress/sql/window.sql | 141 +++++++ 13 files changed, 1232 insertions(+), 224 deletions(-) diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 5e1be90dac..e78eb2a202 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -717,13 +717,58 @@ int8inc(PG_FUNCTION_ARGS) } } +Datum +int8dec(PG_FUNCTION_ARGS) +{ + /* + * When int8 is pass-by-reference, we provide this special case to avoid + * palloc overhead for COUNT(): when called as an aggregate, we know that + * the argument is modifiable local storage, so just update it in-place. + * (If int8 is pass-by-value, then of course this is useless as well as + * incorrect, so just ifdef it out.) + */ +#ifndef USE_FLOAT8_BYVAL /* controls int8 too */ + if (AggCheckCallContext(fcinfo, NULL)) + { + int64 *arg = (int64 *) PG_GETARG_POINTER(0); + int64 result; + + result = *arg - 1; + /* Overflow check */ + if (result > 0 && *arg < 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + + *arg = result; + PG_RETURN_POINTER(arg); + } + else +#endif + { + /* Not called as an aggregate, so just do it the dumb way */ + int64 arg = PG_GETARG_INT64(0); + int64 result; + + result = arg - 1; + /* Overflow check */ + if (result > 0 && arg < 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("bigint out of range"))); + + PG_RETURN_INT64(result); + } +} + + /* - * These functions are exactly like int8inc but are used for aggregates that - * count only non-null values. Since the functions are declared strict, - * the null checks happen before we ever get here, and all we need do is - * increment the state value. We could actually make these pg_proc entries - * point right at int8inc, but then the opr_sanity regression test would - * complain about mismatched entries for a built-in function. + * These functions are exactly like int8inc/int8dec but are used for + * aggregates that count only non-null values. Since the functions are + * declared strict, the null checks happen before we ever get here, and all we + * need do is increment the state value. We could actually make these pg_proc + * entries point right at int8inc/int8dec, but then the opr_sanity regression + * test would complain about mismatched entries for a built-in function. */ Datum @@ -738,6 +783,12 @@ int8inc_float8_float8(PG_FUNCTION_ARGS) return int8inc(fcinfo); } +Datum +int8dec_any(PG_FUNCTION_ARGS) +{ + return int8dec(fcinfo); +} + Datum int8larger(PG_FUNCTION_ARGS) diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 64eb0f8d16..bf4f29d14d 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -2506,22 +2506,19 @@ numeric_float4(PG_FUNCTION_ARGS) * Actually, it's a pointer to a NumericAggState allocated in the aggregate * context. The digit buffers for the NumericVars will be there too. * - * Note that the transition functions don't bother to create a NumericAggState - * until they see the first non-null input value; therefore, the final - * functions will never see N == 0. (The case is represented as a NULL - * state pointer, instead.) - * * ---------------------------------------------------------------------- */ typedef struct NumericAggState { bool calcSumX2; /* if true, calculate sumX2 */ - bool isNaN; /* true if any processed number was NaN */ MemoryContext agg_context; /* context we're calculating in */ int64 N; /* count of processed numbers */ NumericVar sumX; /* sum of processed numbers */ NumericVar sumX2; /* sum of squares of processed numbers */ + int maxScale; /* maximum scale seen so far */ + int64 maxScaleCount; /* number of values seen with maximum scale */ + int64 NaNcount; /* count of NaN values (not included in N!) */ } NumericAggState; /* @@ -2559,16 +2556,28 @@ do_numeric_accum(NumericAggState *state, Numeric newval) NumericVar X2; MemoryContext old_context; - /* result is NaN if any processed number is NaN */ - if (state->isNaN || NUMERIC_IS_NAN(newval)) + /* Count NaN inputs separately from all else */ + if (NUMERIC_IS_NAN(newval)) { - state->isNaN = true; + state->NaNcount++; return; } /* load processed number in short-lived context */ init_var_from_num(newval, &X); + /* + * Track the highest input dscale that we've seen, to support inverse + * transitions (see do_numeric_discard). + */ + if (X.dscale > state->maxScale) + { + state->maxScale = X.dscale; + state->maxScaleCount = 1; + } + else if (X.dscale == state->maxScale) + state->maxScaleCount++; + /* if we need X^2, calculate that in short-lived context */ if (state->calcSumX2) { @@ -2599,6 +2608,97 @@ do_numeric_accum(NumericAggState *state, Numeric newval) MemoryContextSwitchTo(old_context); } +/* + * Attempt to remove an input value from the aggregated state. + * + * If the value cannot be removed then the function will return false; the + * possible reasons for failing are described below. + * + * If we aggregate the values 1.01 and 2 then the result will be 3.01. + * If we are then asked to un-aggregate the 1.01 then we must fail as we + * won't be able to tell what the new aggregated value's dscale should be. + * We don't want to return 2.00 (dscale = 2), since the sum's dscale would + * have been zero if we'd really aggregated only 2. + * + * Note: alternatively, we could count the number of inputs with each possible + * dscale (up to some sane limit). Not yet clear if it's worth the trouble. + */ +static bool +do_numeric_discard(NumericAggState *state, Numeric newval) +{ + NumericVar X; + NumericVar X2; + MemoryContext old_context; + + /* Count NaN inputs separately from all else */ + if (NUMERIC_IS_NAN(newval)) + { + state->NaNcount--; + return true; + } + + /* load processed number in short-lived context */ + init_var_from_num(newval, &X); + + /* + * state->sumX's dscale is the maximum dscale of any of the inputs. + * Removing the last input with that dscale would require us to recompute + * the maximum dscale of the *remaining* inputs, which we cannot do unless + * no more non-NaN inputs remain at all. So we report a failure instead, + * and force the aggregation to be redone from scratch. + */ + if (X.dscale == state->maxScale) + { + if (state->maxScaleCount > 1 || state->maxScale == 0) + { + /* + * Some remaining inputs have same dscale, or dscale hasn't + * gotten above zero anyway + */ + state->maxScaleCount--; + } + else if (state->N == 1) + { + /* No remaining non-NaN inputs at all, so reset maxScale */ + state->maxScale = 0; + state->maxScaleCount = 0; + } + else + { + /* Correct new maxScale is uncertain, must fail */ + return false; + } + } + + /* if we need X^2, calculate that in short-lived context */ + if (state->calcSumX2) + { + init_var(&X2); + mul_var(&X, &X, &X2, X.dscale * 2); + } + + /* The rest of this needs to work in the aggregate context */ + old_context = MemoryContextSwitchTo(state->agg_context); + + if (state->N-- > 1) + { + /* De-accumulate sums */ + sub_var(&(state->sumX), &X, &(state->sumX)); + + if (state->calcSumX2) + sub_var(&(state->sumX2), &X2, &(state->sumX2)); + } + else + { + /* Sums will be reset by next call to do_numeric_accum */ + Assert(state->N == 0); + } + + MemoryContextSwitchTo(old_context); + + return true; +} + /* * Generic transition function for numeric aggregates that require sumX2. */ @@ -2609,14 +2709,12 @@ numeric_accum(PG_FUNCTION_ARGS) state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); - if (!PG_ARGISNULL(1)) - { - /* Create the state data when we see the first non-null input. */ - if (state == NULL) - state = makeNumericAggState(fcinfo, true); + /* Create the state data on the first call */ + if (state == NULL) + state = makeNumericAggState(fcinfo, true); + if (!PG_ARGISNULL(1)) do_numeric_accum(state, PG_GETARG_NUMERIC(1)); - } PG_RETURN_POINTER(state); } @@ -2631,18 +2729,42 @@ numeric_avg_accum(PG_FUNCTION_ARGS) state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); + /* Create the state data on the first call */ + if (state == NULL) + state = makeNumericAggState(fcinfo, false); + + if (!PG_ARGISNULL(1)) + do_numeric_accum(state, PG_GETARG_NUMERIC(1)); + + PG_RETURN_POINTER(state); +} + +/* + * Generic inverse transition function for numeric aggregates + * (with or without requirement for X^2). + */ +Datum +numeric_accum_inv(PG_FUNCTION_ARGS) +{ + NumericAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); + + /* Should not get here with no state */ + if (state == NULL) + elog(ERROR, "numeric_accum_inv called with NULL state"); + if (!PG_ARGISNULL(1)) { - /* Create the state data when we see the first non-null input. */ - if (state == NULL) - state = makeNumericAggState(fcinfo, false); - - do_numeric_accum(state, PG_GETARG_NUMERIC(1)); + /* If we fail to perform the inverse transition, return NULL */ + if (!do_numeric_discard(state, PG_GETARG_NUMERIC(1))) + PG_RETURN_NULL(); } 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 @@ -2659,17 +2781,16 @@ int2_accum(PG_FUNCTION_ARGS) state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); + /* Create the state data on the first call */ + if (state == NULL) + state = makeNumericAggState(fcinfo, true); + if (!PG_ARGISNULL(1)) { Numeric newval; newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, PG_GETARG_DATUM(1))); - - /* Create the state data when we see the first non-null input. */ - if (state == NULL) - state = makeNumericAggState(fcinfo, true); - do_numeric_accum(state, newval); } @@ -2683,17 +2804,16 @@ int4_accum(PG_FUNCTION_ARGS) state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); + /* Create the state data on the first call */ + if (state == NULL) + state = makeNumericAggState(fcinfo, true); + if (!PG_ARGISNULL(1)) { Numeric newval; newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, PG_GETARG_DATUM(1))); - - /* Create the state data when we see the first non-null input. */ - if (state == NULL) - state = makeNumericAggState(fcinfo, true); - do_numeric_accum(state, newval); } @@ -2707,17 +2827,16 @@ int8_accum(PG_FUNCTION_ARGS) state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); + /* Create the state data on the first call */ + if (state == NULL) + state = makeNumericAggState(fcinfo, true); + if (!PG_ARGISNULL(1)) { Numeric newval; newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(1))); - - /* Create the state data when we see the first non-null input. */ - if (state == NULL) - state = makeNumericAggState(fcinfo, true); - do_numeric_accum(state, newval); } @@ -2734,6 +2853,90 @@ int8_avg_accum(PG_FUNCTION_ARGS) state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); + /* Create the state data on the first call */ + if (state == NULL) + state = makeNumericAggState(fcinfo, false); + + if (!PG_ARGISNULL(1)) + { + Numeric newval; + + newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, + PG_GETARG_DATUM(1))); + do_numeric_accum(state, newval); + } + + PG_RETURN_POINTER(state); +} + + +/* + * Inverse transition functions to go with the above. + */ + +Datum +int2_accum_inv(PG_FUNCTION_ARGS) +{ + NumericAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); + + /* Should not get here with no state */ + if (state == NULL) + elog(ERROR, "int2_accum_inv called with NULL state"); + + if (!PG_ARGISNULL(1)) + { + Numeric newval; + + newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, + PG_GETARG_DATUM(1))); + + /* Should never fail, all inputs have dscale 0 */ + if (!do_numeric_discard(state, newval)) + elog(ERROR, "do_numeric_discard failed unexpectedly"); + } + + PG_RETURN_POINTER(state); +} + +Datum +int4_accum_inv(PG_FUNCTION_ARGS) +{ + NumericAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); + + /* Should not get here with no state */ + if (state == NULL) + elog(ERROR, "int4_accum_inv called with NULL state"); + + if (!PG_ARGISNULL(1)) + { + Numeric newval; + + newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, + PG_GETARG_DATUM(1))); + + /* Should never fail, all inputs have dscale 0 */ + if (!do_numeric_discard(state, newval)) + elog(ERROR, "do_numeric_discard failed unexpectedly"); + } + + PG_RETURN_POINTER(state); +} + +Datum +int8_accum_inv(PG_FUNCTION_ARGS) +{ + NumericAggState *state; + + state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); + + /* Should not get here with no state */ + if (state == NULL) + elog(ERROR, "int8_accum_inv called with NULL state"); + if (!PG_ARGISNULL(1)) { Numeric newval; @@ -2741,17 +2944,14 @@ int8_avg_accum(PG_FUNCTION_ARGS) newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(1))); - /* Create the state data when we see the first non-null input. */ - if (state == NULL) - state = makeNumericAggState(fcinfo, false); - - do_numeric_accum(state, newval); + /* Should never fail, all inputs have dscale 0 */ + if (!do_numeric_discard(state, newval)) + elog(ERROR, "do_numeric_discard failed unexpectedly"); } PG_RETURN_POINTER(state); } - Datum numeric_avg(PG_FUNCTION_ARGS) { @@ -2760,10 +2960,12 @@ numeric_avg(PG_FUNCTION_ARGS) Datum sumX_datum; state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); - if (state == NULL) /* there were no non-null inputs */ + + /* If there were no non-null inputs, return NULL */ + if (state == NULL || (state->N + state->NaNcount) == 0) PG_RETURN_NULL(); - if (state->isNaN) /* there was at least one NaN input */ + if (state->NaNcount > 0) /* there was at least one NaN input */ PG_RETURN_NUMERIC(make_result(&const_nan)); N_datum = DirectFunctionCall1(int8_numeric, Int64GetDatum(state->N)); @@ -2778,10 +2980,12 @@ numeric_sum(PG_FUNCTION_ARGS) NumericAggState *state; state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0); - if (state == NULL) /* there were no non-null inputs */ + + /* If there were no non-null inputs, return NULL */ + if (state == NULL || (state->N + state->NaNcount) == 0) PG_RETURN_NULL(); - if (state->isNaN) /* there was at least one NaN input */ + if (state->NaNcount > 0) /* there was at least one NaN input */ PG_RETURN_NUMERIC(make_result(&const_nan)); PG_RETURN_NUMERIC(make_result(&(state->sumX))); @@ -2812,7 +3016,7 @@ numeric_stddev_internal(NumericAggState *state, int rscale; /* Deal with empty input and NaN-input cases */ - if (state == NULL) + if (state == NULL || (state->N + state->NaNcount) == 0) { *is_null = true; return NULL; @@ -2820,7 +3024,7 @@ numeric_stddev_internal(NumericAggState *state, *is_null = false; - if (state->isNaN) + if (state->NaNcount > 0) return make_result(&const_nan); init_var(&vN); @@ -2965,6 +3169,9 @@ numeric_stddev_pop(PG_FUNCTION_ARGS) * data value into the transition data: it doesn't know how to do the type * conversion. The upshot is that these routines have to be marked non-strict * and handle substitution of the first non-null input themselves. + * + * Note: these functions are used only in plain aggregation mode. + * In moving-aggregate mode, we use intX_avg_accum and intX_avg_accum_inv. */ Datum @@ -3107,6 +3314,10 @@ int8_sum(PG_FUNCTION_ARGS) /* * Routines for avg(int2) and avg(int4). The transition datatype * is a two-element int8 array, holding count and sum. + * + * These functions are also used for sum(int2) and sum(int4) when + * operating in moving-aggregate mode, since for correct inverse transitions + * we need to count the inputs. */ typedef struct Int8TransTypeData @@ -3171,6 +3382,62 @@ int4_avg_accum(PG_FUNCTION_ARGS) PG_RETURN_ARRAYTYPE_P(transarray); } +Datum +int2_avg_accum_inv(PG_FUNCTION_ARGS) +{ + ArrayType *transarray; + int16 newval = PG_GETARG_INT16(1); + Int8TransTypeData *transdata; + + /* + * If we're invoked as an aggregate, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we need to make + * a copy of it before scribbling on it. + */ + if (AggCheckCallContext(fcinfo, NULL)) + transarray = PG_GETARG_ARRAYTYPE_P(0); + else + transarray = PG_GETARG_ARRAYTYPE_P_COPY(0); + + if (ARR_HASNULL(transarray) || + ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) + elog(ERROR, "expected 2-element int8 array"); + + transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); + transdata->count--; + transdata->sum -= newval; + + PG_RETURN_ARRAYTYPE_P(transarray); +} + +Datum +int4_avg_accum_inv(PG_FUNCTION_ARGS) +{ + ArrayType *transarray; + int32 newval = PG_GETARG_INT32(1); + Int8TransTypeData *transdata; + + /* + * If we're invoked as an aggregate, we can cheat and modify our first + * parameter in-place to reduce palloc overhead. Otherwise we need to make + * a copy of it before scribbling on it. + */ + if (AggCheckCallContext(fcinfo, NULL)) + transarray = PG_GETARG_ARRAYTYPE_P(0); + else + transarray = PG_GETARG_ARRAYTYPE_P_COPY(0); + + if (ARR_HASNULL(transarray) || + ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) + elog(ERROR, "expected 2-element int8 array"); + + transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); + transdata->count--; + transdata->sum -= newval; + + PG_RETURN_ARRAYTYPE_P(transarray); +} + Datum int8_avg(PG_FUNCTION_ARGS) { @@ -3196,6 +3463,28 @@ int8_avg(PG_FUNCTION_ARGS) PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd)); } +/* + * SUM(int2) and SUM(int4) both return int8, so we can use this + * final function for both. + */ +Datum +int2int4_sum(PG_FUNCTION_ARGS) +{ + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + Int8TransTypeData *transdata; + + if (ARR_HASNULL(transarray) || + ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) + elog(ERROR, "expected 2-element int8 array"); + transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); + + /* SQL defines SUM of no values to be NULL */ + if (transdata->count == 0) + PG_RETURN_NULL(); + + PG_RETURN_DATUM(Int64GetDatumFast(transdata->sum)); +} + /* ---------------------------------------------------------------------- * diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index ce30bb6e9f..efc1e9b992 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -3229,7 +3229,6 @@ interval_mi(PG_FUNCTION_ARGS) (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); - PG_RETURN_INTERVAL_P(result); } @@ -3376,12 +3375,18 @@ interval_div(PG_FUNCTION_ARGS) } /* - * interval_accum and interval_avg implement the AVG(interval) aggregate. + * interval_accum, interval_accum_inv, and interval_avg implement the + * AVG(interval) aggregate. * * The transition datatype for this aggregate is a 2-element array of * intervals, where the first is the running sum and the second contains * the number of values so far in its 'time' field. This is a bit ugly * but it beats inventing a specialized datatype for the purpose. + * + * NOTE: The inverse transition function cannot guarantee exact results + * when using float8 timestamps. However, int8 timestamps are now the + * norm, and the probable range of values is not so wide that disastrous + * cancellation is likely even with float8, so we'll ignore the risk. */ Datum @@ -3402,17 +3407,8 @@ interval_accum(PG_FUNCTION_ARGS) if (ndatums != 2) elog(ERROR, "expected 2-element interval array"); - /* - * XXX memcpy, instead of just extracting a pointer, to work around buggy - * array code: it won't ensure proper alignment of Interval objects on - * machines where double requires 8-byte alignment. That should be fixed, - * but in the meantime... - * - * Note: must use DatumGetPointer here, not DatumGetIntervalP, else some - * compilers optimize into double-aligned load/store anyway. - */ - memcpy((void *) &sumX, DatumGetPointer(transdatums[0]), sizeof(Interval)); - memcpy((void *) &N, DatumGetPointer(transdatums[1]), sizeof(Interval)); + sumX = *(DatumGetIntervalP(transdatums[0])); + N = *(DatumGetIntervalP(transdatums[1])); newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl, IntervalPGetDatum(&sumX), @@ -3428,6 +3424,41 @@ interval_accum(PG_FUNCTION_ARGS) PG_RETURN_ARRAYTYPE_P(result); } +Datum +interval_accum_inv(PG_FUNCTION_ARGS) +{ + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + Interval *newval = PG_GETARG_INTERVAL_P(1); + Datum *transdatums; + int ndatums; + Interval sumX, + N; + Interval *newsum; + ArrayType *result; + + deconstruct_array(transarray, + INTERVALOID, sizeof(Interval), false, 'd', + &transdatums, NULL, &ndatums); + if (ndatums != 2) + elog(ERROR, "expected 2-element interval array"); + + sumX = *(DatumGetIntervalP(transdatums[0])); + N = *(DatumGetIntervalP(transdatums[1])); + + newsum = DatumGetIntervalP(DirectFunctionCall2(interval_mi, + IntervalPGetDatum(&sumX), + IntervalPGetDatum(newval))); + N.time -= 1; + + transdatums[0] = IntervalPGetDatum(newsum); + transdatums[1] = IntervalPGetDatum(&N); + + result = construct_array(transdatums, 2, + INTERVALOID, sizeof(Interval), false, 'd'); + + PG_RETURN_ARRAYTYPE_P(result); +} + Datum interval_avg(PG_FUNCTION_ARGS) { @@ -3443,17 +3474,8 @@ interval_avg(PG_FUNCTION_ARGS) if (ndatums != 2) elog(ERROR, "expected 2-element interval array"); - /* - * XXX memcpy, instead of just extracting a pointer, to work around buggy - * array code: it won't ensure proper alignment of Interval objects on - * machines where double requires 8-byte alignment. That should be fixed, - * but in the meantime... - * - * Note: must use DatumGetPointer here, not DatumGetIntervalP, else some - * compilers optimize into double-aligned load/store anyway. - */ - memcpy((void *) &sumX, DatumGetPointer(transdatums[0]), sizeof(Interval)); - memcpy((void *) &N, DatumGetPointer(transdatums[1]), sizeof(Interval)); + sumX = *(DatumGetIntervalP(transdatums[0])); + N = *(DatumGetIntervalP(transdatums[1])); /* SQL defines AVG of no values to be NULL */ if (N.time == 0) @@ -3461,7 +3483,7 @@ interval_avg(PG_FUNCTION_ARGS) return DirectFunctionCall2(interval_div, IntervalPGetDatum(&sumX), - Float8GetDatum(N.time)); + Float8GetDatum((double) N.time)); } diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 2fb0ce8656..0d301cf1ac 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201404121 +#define CATALOG_VERSION_NO 201404122 #endif diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index 3cb0d754e7..5116beb62a 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -119,177 +119,177 @@ typedef FormData_pg_aggregate *Form_pg_aggregate; */ /* avg */ -DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2101 n 0 int4_avg_accum int8_avg - - - 0 1016 0 0 0 "{0,0}" _null_ )); -DATA(insert ( 2102 n 0 int2_avg_accum int8_avg - - - 0 1016 0 0 0 "{0,0}" _null_ )); -DATA(insert ( 2103 n 0 numeric_avg_accum numeric_avg - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2104 n 0 float4_accum float8_avg - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2105 n 0 float8_accum float8_avg - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2106 n 0 interval_accum interval_avg - - - 0 1187 0 0 0 "{0 second,0 second}" _null_ )); +DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg 0 1016 0 1016 0 "{0,0}" "{0,0}" )); +DATA(insert ( 2102 n 0 int2_avg_accum int8_avg int2_avg_accum int2_avg_accum_inv int8_avg 0 1016 0 1016 0 "{0,0}" "{0,0}" )); +DATA(insert ( 2103 n 0 numeric_avg_accum numeric_avg numeric_avg_accum numeric_accum_inv numeric_avg 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2104 n 0 float4_accum float8_avg - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2105 n 0 float8_accum float8_avg - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2106 n 0 interval_accum interval_avg interval_accum interval_accum_inv interval_avg 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" )); /* sum */ -DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2108 n 0 int4_sum - - - - 0 20 0 0 0 _null_ _null_ )); -DATA(insert ( 2109 n 0 int2_sum - - - - 0 20 0 0 0 _null_ _null_ )); -DATA(insert ( 2110 n 0 float4pl - - - - 0 700 0 0 0 _null_ _null_ )); -DATA(insert ( 2111 n 0 float8pl - - - - 0 701 0 0 0 _null_ _null_ )); -DATA(insert ( 2112 n 0 cash_pl - - - - 0 790 0 0 0 _null_ _null_ )); -DATA(insert ( 2113 n 0 interval_pl - - - - 0 1186 0 0 0 _null_ _null_ )); -DATA(insert ( 2114 n 0 numeric_avg_accum numeric_sum - - - 0 2281 128 0 0 _null_ _null_ )); +DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum 0 20 0 1016 0 _null_ "{0,0}" )); +DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum 0 20 0 1016 0 _null_ "{0,0}" )); +DATA(insert ( 2110 n 0 float4pl - - - - 0 700 0 0 0 _null_ _null_ )); +DATA(insert ( 2111 n 0 float8pl - - - - 0 701 0 0 0 _null_ _null_ )); +DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - 0 790 0 790 0 _null_ _null_ )); +DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - 0 1186 0 1186 0 _null_ _null_ )); +DATA(insert ( 2114 n 0 numeric_avg_accum numeric_sum numeric_avg_accum numeric_accum_inv numeric_sum 0 2281 128 2281 128 _null_ _null_ )); /* max */ -DATA(insert ( 2115 n 0 int8larger - - - - 413 20 0 0 0 _null_ _null_ )); -DATA(insert ( 2116 n 0 int4larger - - - - 521 23 0 0 0 _null_ _null_ )); -DATA(insert ( 2117 n 0 int2larger - - - - 520 21 0 0 0 _null_ _null_ )); -DATA(insert ( 2118 n 0 oidlarger - - - - 610 26 0 0 0 _null_ _null_ )); -DATA(insert ( 2119 n 0 float4larger - - - - 623 700 0 0 0 _null_ _null_ )); -DATA(insert ( 2120 n 0 float8larger - - - - 674 701 0 0 0 _null_ _null_ )); -DATA(insert ( 2121 n 0 int4larger - - - - 563 702 0 0 0 _null_ _null_ )); -DATA(insert ( 2122 n 0 date_larger - - - - 1097 1082 0 0 0 _null_ _null_ )); -DATA(insert ( 2123 n 0 time_larger - - - - 1112 1083 0 0 0 _null_ _null_ )); -DATA(insert ( 2124 n 0 timetz_larger - - - - 1554 1266 0 0 0 _null_ _null_ )); -DATA(insert ( 2125 n 0 cashlarger - - - - 903 790 0 0 0 _null_ _null_ )); -DATA(insert ( 2126 n 0 timestamp_larger - - - - 2064 1114 0 0 0 _null_ _null_ )); -DATA(insert ( 2127 n 0 timestamptz_larger - - - - 1324 1184 0 0 0 _null_ _null_ )); -DATA(insert ( 2128 n 0 interval_larger - - - - 1334 1186 0 0 0 _null_ _null_ )); -DATA(insert ( 2129 n 0 text_larger - - - - 666 25 0 0 0 _null_ _null_ )); -DATA(insert ( 2130 n 0 numeric_larger - - - - 1756 1700 0 0 0 _null_ _null_ )); -DATA(insert ( 2050 n 0 array_larger - - - - 1073 2277 0 0 0 _null_ _null_ )); -DATA(insert ( 2244 n 0 bpchar_larger - - - - 1060 1042 0 0 0 _null_ _null_ )); -DATA(insert ( 2797 n 0 tidlarger - - - - 2800 27 0 0 0 _null_ _null_ )); -DATA(insert ( 3526 n 0 enum_larger - - - - 3519 3500 0 0 0 _null_ _null_ )); +DATA(insert ( 2115 n 0 int8larger - - - - 413 20 0 0 0 _null_ _null_ )); +DATA(insert ( 2116 n 0 int4larger - - - - 521 23 0 0 0 _null_ _null_ )); +DATA(insert ( 2117 n 0 int2larger - - - - 520 21 0 0 0 _null_ _null_ )); +DATA(insert ( 2118 n 0 oidlarger - - - - 610 26 0 0 0 _null_ _null_ )); +DATA(insert ( 2119 n 0 float4larger - - - - 623 700 0 0 0 _null_ _null_ )); +DATA(insert ( 2120 n 0 float8larger - - - - 674 701 0 0 0 _null_ _null_ )); +DATA(insert ( 2121 n 0 int4larger - - - - 563 702 0 0 0 _null_ _null_ )); +DATA(insert ( 2122 n 0 date_larger - - - - 1097 1082 0 0 0 _null_ _null_ )); +DATA(insert ( 2123 n 0 time_larger - - - - 1112 1083 0 0 0 _null_ _null_ )); +DATA(insert ( 2124 n 0 timetz_larger - - - - 1554 1266 0 0 0 _null_ _null_ )); +DATA(insert ( 2125 n 0 cashlarger - - - - 903 790 0 0 0 _null_ _null_ )); +DATA(insert ( 2126 n 0 timestamp_larger - - - - 2064 1114 0 0 0 _null_ _null_ )); +DATA(insert ( 2127 n 0 timestamptz_larger - - - - 1324 1184 0 0 0 _null_ _null_ )); +DATA(insert ( 2128 n 0 interval_larger - - - - 1334 1186 0 0 0 _null_ _null_ )); +DATA(insert ( 2129 n 0 text_larger - - - - 666 25 0 0 0 _null_ _null_ )); +DATA(insert ( 2130 n 0 numeric_larger - - - - 1756 1700 0 0 0 _null_ _null_ )); +DATA(insert ( 2050 n 0 array_larger - - - - 1073 2277 0 0 0 _null_ _null_ )); +DATA(insert ( 2244 n 0 bpchar_larger - - - - 1060 1042 0 0 0 _null_ _null_ )); +DATA(insert ( 2797 n 0 tidlarger - - - - 2800 27 0 0 0 _null_ _null_ )); +DATA(insert ( 3526 n 0 enum_larger - - - - 3519 3500 0 0 0 _null_ _null_ )); /* min */ -DATA(insert ( 2131 n 0 int8smaller - - - - 412 20 0 0 0 _null_ _null_ )); -DATA(insert ( 2132 n 0 int4smaller - - - - 97 23 0 0 0 _null_ _null_ )); -DATA(insert ( 2133 n 0 int2smaller - - - - 95 21 0 0 0 _null_ _null_ )); -DATA(insert ( 2134 n 0 oidsmaller - - - - 609 26 0 0 0 _null_ _null_ )); -DATA(insert ( 2135 n 0 float4smaller - - - - 622 700 0 0 0 _null_ _null_ )); -DATA(insert ( 2136 n 0 float8smaller - - - - 672 701 0 0 0 _null_ _null_ )); -DATA(insert ( 2137 n 0 int4smaller - - - - 562 702 0 0 0 _null_ _null_ )); -DATA(insert ( 2138 n 0 date_smaller - - - - 1095 1082 0 0 0 _null_ _null_ )); -DATA(insert ( 2139 n 0 time_smaller - - - - 1110 1083 0 0 0 _null_ _null_ )); -DATA(insert ( 2140 n 0 timetz_smaller - - - - 1552 1266 0 0 0 _null_ _null_ )); -DATA(insert ( 2141 n 0 cashsmaller - - - - 902 790 0 0 0 _null_ _null_ )); -DATA(insert ( 2142 n 0 timestamp_smaller - - - - 2062 1114 0 0 0 _null_ _null_ )); -DATA(insert ( 2143 n 0 timestamptz_smaller - - - - 1322 1184 0 0 0 _null_ _null_ )); -DATA(insert ( 2144 n 0 interval_smaller - - - - 1332 1186 0 0 0 _null_ _null_ )); -DATA(insert ( 2145 n 0 text_smaller - - - - 664 25 0 0 0 _null_ _null_ )); -DATA(insert ( 2146 n 0 numeric_smaller - - - - 1754 1700 0 0 0 _null_ _null_ )); -DATA(insert ( 2051 n 0 array_smaller - - - - 1072 2277 0 0 0 _null_ _null_ )); -DATA(insert ( 2245 n 0 bpchar_smaller - - - - 1058 1042 0 0 0 _null_ _null_ )); -DATA(insert ( 2798 n 0 tidsmaller - - - - 2799 27 0 0 0 _null_ _null_ )); -DATA(insert ( 3527 n 0 enum_smaller - - - - 3518 3500 0 0 0 _null_ _null_ )); +DATA(insert ( 2131 n 0 int8smaller - - - - 412 20 0 0 0 _null_ _null_ )); +DATA(insert ( 2132 n 0 int4smaller - - - - 97 23 0 0 0 _null_ _null_ )); +DATA(insert ( 2133 n 0 int2smaller - - - - 95 21 0 0 0 _null_ _null_ )); +DATA(insert ( 2134 n 0 oidsmaller - - - - 609 26 0 0 0 _null_ _null_ )); +DATA(insert ( 2135 n 0 float4smaller - - - - 622 700 0 0 0 _null_ _null_ )); +DATA(insert ( 2136 n 0 float8smaller - - - - 672 701 0 0 0 _null_ _null_ )); +DATA(insert ( 2137 n 0 int4smaller - - - - 562 702 0 0 0 _null_ _null_ )); +DATA(insert ( 2138 n 0 date_smaller - - - - 1095 1082 0 0 0 _null_ _null_ )); +DATA(insert ( 2139 n 0 time_smaller - - - - 1110 1083 0 0 0 _null_ _null_ )); +DATA(insert ( 2140 n 0 timetz_smaller - - - - 1552 1266 0 0 0 _null_ _null_ )); +DATA(insert ( 2141 n 0 cashsmaller - - - - 902 790 0 0 0 _null_ _null_ )); +DATA(insert ( 2142 n 0 timestamp_smaller - - - - 2062 1114 0 0 0 _null_ _null_ )); +DATA(insert ( 2143 n 0 timestamptz_smaller - - - - 1322 1184 0 0 0 _null_ _null_ )); +DATA(insert ( 2144 n 0 interval_smaller - - - - 1332 1186 0 0 0 _null_ _null_ )); +DATA(insert ( 2145 n 0 text_smaller - - - - 664 25 0 0 0 _null_ _null_ )); +DATA(insert ( 2146 n 0 numeric_smaller - - - - 1754 1700 0 0 0 _null_ _null_ )); +DATA(insert ( 2051 n 0 array_smaller - - - - 1072 2277 0 0 0 _null_ _null_ )); +DATA(insert ( 2245 n 0 bpchar_smaller - - - - 1058 1042 0 0 0 _null_ _null_ )); +DATA(insert ( 2798 n 0 tidsmaller - - - - 2799 27 0 0 0 _null_ _null_ )); +DATA(insert ( 3527 n 0 enum_smaller - - - - 3518 3500 0 0 0 _null_ _null_ )); /* count */ -DATA(insert ( 2147 n 0 int8inc_any - - - - 0 20 0 0 0 "0" _null_ )); -DATA(insert ( 2803 n 0 int8inc - - - - 0 20 0 0 0 "0" _null_ )); +DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - 0 20 0 20 0 "0" "0" )); +DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - 0 20 0 20 0 "0" "0" )); /* var_pop */ -DATA(insert ( 2718 n 0 int8_accum numeric_var_pop - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2719 n 0 int4_accum numeric_var_pop - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2720 n 0 int2_accum numeric_var_pop - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2723 n 0 numeric_accum numeric_var_pop - - - 0 2281 128 0 0 _null_ _null_ )); +DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2719 n 0 int4_accum numeric_var_pop int4_accum int4_accum_inv numeric_var_pop 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2720 n 0 int2_accum numeric_var_pop int2_accum int2_accum_inv numeric_var_pop 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2723 n 0 numeric_accum numeric_var_pop numeric_accum numeric_accum_inv numeric_var_pop 0 2281 128 2281 128 _null_ _null_ )); /* var_samp */ -DATA(insert ( 2641 n 0 int8_accum numeric_var_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2642 n 0 int4_accum numeric_var_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2643 n 0 int2_accum numeric_var_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2646 n 0 numeric_accum numeric_var_samp - - - 0 2281 128 0 0 _null_ _null_ )); +DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2642 n 0 int4_accum numeric_var_samp int4_accum int4_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2643 n 0 int2_accum numeric_var_samp int2_accum int2_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2646 n 0 numeric_accum numeric_var_samp numeric_accum numeric_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ )); /* variance: historical Postgres syntax for var_samp */ -DATA(insert ( 2148 n 0 int8_accum numeric_var_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2149 n 0 int4_accum numeric_var_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2150 n 0 int2_accum numeric_var_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2153 n 0 numeric_accum numeric_var_samp - - - 0 2281 128 0 0 _null_ _null_ )); +DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2149 n 0 int4_accum numeric_var_samp int4_accum int4_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2150 n 0 int2_accum numeric_var_samp int2_accum int2_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2153 n 0 numeric_accum numeric_var_samp numeric_accum numeric_accum_inv numeric_var_samp 0 2281 128 2281 128 _null_ _null_ )); /* stddev_pop */ -DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2725 n 0 int4_accum numeric_stddev_pop - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2726 n 0 int2_accum numeric_stddev_pop - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2729 n 0 numeric_accum numeric_stddev_pop - - - 0 2281 128 0 0 _null_ _null_ )); +DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2725 n 0 int4_accum numeric_stddev_pop int4_accum int4_accum_inv numeric_stddev_pop 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2726 n 0 int2_accum numeric_stddev_pop int2_accum int2_accum_inv numeric_stddev_pop 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2729 n 0 numeric_accum numeric_stddev_pop numeric_accum numeric_accum_inv numeric_stddev_pop 0 2281 128 2281 128 _null_ _null_ )); /* stddev_samp */ -DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2713 n 0 int4_accum numeric_stddev_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2714 n 0 int2_accum numeric_stddev_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2717 n 0 numeric_accum numeric_stddev_samp - - - 0 2281 128 0 0 _null_ _null_ )); +DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2713 n 0 int4_accum numeric_stddev_samp int4_accum int4_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2714 n 0 int2_accum numeric_stddev_samp int2_accum int2_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2717 n 0 numeric_accum numeric_stddev_samp numeric_accum numeric_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ )); /* stddev: historical Postgres syntax for stddev_samp */ -DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2155 n 0 int4_accum numeric_stddev_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2156 n 0 int2_accum numeric_stddev_samp - - - 0 2281 128 0 0 _null_ _null_ )); -DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); -DATA(insert ( 2159 n 0 numeric_accum numeric_stddev_samp - - - 0 2281 128 0 0 _null_ _null_ )); +DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2155 n 0 int4_accum numeric_stddev_samp int4_accum int4_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2156 n 0 int2_accum numeric_stddev_samp int2_accum int2_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ )); +DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - 0 1022 0 0 0 "{0,0,0}" _null_ )); +DATA(insert ( 2159 n 0 numeric_accum numeric_stddev_samp numeric_accum numeric_accum_inv numeric_stddev_samp 0 2281 128 2281 128 _null_ _null_ )); /* SQL2003 binary regression aggregates */ -DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - 0 20 0 0 0 "0" _null_ )); -DATA(insert ( 2819 n 0 float8_regr_accum float8_regr_sxx - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); -DATA(insert ( 2820 n 0 float8_regr_accum float8_regr_syy - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); -DATA(insert ( 2821 n 0 float8_regr_accum float8_regr_sxy - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); -DATA(insert ( 2822 n 0 float8_regr_accum float8_regr_avgx - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); -DATA(insert ( 2823 n 0 float8_regr_accum float8_regr_avgy - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); -DATA(insert ( 2824 n 0 float8_regr_accum float8_regr_r2 - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); -DATA(insert ( 2825 n 0 float8_regr_accum float8_regr_slope - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); -DATA(insert ( 2826 n 0 float8_regr_accum float8_regr_intercept - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); -DATA(insert ( 2827 n 0 float8_regr_accum float8_covar_pop - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); -DATA(insert ( 2828 n 0 float8_regr_accum float8_covar_samp - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); -DATA(insert ( 2829 n 0 float8_regr_accum float8_corr - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - 0 20 0 0 0 "0" _null_ )); +DATA(insert ( 2819 n 0 float8_regr_accum float8_regr_sxx - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2820 n 0 float8_regr_accum float8_regr_syy - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2821 n 0 float8_regr_accum float8_regr_sxy - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2822 n 0 float8_regr_accum float8_regr_avgx - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2823 n 0 float8_regr_accum float8_regr_avgy - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2824 n 0 float8_regr_accum float8_regr_r2 - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2825 n 0 float8_regr_accum float8_regr_slope - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2826 n 0 float8_regr_accum float8_regr_intercept - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2827 n 0 float8_regr_accum float8_covar_pop - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2828 n 0 float8_regr_accum float8_covar_samp - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); +DATA(insert ( 2829 n 0 float8_regr_accum float8_corr - - - 0 1022 0 0 0 "{0,0,0,0,0,0}" _null_ )); /* boolean-and and boolean-or */ -DATA(insert ( 2517 n 0 booland_statefunc - - - - 58 16 0 0 0 _null_ _null_ )); -DATA(insert ( 2518 n 0 boolor_statefunc - - - - 59 16 0 0 0 _null_ _null_ )); -DATA(insert ( 2519 n 0 booland_statefunc - - - - 58 16 0 0 0 _null_ _null_ )); +DATA(insert ( 2517 n 0 booland_statefunc - - - - 58 16 0 0 0 _null_ _null_ )); +DATA(insert ( 2518 n 0 boolor_statefunc - - - - 59 16 0 0 0 _null_ _null_ )); +DATA(insert ( 2519 n 0 booland_statefunc - - - - 58 16 0 0 0 _null_ _null_ )); /* bitwise integer */ -DATA(insert ( 2236 n 0 int2and - - - - 0 21 0 0 0 _null_ _null_ )); -DATA(insert ( 2237 n 0 int2or - - - - 0 21 0 0 0 _null_ _null_ )); -DATA(insert ( 2238 n 0 int4and - - - - 0 23 0 0 0 _null_ _null_ )); -DATA(insert ( 2239 n 0 int4or - - - - 0 23 0 0 0 _null_ _null_ )); -DATA(insert ( 2240 n 0 int8and - - - - 0 20 0 0 0 _null_ _null_ )); -DATA(insert ( 2241 n 0 int8or - - - - 0 20 0 0 0 _null_ _null_ )); -DATA(insert ( 2242 n 0 bitand - - - - 0 1560 0 0 0 _null_ _null_ )); -DATA(insert ( 2243 n 0 bitor - - - - 0 1560 0 0 0 _null_ _null_ )); +DATA(insert ( 2236 n 0 int2and - - - - 0 21 0 0 0 _null_ _null_ )); +DATA(insert ( 2237 n 0 int2or - - - - 0 21 0 0 0 _null_ _null_ )); +DATA(insert ( 2238 n 0 int4and - - - - 0 23 0 0 0 _null_ _null_ )); +DATA(insert ( 2239 n 0 int4or - - - - 0 23 0 0 0 _null_ _null_ )); +DATA(insert ( 2240 n 0 int8and - - - - 0 20 0 0 0 _null_ _null_ )); +DATA(insert ( 2241 n 0 int8or - - - - 0 20 0 0 0 _null_ _null_ )); +DATA(insert ( 2242 n 0 bitand - - - - 0 1560 0 0 0 _null_ _null_ )); +DATA(insert ( 2243 n 0 bitor - - - - 0 1560 0 0 0 _null_ _null_ )); /* xml */ -DATA(insert ( 2901 n 0 xmlconcat2 - - - - 0 142 0 0 0 _null_ _null_ )); +DATA(insert ( 2901 n 0 xmlconcat2 - - - - 0 142 0 0 0 _null_ _null_ )); /* array */ -DATA(insert ( 2335 n 0 array_agg_transfn array_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 2335 n 0 array_agg_transfn array_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ )); /* text */ -DATA(insert ( 3538 n 0 string_agg_transfn string_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3538 n 0 string_agg_transfn string_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ )); /* bytea */ -DATA(insert ( 3545 n 0 bytea_string_agg_transfn bytea_string_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3545 n 0 bytea_string_agg_transfn bytea_string_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ )); /* json */ -DATA(insert ( 3175 n 0 json_agg_transfn json_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3197 n 0 json_object_agg_transfn json_object_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3175 n 0 json_agg_transfn json_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3197 n 0 json_object_agg_transfn json_object_agg_finalfn - - - 0 2281 0 0 0 _null_ _null_ )); /* ordered-set and hypothetical-set aggregates */ -DATA(insert ( 3972 o 1 ordered_set_transition percentile_disc_final - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3974 o 1 ordered_set_transition percentile_cont_float8_final - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3976 o 1 ordered_set_transition percentile_cont_interval_final - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3978 o 1 ordered_set_transition percentile_disc_multi_final - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3980 o 1 ordered_set_transition percentile_cont_float8_multi_final - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3982 o 1 ordered_set_transition percentile_cont_interval_multi_final - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3984 o 0 ordered_set_transition mode_final - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3986 h 1 ordered_set_transition_multi rank_final - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3988 h 1 ordered_set_transition_multi percent_rank_final - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3990 h 1 ordered_set_transition_multi cume_dist_final - - - 0 2281 0 0 0 _null_ _null_ )); -DATA(insert ( 3992 h 1 ordered_set_transition_multi dense_rank_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3972 o 1 ordered_set_transition percentile_disc_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3974 o 1 ordered_set_transition percentile_cont_float8_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3976 o 1 ordered_set_transition percentile_cont_interval_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3978 o 1 ordered_set_transition percentile_disc_multi_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3980 o 1 ordered_set_transition percentile_cont_float8_multi_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3982 o 1 ordered_set_transition percentile_cont_interval_multi_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3984 o 0 ordered_set_transition mode_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3986 h 1 ordered_set_transition_multi rank_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3988 h 1 ordered_set_transition_multi percent_rank_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3990 h 1 ordered_set_transition_multi cume_dist_final - - - 0 2281 0 0 0 _null_ _null_ )); +DATA(insert ( 3992 h 1 ordered_set_transition_multi dense_rank_final - - - 0 2281 0 0 0 _null_ _null_ )); /* diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 7b9c5870fa..a24f4e02f9 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -1311,8 +1311,12 @@ DESCR("truncate interval to specified units"); DATA(insert OID = 1219 ( int8inc PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 20 "20" _null_ _null_ _null_ _null_ int8inc _null_ _null_ _null_ )); DESCR("increment"); +DATA(insert OID = 3546 ( int8dec PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 20 "20" _null_ _null_ _null_ _null_ int8dec _null_ _null_ _null_ )); +DESCR("decrement"); DATA(insert OID = 2804 ( int8inc_any PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 20 "20 2276" _null_ _null_ _null_ _null_ int8inc_any _null_ _null_ _null_ )); DESCR("increment, ignores second argument"); +DATA(insert OID = 3547 ( int8dec_any PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 20 "20 2276" _null_ _null_ _null_ _null_ int8dec_any _null_ _null_ _null_ )); +DESCR("decrement, ignores second argument"); DATA(insert OID = 1230 ( int8abs PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 20 "20" _null_ _null_ _null_ _null_ int8abs _null_ _null_ _null_ )); DATA(insert OID = 1236 ( int8larger PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 20 "20 20" _null_ _null_ _null_ _null_ int8larger _null_ _null_ _null_ )); @@ -2423,6 +2427,8 @@ DATA(insert OID = 1833 ( numeric_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 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 = 3548 ( numeric_accum_inv 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_inv _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_ )); @@ -2431,6 +2437,12 @@ DATA(insert OID = 1836 ( int8_accum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 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 = 3567 ( int2_accum_inv 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_inv _null_ _null_ _null_ )); +DESCR("aggregate transition function"); +DATA(insert OID = 3568 ( int4_accum_inv 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_inv _null_ _null_ _null_ )); +DESCR("aggregate transition function"); +DATA(insert OID = 3569 ( int8_accum_inv 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_inv _null_ _null_ _null_ )); +DESCR("aggregate transition function"); DATA(insert OID = 3178 ( 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 = 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_ )); @@ -2451,14 +2463,22 @@ DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 DESCR("aggregate transition function"); DATA(insert OID = 1843 ( interval_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1187 "1187 1186" _null_ _null_ _null_ _null_ interval_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); +DATA(insert OID = 3549 ( interval_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1187 "1187 1186" _null_ _null_ _null_ _null_ interval_accum_inv _null_ _null_ _null_ )); +DESCR("aggregate transition function"); DATA(insert OID = 1844 ( interval_avg PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1186 "1187" _null_ _null_ _null_ _null_ interval_avg _null_ _null_ _null_ )); DESCR("aggregate final function"); DATA(insert OID = 1962 ( int2_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1016 "1016 21" _null_ _null_ _null_ _null_ int2_avg_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); DATA(insert OID = 1963 ( int4_avg_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1016 "1016 23" _null_ _null_ _null_ _null_ int4_avg_accum _null_ _null_ _null_ )); DESCR("aggregate transition function"); +DATA(insert OID = 3570 ( int2_avg_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1016 "1016 21" _null_ _null_ _null_ _null_ int2_avg_accum_inv _null_ _null_ _null_ )); +DESCR("aggregate transition function"); +DATA(insert OID = 3571 ( int4_avg_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1016 "1016 23" _null_ _null_ _null_ _null_ int4_avg_accum_inv _null_ _null_ _null_ )); +DESCR("aggregate transition function"); DATA(insert OID = 1964 ( int8_avg PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1700 "1016" _null_ _null_ _null_ _null_ int8_avg _null_ _null_ _null_ )); DESCR("aggregate final function"); +DATA(insert OID = 3572 ( int2int4_sum PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 20 "1016" _null_ _null_ _null_ _null_ int2int4_sum _null_ _null_ _null_ )); +DESCR("aggregate final function"); DATA(insert OID = 2805 ( int8inc_float8_float8 PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 20 "20 701 701" _null_ _null_ _null_ _null_ int8inc_float8_float8 _null_ _null_ _null_ )); DESCR("aggregate transition function"); DATA(insert OID = 2806 ( float8_regr_accum PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1022 "1022 701 701" _null_ _null_ _null_ _null_ float8_regr_accum _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 5907cb13fd..f7cc1af2ca 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -1005,9 +1005,13 @@ extern Datum float4_numeric(PG_FUNCTION_ARGS); extern Datum numeric_float4(PG_FUNCTION_ARGS); extern Datum numeric_accum(PG_FUNCTION_ARGS); extern Datum numeric_avg_accum(PG_FUNCTION_ARGS); +extern Datum numeric_accum_inv(PG_FUNCTION_ARGS); extern Datum int2_accum(PG_FUNCTION_ARGS); extern Datum int4_accum(PG_FUNCTION_ARGS); extern Datum int8_accum(PG_FUNCTION_ARGS); +extern Datum int2_accum_inv(PG_FUNCTION_ARGS); +extern Datum int4_accum_inv(PG_FUNCTION_ARGS); +extern Datum int8_accum_inv(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); @@ -1020,7 +1024,10 @@ extern Datum int4_sum(PG_FUNCTION_ARGS); extern Datum int8_sum(PG_FUNCTION_ARGS); extern Datum int2_avg_accum(PG_FUNCTION_ARGS); extern Datum int4_avg_accum(PG_FUNCTION_ARGS); +extern Datum int2_avg_accum_inv(PG_FUNCTION_ARGS); +extern Datum int4_avg_accum_inv(PG_FUNCTION_ARGS); extern Datum int8_avg(PG_FUNCTION_ARGS); +extern Datum int2int4_sum(PG_FUNCTION_ARGS); extern Datum width_bucket_numeric(PG_FUNCTION_ARGS); extern Datum hash_numeric(PG_FUNCTION_ARGS); diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h index d63e3a9a5a..0e4b949946 100644 --- a/src/include/utils/int8.h +++ b/src/include/utils/int8.h @@ -74,8 +74,10 @@ extern Datum int8div(PG_FUNCTION_ARGS); extern Datum int8abs(PG_FUNCTION_ARGS); extern Datum int8mod(PG_FUNCTION_ARGS); extern Datum int8inc(PG_FUNCTION_ARGS); +extern Datum int8dec(PG_FUNCTION_ARGS); extern Datum int8inc_any(PG_FUNCTION_ARGS); extern Datum int8inc_float8_float8(PG_FUNCTION_ARGS); +extern Datum int8dec_any(PG_FUNCTION_ARGS); extern Datum int8larger(PG_FUNCTION_ARGS); extern Datum int8smaller(PG_FUNCTION_ARGS); diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 2731c6a25f..94328b3193 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -184,6 +184,7 @@ extern Datum interval_mul(PG_FUNCTION_ARGS); extern Datum mul_d_interval(PG_FUNCTION_ARGS); extern Datum interval_div(PG_FUNCTION_ARGS); extern Datum interval_accum(PG_FUNCTION_ARGS); +extern Datum interval_accum_inv(PG_FUNCTION_ARGS); extern Datum interval_avg(PG_FUNCTION_ARGS); extern Datum timestamp_mi(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 93ff18d589..b2d671a08c 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -936,13 +936,13 @@ WHERE a.aggfnoid = p.oid AND ----------+---------+-----+--------- (0 rows) --- transfn and mtransfn should have same strictness setting. -SELECT a.aggfnoid::oid, p.proname, ptr.oid, ptr.proname, mptr.oid, mptr.proname -FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS ptr, pg_proc AS mptr +-- mtransfn and minvtransfn should have same strictness setting. +SELECT a.aggfnoid::oid, p.proname, ptr.oid, ptr.proname, iptr.oid, iptr.proname +FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS ptr, pg_proc AS iptr WHERE a.aggfnoid = p.oid AND - a.aggtransfn = ptr.oid AND - a.aggmtransfn = mptr.oid AND - ptr.proisstrict != mptr.proisstrict; + a.aggmtransfn = ptr.oid AND + a.aggminvtransfn = iptr.oid AND + ptr.proisstrict != iptr.proisstrict; aggfnoid | proname | oid | proname | oid | proname ----------+---------+-----+---------+-----+--------- (0 rows) diff --git a/src/test/regress/expected/window.out b/src/test/regress/expected/window.out index d9cb0addb3..f08bd9c9ad 100644 --- a/src/test/regress/expected/window.out +++ b/src/test/regress/expected/window.out @@ -1294,3 +1294,478 @@ WINDOW fwd AS ( t | t | t (1 row) +-- +-- Test various built-in aggregates that have moving-aggregate support +-- +-- test inverse transition functions handle NULLs properly +SELECT i,AVG(v::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + i | avg +---+-------------------- + 1 | 1.5000000000000000 + 2 | 2.0000000000000000 + 3 | + 4 | +(4 rows) + +SELECT i,AVG(v::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + i | avg +---+-------------------- + 1 | 1.5000000000000000 + 2 | 2.0000000000000000 + 3 | + 4 | +(4 rows) + +SELECT i,AVG(v::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + i | avg +---+-------------------- + 1 | 1.5000000000000000 + 2 | 2.0000000000000000 + 3 | + 4 | +(4 rows) + +SELECT i,AVG(v::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1.5),(2,2.5),(3,NULL),(4,NULL)) t(i,v); + i | avg +---+-------------------- + 1 | 2.0000000000000000 + 2 | 2.5000000000000000 + 3 | + 4 | +(4 rows) + +SELECT i,AVG(v::interval) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,'1 sec'),(2,'2 sec'),(3,NULL),(4,NULL)) t(i,v); + i | avg +---+------------ + 1 | @ 1.5 secs + 2 | @ 2 secs + 3 | + 4 | +(4 rows) + +SELECT i,SUM(v::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + i | sum +---+----- + 1 | 3 + 2 | 2 + 3 | + 4 | +(4 rows) + +SELECT i,SUM(v::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + i | sum +---+----- + 1 | 3 + 2 | 2 + 3 | + 4 | +(4 rows) + +SELECT i,SUM(v::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + i | sum +---+----- + 1 | 3 + 2 | 2 + 3 | + 4 | +(4 rows) + +SELECT i,SUM(v::money) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,'1.10'),(2,'2.20'),(3,NULL),(4,NULL)) t(i,v); + i | sum +---+------- + 1 | $3.30 + 2 | $2.20 + 3 | + 4 | +(4 rows) + +SELECT i,SUM(v::interval) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,'1 sec'),(2,'2 sec'),(3,NULL),(4,NULL)) t(i,v); + i | sum +---+---------- + 1 | @ 3 secs + 2 | @ 2 secs + 3 | + 4 | +(4 rows) + +SELECT i,SUM(v::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1.1),(2,2.2),(3,NULL),(4,NULL)) t(i,v); + i | sum +---+----- + 1 | 3.3 + 2 | 2.2 + 3 | + 4 | +(4 rows) + +SELECT SUM(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1.01),(2,2),(3,3)) v(i,n); + sum +------ + 6.01 + 5 + 3 +(3 rows) + +SELECT i,COUNT(v) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + i | count +---+------- + 1 | 2 + 2 | 1 + 3 | 0 + 4 | 0 +(4 rows) + +SELECT i,COUNT(*) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + i | count +---+------- + 1 | 4 + 2 | 3 + 3 | 2 + 4 | 1 +(4 rows) + +SELECT VAR_POP(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + var_pop +----------------------- + 21704.000000000000 + 13868.750000000000 + 11266.666666666667 + 4225.0000000000000000 + 0 +(5 rows) + +SELECT VAR_POP(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + var_pop +----------------------- + 21704.000000000000 + 13868.750000000000 + 11266.666666666667 + 4225.0000000000000000 + 0 +(5 rows) + +SELECT VAR_POP(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + var_pop +----------------------- + 21704.000000000000 + 13868.750000000000 + 11266.666666666667 + 4225.0000000000000000 + 0 +(5 rows) + +SELECT VAR_POP(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + var_pop +----------------------- + 21704.000000000000 + 13868.750000000000 + 11266.666666666667 + 4225.0000000000000000 + 0 +(5 rows) + +SELECT VAR_SAMP(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + var_samp +----------------------- + 27130.000000000000 + 18491.666666666667 + 16900.000000000000 + 8450.0000000000000000 + +(5 rows) + +SELECT VAR_SAMP(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + var_samp +----------------------- + 27130.000000000000 + 18491.666666666667 + 16900.000000000000 + 8450.0000000000000000 + +(5 rows) + +SELECT VAR_SAMP(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + var_samp +----------------------- + 27130.000000000000 + 18491.666666666667 + 16900.000000000000 + 8450.0000000000000000 + +(5 rows) + +SELECT VAR_SAMP(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + var_samp +----------------------- + 27130.000000000000 + 18491.666666666667 + 16900.000000000000 + 8450.0000000000000000 + +(5 rows) + +SELECT VARIANCE(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + variance +----------------------- + 27130.000000000000 + 18491.666666666667 + 16900.000000000000 + 8450.0000000000000000 + +(5 rows) + +SELECT VARIANCE(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + variance +----------------------- + 27130.000000000000 + 18491.666666666667 + 16900.000000000000 + 8450.0000000000000000 + +(5 rows) + +SELECT VARIANCE(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + variance +----------------------- + 27130.000000000000 + 18491.666666666667 + 16900.000000000000 + 8450.0000000000000000 + +(5 rows) + +SELECT VARIANCE(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + variance +----------------------- + 27130.000000000000 + 18491.666666666667 + 16900.000000000000 + 8450.0000000000000000 + +(5 rows) + +SELECT STDDEV_POP(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + stddev_pop +--------------------- + 147.322774885623 + 147.322774885623 + 117.765657133139 + 106.144555520604 + 65.0000000000000000 + 0 +(6 rows) + +SELECT STDDEV_POP(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + stddev_pop +--------------------- + 147.322774885623 + 147.322774885623 + 117.765657133139 + 106.144555520604 + 65.0000000000000000 + 0 +(6 rows) + +SELECT STDDEV_POP(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + stddev_pop +--------------------- + 147.322774885623 + 147.322774885623 + 117.765657133139 + 106.144555520604 + 65.0000000000000000 + 0 +(6 rows) + +SELECT STDDEV_POP(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + stddev_pop +--------------------- + 147.322774885623 + 147.322774885623 + 117.765657133139 + 106.144555520604 + 65.0000000000000000 + 0 +(6 rows) + +SELECT STDDEV_SAMP(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + stddev_samp +--------------------- + 164.711869639076 + 164.711869639076 + 135.984067694222 + 130.000000000000 + 91.9238815542511782 + +(6 rows) + +SELECT STDDEV_SAMP(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + stddev_samp +--------------------- + 164.711869639076 + 164.711869639076 + 135.984067694222 + 130.000000000000 + 91.9238815542511782 + +(6 rows) + +SELECT STDDEV_SAMP(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + stddev_samp +--------------------- + 164.711869639076 + 164.711869639076 + 135.984067694222 + 130.000000000000 + 91.9238815542511782 + +(6 rows) + +SELECT STDDEV_SAMP(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + stddev_samp +--------------------- + 164.711869639076 + 164.711869639076 + 135.984067694222 + 130.000000000000 + 91.9238815542511782 + +(6 rows) + +SELECT STDDEV(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(0,NULL),(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + stddev +--------------------- + 164.711869639076 + 164.711869639076 + 135.984067694222 + 130.000000000000 + 91.9238815542511782 + +(6 rows) + +SELECT STDDEV(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(0,NULL),(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + stddev +--------------------- + 164.711869639076 + 164.711869639076 + 135.984067694222 + 130.000000000000 + 91.9238815542511782 + +(6 rows) + +SELECT STDDEV(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(0,NULL),(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + stddev +--------------------- + 164.711869639076 + 164.711869639076 + 135.984067694222 + 130.000000000000 + 91.9238815542511782 + +(6 rows) + +SELECT STDDEV(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(0,NULL),(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + stddev +--------------------- + 164.711869639076 + 164.711869639076 + 135.984067694222 + 130.000000000000 + 91.9238815542511782 + +(6 rows) + +-- test that inverse transition functions work with various frame options +SELECT i,SUM(v::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND CURRENT ROW) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + i | sum +---+----- + 1 | 1 + 2 | 2 + 3 | + 4 | +(4 rows) + +SELECT i,SUM(v::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + i | sum +---+----- + 1 | 3 + 2 | 2 + 3 | + 4 | +(4 rows) + +SELECT i,SUM(v::int) OVER (ORDER BY i ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,3),(4,4)) t(i,v); + i | sum +---+----- + 1 | 3 + 2 | 6 + 3 | 9 + 4 | 7 +(4 rows) + +-- ensure aggregate over numeric properly recovers from NaN values +SELECT a, b, + SUM(b) OVER(ORDER BY A ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) +FROM (VALUES(1,1::numeric),(2,2),(3,'NaN'),(4,3),(5,4)) t(a,b); + a | b | sum +---+-----+----- + 1 | 1 | 1 + 2 | 2 | 3 + 3 | NaN | NaN + 4 | 3 | NaN + 5 | 4 | 7 +(5 rows) + +-- It might be tempting for someone to add an inverse trans function for +-- float and double precision. This should not be done as it can give incorrect +-- results. This test should fail if anyone ever does this without thinking too +-- hard about it. +SELECT to_char(SUM(n::float8) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING),'999999999999999999999D9') + FROM (VALUES(1,1e20),(2,1)) n(i,n); + to_char +-------------------------- + 100000000000000000000 + 1.0 +(2 rows) + diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 22998a553c..dc1acb9eaa 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -760,14 +760,14 @@ WHERE a.aggfnoid = p.oid AND a.aggminitval IS NULL AND NOT binary_coercible(p.proargtypes[0], a.aggmtranstype); --- transfn and mtransfn should have same strictness setting. +-- mtransfn and minvtransfn should have same strictness setting. -SELECT a.aggfnoid::oid, p.proname, ptr.oid, ptr.proname, mptr.oid, mptr.proname -FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS ptr, pg_proc AS mptr +SELECT a.aggfnoid::oid, p.proname, ptr.oid, ptr.proname, iptr.oid, iptr.proname +FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS ptr, pg_proc AS iptr WHERE a.aggfnoid = p.oid AND - a.aggtransfn = ptr.oid AND - a.aggmtransfn = mptr.oid AND - ptr.proisstrict != mptr.proisstrict; + a.aggmtransfn = ptr.oid AND + a.aggminvtransfn = iptr.oid AND + ptr.proisstrict != iptr.proisstrict; -- Cross-check aggsortop (if present) against pg_operator. -- We expect to find entries for bool_and, bool_or, every, max, and min. diff --git a/src/test/regress/sql/window.sql b/src/test/regress/sql/window.sql index 5bae12bd33..11c96aa8bc 100644 --- a/src/test/regress/sql/window.sql +++ b/src/test/regress/sql/window.sql @@ -476,3 +476,144 @@ JOIN sum_following ON sum_following.i = vs.i WINDOW fwd AS ( ORDER BY vs.i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ); + +-- +-- Test various built-in aggregates that have moving-aggregate support +-- + +-- test inverse transition functions handle NULLs properly +SELECT i,AVG(v::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,AVG(v::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,AVG(v::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,AVG(v::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1.5),(2,2.5),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,AVG(v::interval) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,'1 sec'),(2,'2 sec'),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,SUM(v::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,SUM(v::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,SUM(v::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,SUM(v::money) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,'1.10'),(2,'2.20'),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,SUM(v::interval) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,'1 sec'),(2,'2 sec'),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,SUM(v::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1.1),(2,2.2),(3,NULL),(4,NULL)) t(i,v); + +SELECT SUM(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1.01),(2,2),(3,3)) v(i,n); + +SELECT i,COUNT(v) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,COUNT(*) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + +SELECT VAR_POP(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VAR_POP(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VAR_POP(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VAR_POP(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VAR_SAMP(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VAR_SAMP(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VAR_SAMP(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VAR_SAMP(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VARIANCE(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VARIANCE(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VARIANCE(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT VARIANCE(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT STDDEV_POP(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + +SELECT STDDEV_POP(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + +SELECT STDDEV_POP(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + +SELECT STDDEV_POP(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + +SELECT STDDEV_SAMP(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + +SELECT STDDEV_SAMP(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + +SELECT STDDEV_SAMP(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + +SELECT STDDEV_SAMP(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(1,NULL),(2,600),(3,470),(4,170),(5,430),(6,300)) r(i,n); + +SELECT STDDEV(n::bigint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(0,NULL),(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT STDDEV(n::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(0,NULL),(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT STDDEV(n::smallint) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(0,NULL),(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +SELECT STDDEV(n::numeric) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + FROM (VALUES(0,NULL),(1,600),(2,470),(3,170),(4,430),(5,300)) r(i,n); + +-- test that inverse transition functions work with various frame options +SELECT i,SUM(v::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND CURRENT ROW) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,SUM(v::int) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,NULL),(4,NULL)) t(i,v); + +SELECT i,SUM(v::int) OVER (ORDER BY i ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) + FROM (VALUES(1,1),(2,2),(3,3),(4,4)) t(i,v); + +-- ensure aggregate over numeric properly recovers from NaN values +SELECT a, b, + SUM(b) OVER(ORDER BY A ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) +FROM (VALUES(1,1::numeric),(2,2),(3,'NaN'),(4,3),(5,4)) t(a,b); + +-- It might be tempting for someone to add an inverse trans function for +-- float and double precision. This should not be done as it can give incorrect +-- results. This test should fail if anyone ever does this without thinking too +-- hard about it. +SELECT to_char(SUM(n::float8) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING),'999999999999999999999D9') + FROM (VALUES(1,1e20),(2,1)) n(i,n);