]> granicus.if.org Git - postgresql/commitdiff
Provide moving-aggregate support for a bunch of numerical aggregates.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 13 Apr 2014 00:33:09 +0000 (20:33 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 13 Apr 2014 00:33:09 +0000 (20:33 -0400)
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

13 files changed:
src/backend/utils/adt/int8.c
src/backend/utils/adt/numeric.c
src/backend/utils/adt/timestamp.c
src/include/catalog/catversion.h
src/include/catalog/pg_aggregate.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/include/utils/int8.h
src/include/utils/timestamp.h
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/window.out
src/test/regress/sql/opr_sanity.sql
src/test/regress/sql/window.sql

index 5e1be90dac3e160b45f5e182f9a5133fe102595e..e78eb2a2022ece8f4a41c46dc9e316266e68385e 100644 (file)
@@ -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)
index 64eb0f8d16e668adfaca3e6527d4d97b82ecbe34..bf4f29d14d70471dd8a5345ae9e3b586f28edb88 100644 (file)
@@ -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);
 
-       if (!PG_ARGISNULL(1))
-       {
-               /* Create the state data when we see the first non-null input. */
-               if (state == NULL)
-                       state = makeNumericAggState(fcinfo, false);
+       /* 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))
+       {
+               /* 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,23 +2853,104 @@ 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);
+       }
 
-               /* Create the state data when we see the first non-null input. */
-               if (state == NULL)
-                       state = makeNumericAggState(fcinfo, false);
+       PG_RETURN_POINTER(state);
+}
 
-               do_numeric_accum(state, newval);
+
+/*
+ * 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;
+
+               newval = DatumGetNumeric(DirectFunctionCall1(int8_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
 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));
+}
+
 
 /* ----------------------------------------------------------------------
  *
index ce30bb6e9fa65e503beeea7ccd9cf82bf050bd09..efc1e9b99257a548d04b36e3882b91f8fa3682d7 100644 (file)
@@ -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));
 }
 
 
index 2fb0ce8656352ef7baede4479c2dbd28ae570e69..0d301cf1ace0db124e85277c635a4e6bf10045cd 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201404121
+#define CATALOG_VERSION_NO     201404122
 
 #endif
index 3cb0d754e7d0cd35183b6f2be07932bd9529aa1a..5116beb62a901e2995d4d638013e3768ddeadaa6 100644 (file)
@@ -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_ ));
 
 
 /*
index 7b9c5870fac6c86b2cc42bbe46d938412fed709a..a24f4e02f96198dac7664a532d8e4c9086d0dedd 100644 (file)
@@ -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_ ));
index 5907cb13fd31d0b5cd0ca5a61311c32c5864f7eb..f7cc1af2caf9c8de492ea01419d06a1eb84f51f0 100644 (file)
@@ -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);
 
index d63e3a9a5a462629c635c56b28b2839da6f42ff8..0e4b949946762303956a18b0586cf04f583801e4 100644 (file)
@@ -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);
 
index 2731c6a25f4f58cf8b696ccebb395916c816d15b..94328b319368124a903fdce221c4978cf6d4b035 100644 (file)
@@ -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);
index 93ff18d589331a79b03ff864cb6862cec4499935..b2d671a08c605f35b0190b49e0399fdfa2fdf1be 100644 (file)
@@ -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)
index d9cb0addb32a11345b06e04d2056819bb50d8415..f08bd9c9adce24e620c4f98e3d4f14361e1510cc 100644 (file)
@@ -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)
+
index 22998a553caa294971044c82fbd7448eb9ba3d34..dc1acb9eaace45e7522cc2069d0866049243bcc4 100644 (file)
@@ -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.
index 5bae12bd33d0aa613de9c7036f0e313ec1042b05..11c96aa8bc057e8ab21cb0e2ace1208ea7398e2f 100644 (file)
@@ -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);