diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2014-04-12 20:33:09 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2014-04-12 20:33:09 -0400 |
commit | 9d229f399e87d2ae7132c2e8feef317ce1479728 (patch) | |
tree | f808e533fa6b89202733e2b8666361dc5482ca97 /src/backend/utils/adt/timestamp.c | |
parent | a9d9acbf219b9e96585779cd5f99d674d4ccba74 (diff) | |
download | postgresql-9d229f399e87d2ae7132c2e8feef317ce1479728.tar.gz postgresql-9d229f399e87d2ae7132c2e8feef317ce1479728.zip |
Provide moving-aggregate support for a bunch of numerical aggregates.
First installment of the promised moving-aggregate support in built-in
aggregates: count(), sum(), avg(), stddev() and variance() for
assorted datatypes, though not for float4/float8.
In passing, remove a 2001-vintage kluge in interval_accum(): interval
array elements have been properly aligned since around 2003, but
nobody remembered to take out this workaround. Also, fix a thinko
in the opr_sanity tests for moving-aggregate catalog entries.
David Rowley and Florian Pflug, reviewed by Dean Rasheed
Diffstat (limited to 'src/backend/utils/adt/timestamp.c')
-rw-r--r-- | src/backend/utils/adt/timestamp.c | 72 |
1 files changed, 47 insertions, 25 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index ce30bb6e9fa..efc1e9b9925 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -3229,7 +3229,6 @@ interval_mi(PG_FUNCTION_ARGS) (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("interval out of range"))); - PG_RETURN_INTERVAL_P(result); } @@ -3376,12 +3375,18 @@ interval_div(PG_FUNCTION_ARGS) } /* - * interval_accum and interval_avg implement the AVG(interval) aggregate. + * interval_accum, interval_accum_inv, and interval_avg implement the + * AVG(interval) aggregate. * * The transition datatype for this aggregate is a 2-element array of * intervals, where the first is the running sum and the second contains * the number of values so far in its 'time' field. This is a bit ugly * but it beats inventing a specialized datatype for the purpose. + * + * NOTE: The inverse transition function cannot guarantee exact results + * when using float8 timestamps. However, int8 timestamps are now the + * norm, and the probable range of values is not so wide that disastrous + * cancellation is likely even with float8, so we'll ignore the risk. */ Datum @@ -3402,17 +3407,8 @@ interval_accum(PG_FUNCTION_ARGS) if (ndatums != 2) elog(ERROR, "expected 2-element interval array"); - /* - * XXX memcpy, instead of just extracting a pointer, to work around buggy - * array code: it won't ensure proper alignment of Interval objects on - * machines where double requires 8-byte alignment. That should be fixed, - * but in the meantime... - * - * Note: must use DatumGetPointer here, not DatumGetIntervalP, else some - * compilers optimize into double-aligned load/store anyway. - */ - memcpy((void *) &sumX, DatumGetPointer(transdatums[0]), sizeof(Interval)); - memcpy((void *) &N, DatumGetPointer(transdatums[1]), sizeof(Interval)); + sumX = *(DatumGetIntervalP(transdatums[0])); + N = *(DatumGetIntervalP(transdatums[1])); newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl, IntervalPGetDatum(&sumX), @@ -3429,6 +3425,41 @@ interval_accum(PG_FUNCTION_ARGS) } 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) { ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); @@ -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)); } |