[WIP Patch] Using 128-bit integers for sum, avg and statistics aggregates
Hi,
There was recently talk about if we should start using 128-bit integers
(where available) to speed up the aggregate functions over integers
which uses numeric for their internal state. So I hacked together a
patch for this to see what the performance gain would be.
Previous thread:
/messages/by-id/20141017182500.GF2075@alap3.anarazel.de
What the patch does is switching from using numerics in the aggregate
state to int128 and then convert the type from the 128-bit integer in
the final function.
The functions where we can make use of int128 states are:
- sum(int8)
- avg(int8)
- var_*(int2)
- var_*(int4)
- stdev_*(int2)
- stdev_*(int4)
The initial benchmark results look very promising. When summing 10
million int8 I get a speedup of ~2.5x and similarly for var_samp() on 10
million int4 I see a speed up of ~3.7x. To me this indicates that it is
worth the extra code. What do you say? Is this worth implementing?
The current patch still requires work. I have not written the detection
of int128 support yet, and the patch needs code cleanup (for example: I
used an int16_ prefix on the added functions, suggestions for better
names are welcome). I also need to decide on what estimate to use for
the size of that state.
The patch should work and pass make check on platforms where __int128_t
is supported.
The simple benchmarks:
CREATE TABLE test_int8 AS SELECT x::int8 FROM generate_series(1,
10000000) x;
Before:
# SELECT sum(x) FROM test_int8;
sum
----------------
50000005000000
(1 row)
Time: 2521.217 ms
After:
# SELECT sum(x) FROM test_int8;
sum
----------------
50000005000000
(1 row)
Time: 1022.811 ms
CREATE TABLE test_int4 AS SELECT x::int4 FROM generate_series(1,
10000000) x;
Before:
# SELECT var_samp(x) FROM test_int4;
var_samp
--------------------
8333334166666.6667
(1 row)
Time: 3808.546 ms
After:
# SELECT var_samp(x) FROM test_int4;
var_samp
--------------------
8333334166666.6667
(1 row)
Time: 1033.243 ms
Andreas
Attachments:
int128-agg-v1.patchtext/x-patch; name=int128-agg-v1.patchDownload
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
new file mode 100644
index 2d6a4cb..65a3d08
*** a/src/backend/utils/adt/numeric.c
--- b/src/backend/utils/adt/numeric.c
*************** typedef int16 NumericDigit;
*** 119,124 ****
--- 119,129 ----
* The weight is arbitrary in that case, but we normally set it to zero.
*/
+ /* FIXME: Do this properly */
+ typedef __int128_t int128;
+ typedef __uint128_t uint128;
+ #define HAVE_INT128 1
+
struct NumericShort
{
uint16 n_header; /* Sign + display scale + weight */
*************** static void apply_typmod(NumericVar *var
*** 389,394 ****
--- 394,402 ----
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
static void int8_to_numericvar(int64 val, NumericVar *var);
+ #ifdef HAVE_INT128
+ static void int16_to_numericvar(int128 val, NumericVar *var);
+ #endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
*************** numeric_accum_inv(PG_FUNCTION_ARGS)
*** 2775,2783 ****
--- 2783,2867 ----
* routines for SUM and AVG of these datatypes.
*/
+ #ifdef HAVE_INT128
+ typedef struct Int16AggState
+ {
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+ } Int16AggState;
+
+ /*
+ * Prepare state data for a numeric aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+ static Int16AggState *
+ makeInt16AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+ {
+ Int16AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int16AggState *) palloc0(sizeof(Int16AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+ }
+
+ /*
+ * Accumulate a new input value for numeric aggregate functions.
+ */
+ static void
+ do_int16_accum(Int16AggState *state, int128 newval)
+ {
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+ }
+
+ /*
+ * Remove an input value from the aggregated state.
+ */
+ static void
+ do_int16_discard(Int16AggState *state, int128 newval)
+ {
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+ }
+ #endif
+
Datum
int2_accum(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, true);
+
+ if (!PG_ARGISNULL(1))
+ {
+ int16 newval = PG_GETARG_INT16(1);
+
+ do_int16_accum(state, newval);
+ }
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int2_accum(PG_FUNCTION_ARGS)
*** 2794,2799 ****
--- 2878,2884 ----
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int2_accum(PG_FUNCTION_ARGS)
*** 2801,2806 ****
--- 2886,2907 ----
Datum
int4_accum(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, true);
+
+ if (!PG_ARGISNULL(1))
+ {
+ int32 newval = PG_GETARG_INT32(1);
+
+ do_int16_accum(state, newval);
+ }
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int4_accum(PG_FUNCTION_ARGS)
*** 2817,2822 ****
--- 2918,2924 ----
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int8_accum(PG_FUNCTION_ARGS)
*** 2850,2855 ****
--- 2952,2973 ----
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, false);
+
+ if (!PG_ARGISNULL(1))
+ {
+ int64 newval = PG_GETARG_INT64(1);
+
+ do_int16_accum(state, newval);
+ }
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int8_avg_accum(PG_FUNCTION_ARGS)
*** 2866,2871 ****
--- 2984,2990 ----
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int8_avg_accum(PG_FUNCTION_ARGS)
*** 2878,2883 ****
--- 2997,3018 ----
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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))
+ {
+ int16 newval = PG_GETARG_INT16(1);
+
+ do_int16_discard(state, newval);
+ }
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int2_accum_inv(PG_FUNCTION_ARGS)
*** 2897,2902 ****
--- 3032,3038 ----
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int2_accum_inv(PG_FUNCTION_ARGS)
*** 2904,2909 ****
--- 3040,3061 ----
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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))
+ {
+ int32 newval = PG_GETARG_INT32(1);
+
+ do_int16_discard(state, newval);
+ }
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int4_accum_inv(PG_FUNCTION_ARGS)
*** 2923,2928 ****
--- 3075,3081 ----
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int8_accum_inv(PG_FUNCTION_ARGS)
*** 2954,2959 ****
--- 3107,3213 ----
}
Datum
+ int8_avg_accum_inv(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ {
+ int64 newval = PG_GETARG_INT64(1);
+
+ do_int16_discard(state, newval);
+ }
+ #else
+ 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_avg_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");
+ }
+ #endif
+
+ PG_RETURN_POINTER(state);
+ }
+
+ Datum
+ int16_sum(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_sum(fcinfo);
+ #endif
+ }
+
+ Datum
+ int16_avg(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+ #else
+ return numeric_avg(fcinfo);
+ #endif
+ }
+
+ Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
*************** numeric_stddev_pop(PG_FUNCTION_ARGS)
*** 3155,3160 ****
--- 3409,3529 ----
PG_RETURN_NUMERIC(res);
}
+ #ifdef HAVE_INT128
+ static Numeric
+ int16_stddev_internal(Int16AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+ {
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state) {
+ numstate.N = state->N;
+ int16_to_numericvar(state->sumX, &numstate.sumX);
+ int16_to_numericvar(state->sumX2, &numstate.sumX2);
+ } else {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+ }
+ #endif
+
+ Datum
+ int16_var_samp(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = int16_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_var_samp(fcinfo);
+ #endif
+ }
+
+ Datum
+ int16_stddev_samp(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = int16_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_stddev_samp(fcinfo);
+ #endif
+ }
+
+ Datum
+ int16_var_pop(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = int16_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_var_pop(fcinfo);
+ #endif
+ }
+
+ Datum
+ int16_stddev_pop(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = int16_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_stddev_pop(fcinfo);
+ #endif
+ }
+
/*
* SUM transition functions for integer datatypes.
*
*************** int8_to_numericvar(int64 val, NumericVar
*** 4377,4382 ****
--- 4746,4798 ----
var->weight = ndigits - 1;
}
+ #ifdef HAVE_INT128
+ /*
+ * Convert 128 bit integer to numeric.
+ */
+ static void
+ int16_to_numericvar(int128 val, NumericVar *var)
+ {
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int16 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+ }
+ #endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
new file mode 100644
index 3ba9e5e..b204bb2
*** a/src/include/catalog/pg_aggregate.h
--- b/src/include/catalog/pg_aggregate.h
*************** typedef FormData_pg_aggregate *Form_pg_a
*** 125,131 ****
*/
/* avg */
! DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
--- 125,131 ----
*/
/* avg */
! DATA(insert ( 2100 n 0 int8_avg_accum int16_avg int8_avg_accum int8_avg_accum_inv int16_avg f f 0 2281 48 2281 48 _null_ _null_ ));
DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
*************** DATA(insert ( 2105 n 0 float8_accum floa
*** 134,140 ****
DATA(insert ( 2106 n 0 interval_accum interval_avg interval_accum interval_accum_inv interval_avg f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
! DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
--- 134,140 ----
DATA(insert ( 2106 n 0 interval_accum interval_avg interval_accum interval_accum_inv interval_avg f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
! DATA(insert ( 2107 n 0 int8_avg_accum int16_sum int8_avg_accum int8_avg_accum_inv int16_sum f f 0 2281 48 2281 48 _null_ _null_ ));
DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
*************** DATA(insert ( 2803 n 0 int8inc - in
*** 195,242 ****
/* var_pop */
DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
--- 195,242 ----
/* var_pop */
DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2719 n 0 int4_accum int16_var_pop int4_accum int4_accum_inv int16_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2720 n 0 int2_accum int16_var_pop int2_accum int2_accum_inv int16_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2642 n 0 int4_accum int16_var_samp int4_accum int4_accum_inv int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2643 n 0 int2_accum int16_var_samp int2_accum int2_accum_inv int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2149 n 0 int4_accum int16_var_samp int4_accum int4_accum_inv int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2150 n 0 int2_accum int16_var_samp int2_accum int2_accum_inv int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2725 n 0 int4_accum int16_stddev_pop int4_accum int4_accum_inv int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2726 n 0 int2_accum int16_stddev_pop int2_accum int2_accum_inv int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2713 n 0 int4_accum int16_stddev_samp int4_accum int4_accum_inv int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2714 n 0 int2_accum int16_stddev_samp int2_accum int2_accum_inv int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2155 n 0 int4_accum int16_stddev_samp int4_accum int4_accum_inv int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2156 n 0 int2_accum int16_stddev_samp int2_accum int2_accum_inv int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index b6dc1b8..6564f0c
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DATA(insert OID = 3568 ( int4_accum_inv
*** 2455,2460 ****
--- 2455,2462 ----
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 = 13569 ( int8_avg_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_avg_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_ ));
*************** DATA(insert OID = 1841 ( int4_sum P
*** 2473,2478 ****
--- 2475,2494 ----
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+
+ DATA(insert OID = 13178 ( int16_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ int16_sum _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 11837 ( int16_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ int16_avg _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 12514 ( int16_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ int16_var_pop _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 11838 ( int16_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ int16_var_samp _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 12596 ( int16_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ int16_stddev_pop _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 11839 ( int16_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ int16_stddev_samp _null_ _null_ _null_ ));
+ DESCR("aggregate final 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_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
new file mode 100644
index fb1b4a4..02d2c88
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
*************** extern Datum numeric_var_pop(PG_FUNCTION
*** 1018,1031 ****
--- 1018,1038 ----
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+ extern Datum int16_var_pop(PG_FUNCTION_ARGS);
+ extern Datum int16_var_samp(PG_FUNCTION_ARGS);
+ extern Datum int16_stddev_pop(PG_FUNCTION_ARGS);
+ extern Datum int16_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
+ extern Datum int16_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_accum_inv(PG_FUNCTION_ARGS);
extern Datum int8_avg(PG_FUNCTION_ARGS);
+ extern Datum int16_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);
On Sat, Oct 25, 2014 at 12:38 PM, Andreas Karlsson <andreas@proxel.se>
wrote:
Hi,
There was recently talk about if we should start using 128-bit integers
(where available) to speed up the aggregate functions over integers which
uses numeric for their internal state. So I hacked together a patch for
this to see what the performance gain would be.Previous thread: /messages/by-id/20141017182500.
GF2075@alap3.anarazel.deWhat the patch does is switching from using numerics in the aggregate
state to int128 and then convert the type from the 128-bit integer in the
final function.The functions where we can make use of int128 states are:
- sum(int8)
- avg(int8)
- var_*(int2)
- var_*(int4)
- stdev_*(int2)
- stdev_*(int4)The initial benchmark results look very promising. When summing 10 million
int8 I get a speedup of ~2.5x and similarly for var_samp() on 10 million
int4 I see a speed up of ~3.7x. To me this indicates that it is worth the
extra code. What do you say? Is this worth implementing?The current patch still requires work. I have not written the detection of
int128 support yet, and the patch needs code cleanup (for example: I used
an int16_ prefix on the added functions, suggestions for better names are
welcome). I also need to decide on what estimate to use for the size of
that state.The patch should work and pass make check on platforms where __int128_t is
supported.The simple benchmarks:
CREATE TABLE test_int8 AS SELECT x::int8 FROM generate_series(1, 10000000)
x;Before:
# SELECT sum(x) FROM test_int8;
sum
----------------
50000005000000
(1 row)Time: 2521.217 ms
After:
# SELECT sum(x) FROM test_int8;
sum
----------------
50000005000000
(1 row)Time: 1022.811 ms
CREATE TABLE test_int4 AS SELECT x::int4 FROM generate_series(1, 10000000)
x;Before:
# SELECT var_samp(x) FROM test_int4;
var_samp
--------------------
8333334166666.6667
(1 row)Time: 3808.546 ms
After:
# SELECT var_samp(x) FROM test_int4;
var_samp
--------------------
8333334166666.6667
(1 row)Time: 1033.243 ms
Andreas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
These are some nice improvements.
As far as I'm aware int128 types are supported on every major compiler when
compiling for 64bit platforms. Right?
On Sat, Oct 25, 2014 at 9:38 AM, Andreas Karlsson <andreas@proxel.se> wrote:
Hi,
There was recently talk about if we should start using 128-bit integers
(where available) to speed up the aggregate functions over integers which
uses numeric for their internal state. So I hacked together a patch for this
to see what the performance gain would be.Previous thread:
/messages/by-id/20141017182500.GF2075@alap3.anarazel.deWhat the patch does is switching from using numerics in the aggregate state
to int128 and then convert the type from the 128-bit integer in the final
function.The functions where we can make use of int128 states are:
- sum(int8)
- avg(int8)
- var_*(int2)
- var_*(int4)
- stdev_*(int2)
- stdev_*(int4)The initial benchmark results look very promising. When summing 10 million
int8 I get a speedup of ~2.5x and similarly for var_samp() on 10 million
int4 I see a speed up of ~3.7x. To me this indicates that it is worth the
extra code. What do you say? Is this worth implementing?
yes.
merlin
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2014-10-28 11:05:11 -0200, Arthur Silva wrote:
On Sat, Oct 25, 2014 at 12:38 PM, Andreas Karlsson <andreas@proxel.se>
As far as I'm aware int128 types are supported on every major compiler when
compiling for 64bit platforms. Right?
Depends on what you call major. IIRC some not that old msvc versions
don't for example. Also, there's a couple 32 platforms with int128 bit
support. So I think we should just add a configure test defining the
type + a feature macro.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 10/28/2014 02:05 PM, Arthur Silva wrote:
As far as I'm aware int128 types are supported on every major compiler
when compiling for 64bit platforms. Right?
Both gcc and clang support __int128_t, but I do not know about other
compilers like icc and MSVC.
Andreas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 10/28/2014 03:24 PM, Andres Freund wrote:
On 2014-10-28 11:05:11 -0200, Arthur Silva wrote:
On Sat, Oct 25, 2014 at 12:38 PM, Andreas Karlsson <andreas@proxel.se>
As far as I'm aware int128 types are supported on every major compiler when
compiling for 64bit platforms. Right?Depends on what you call major. IIRC some not that old msvc versions
don't for example. Also, there's a couple 32 platforms with int128 bit
support. So I think we should just add a configure test defining the
type + a feature macro.
It wouldn't be too hard to just do:
struct {
int64 high_bits;
uint64 low_bits;
} pg_int128;
and some macros for the + - etc. operators. It might be less work than
trying to deal with the portability issues of a native C datatype for this.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2014-10-28 15:54:30 +0200, Heikki Linnakangas wrote:
On 10/28/2014 03:24 PM, Andres Freund wrote:
On 2014-10-28 11:05:11 -0200, Arthur Silva wrote:
On Sat, Oct 25, 2014 at 12:38 PM, Andreas Karlsson <andreas@proxel.se>
As far as I'm aware int128 types are supported on every major compiler when
compiling for 64bit platforms. Right?Depends on what you call major. IIRC some not that old msvc versions
don't for example. Also, there's a couple 32 platforms with int128 bit
support. So I think we should just add a configure test defining the
type + a feature macro.It wouldn't be too hard to just do:
struct {
int64 high_bits;
uint64 low_bits;
} pg_int128;and some macros for the + - etc. operators. It might be less work than
trying to deal with the portability issues of a native C datatype for this.
And noticeably slower. At least x86-64 does all of this in hardware...
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Heikki Linnakangas <hlinnakangas@vmware.com> writes:
It wouldn't be too hard to just do:
struct {
int64 high_bits;
uint64 low_bits;
} pg_int128;
and some macros for the + - etc. operators. It might be less work than
trying to deal with the portability issues of a native C datatype for this.
-1. That's not that easy, especially for division, or if you want to
worry about overflow. The point of this patch IMO is to get some low
hanging fruit; coding our own int128 arithmetic doesn't sound like
"low hanging" to me.
Also, we've already got the configure infrastructure for detecting
whether a platform has working int64. It really shouldn't be much
work to transpose that to int128 (especially if we don't care about
printf support, which I think we don't).
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 10/28/2014 04:06 PM, Tom Lane wrote:
Heikki Linnakangas <hlinnakangas@vmware.com> writes:
It wouldn't be too hard to just do:
struct {
int64 high_bits;
uint64 low_bits;
} pg_int128;and some macros for the + - etc. operators. It might be less work than
trying to deal with the portability issues of a native C datatype for this.-1. That's not that easy, especially for division, or if you want to
worry about overflow.
The patch doesn't do division with the 128-bit integers. It only does
addition and multiplication. Those are pretty straightforward to implement.
The point of this patch IMO is to get some low
hanging fruit; coding our own int128 arithmetic doesn't sound like
"low hanging" to me.
I wasn't thinking of writing a full-fledged 128-bit type, just the the
few operations needed for this patch.
Also, we've already got the configure infrastructure for detecting
whether a platform has working int64. It really shouldn't be much
work to transpose that to int128 (especially if we don't care about
printf support, which I think we don't).
It would be nicer to be able to use the same code on all platforms. With
a configure test, we'd still need a fallback implementation for
platforms that don't have it.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 10/28/2014 03:40 PM, Heikki Linnakangas wrote:
The patch doesn't do division with the 128-bit integers. It only does
addition and multiplication. Those are pretty straightforward to implement.
The patch uses division when converting from __int128_t to Numeric.
- Andreas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 10/28/2014 04:47 PM, Andreas Karlsson wrote:
On 10/28/2014 03:40 PM, Heikki Linnakangas wrote:
The patch doesn't do division with the 128-bit integers. It only does
addition and multiplication. Those are pretty straightforward to implement.The patch uses division when converting from __int128_t to Numeric.
Oh, I see. Hmph, looks like I'm losing an argument..
Moving on to other issues, isn't 128 bits too small to store the squares
of the processed numbers? That could overflow..
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 10/28/2014 04:01 PM, Heikki Linnakangas wrote:
Moving on to other issues, isn't 128 bits too small to store the squares
of the processed numbers? That could overflow..
Yeah, which is why stddev_*(int8) and var_*(int8) still have to use
Numeric in the aggregate state. For the int2 and int4 versions it is
fine to use __int128_t.
Andreas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
Here is version 2 of the patch which detects the presence of gcc/clang
style 128-bit integers and has been cleaned up to a reviewable state. I
have not added support for any other compilers since I found no
documentation 128-bit support with icc or MSVC. I do not have access to
any Windows machines either.
A couple of things I was not sure about was the naming of the new
functions and if I should ifdef the size of the aggregate state in the
catalog or not.
--
Andreas Karlsson
Attachments:
int128-agg-v2.patchtext/x-patch; name=int128-agg-v2.patchDownload
On 11/13/2014 02:03 AM, Andreas Karlsson wrote:
Here is version 2 of the patch which detects the presence of gcc/clang
style 128-bit integers and has been cleaned up to a reviewable state. I
have not added support for any other compilers since I found no
documentation 128-bit support with icc or MSVC. I do not have access to
any Windows machines either.A couple of things I was not sure about was the naming of the new
functions and if I should ifdef the size of the aggregate state in the
catalog or not.
The correct file is attached in the message.
--
Andreas Karlsson
Attachments:
int128-agg-v2.patchtext/x-patch; name=int128-agg-v2.patchDownload
diff --git a/configure b/configure
new file mode 100755
index c4f70e8..f11f1c8
*** a/configure
--- b/configure
*************** _ACEOF
*** 13734,13739 ****
--- 13734,13751 ----
fi
+ ac_fn_c_check_type "$LINENO" "__int128_t" "ac_cv_type___int128_t" "#include <stdint.h>
+ "
+ ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "#include <stdint.h>
+ "
+ if test "x$ac_cv_type___int128_t" = xyes && test "x$ac_cv_type___uint128_t" = xyes; then :
+
+ cat >>confdefs.h <<_ACEOF
+ #define HAVE_GCC_INT128_T 1
+ _ACEOF
+
+ fi
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
new file mode 100644
index d61af92..d53905c
*** a/src/backend/utils/adt/numeric.c
--- b/src/backend/utils/adt/numeric.c
*************** static void apply_typmod(NumericVar *var
*** 402,407 ****
--- 402,410 ----
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
static void int8_to_numericvar(int64 val, NumericVar *var);
+ #ifdef HAVE_INT128
+ static void int16_to_numericvar(int128 val, NumericVar *var);
+ #endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
*************** numeric_float4(PG_FUNCTION_ARGS)
*** 2639,2644 ****
--- 2642,2650 ----
* Actually, it's a pointer to a NumericAggState allocated in the aggregate
* context. The digit buffers for the NumericVars will be there too.
*
+ * On platforms which support 128-bit integers some aggergates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
*************** numeric_accum_inv(PG_FUNCTION_ARGS)
*** 2897,2902 ****
--- 2903,2967 ----
PG_RETURN_POINTER(state);
}
+ #ifdef HAVE_INT128
+ typedef struct Int16AggState
+ {
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+ } Int16AggState;
+
+ /*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+ static Int16AggState *
+ makeInt16AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+ {
+ Int16AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int16AggState *) palloc0(sizeof(Int16AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+ }
+
+ /*
+ * Accumulate a new input value for 128-bit aggregate functions.
+ */
+ static void
+ do_int16_accum(Int16AggState *state, int128 newval)
+ {
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+ }
+
+ /*
+ * Remove an input value from the aggregated state.
+ */
+ static void
+ do_int16_discard(Int16AggState *state, int128 newval)
+ {
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+ }
+ #endif
/*
* Integer data types all use Numeric accumulators to share code and
*************** numeric_accum_inv(PG_FUNCTION_ARGS)
*** 2905,2915 ****
--- 2970,2996 ----
* for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
* for stddev/variance --- there are faster special-purpose accumulator
* routines for SUM and AVG of these datatypes.
+ *
+ * Similarily we can, where available, use 128-bit integer accumulators
+ * for sum(X) for int8 and sum(X*X) for int2 and int4, but not sum(X*X)
+ * for int8.
*/
Datum
int2_accum(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, true);
+
+ if (!PG_ARGISNULL(1))
+ do_int16_accum(state, (in128) PG_GETARG_INT16(1));
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int2_accum(PG_FUNCTION_ARGS)
*** 2926,2931 ****
--- 3007,3013 ----
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int2_accum(PG_FUNCTION_ARGS)
*** 2933,2938 ****
--- 3015,3032 ----
Datum
int4_accum(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, true);
+
+ if (!PG_ARGISNULL(1))
+ do_int16_accum(state, (in128) PG_GETARG_INT32(1));
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int4_accum(PG_FUNCTION_ARGS)
*** 2949,2954 ****
--- 3043,3049 ----
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int8_accum(PG_FUNCTION_ARGS)
*** 2982,2987 ****
--- 3077,3095 ----
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, false);
+
+ if (!PG_ARGISNULL(1))
+ do_int16_accum(state, (in128) PG_GETARG_INT64(1));
+
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int8_avg_accum(PG_FUNCTION_ARGS)
*** 2998,3003 ****
--- 3106,3112 ----
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int8_avg_accum(PG_FUNCTION_ARGS)
*** 3010,3015 ****
--- 3119,3136 ----
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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))
+ do_int16_discard(state, (int128) PG_GETARG_INT16(1));
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int2_accum_inv(PG_FUNCTION_ARGS)
*** 3029,3034 ****
--- 3150,3156 ----
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int2_accum_inv(PG_FUNCTION_ARGS)
*** 3036,3041 ****
--- 3158,3175 ----
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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))
+ do_int16_discard(state, (int128) PG_GETARG_INT32(1));
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int4_accum_inv(PG_FUNCTION_ARGS)
*** 3055,3060 ****
--- 3189,3195 ----
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int8_accum_inv(PG_FUNCTION_ARGS)
*** 3086,3091 ****
--- 3221,3323 ----
}
Datum
+ int8_avg_accum_inv(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ do_int16_discard(state, (int128) PG_GETARG_INT64(1));
+ #else
+ 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_avg_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");
+ }
+ #endif
+
+ PG_RETURN_POINTER(state);
+ }
+
+ Datum
+ numeric_int16_sum(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_sum(fcinfo);
+ #endif
+ }
+
+ Datum
+ numeric_int16_avg(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+ #else
+ return numeric_avg(fcinfo);
+ #endif
+ }
+
+ Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
*************** numeric_stddev_pop(PG_FUNCTION_ARGS)
*** 3287,3292 ****
--- 3519,3639 ----
PG_RETURN_NUMERIC(res);
}
+ #ifdef HAVE_INT128
+ static Numeric
+ numeric_int16_stddev_internal(Int16AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+ {
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state) {
+ numstate.N = state->N;
+ int16_to_numericvar(state->sumX, &numstate.sumX);
+ int16_to_numericvar(state->sumX2, &numstate.sumX2);
+ } else {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+ }
+ #endif
+
+ Datum
+ numeric_int16_var_samp(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_var_samp(fcinfo);
+ #endif
+ }
+
+ Datum
+ numeric_int16_stddev_samp(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_stddev_samp(fcinfo);
+ #endif
+ }
+
+ Datum
+ numeric_int16_var_pop(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_var_pop(fcinfo);
+ #endif
+ }
+
+ Datum
+ numeric_int16_stddev_pop(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_stddev_pop(fcinfo);
+ #endif
+ }
+
/*
* SUM transition functions for integer datatypes.
*
*************** int8_to_numericvar(int64 val, NumericVar
*** 4509,4514 ****
--- 4856,4908 ----
var->weight = ndigits - 1;
}
+ #ifdef HAVE_INT128
+ /*
+ * Convert 128 bit integer to numeric.
+ */
+ static void
+ int16_to_numericvar(int128 val, NumericVar *var)
+ {
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int16 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+ }
+ #endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/c.h b/src/include/c.h
new file mode 100644
index ce38d78..d713d1e
*** a/src/include/c.h
--- b/src/include/c.h
*************** typedef unsigned long long int uint64;
*** 297,302 ****
--- 297,312 ----
#define HAVE_INT64_TIMESTAMP
#endif
+ /*
+ * 128-bit integers
+ */
+ #ifdef HAVE_GCC_INT128_T
+ typedef __int128_t int128;
+ typedef __uint128_t uint128;
+
+ #define HAVE_INT128
+ #endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
new file mode 100644
index 3ba9e5e..576288b
*** a/src/include/catalog/pg_aggregate.h
--- b/src/include/catalog/pg_aggregate.h
*************** typedef FormData_pg_aggregate *Form_pg_a
*** 125,147 ****
*/
/* avg */
! DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
! DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
! DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
! DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
! DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
! DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
! DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
--- 125,147 ----
*/
/* avg */
! DATA(insert ( 2100 n 0 int8_avg_accum numeric_int16_avg int8_avg_accum int8_avg_accum_inv numeric_int16_avg f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
! DATA(insert ( 2107 n 0 int8_avg_accum numeric_int16_sum int8_avg_accum int8_avg_accum_inv numeric_int16_sum f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
! DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
! DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
! DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
! DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
! DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
*************** DATA(insert ( 2147 n 0 int8inc_any -
*** 194,245 ****
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
! DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
! DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
! DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
! DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
! DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
! DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
--- 194,245 ----
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
! DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2719 n 0 int4_accum numeric_int16_var_pop int4_accum int4_accum_inv numeric_int16_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2720 n 0 int2_accum numeric_int16_var_pop int2_accum int2_accum_inv numeric_int16_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
! DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2642 n 0 int4_accum numeric_int16_var_samp int4_accum int4_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2643 n 0 int2_accum numeric_int16_var_samp int2_accum int2_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
! DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2149 n 0 int4_accum numeric_int16_var_samp int4_accum int4_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2150 n 0 int2_accum numeric_int16_var_samp int2_accum int2_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
! DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2725 n 0 int4_accum numeric_int16_stddev_pop int4_accum int4_accum_inv numeric_int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2726 n 0 int2_accum numeric_int16_stddev_pop int2_accum int2_accum_inv numeric_int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
! DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2713 n 0 int4_accum numeric_int16_stddev_samp int4_accum int4_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2714 n 0 int2_accum numeric_int16_stddev_samp int2_accum int2_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
! DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2155 n 0 int4_accum numeric_int16_stddev_samp int4_accum int4_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2156 n 0 int2_accum numeric_int16_stddev_samp int2_accum int2_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index 5d4e889..e813550
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DATA(insert OID = 3568 ( int4_accum_inv
*** 2484,2489 ****
--- 2484,2491 ----
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 = 3261 ( int8_avg_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_avg_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_ ));
*************** DATA(insert OID = 1841 ( int4_sum P
*** 2502,2507 ****
--- 2504,2522 ----
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+ DATA(insert OID = 3262 ( numeric_int16_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_sum _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 3263 ( numeric_int16_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_avg _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 3264 ( numeric_int16_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_var_pop _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 3265 ( numeric_int16_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_var_samp _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 3266 ( numeric_int16_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_stddev_pop _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 3267 ( numeric_int16_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_stddev_samp _null_ _null_ _null_ ));
+ DESCR("aggregate final 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_ ));
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
new file mode 100644
index 3e78d65..e42212b
*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 198,203 ****
--- 198,206 ----
/* Define to 1 if you have __sync_compare_and_swap(int64 *, int64, int64). */
#undef HAVE_GCC__SYNC_INT64_CAS
+ /* Define to 1 if you have __int128_t and __unit128_t */
+ #undef HAVE_GCC_INT128_T
+
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
new file mode 100644
index 3ba34f8..0ce89ae
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
*************** extern Datum numeric_var_pop(PG_FUNCTION
*** 1018,1023 ****
--- 1018,1029 ----
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_sum(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_avg(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_var_pop(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_var_samp(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_stddev_pop(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
*************** extern Datum int2_avg_accum(PG_FUNCTION_
*** 1025,1030 ****
--- 1031,1037 ----
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_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);
Andreas Karlsson wrote:
On 11/13/2014 02:03 AM, Andreas Karlsson wrote:
Here is version 2 of the patch which detects the presence of gcc/clang
style 128-bit integers and has been cleaned up to a reviewable state. I
have not added support for any other compilers since I found no
documentation 128-bit support with icc or MSVC. I do not have access to
any Windows machines either.A couple of things I was not sure about was the naming of the new
functions and if I should ifdef the size of the aggregate state in the
catalog or not.
configure is a generated file. If your patch touches it but not
configure.in, there is a problem.
diff --git a/configure b/configure
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 11/13/2014 03:38 AM, Alvaro Herrera wrote:
configure is a generated file. If your patch touches it but not
configure.in, there is a problem.
Thanks for pointing it out, I have now fixed it.
--
Andreas Karlsson
Attachments:
int128-agg-v3.patchtext/x-patch; name=int128-agg-v3.patchDownload
diff --git a/configure b/configure
new file mode 100755
index c4f70e8..bb801b4
*** a/configure
--- b/configure
*************** _ACEOF
*** 13735,13740 ****
--- 13735,13763 ----
fi
+ # Check if platform support gcc style 128-bit integers.
+ ac_fn_c_check_type "$LINENO" "__int128_t" "ac_cv_type___int128_t" "#include <stdint.h>
+ "
+ if test "x$ac_cv_type___int128_t" = xyes; then :
+
+ cat >>confdefs.h <<_ACEOF
+ #define HAVE___INT128_T 1
+ _ACEOF
+
+
+ fi
+ ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "#include <stdint.h>
+ "
+ if test "x$ac_cv_type___uint128_t" = xyes; then :
+
+ cat >>confdefs.h <<_ACEOF
+ #define HAVE___UINT128_T 1
+ _ACEOF
+
+
+ fi
+
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "#include <signal.h>
diff --git a/configure.in b/configure.in
new file mode 100644
index 2465f26..1b8a59f
*** a/configure.in
--- b/configure.in
*************** AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX
*** 1751,1756 ****
--- 1751,1759 ----
AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
[#include <stdio.h>])
+ # Check if platform support gcc style 128-bit integers.
+ AC_CHECK_TYPES([__int128_t, __uint128_t], [], [], [#include <stdint.h>])
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
new file mode 100644
index d61af92..98183b4
*** a/src/backend/utils/adt/numeric.c
--- b/src/backend/utils/adt/numeric.c
*************** static void apply_typmod(NumericVar *var
*** 402,407 ****
--- 402,410 ----
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
static void int8_to_numericvar(int64 val, NumericVar *var);
+ #ifdef HAVE_INT128
+ static void int16_to_numericvar(int128 val, NumericVar *var);
+ #endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
*************** numeric_float4(PG_FUNCTION_ARGS)
*** 2639,2644 ****
--- 2642,2650 ----
* Actually, it's a pointer to a NumericAggState allocated in the aggregate
* context. The digit buffers for the NumericVars will be there too.
*
+ * On platforms which support 128-bit integers some aggergates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
*************** numeric_accum_inv(PG_FUNCTION_ARGS)
*** 2897,2902 ****
--- 2903,2967 ----
PG_RETURN_POINTER(state);
}
+ #ifdef HAVE_INT128
+ typedef struct Int16AggState
+ {
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+ } Int16AggState;
+
+ /*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+ static Int16AggState *
+ makeInt16AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+ {
+ Int16AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int16AggState *) palloc0(sizeof(Int16AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+ }
+
+ /*
+ * Accumulate a new input value for 128-bit aggregate functions.
+ */
+ static void
+ do_int16_accum(Int16AggState *state, int128 newval)
+ {
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+ }
+
+ /*
+ * Remove an input value from the aggregated state.
+ */
+ static void
+ do_int16_discard(Int16AggState *state, int128 newval)
+ {
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+ }
+ #endif
/*
* Integer data types all use Numeric accumulators to share code and
*************** numeric_accum_inv(PG_FUNCTION_ARGS)
*** 2905,2915 ****
--- 2970,2996 ----
* for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
* for stddev/variance --- there are faster special-purpose accumulator
* routines for SUM and AVG of these datatypes.
+ *
+ * Similarily we can, where available, use 128-bit integer accumulators
+ * for sum(X) for int8 and sum(X*X) for int2 and int4, but not sum(X*X)
+ * for int8.
*/
Datum
int2_accum(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, true);
+
+ if (!PG_ARGISNULL(1))
+ do_int16_accum(state, (int128) PG_GETARG_INT16(1));
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int2_accum(PG_FUNCTION_ARGS)
*** 2926,2931 ****
--- 3007,3013 ----
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int2_accum(PG_FUNCTION_ARGS)
*** 2933,2938 ****
--- 3015,3032 ----
Datum
int4_accum(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, true);
+
+ if (!PG_ARGISNULL(1))
+ do_int16_accum(state, (int128) PG_GETARG_INT32(1));
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int4_accum(PG_FUNCTION_ARGS)
*** 2949,2954 ****
--- 3043,3049 ----
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int8_accum(PG_FUNCTION_ARGS)
*** 2982,2987 ****
--- 3077,3095 ----
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, false);
+
+ if (!PG_ARGISNULL(1))
+ do_int16_accum(state, (int128) PG_GETARG_INT64(1));
+
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int8_avg_accum(PG_FUNCTION_ARGS)
*** 2998,3003 ****
--- 3106,3112 ----
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int8_avg_accum(PG_FUNCTION_ARGS)
*** 3010,3015 ****
--- 3119,3136 ----
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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))
+ do_int16_discard(state, (int128) PG_GETARG_INT16(1));
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int2_accum_inv(PG_FUNCTION_ARGS)
*** 3029,3034 ****
--- 3150,3156 ----
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int2_accum_inv(PG_FUNCTION_ARGS)
*** 3036,3041 ****
--- 3158,3175 ----
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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))
+ do_int16_discard(state, (int128) PG_GETARG_INT32(1));
+ #else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
*************** int4_accum_inv(PG_FUNCTION_ARGS)
*** 3055,3060 ****
--- 3189,3195 ----
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
+ #endif
PG_RETURN_POINTER(state);
}
*************** int8_accum_inv(PG_FUNCTION_ARGS)
*** 3086,3091 ****
--- 3221,3323 ----
}
Datum
+ int8_avg_accum_inv(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ do_int16_discard(state, (int128) PG_GETARG_INT64(1));
+ #else
+ 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_avg_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");
+ }
+ #endif
+
+ PG_RETURN_POINTER(state);
+ }
+
+ Datum
+ numeric_int16_sum(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_sum(fcinfo);
+ #endif
+ }
+
+ Datum
+ numeric_int16_avg(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+ #else
+ return numeric_avg(fcinfo);
+ #endif
+ }
+
+ Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
*************** numeric_stddev_pop(PG_FUNCTION_ARGS)
*** 3287,3292 ****
--- 3519,3639 ----
PG_RETURN_NUMERIC(res);
}
+ #ifdef HAVE_INT128
+ static Numeric
+ numeric_int16_stddev_internal(Int16AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+ {
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state) {
+ numstate.N = state->N;
+ int16_to_numericvar(state->sumX, &numstate.sumX);
+ int16_to_numericvar(state->sumX2, &numstate.sumX2);
+ } else {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+ }
+ #endif
+
+ Datum
+ numeric_int16_var_samp(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_var_samp(fcinfo);
+ #endif
+ }
+
+ Datum
+ numeric_int16_stddev_samp(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_stddev_samp(fcinfo);
+ #endif
+ }
+
+ Datum
+ numeric_int16_var_pop(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_var_pop(fcinfo);
+ #endif
+ }
+
+ Datum
+ numeric_int16_stddev_pop(PG_FUNCTION_ARGS)
+ {
+ #ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+ #else
+ return numeric_stddev_pop(fcinfo);
+ #endif
+ }
+
/*
* SUM transition functions for integer datatypes.
*
*************** int8_to_numericvar(int64 val, NumericVar
*** 4509,4514 ****
--- 4856,4908 ----
var->weight = ndigits - 1;
}
+ #ifdef HAVE_INT128
+ /*
+ * Convert 128 bit integer to numeric.
+ */
+ static void
+ int16_to_numericvar(int128 val, NumericVar *var)
+ {
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int16 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+ }
+ #endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/c.h b/src/include/c.h
new file mode 100644
index ce38d78..9089a09
*** a/src/include/c.h
--- b/src/include/c.h
*************** typedef unsigned long long int uint64;
*** 297,302 ****
--- 297,312 ----
#define HAVE_INT64_TIMESTAMP
#endif
+ /*
+ * 128-bit integers
+ */
+ #if defined(HAVE___INT128_T) && defined(HAVE___UINT128_T)
+ typedef __int128_t int128;
+ typedef __uint128_t uint128;
+
+ #define HAVE_INT128
+ #endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
new file mode 100644
index 3ba9e5e..576288b
*** a/src/include/catalog/pg_aggregate.h
--- b/src/include/catalog/pg_aggregate.h
*************** typedef FormData_pg_aggregate *Form_pg_a
*** 125,147 ****
*/
/* avg */
! DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
! DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
! DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
! DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
! DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
! DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
! DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
--- 125,147 ----
*/
/* avg */
! DATA(insert ( 2100 n 0 int8_avg_accum numeric_int16_avg int8_avg_accum int8_avg_accum_inv numeric_int16_avg f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
! DATA(insert ( 2107 n 0 int8_avg_accum numeric_int16_sum int8_avg_accum int8_avg_accum_inv numeric_int16_sum f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
! DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
! DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
! DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
! DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
! DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
*************** DATA(insert ( 2147 n 0 int8inc_any -
*** 194,245 ****
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
! DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
! DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
! DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
! DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
! DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
! DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
--- 194,245 ----
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
! DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2719 n 0 int4_accum numeric_int16_var_pop int4_accum int4_accum_inv numeric_int16_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2720 n 0 int2_accum numeric_int16_var_pop int2_accum int2_accum_inv numeric_int16_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
! DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2642 n 0 int4_accum numeric_int16_var_samp int4_accum int4_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2643 n 0 int2_accum numeric_int16_var_samp int2_accum int2_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
! DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2149 n 0 int4_accum numeric_int16_var_samp int4_accum int4_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2150 n 0 int2_accum numeric_int16_var_samp int2_accum int2_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
! DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2725 n 0 int4_accum numeric_int16_stddev_pop int4_accum int4_accum_inv numeric_int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2726 n 0 int2_accum numeric_int16_stddev_pop int2_accum int2_accum_inv numeric_int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
! DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2713 n 0 int4_accum numeric_int16_stddev_samp int4_accum int4_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2714 n 0 int2_accum numeric_int16_stddev_samp int2_accum int2_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
! DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
! DATA(insert ( 2155 n 0 int4_accum numeric_int16_stddev_samp int4_accum int4_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2156 n 0 int2_accum numeric_int16_stddev_samp int2_accum int2_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
! DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
! DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index 5d4e889..e813550
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DATA(insert OID = 3568 ( int4_accum_inv
*** 2484,2489 ****
--- 2484,2491 ----
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 = 3261 ( int8_avg_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_avg_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_ ));
*************** DATA(insert OID = 1841 ( int4_sum P
*** 2502,2507 ****
--- 2504,2522 ----
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+ DATA(insert OID = 3262 ( numeric_int16_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_sum _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 3263 ( numeric_int16_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_avg _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 3264 ( numeric_int16_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_var_pop _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 3265 ( numeric_int16_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_var_samp _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 3266 ( numeric_int16_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_stddev_pop _null_ _null_ _null_ ));
+ DESCR("aggregate final function");
+ DATA(insert OID = 3267 ( numeric_int16_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_stddev_samp _null_ _null_ _null_ ));
+ DESCR("aggregate final 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_ ));
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
new file mode 100644
index 3e78d65..9341f75
*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 198,203 ****
--- 198,209 ----
/* Define to 1 if you have __sync_compare_and_swap(int64 *, int64, int64). */
#undef HAVE_GCC__SYNC_INT64_CAS
+ /* Define to 1 if you have __int128_t */
+ #undef HAVE___INT128_T
+
+ /* Define to 1 if you have __uint128_t */
+ #undef HAVE___UINT128_T
+
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
new file mode 100644
index 3ba34f8..0ce89ae
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
*************** extern Datum numeric_var_pop(PG_FUNCTION
*** 1018,1023 ****
--- 1018,1029 ----
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_sum(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_avg(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_var_pop(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_var_samp(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_stddev_pop(PG_FUNCTION_ARGS);
+ extern Datum numeric_int16_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
*************** extern Datum int2_avg_accum(PG_FUNCTION_
*** 1025,1030 ****
--- 1031,1037 ----
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_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);
On 11/13/14 7:57 PM, Andreas Karlsson wrote:
On 11/13/2014 03:38 AM, Alvaro Herrera wrote:
configure is a generated file. If your patch touches it but not
configure.in, there is a problem.Thanks for pointing it out, I have now fixed it.
There is something odd about your patch. I claims that all files are
new files, e.g.:
diff --git a/src/backend/utils/adt/numeric.c
b/src/backend/utils/adt/numeric.c
new file mode 100644
index d61af92..98183b4
*** a/src/backend/utils/adt/numeric.c
--- b/src/backend/utils/adt/numeric.c
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 11/14/2014 02:25 AM, Peter Eisentraut wrote:
There is something odd about your patch. I claims that all files are
new files, e.g.:diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c new file mode 100644 index d61af92..98183b4 *** a/src/backend/utils/adt/numeric.c --- b/src/backend/utils/adt/numeric.c
Those lines look fine to me.
It does not say I have added a new file, it only claims I have changed
the mode of the file. And that is an artifact from using the script
src/tools/git-external-diff which always outputs a line with "new file
mode".
--
Andreas Karlsson
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 14 November 2014 at 13:57, Andreas Karlsson <andreas@proxel.se> wrote:
On 11/13/2014 03:38 AM, Alvaro Herrera wrote:
configure is a generated file. If your patch touches it but not
configure.in, there is a problem.Thanks for pointing it out, I have now fixed it.
Hi Andreas,
These are some very promising performance increases.
I've done a quick pass of reading the patch. I currently don't have a
system with a 128bit int type, but I'm working on that.
Just a couple of things that could do with being fixed:
This fragment needs fixed to put braces on new lines
if (state) {
numstate.N = state->N;
int16_to_numericvar(state->sumX, &numstate.sumX);
int16_to_numericvar(state->sumX2, &numstate.sumX2);
} else {
numstate.N = 0;
}
It also looks like your OIDs have been nabbed by some jsonb stuff.
DETAIL: Key (oid)=(3267) is duplicated.
I'm also wondering why in numeric_int16_sum() you're doing:
#else
return numeric_sum(fcinfo);
#endif
but you're not doing return int8_accum() in the #else part
of int8_avg_accum()
The same goes for int8_accum_inv() and int8_avg_accum_inv(), though perhaps
you're doing it here because of the elog() showing the wrong function name.
Although that's a pretty much "shouldn't ever happen" case that mightn't be
worth worrying about.
Also since I don't currently have a machine with a working int128, I
decided to benchmark master vs patched to see if there was any sort of
performance regression due to numeric_int16_sum calling numeric_sum, but
I'm a bit confused with the performance results as it seems there's quite a
good increase in performance with the patch, I'd have expected there to be
no change.
CREATE TABLE t (value bigint not null);
insert into t select a.a from generate_series(1,5000000) a(a);
vacuum;
int128_bench.sql has select sum(value) from t;
Master:
D:\Postgres\installb\bin>pgbench.exe -f d:\int128_bench.sql -n -T 120
postgres
transaction type: Custom query
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
duration: 120 s
number of transactions actually processed: 92
latency average: 1304.348 ms
tps = 0.762531 (including connections establishing)
tps = 0.762642 (excluding connections establishing)
Patched:
D:\Postgres\install\bin>pgbench.exe -f d:\int128_bench.sql -n -T 120
postgres
transaction type: Custom query
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
duration: 120 s
number of transactions actually processed: 99
latency average: 1212.121 ms
tps = 0.818067 (including connections establishing)
tps = 0.818199 (excluding connections establishing)
Postgresql.conf is the same in both instances.
I've yet to discover why this is any faster.
Regards
David Rowley
On Tue, Dec 16, 2014 at 7:04 PM, David Rowley <dgrowleyml@gmail.com> wrote:
It also looks like your OIDs have been nabbed by some jsonb stuff.
DETAIL: Key (oid)=(3267) is duplicated.
Use src/include/catalog/unused_oids to track the OIDs not yet used in
the catalogs when adding new objects for a feature.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Nov 14, 2014 at 01:57:16AM +0100, Andreas Karlsson wrote:
*** a/configure.in --- b/configure.in *************** AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX *** 1751,1756 **** --- 1751,1759 ---- AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [], [#include <stdio.h>])+ # Check if platform support gcc style 128-bit integers. + AC_CHECK_TYPES([__int128_t, __uint128_t], [], [], [#include <stdint.h>]) + # We also check for sig_atomic_t, which *should* be defined per ANSI # C, but is missing on some old platforms. AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
__int128_t and __uint128_t are GCC extensions and are not related to
stdint.h.
*** a/src/include/pg_config.h.in --- b/src/include/pg_config.h.in *************** *** 198,203 **** --- 198,209 ---- /* Define to 1 if you have __sync_compare_and_swap(int64 *, int64, int64). */ #undef HAVE_GCC__SYNC_INT64_CAS+ /* Define to 1 if you have __int128_t */ + #undef HAVE___INT128_T + + /* Define to 1 if you have __uint128_t */ + #undef HAVE___UINT128_T + /* Define to 1 if you have the `getaddrinfo' function. */ #undef HAVE_GETADDRINFO
These changes don't match what my autoconf does. Not a big deal I guess,
but if this is merged as-is the next time someone runs autoreconf it'll
write these lines differently to a different location of the file and the
change will end up as a part of an unrelated commit.
*** a/src/backend/utils/adt/numeric.c --- b/src/backend/utils/adt/numeric.c *************** static void apply_typmod(NumericVar *var *** 402,407 **** --- 402,410 ---- static int32 numericvar_to_int4(NumericVar *var); static bool numericvar_to_int8(NumericVar *var, int64 *result); static void int8_to_numericvar(int64 val, NumericVar *var); + #ifdef HAVE_INT128 + static void int16_to_numericvar(int128 val, NumericVar *var); + #endif
Existing code uses int4 and int8 to refer to 32 and 64 bit integers as
they're also PG datatypes, but int16 isn't one and it looks a lot like
int16_t. I think it would make sense to just call it int128 internally
everywhere instead of int16 which isn't used anywhere else to refer to 128
bit integers.
new file mode 100755
I guess src/tools/git-external-diff generated these bogus "new file mode"
lines? I know the project policy says that context diffs should be used,
but it seems to me that most people just use unified diffs these days so I'd
just use "git show" or "git format-patch -1" to generate the patches. The
ones generated by "git format-patch" can be easily applied by reviewers
using "git am".
/ Oskari
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 12/22/2014 11:47 PM, Oskari Saarenmaa wrote:
__int128_t and __uint128_t are GCC extensions and are not related to
stdint.h.[...]
These changes don't match what my autoconf does. Not a big deal I guess,
but if this is merged as-is the next time someone runs autoreconf it'll
write these lines differently to a different location of the file and the
change will end up as a part of an unrelated commit.
Thanks for the feedback. These two issues will be fixed in the next version.
*** a/src/backend/utils/adt/numeric.c --- b/src/backend/utils/adt/numeric.c *************** static void apply_typmod(NumericVar *var *** 402,407 **** --- 402,410 ---- static int32 numericvar_to_int4(NumericVar *var); static bool numericvar_to_int8(NumericVar *var, int64 *result); static void int8_to_numericvar(int64 val, NumericVar *var); + #ifdef HAVE_INT128 + static void int16_to_numericvar(int128 val, NumericVar *var); + #endifExisting code uses int4 and int8 to refer to 32 and 64 bit integers as
they're also PG datatypes, but int16 isn't one and it looks a lot like
int16_t. I think it would make sense to just call it int128 internally
everywhere instead of int16 which isn't used anywhere else to refer to 128
bit integers.
Perhaps. I switched opinion on this several times while coding. On one
side there is consistency, on the other there is the risk of confusing
the different meanings of int16. I am still not sure which of these I
think is the least bad.
new file mode 100755
I guess src/tools/git-external-diff generated these bogus "new file mode"
lines? I know the project policy says that context diffs should be used,
but it seems to me that most people just use unified diffs these days so I'd
just use "git show" or "git format-patch -1" to generate the patches. The
ones generated by "git format-patch" can be easily applied by reviewers
using "git am".
At the time of submitting my patch I had not noticed the slow change
from git-external-diff to regular git diffs. The change snuck up on me.
The new version of the patch will be submitted in the standard git
format which is what I am more used to work with.
--
Andreas Karlsson
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 12/16/2014 11:04 AM, David Rowley wrote:> These are some very
promising performance increases.
I've done a quick pass of reading the patch. I currently don't have a
system with a 128bit int type, but I'm working on that.
Sorry for taking some time to get back. I have been busy before
Christmas. A new version of the patch is attached.
This fragment needs fixed to put braces on new lines
Fixed!
It also looks like your OIDs have been nabbed by some jsonb stuff.
Fixed!
I'm also wondering why in numeric_int16_sum() you're doing:
#else
return numeric_sum(fcinfo);
#endifbut you're not doing return int8_accum() in the #else part
of int8_avg_accum()
The same goes for int8_accum_inv() and int8_avg_accum_inv(), though
perhaps you're doing it here because of the elog() showing the wrong
function name. Although that's a pretty much "shouldn't ever happen"
case that mightn't be worth worrying about.
No strong reason. I did it for symmetry with int2_accum() and int4_accum().
Also since I don't currently have a machine with a working int128, I
decided to benchmark master vs patched to see if there was any sort of
performance regression due to numeric_int16_sum calling numeric_sum, but
I'm a bit confused with the performance results as it seems there's
quite a good increase in performance with the patch, I'd have expected
there to be no change.
Weird, I noticed similar results when doing my benchmarks, but given
that I did not change the accumulator function other than adding an
ifdef I am not totally sure if this difference is real.
master
tps = 1.001984 (excluding connections establishing)
Without int128
tps = 1.014511 (excluding connections establishing)
With int128
tps = 3.185956 (excluding connections establishing)
--
Andreas Karlsson
Attachments:
int128-agg-v4.patchtext/x-patch; name=int128-agg-v4.patchDownload
diff --git a/configure b/configure
index 7594401..15f4eaf 100755
--- a/configure
+++ b/configure
@@ -13771,6 +13771,27 @@ _ACEOF
fi
+# Check if platform support gcc style 128-bit integers.
+ac_fn_c_check_type "$LINENO" "__int128_t" "ac_cv_type___int128_t" "$ac_includes_default"
+if test "x$ac_cv_type___int128_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE___INT128_T 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "$ac_includes_default"
+if test "x$ac_cv_type___uint128_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE___UINT128_T 1
+_ACEOF
+
+
+fi
+
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "#include <signal.h>
diff --git a/configure.in b/configure.in
index 0dc3f18..1271682 100644
--- a/configure.in
+++ b/configure.in
@@ -1752,6 +1752,9 @@ AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX_ALIGNOF, [Define as the maximum alignme
AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
[#include <stdio.h>])
+# Check if platform support gcc style 128-bit integers.
+AC_CHECK_TYPES([__int128_t, __uint128_t], [], [], [])
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index d841b6f..eb0fef4 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -402,6 +402,9 @@ static void apply_typmod(NumericVar *var, int32 typmod);
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
static void int8_to_numericvar(int64 val, NumericVar *var);
+#ifdef HAVE_INT128
+static void int16_to_numericvar(int128 val, NumericVar *var);
+#endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
@@ -2659,6 +2662,9 @@ 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.
*
+ * On platforms which support 128-bit integers some aggergates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
@@ -2917,6 +2923,65 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(state);
}
+#ifdef HAVE_INT128
+typedef struct Int16AggState
+{
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+} Int16AggState;
+
+/*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+static Int16AggState *
+makeInt16AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+{
+ Int16AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int16AggState *) palloc0(sizeof(Int16AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
+
+/*
+ * Accumulate a new input value for 128-bit aggregate functions.
+ */
+static void
+do_int16_accum(Int16AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+}
+
+/*
+ * Remove an input value from the aggregated state.
+ */
+static void
+do_int16_discard(Int16AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+}
+#endif
/*
* Integer data types all use Numeric accumulators to share code and
@@ -2925,11 +2990,27 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
* for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
* for stddev/variance --- there are faster special-purpose accumulator
* routines for SUM and AVG of these datatypes.
+ *
+ * Similarily we can, where available, use 128-bit integer accumulators
+ * for sum(X) for int8 and sum(X*X) for int2 and int4, but not sum(X*X)
+ * for int8.
*/
Datum
int2_accum(PG_FUNCTION_ARGS)
{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, true);
+
+ if (!PG_ARGISNULL(1))
+ do_int16_accum(state, (int128) PG_GETARG_INT16(1));
+#else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -2946,6 +3027,7 @@ int2_accum(PG_FUNCTION_ARGS)
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+#endif
PG_RETURN_POINTER(state);
}
@@ -2953,6 +3035,18 @@ int2_accum(PG_FUNCTION_ARGS)
Datum
int4_accum(PG_FUNCTION_ARGS)
{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, true);
+
+ if (!PG_ARGISNULL(1))
+ do_int16_accum(state, (int128) PG_GETARG_INT32(1));
+#else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -2969,6 +3063,7 @@ int4_accum(PG_FUNCTION_ARGS)
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+#endif
PG_RETURN_POINTER(state);
}
@@ -3002,6 +3097,19 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt16AggState(fcinfo, false);
+
+ if (!PG_ARGISNULL(1))
+ do_int16_accum(state, (int128) PG_GETARG_INT64(1));
+
+#else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -3018,6 +3126,7 @@ int8_avg_accum(PG_FUNCTION_ARGS)
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+#endif
PG_RETURN_POINTER(state);
}
@@ -3030,6 +3139,18 @@ int8_avg_accum(PG_FUNCTION_ARGS)
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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))
+ do_int16_discard(state, (int128) PG_GETARG_INT16(1));
+#else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -3049,6 +3170,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
+#endif
PG_RETURN_POINTER(state);
}
@@ -3056,6 +3178,18 @@ int2_accum_inv(PG_FUNCTION_ARGS)
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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))
+ do_int16_discard(state, (int128) PG_GETARG_INT32(1));
+#else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -3075,6 +3209,7 @@ int4_accum_inv(PG_FUNCTION_ARGS)
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
+#endif
PG_RETURN_POINTER(state);
}
@@ -3106,6 +3241,103 @@ int8_accum_inv(PG_FUNCTION_ARGS)
}
Datum
+int8_avg_accum_inv(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ do_int16_discard(state, (int128) PG_GETARG_INT64(1));
+#else
+ 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_avg_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");
+ }
+#endif
+
+ PG_RETURN_POINTER(state);
+}
+
+Datum
+numeric_int16_sum(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_sum(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_avg(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+#else
+ return numeric_avg(fcinfo);
+#endif
+}
+
+Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
@@ -3307,6 +3539,124 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
+#ifdef HAVE_INT128
+static Numeric
+numeric_int16_stddev_internal(Int16AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+{
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state)
+ {
+ numstate.N = state->N;
+ int16_to_numericvar(state->sumX, &numstate.sumX);
+ int16_to_numericvar(state->sumX2, &numstate.sumX2);
+ }
+ else
+ {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+}
+#endif
+
+Datum
+numeric_int16_var_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_stddev_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_var_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_pop(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_stddev_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int16AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_pop(fcinfo);
+#endif
+}
+
/*
* SUM transition functions for integer datatypes.
*
@@ -4529,6 +4879,53 @@ int8_to_numericvar(int64 val, NumericVar *var)
var->weight = ndigits - 1;
}
+#ifdef HAVE_INT128
+/*
+ * Convert 128 bit integer to numeric.
+ */
+static void
+int16_to_numericvar(int128 val, NumericVar *var)
+{
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int16 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+}
+#endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/c.h b/src/include/c.h
index 93d6924..cd90d60 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -297,6 +297,16 @@ typedef unsigned long long int uint64;
#define HAVE_INT64_TIMESTAMP
#endif
+/*
+ * 128-bit integers
+ */
+#if defined(HAVE___INT128_T) && defined(HAVE___UINT128_T)
+typedef __int128_t int128;
+typedef __uint128_t uint128;
+
+#define HAVE_INT128
+#endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 10cdea1..7f25a37 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -125,23 +125,23 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
+DATA(insert ( 2100 n 0 int8_avg_accum numeric_int16_avg int8_avg_accum int8_avg_accum_inv numeric_int16_avg f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
-DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
-DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
-DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
-DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2107 n 0 int8_avg_accum numeric_int16_sum int8_avg_accum int8_avg_accum_inv numeric_int16_sum f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
+DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
+DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
+DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
@@ -194,52 +194,52 @@ DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - f f 0 2
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
-DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2719 n 0 int4_accum numeric_int16_var_pop int4_accum int4_accum_inv numeric_int16_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2720 n 0 int2_accum numeric_int16_var_pop int2_accum int2_accum_inv numeric_int16_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
-DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2642 n 0 int4_accum numeric_int16_var_samp int4_accum int4_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2643 n 0 int2_accum numeric_int16_var_samp int2_accum int2_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
-DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2149 n 0 int4_accum numeric_int16_var_samp int4_accum int4_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2150 n 0 int2_accum numeric_int16_var_samp int2_accum int2_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
-DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2725 n 0 int4_accum numeric_int16_stddev_pop int4_accum int4_accum_inv numeric_int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2726 n 0 int2_accum numeric_int16_stddev_pop int2_accum int2_accum_inv numeric_int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
-DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2713 n 0 int4_accum numeric_int16_stddev_samp int4_accum int4_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2714 n 0 int2_accum numeric_int16_stddev_samp int2_accum int2_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
-DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2155 n 0 int4_accum numeric_int16_stddev_samp int4_accum int4_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2156 n 0 int2_accum numeric_int16_stddev_samp int2_accum int2_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 484b853..f8695e5 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2491,6 +2491,8 @@ DATA(insert OID = 3568 ( int4_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i
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 = 3387 ( int8_avg_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_avg_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_ ));
@@ -2509,6 +2511,19 @@ DATA(insert OID = 1841 ( int4_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+DATA(insert OID = 3388 ( numeric_int16_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_sum _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3389 ( numeric_int16_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_avg _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3390 ( numeric_int16_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_var_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3391 ( numeric_int16_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_var_samp _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3392 ( numeric_int16_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_stddev_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3393 ( numeric_int16_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_stddev_samp _null_ _null_ _null_ ));
+DESCR("aggregate final 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_ ));
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 465281c..9857ee9 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -678,6 +678,12 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#undef HAVE__VA_ARGS
+/* Define to 1 if the system has the type `__int128_t'. */
+#undef HAVE___INT128_T
+
+/* Define to 1 if the system has the type `__uint128_t'. */
+#undef HAVE___UINT128_T
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#undef INT64_MODIFIER
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 7c4d291..167101a 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1023,6 +1023,12 @@ extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_sum(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_avg(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_var_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_var_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_stddev_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
@@ -1030,6 +1036,7 @@ 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_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);
On 24 December 2014 at 16:04, Andreas Karlsson <andreas@proxel.se> wrote:
On 12/16/2014 11:04 AM, David Rowley wrote:> These are some very promising
performance increases.
I've done a quick pass of reading the patch. I currently don't have a
system with a 128bit int type, but I'm working on that.Sorry for taking some time to get back. I have been busy before Christmas.
A new version of the patch is attached.
Ok I've had another look at this, and I think the only things that I have
to say have been mentioned already:
1. Do we need to keep the 128 byte aggregate state size for machines
without 128 bit ints? This has been reduced to 48 bytes in the patch, which
is in favour code being compiled with a compiler which has 128 bit ints. I
kind of think that we need to keep the 128 byte estimates for compilers
that don't support int128, but I'd like to hear any counter arguments.
2. References to int16 meaning 16 bytes. I'm really in two minds about
this, it's quite nice to keep the natural flow, int4, int8, int16, but I
can't help think that this will confuse someone one day. I think it'll be a
long time before it confused anyone if we called it int128 instead, but I'm
not that excited about seeing it renamed either. I'd like to hear what
others have to say... Is there a chance that some sql standard in the
distant future will have HUGEINT and we might regret not getting the
internal names nailed down?
I also checked the performance of some windowing function calls, since
these call the final function for each row, I thought I'd better make sure
there was no regression as the final function must perform a conversion
from int128 to numeric for each row.
It seems there's still an increase in performance:
Setup:
create table bi_win (i bigint primary key);
insert into bi_win select x.x from generate_series(1,10000) x(x);
vacuum analyze;
Query:
select sum(i) over () from bi_win;
** Master
./pgbench -f ~/int128_window.sql -n -T 60 postgres
transaction type: Custom query
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
duration: 60 s
number of transactions actually processed: 6567
latency average: 9.137 ms
tps = 109.445841 (including connections establishing)
tps = 109.456941 (excluding connections establishing)
** Patched
./pgbench -f ~/int128_window.sql -n -T 60 postgres
transaction type: Custom query
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
duration: 60 s
number of transactions actually processed: 7841
latency average: 7.652 ms
tps = 130.670253 (including connections establishing)
tps = 130.675743 (excluding connections establishing)
Setup:
create table i_win (i int primary key);
insert into i_win select x.x from generate_series(1,10000) x(x);
vacuum analyze;
Query:
select stddev(i) over () from i_win;
** Master
./pgbench -f ~/int128_window.sql -n -T 60 postgres
transaction type: Custom query
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
duration: 60 s
number of transactions actually processed: 5084
latency average: 11.802 ms
tps = 84.730362 (including connections establishing)
tps = 84.735693 (excluding connections establishing)
** Patched
./pgbench -f ~/int128_window.sql -n -T 60 postgres
transaction type: Custom query
scaling factor: 1
query mode: simple
number of clients: 1
number of threads: 1
duration: 60 s
number of transactions actually processed: 7557
latency average: 7.940 ms
tps = 125.934787 (including connections establishing)
tps = 125.943176 (excluding connections establishing)
Regards
David Rowley
On Fri, Dec 26, 2014 at 7:57 AM, David Rowley <dgrowleyml@gmail.com> wrote:
1. Do we need to keep the 128 byte aggregate state size for machines without
128 bit ints? This has been reduced to 48 bytes in the patch, which is in
favour code being compiled with a compiler which has 128 bit ints. I kind
of think that we need to keep the 128 byte estimates for compilers that
don't support int128, but I'd like to hear any counter arguments.
I think you're referring to the estimated state size in pg_aggregate
here, and I'd say it's probably not a big deal one way or the other.
Presumably, at some point, 128-bit arithmetic will become common
enough that we'll want to change that estimate, but I don't know
whether we've reached that point or not.
2. References to int16 meaning 16 bytes. I'm really in two minds about this,
it's quite nice to keep the natural flow, int4, int8, int16, but I can't
help think that this will confuse someone one day. I think it'll be a long
time before it confused anyone if we called it int128 instead, but I'm not
that excited about seeing it renamed either. I'd like to hear what others
have to say... Is there a chance that some sql standard in the distant
future will have HUGEINT and we might regret not getting the internal names
nailed down?
Yeah, I think using int16 to mean 16-bytes will be confusing to
someone almost immediately.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 31 December 2014 at 18:20, Robert Haas <robertmhaas@gmail.com> wrote:
On Fri, Dec 26, 2014 at 7:57 AM, David Rowley <dgrowleyml@gmail.com>
wrote:1. Do we need to keep the 128 byte aggregate state size for machines
without
128 bit ints? This has been reduced to 48 bytes in the patch, which is in
favour code being compiled with a compiler which has 128 bit ints. Ikind
of think that we need to keep the 128 byte estimates for compilers that
don't support int128, but I'd like to hear any counter arguments.I think you're referring to the estimated state size in pg_aggregate
here, and I'd say it's probably not a big deal one way or the other.
Presumably, at some point, 128-bit arithmetic will become common
enough that we'll want to change that estimate, but I don't know
whether we've reached that point or not.
Yeah, that's what I was talking about.
I'm just looking at the code which uses this size estimate
in choose_hashed_grouping(). I'd be a bit worried giving the difference
between 48 and 128 that we'd under estimate the hash size too much and end
up going to disk during hashagg.
I think the patch should be modified so that it uses 128 bytes for the size
estimate on machines that don't support int128, but I'm not quite sure at
this stage if that causes issues for replication, if 1 machine had support
and one didn't, would it matter if the pg_aggregate row on the replica was
48 bytes instead of 128? Is this worth worrying about?
2. References to int16 meaning 16 bytes. I'm really in two minds about
this,
it's quite nice to keep the natural flow, int4, int8, int16, but I can't
help think that this will confuse someone one day. I think it'll be along
time before it confused anyone if we called it int128 instead, but I'm
not
that excited about seeing it renamed either. I'd like to hear what others
have to say... Is there a chance that some sql standard in the distant
future will have HUGEINT and we might regret not getting the internalnames
nailed down?
Yeah, I think using int16 to mean 16-bytes will be confusing to
someone almost immediately.
hmm, I think it should be changed to int128 then. Pitty int4 was selected
as a name instead of int32 back in the day...
I'm going to mark the patch as waiting on author, pending those two changes.
My view with the size estimates change is that if a committer deems it
overkill, then they can rip it out, but at least it's been thought of and
considered rather than forgotten about.
Regards
David Rowley
On 2015-01-01 03:00:50 +1300, David Rowley wrote:
2. References to int16 meaning 16 bytes. I'm really in two minds about
this,
it's quite nice to keep the natural flow, int4, int8, int16, but I can't
help think that this will confuse someone one day. I think it'll be along
time before it confused anyone if we called it int128 instead, but I'm
not
that excited about seeing it renamed either. I'd like to hear what others
have to say... Is there a chance that some sql standard in the distant
future will have HUGEINT and we might regret not getting the internalnames
nailed down?
Yeah, I think using int16 to mean 16-bytes will be confusing to
someone almost immediately.hmm, I think it should be changed to int128 then. Pitty int4 was selected
as a name instead of int32 back in the day...
Note that the C datatype has been int32/int64 for a while now, it's just
the SQL datatype and the names of its support functions. Given that,
afaiu, we're talking about the C datatype it seems pretty clear that it
should be named int128.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Dec 31, 2014 at 9:00 AM, David Rowley <dgrowleyml@gmail.com> wrote:
Yeah, that's what I was talking about.
I'm just looking at the code which uses this size estimate in
choose_hashed_grouping(). I'd be a bit worried giving the difference between
48 and 128 that we'd under estimate the hash size too much and end up going
to disk during hashagg.
That's an issue, but the problem is that...
I think the patch should be modified so that it uses 128 bytes for the size
estimate on machines that don't support int128, but I'm not quite sure at
this stage if that causes issues for replication, if 1 machine had support
and one didn't, would it matter if the pg_aggregate row on the replica was
48 bytes instead of 128? Is this worth worrying about?
...if we do this, then yes, there is an incompatibility between
binaries compiled with this option and binaries compiled without it.
They generate different system catalog contents after initdb and we
shouldn't use one set of binaries with an initdb done the other way.
That seems like serious overkill, especially since this could not
inconceivably flip between one recompile and the next if the
administrator has run 'yum update' in the meantime. So I'd argue for
picking one estimate and using it across the board, and living with
the fact that it's sometimes going to be wrong. Such is the lot in
life of an estimate.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 12/31/14, 8:13 AM, Andres Freund wrote:
On 2015-01-01 03:00:50 +1300, David Rowley wrote:
2. References to int16 meaning 16 bytes. I'm really in two minds about
this,
it's quite nice to keep the natural flow, int4, int8, int16, but I can't
help think that this will confuse someone one day. I think it'll be along
time before it confused anyone if we called it int128 instead, but I'm
not
that excited about seeing it renamed either. I'd like to hear what others
have to say... Is there a chance that some sql standard in the distant
future will have HUGEINT and we might regret not getting the internalnames
nailed down?
Yeah, I think using int16 to mean 16-bytes will be confusing to
someone almost immediately.hmm, I think it should be changed to int128 then. Pitty int4 was selected
as a name instead of int32 back in the day...Note that the C datatype has been int32/int64 for a while now, it's just
the SQL datatype and the names of its support functions. Given that,
afaiu, we're talking about the C datatype it seems pretty clear that it
should be named int128.
Should we start down this road with SQL too, by creating int32, 64 and 128 (if needed?), and changing docs as needed?
Presumably that would be best as a separate patch...
--
Jim Nasby, Data Architect, Blue Treble Consulting
Data in Trouble? Get it in Treble! http://BlueTreble.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Jim Nasby <Jim.Nasby@BlueTreble.com> writes:
On 12/31/14, 8:13 AM, Andres Freund wrote:
Note that the C datatype has been int32/int64 for a while now, it's just
the SQL datatype and the names of its support functions. Given that,
afaiu, we're talking about the C datatype it seems pretty clear that it
should be named int128.
I don't think there was any debate about calling the C typedef int128.
The question at hand was that there are some existing C functions whose
names follow the int2/int4/int8 convention, and it's not very clear what
to do with their 128-bit analogues. Having said that, I'm fine with
switching to int128 for the C names of the new functions; but it is
definitely less than consistent with what we're doing elsewhere.
Should we start down this road with SQL too, by creating int32, 64 and 128 (if needed?), and changing docs as needed?
No. The situation is messy enough without changing our conventions at
the SQL level; that will introduce breakage into user applications,
for no very good reason because we've never had any inconsistency there.
What might be worth trying is establishing a hard-and-fast boundary
between C land and SQL land, with bitwise names in C and bytewise names
in SQL. This would mean, for example, that int4pl() would be renamed to
int32pl() so far as the C function goes, but the function's SQL name would
remain the same. That would introduce visible inconsistency between such
functions' pg_proc.proname and pg_proc.prosrc fields, but at least the
inconsistency would follow a very clear pattern. And I doubt that very
many user applications are depending on the contents of pg_proc.prosrc.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 01/02/2015 11:41 PM, Tom Lane wrote:
What might be worth trying is establishing a hard-and-fast boundary
between C land and SQL land, with bitwise names in C and bytewise names
in SQL. This would mean, for example, that int4pl() would be renamed to
int32pl() so far as the C function goes, but the function's SQL name would
remain the same.
I don't like that. I read int4pl as the function implementing plus
operator for the SQL-visible int4 datatype, so int4pl makes perfect sense.
That would introduce visible inconsistency between such
functions' pg_proc.proname and pg_proc.prosrc fields, but at least the
inconsistency would follow a very clear pattern. And I doubt that very
many user applications are depending on the contents of pg_proc.prosrc.
Someone might be doing
DirectFunctionCall2(int4pl, ...)
in an extension. Well, probably not too likely for int4pl, as you could
just use the native C + operator, but it's not inconceivable for
something like int4recv().
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Heikki Linnakangas <hlinnakangas@vmware.com> writes:
On 01/02/2015 11:41 PM, Tom Lane wrote:
What might be worth trying is establishing a hard-and-fast boundary
between C land and SQL land, with bitwise names in C and bytewise names
in SQL. This would mean, for example, that int4pl() would be renamed to
int32pl() so far as the C function goes, but the function's SQL name would
remain the same.
I don't like that. I read int4pl as the function implementing plus
operator for the SQL-visible int4 datatype, so int4pl makes perfect sense.
I agree with that so far as the SQL name for the function goes, which is
part of why I don't think we should rename anything at the SQL level.
But right now at the C level, it's unclear how things should be named,
and I think we don't really want a situation where the most appropriate
name is so unclear and potentially confusing. We're surviving fine with
"int32" in C meaning "int4" in SQL so far as the type names go, so why not
copy that naming approach for function names?
That would introduce visible inconsistency between such
functions' pg_proc.proname and pg_proc.prosrc fields, but at least the
inconsistency would follow a very clear pattern. And I doubt that very
many user applications are depending on the contents of pg_proc.prosrc.
Someone might be doing
DirectFunctionCall2(int4pl, ...)
in an extension. Well, probably not too likely for int4pl, as you could
just use the native C + operator, but it's not inconceivable for
something like int4recv().
We don't have a lot of hesitation about breaking individual function calls
in extensions, so long as (1) you'll get a compile error and (2) it's
clear how to update the code. See for instance the multitude of cases
where we've added new arguments to existing C functions. So I don't think
this objection holds a lot of water, especially when (as you note) there's
not that much reason to be calling most of these functions directly from C.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 1/2/15, 4:18 PM, Tom Lane wrote:
Heikki Linnakangas<hlinnakangas@vmware.com> writes:
On 01/02/2015 11:41 PM, Tom Lane wrote:
What might be worth trying is establishing a hard-and-fast boundary
between C land and SQL land, with bitwise names in C and bytewise names
in SQL. This would mean, for example, that int4pl() would be renamed to
int32pl() so far as the C function goes, but the function's SQL name would
remain the same.I don't like that. I read int4pl as the function implementing plus
operator for the SQL-visible int4 datatype, so int4pl makes perfect sense.I agree with that so far as the SQL name for the function goes, which is
part of why I don't think we should rename anything at the SQL level.
But right now at the C level, it's unclear how things should be named,
and I think we don't really want a situation where the most appropriate
name is so unclear and potentially confusing. We're surviving fine with
"int32" in C meaning "int4" in SQL so far as the type names go, so why not
copy that naming approach for function names?
Realistically, how many non-developers actually use the intXX SQL names? I don't think I've ever seen it; the only places I recall seeing it done are code snippets on developer blogs. Everyone else uses smallint, etc.
I know we're all gun-shy about this after standard_conforming_strings, but that affected *everyone*. I believe this change would affect very, very few users.
Also, note that I'm not talking about removing anything yet; that would come later.
--
Jim Nasby, Data Architect, Blue Treble Consulting
Data in Trouble? Get it in Treble! http://BlueTreble.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Jan 2, 2015 at 7:57 PM, Jim Nasby <Jim.Nasby@bluetreble.com> wrote:
On 1/2/15, 4:18 PM, Tom Lane wrote:
Heikki Linnakangas<hlinnakangas@vmware.com> writes:
On 01/02/2015 11:41 PM, Tom Lane wrote:
What might be worth trying is establishing a hard-and-fast boundary
between C land and SQL land, with bitwise names in C and bytewise
names
in SQL. This would mean, for example, that int4pl() would be renamed
to
int32pl() so far as the C function goes, but the function's SQL name
would
remain the same.I don't like that. I read int4pl as the function implementing plus
operator for the SQL-visible int4 datatype, so int4pl makes perfect
sense.I agree with that so far as the SQL name for the function goes, which is
part of why I don't think we should rename anything at the SQL level.
But right now at the C level, it's unclear how things should be named,
and I think we don't really want a situation where the most appropriate
name is so unclear and potentially confusing. We're surviving fine with
"int32" in C meaning "int4" in SQL so far as the type names go, so why not
copy that naming approach for function names?Realistically, how many non-developers actually use the intXX SQL names? I
don't think I've ever seen it; the only places I recall seeing it done are
code snippets on developer blogs. Everyone else uses smallint, etc.I know we're all gun-shy about this after standard_conforming_strings, but
that affected *everyone*. I believe this change would affect very, very few
users.Also, note that I'm not talking about removing anything yet; that would come
later.
I think it's naive to think the intXX names wouldn't be used just
because they're postgres-specific. Especially when pgadmin3 generates
them.
Many scripts of mine have them because pgadmin3 generated them, many
others have them because I grew accustomed to using them, especially
when I don't care being postgres-specific. float8 vs double precision
and stuff like that.
Lets not generalize anecdote (me using them), lets just pay attention
to the fact that lots of tools expose them (pgadmin3 among them).
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
+# Check if platform support gcc style 128-bit integers. +AC_CHECK_TYPES([__int128_t, __uint128_t], [], [], [])
Hm, I'm not sure that's sufficent. Three things:
a) Afaics only __int128/unsigned __int128 is defined. See
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html
b) I'm doubtful that AC_CHECK_TYPES is a sufficiently good test on all
platforms. IIRC gcc will generate calls to functions to do the actual
arithmetic, and I don't think they're guranteed to be available on
platforms. That how it .e.g. behaves for atomic operations. So my
guess is that you'll need to check that a program that does actual
arithmetic still links.
c) Personally I don't see the point of testing __uint128_t. That's just
a pointless test that makes configure run for longer.
+#ifdef HAVE_INT128 +typedef struct Int16AggState +{ + bool calcSumX2; /* if true, calculate sumX2 */ + int64 N; /* count of processed numbers */ + int128 sumX; /* sum of processed numbers */ + int128 sumX2; /* sum of squares of processed numbers */ +} Int16AggState;
Not the biggest fan of the variable naming here, but that's not your
fault, you're just consistent which is good.
@@ -3030,6 +3139,18 @@ int8_avg_accum(PG_FUNCTION_ARGS) Datum int2_accum_inv(PG_FUNCTION_ARGS) { +#ifdef HAVE_INT128 + Int16AggState *state; + + state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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)) + do_int16_discard(state, (int128) PG_GETARG_INT16(1)); +#else NumericAggState *state;state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -3049,6 +3170,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
Hm. It might be nicer to move the if (!state) elog() outside the ifdef,
and add curly parens inside the ifdef.
--- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -678,6 +678,12 @@ /* Define to 1 if your compiler understands __VA_ARGS__ in macros. */ #undef HAVE__VA_ARGS
z> +/* Define to 1 if the system has the type `__int128_t'. */
+#undef HAVE___INT128_T + +/* Define to 1 if the system has the type `__uint128_t'. */ +#undef HAVE___UINT128_T
pg_config.h.win32 should be updated as well.
Greetings,
Andres Freund
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 01/11/2015 02:36 AM, Andres Freund wrote:
a) Afaics only __int128/unsigned __int128 is defined. See
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html
Both GCC and Clang defines both of them. Which you use seems to just be
a matter of preference.
b) I'm doubtful that AC_CHECK_TYPES is a sufficiently good test on all
platforms. IIRC gcc will generate calls to functions to do the actual
arithmetic, and I don't think they're guranteed to be available on
platforms. That how it .e.g. behaves for atomic operations. So my
guess is that you'll need to check that a program that does actual
arithmetic still links.
I too thought some about this and decided to look at how other projects
handled this. The projects I have looked at seems to trust that if
__int128_t is defined it will also work.
https://github.com/python/cpython/blob/master/configure#L7778
http://cgit.freedesktop.org/cairo/tree/build/configure.ac.system#n88
But after some more searching now I notice that at least gstreamer does
not trust this to be true.
https://github.com/ensonic/gstreamer/blob/master/configure.ac#L382
Should I fix it to actually compile some code which uses the 128-bit types?
c) Personally I don't see the point of testing __uint128_t. That's just
a pointless test that makes configure run for longer.
Ok, will remove it in the next version of the patch.
@@ -3030,6 +3139,18 @@ int8_avg_accum(PG_FUNCTION_ARGS) Datum int2_accum_inv(PG_FUNCTION_ARGS) { +#ifdef HAVE_INT128 + Int16AggState *state; + + state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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)) + do_int16_discard(state, (int128) PG_GETARG_INT16(1)); +#else NumericAggState *state;state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -3049,6 +3170,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}Hm. It might be nicer to move the if (!state) elog() outside the ifdef,
and add curly parens inside the ifdef.
The reason I did so was because the type of the state differs and I did
not feel like having two ifdef blocks. I have no strong opinion about
this though.
pg_config.h.win32 should be updated as well.
Is it possible to update it without running Windows?
--
Andreas Karlsson
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andreas Karlsson <andreas@proxel.se> writes:
On 01/11/2015 02:36 AM, Andres Freund wrote:
b) I'm doubtful that AC_CHECK_TYPES is a sufficiently good test on all
platforms.
Should I fix it to actually compile some code which uses the 128-bit types?
We used to have code in configure to test that int64 works. Please copy
that (at least as much as necessary; perhaps we don't need to check for
sprintf support).
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 11/01/15 05:07, Andreas Karlsson wrote:
On 01/11/2015 02:36 AM, Andres Freund wrote:
@@ -3030,6 +3139,18 @@ int8_avg_accum(PG_FUNCTION_ARGS) Datum int2_accum_inv(PG_FUNCTION_ARGS) { +#ifdef HAVE_INT128 + Int16AggState *state; + + state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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)) + do_int16_discard(state, (int128) PG_GETARG_INT16(1)); +#else NumericAggState *state;state = PG_ARGISNULL(0) ? NULL : (NumericAggState *)
PG_GETARG_POINTER(0);
@@ -3049,6 +3170,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}Hm. It might be nicer to move the if (!state) elog() outside the ifdef,
and add curly parens inside the ifdef.The reason I did so was because the type of the state differs and I did
not feel like having two ifdef blocks. I have no strong opinion about
this though.
I think Andres means you should move the NULL check before the ifdef and
then use curly braces inside the the ifdef/else so that you can define
the state variable there. That can be done with single ifdef.
int2_accum_inv(PG_FUNCTION_ARGS)
{
... null check ...
{
#ifdef HAVE_INT128
Int16AggState *state;
...
#else
NumericAggState *state;
...
#endif
PG_RETURN_POINTER(state);
}
}
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-01-11 05:07:13 +0100, Andreas Karlsson wrote:
On 01/11/2015 02:36 AM, Andres Freund wrote:
a) Afaics only __int128/unsigned __int128 is defined. See
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.htmlBoth GCC and Clang defines both of them. Which you use seems to just be a
matter of preference.
Only __int128 is documented, the other stuff is just legacy (and
internally documented to be just backward compat stuff).
b) I'm doubtful that AC_CHECK_TYPES is a sufficiently good test on all
platforms. IIRC gcc will generate calls to functions to do the actual
arithmetic, and I don't think they're guranteed to be available on
platforms. That how it .e.g. behaves for atomic operations. So my
guess is that you'll need to check that a program that does actual
arithmetic still links.I too thought some about this and decided to look at how other projects
handled this. The projects I have looked at seems to trust that if
__int128_t is defined it will also work.https://github.com/python/cpython/blob/master/configure#L7778
http://cgit.freedesktop.org/cairo/tree/build/configure.ac.system#n88But after some more searching now I notice that at least gstreamer does not
trust this to be true.https://github.com/ensonic/gstreamer/blob/master/configure.ac#L382
Should I fix it to actually compile some code which uses the 128-bit types?
Yes, compile + link please. As Tom said, best also test some arithmetics.
@@ -3030,6 +3139,18 @@ int8_avg_accum(PG_FUNCTION_ARGS) Datum int2_accum_inv(PG_FUNCTION_ARGS) { +#ifdef HAVE_INT128 + Int16AggState *state; + + state = PG_ARGISNULL(0) ? NULL : (Int16AggState *) 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)) + do_int16_discard(state, (int128) PG_GETARG_INT16(1)); +#else NumericAggState *state;state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -3049,6 +3170,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}Hm. It might be nicer to move the if (!state) elog() outside the ifdef,
and add curly parens inside the ifdef.The reason I did so was because the type of the state differs and I did not
feel like having two ifdef blocks. I have no strong opinion about this
though.
Petr explained what I was thinking of.
pg_config.h.win32 should be updated as well.
Is it possible to update it without running Windows?
Just copy the relevant hunks by hand. In your case the #undef's
generated are sufficient. There are others where we want to define
things unconditionally.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 12/31/2014 03:00 PM, David Rowley wrote:
hmm, I think it should be changed to int128 then. Pitty int4 was
selected as a name instead of int32 back in the day...I'm going to mark the patch as waiting on author, pending those two changes.
My view with the size estimates change is that if a committer deems it
overkill, then they can rip it out, but at least it's been thought of
and considered rather than forgotten about.
Did we come to any conclusion about naming conventions?
I am still unsure on this question. In some cases 128 is much nicer than
16, for example Int128AggState is nicer than Int16AggState and the same
is true for do_int128_accum vs do_int16_accum, but the tricky cases are
things like int16_to_numericvar where there already is a
int8_to_numericvar function and what we should call the functions in
pg_proc (currently named numeric_int16_*).
I also agree with Robert about that we should just pick one estimate and
use that. I picked the smaller one, but that might be too optimistic so
feel free to ask me to switch it back or to pick something in between
the two estimates.
--
Andreas Karlsson
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 01/11/2015 02:36 AM, Andres Freund wrote:
a) Afaics only __int128/unsigned __int128 is defined. See
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.htmlb) I'm doubtful that AC_CHECK_TYPES is a sufficiently good test on all
platforms. IIRC gcc will generate calls to functions to do the actual
arithmetic, and I don't think they're guranteed to be available on
platforms. That how it .e.g. behaves for atomic operations. So my
guess is that you'll need to check that a program that does actual
arithmetic still links.c) Personally I don't see the point of testing __uint128_t. That's just
a pointless test that makes configure run for longer.
The next version will fix all these issues.
Hm. It might be nicer to move the if (!state) elog() outside the ifdef,
and add curly parens inside the ifdef.
Since that change only really works for the *_inv functions I decided to
leave them all as-is for consistency.
--- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -678,6 +678,12 @@ /* Define to 1 if your compiler understands __VA_ARGS__ in macros. */ #undef HAVE__VA_ARGSz> +/* Define to 1 if the system has the type `__int128_t'. */
+#undef HAVE___INT128_T + +/* Define to 1 if the system has the type `__uint128_t'. */ +#undef HAVE___UINT128_Tpg_config.h.win32 should be updated as well.
Will be fixed in the next version.
--
Andreas Karlsson
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
A new version of the patch is attached, which changes the following:
- Changed from using __int128_t to __int128.
- Actually compiles and runs code in configure to see that int128 works.
- No longer tests for __uint128_t.
- Updated pg_config.h.win32
- Renamed some things from int12 to int128, there are still some places
with int16 which I am not sure what to do with.
A remaining issue is what estimate we should pick for the size of the
aggregate state. This patch uses the size of the int128 version for the
estimate, but I have no strong opinions on which we should use.
--
Andreas Karlsson
Attachments:
int128-agg-v5.patchtext/x-patch; name=int128-agg-v5.patchDownload
diff --git a/configure b/configure
index 8490eb7..d9b0e8f 100755
--- a/configure
+++ b/configure
@@ -13743,6 +13743,49 @@ _ACEOF
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking __int128" >&5
+$as_echo_n "checking __int128... " >&6; }
+if test "$cross_compiling" = yes; then :
+ have___int128=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does_int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+main() {
+ exit(! does_int128_work());
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have___int128=yes
+else
+ have___int128=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have___int128" >&5
+$as_echo "$have___int128" >&6; }
+if test x"$have___int128" = xyes ; then
+
+$as_echo "#define HAVE___INT128 1" >>confdefs.h
+
+fi
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "#include <signal.h>
diff --git a/configure.in b/configure.in
index b4bd09e..189e2f0 100644
--- a/configure.in
+++ b/configure.in
@@ -1760,6 +1760,30 @@ AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX_ALIGNOF, [Define as the maximum alignme
AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
[#include <stdio.h>])
+AC_MSG_CHECKING([__int128])
+AC_TRY_RUN([
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does_int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+main() {
+ exit(! does_int128_work());
+}
+ ], [have___int128=yes], [have___int128=no], [have___int128=no])
+AC_MSG_RESULT([$have___int128])
+if test x"$have___int128" = xyes ; then
+ AC_DEFINE(HAVE___INT128, 1, [Define to 1 if the system has the type `__int128'.])
+fi
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index a8609e8..8344343 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -402,6 +402,9 @@ static void apply_typmod(NumericVar *var, int32 typmod);
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
static void int8_to_numericvar(int64 val, NumericVar *var);
+#ifdef HAVE_INT128
+static void int16_to_numericvar(int128 val, NumericVar *var);
+#endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
@@ -2659,6 +2662,9 @@ 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.
*
+ * On platforms which support 128-bit integers some aggergates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
@@ -2917,6 +2923,65 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(state);
}
+#ifdef HAVE_INT128
+typedef struct Int128AggState
+{
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+} Int128AggState;
+
+/*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+static Int128AggState *
+makeInt128AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+{
+ Int128AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int128AggState *) palloc0(sizeof(Int128AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
+
+/*
+ * Accumulate a new input value for 128-bit aggregate functions.
+ */
+static void
+do_int128_accum(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+}
+
+/*
+ * Remove an input value from the aggregated state.
+ */
+static void
+do_int128_discard(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+}
+#endif
/*
* Integer data types all use Numeric accumulators to share code and
@@ -2925,11 +2990,27 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
* for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
* for stddev/variance --- there are faster special-purpose accumulator
* routines for SUM and AVG of these datatypes.
+ *
+ * Similarily we can, where available, use 128-bit integer accumulators
+ * for sum(X) for int8 and sum(X*X) for int2 and int4, but not sum(X*X)
+ * for int8.
*/
Datum
int2_accum(PG_FUNCTION_ARGS)
{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt128AggState(fcinfo, true);
+
+ if (!PG_ARGISNULL(1))
+ do_int128_accum(state, (int128) PG_GETARG_INT16(1));
+#else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -2946,6 +3027,7 @@ int2_accum(PG_FUNCTION_ARGS)
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+#endif
PG_RETURN_POINTER(state);
}
@@ -2953,6 +3035,18 @@ int2_accum(PG_FUNCTION_ARGS)
Datum
int4_accum(PG_FUNCTION_ARGS)
{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt128AggState(fcinfo, true);
+
+ if (!PG_ARGISNULL(1))
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -2969,6 +3063,7 @@ int4_accum(PG_FUNCTION_ARGS)
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+#endif
PG_RETURN_POINTER(state);
}
@@ -3002,6 +3097,19 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* Create the state data on the first call */
+ if (state == NULL)
+ state = makeInt128AggState(fcinfo, false);
+
+ if (!PG_ARGISNULL(1))
+ do_int128_accum(state, (int128) PG_GETARG_INT64(1));
+
+#else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -3018,6 +3126,7 @@ int8_avg_accum(PG_FUNCTION_ARGS)
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
}
+#endif
PG_RETURN_POINTER(state);
}
@@ -3030,6 +3139,18 @@ int8_avg_accum(PG_FUNCTION_ARGS)
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) 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))
+ do_int128_discard(state, (int128) PG_GETARG_INT16(1));
+#else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -3049,6 +3170,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
+#endif
PG_RETURN_POINTER(state);
}
@@ -3056,6 +3178,18 @@ int2_accum_inv(PG_FUNCTION_ARGS)
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) 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))
+ do_int128_discard(state, (int128) PG_GETARG_INT32(1));
+#else
NumericAggState *state;
state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
@@ -3075,6 +3209,7 @@ int4_accum_inv(PG_FUNCTION_ARGS)
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
}
+#endif
PG_RETURN_POINTER(state);
}
@@ -3106,6 +3241,103 @@ int8_accum_inv(PG_FUNCTION_ARGS)
}
Datum
+int8_avg_accum_inv(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ do_int128_discard(state, (int128) PG_GETARG_INT64(1));
+#else
+ 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_avg_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");
+ }
+#endif
+
+ PG_RETURN_POINTER(state);
+}
+
+Datum
+numeric_int16_sum(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_sum(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_avg(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+#else
+ return numeric_avg(fcinfo);
+#endif
+}
+
+Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
@@ -3307,6 +3539,124 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
+#ifdef HAVE_INT128
+static Numeric
+numeric_int16_stddev_internal(Int128AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+{
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state)
+ {
+ numstate.N = state->N;
+ int16_to_numericvar(state->sumX, &numstate.sumX);
+ int16_to_numericvar(state->sumX2, &numstate.sumX2);
+ }
+ else
+ {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+}
+#endif
+
+Datum
+numeric_int16_var_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_stddev_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_var_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_pop(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_stddev_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_pop(fcinfo);
+#endif
+}
+
/*
* SUM transition functions for integer datatypes.
*
@@ -4529,6 +4879,53 @@ int8_to_numericvar(int64 val, NumericVar *var)
var->weight = ndigits - 1;
}
+#ifdef HAVE_INT128
+/*
+ * Convert 128 bit integer to numeric.
+ */
+static void
+int16_to_numericvar(int128 val, NumericVar *var)
+{
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int16 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+}
+#endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/c.h b/src/include/c.h
index c929d3d..b119ea3 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -297,6 +297,16 @@ typedef unsigned long long int uint64;
#define HAVE_INT64_TIMESTAMP
#endif
+/*
+ * 128-bit integers
+ */
+#if defined(HAVE___INT128)
+typedef __int128 int128;
+typedef unsigned __int128 uint128;
+
+#define HAVE_INT128
+#endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 5e1196d..0e7bd9a 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -125,23 +125,23 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
+DATA(insert ( 2100 n 0 int8_avg_accum numeric_int16_avg int8_avg_accum int8_avg_accum_inv numeric_int16_avg f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
-DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
-DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
-DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
-DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2107 n 0 int8_avg_accum numeric_int16_sum int8_avg_accum int8_avg_accum_inv numeric_int16_sum f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
+DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
+DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
+DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
@@ -194,52 +194,52 @@ DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - f f 0 2
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
-DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2719 n 0 int4_accum numeric_int16_var_pop int4_accum int4_accum_inv numeric_int16_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2720 n 0 int2_accum numeric_int16_var_pop int2_accum int2_accum_inv numeric_int16_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
-DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2642 n 0 int4_accum numeric_int16_var_samp int4_accum int4_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2643 n 0 int2_accum numeric_int16_var_samp int2_accum int2_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
-DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2149 n 0 int4_accum numeric_int16_var_samp int4_accum int4_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2150 n 0 int2_accum numeric_int16_var_samp int2_accum int2_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
-DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2725 n 0 int4_accum numeric_int16_stddev_pop int4_accum int4_accum_inv numeric_int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2726 n 0 int2_accum numeric_int16_stddev_pop int2_accum int2_accum_inv numeric_int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
-DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2713 n 0 int4_accum numeric_int16_stddev_samp int4_accum int4_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2714 n 0 int2_accum numeric_int16_stddev_samp int2_accum int2_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
-DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2155 n 0 int4_accum numeric_int16_stddev_samp int4_accum int4_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2156 n 0 int2_accum numeric_int16_stddev_samp int2_accum int2_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 9edfdb8..d11e355 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2491,6 +2491,8 @@ DATA(insert OID = 3568 ( int4_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i
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 = 3387 ( int8_avg_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_avg_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_ ));
@@ -2509,6 +2511,19 @@ DATA(insert OID = 1841 ( int4_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+DATA(insert OID = 3388 ( numeric_int16_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_sum _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3389 ( numeric_int16_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_avg _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3390 ( numeric_int16_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_var_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3391 ( numeric_int16_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_var_samp _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3392 ( numeric_int16_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_stddev_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3393 ( numeric_int16_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_stddev_samp _null_ _null_ _null_ ));
+DESCR("aggregate final 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_ ));
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 995fb65..d8a1971 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -678,6 +678,9 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#undef HAVE__VA_ARGS
+/* Define to 1 if the system has the type `__int128'. */
+#undef HAVE___INT128
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#undef INT64_MODIFIER
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 69d0e31..26a7e80 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -532,6 +532,9 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#define HAVE__VA_ARGS 1
+/* Define to 1 if the system has the type `__int128'. */
+#define HAVE___INT128 1
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#define INT64_MODIFIER "ll"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index bc4517d..4e770a3 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1027,6 +1027,12 @@ extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_sum(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_avg(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_var_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_var_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_stddev_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
@@ -1034,6 +1040,7 @@ 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_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);
On 23/01/15 00:40, Andreas Karlsson wrote:
- Renamed some things from int12 to int128, there are still some places
with int16 which I am not sure what to do with.
I'd vote for renaming them to int128 too, there is enough C functions
that user int16 for 16bit integer that this is going to be confusing
otherwise.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 01/23/2015 02:58 AM, Petr Jelinek wrote:
On 23/01/15 00:40, Andreas Karlsson wrote:
- Renamed some things from int12 to int128, there are still some places
with int16 which I am not sure what to do with.I'd vote for renaming them to int128 too, there is enough C functions
that user int16 for 16bit integer that this is going to be confusing
otherwise.
Do you also think the SQL functions should be named numeric_int128_sum,
numeric_int128_avg, etc?
--
Andreas Karlsson
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-01-27 08:21:57 +0100, Andreas Karlsson wrote:
On 01/23/2015 02:58 AM, Petr Jelinek wrote:
On 23/01/15 00:40, Andreas Karlsson wrote:
- Renamed some things from int12 to int128, there are still some places
with int16 which I am not sure what to do with.I'd vote for renaming them to int128 too, there is enough C functions
that user int16 for 16bit integer that this is going to be confusing
otherwise.Do you also think the SQL functions should be named numeric_int128_sum,
numeric_int128_avg, etc?
I'm pretty sure we already decided upthread that the SQL interface is
going to keep usint int4/8 and by extension int16.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 01/27/2015 09:05 AM, Andres Freund wrote:
On 2015-01-27 08:21:57 +0100, Andreas Karlsson wrote:
On 01/23/2015 02:58 AM, Petr Jelinek wrote:
On 23/01/15 00:40, Andreas Karlsson wrote:
- Renamed some things from int12 to int128, there are still some places
with int16 which I am not sure what to do with.I'd vote for renaming them to int128 too, there is enough C functions
that user int16 for 16bit integer that this is going to be confusing
otherwise.Do you also think the SQL functions should be named numeric_int128_sum,
numeric_int128_avg, etc?I'm pretty sure we already decided upthread that the SQL interface is
going to keep usint int4/8 and by extension int16.
Excellent, then I will leave my latest patch as-is and let the reviewer
say what he thinks.
--
Andreas Karlsson
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Jan 26, 2015 at 11:21 PM, Andreas Karlsson <andreas@proxel.se> wrote:
Do you also think the SQL functions should be named numeric_int128_sum,
numeric_int128_avg, etc?
Some quick review comments. These apply to int128-agg-v5.patch.
* Why is there no declaration of the function
numeric_int16_stddev_internal() within numeric.c?
* I concur with others - we should stick to int16 for the SQL
interface. The inconsistency there is perhaps slightly confusing, but
that's historic.
* I'm not sure about the idea of "polymorphic" catalog functions (that
return the type "internal", but the actual struct returned varying
based on build settings).
I tend to think that things would be better if there was always a
uniform return type for such "internal" type returning functions, but
that *its* structure varied according to the availability of int128
(i.e. HAVE_INT128) at compile time. What we should probably do is have
a third aggregate struct, that encapsulates this idea of (say)
int2_accum() piggybacking on one of either Int128AggState or
NumericAggState directly. Maybe that would be called PolyNumAggState.
Then this common code is all that is needed on both types of build (at
the top of int4_accum(), for example):
PolyNumAggState *state;
state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
I'm not sure if I'd do this with a containing struct or a simple
"#ifdef HAVE_INT128 typedef #else ... ", but I think it's an
improvement either way.
* You didn't update this unequivocal comment to not be so strong:
* Integer data types all use Numeric accumulators to share code and
* avoid risk of overflow.
That's all I have for now...
--
Peter Geoghegan
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Jan 29, 2015 at 8:28 AM, Peter Geoghegan <pg@heroku.com> wrote:
On Mon, Jan 26, 2015 at 11:21 PM, Andreas Karlsson <andreas@proxel.se>
wrote:Do you also think the SQL functions should be named numeric_int128_sum,
numeric_int128_avg, etc?Some quick review comments. These apply to int128-agg-v5.patch.
Andreas, are you planning to continue working on this patch? Peter has
provided some comments that are still unanswered.
--
Michael
On 02/13/2015 02:07 PM, Michael Paquier wrote:
Andreas, are you planning to continue working on this patch? Peter has
provided some comments that are still unanswered.
Yes, but I am quite busy right now. I will try to find time some time
later this week.
--
Andreas Karlsson
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 01/29/2015 12:28 AM, Peter Geoghegan wrote:
On Mon, Jan 26, 2015 at 11:21 PM, Andreas Karlsson <andreas@proxel.se> wrote:
Do you also think the SQL functions should be named numeric_int128_sum,
numeric_int128_avg, etc?Some quick review comments. These apply to int128-agg-v5.patch.
* Why is there no declaration of the function
numeric_int16_stddev_internal() within numeric.c?
Because there is no declaration of numeric_stddev_internal() either. If
there should be I could add declarations for both.
* I concur with others - we should stick to int16 for the SQL
interface. The inconsistency there is perhaps slightly confusing, but
that's historic.
Agreed.
* I'm not sure about the idea of "polymorphic" catalog functions (that
return the type "internal", but the actual struct returned varying
based on build settings).I tend to think that things would be better if there was always a
uniform return type for such "internal" type returning functions, but
that *its* structure varied according to the availability of int128
(i.e. HAVE_INT128) at compile time. What we should probably do is have
a third aggregate struct, that encapsulates this idea of (say)
int2_accum() piggybacking on one of either Int128AggState or
NumericAggState directly. Maybe that would be called PolyNumAggState.
Then this common code is all that is needed on both types of build (at
the top of int4_accum(), for example):PolyNumAggState *state;
state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
I'm not sure if I'd do this with a containing struct or a simple
"#ifdef HAVE_INT128 typedef #else ... ", but I think it's an
improvement either way.
Not entirely sure exactly what I mean but I have changed to something
like this, relying on typedef, in the attached version of the patch. I
think it looks better after the changes.
* You didn't update this unequivocal comment to not be so strong:
* Integer data types all use Numeric accumulators to share code and
* avoid risk of overflow.
Fixed.
I have attached a new version of the patch which fixes the issues above
plus moves the autoconf code to the right place (from configure.in to
c-compiler.m4).
--
Andreas Karlsson
Attachments:
int128-agg-v6.patchtext/x-patch; name=int128-agg-v6.patchDownload
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 509f961..cea74e1 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -125,6 +125,41 @@ undefine([Ac_cachevar])dnl
])# PGAC_TYPE_64BIT_INT
+# PGAC_TYPE_64BIT_INT(TYPE)
+# -------------------------
+# Check if __int128 is a working 128 bit integer type and
+# define HAVE___INT128 if so.
+AC_DEFUN([PGAC_HAVE___INT128],
+[AC_CACHE_CHECK(for __int128, pgac_cv_have___int128,
+[AC_TRY_RUN([
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does_int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+main() {
+ exit(! does_int128_work());
+}],
+[pgac_cv_have___int128=yes],
+[pgac_cv_have___int128=no],
+[# If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([], [sizeof(__int128) == 16])],
+ pgac_cv_have___int128=yes,
+ pgac_cv_have___int128=no)])])
+
+if test x"$pgac_cv_have___int128" = xyes ; then
+ AC_DEFINE(HAVE___INT128, 1, [Define to 1 if the system has the type `__int128'.])
+fi])# PGAC_TYPE_64BIT_INT
+
# PGAC_C_FUNCNAME_SUPPORT
# -----------------------
diff --git a/configure b/configure
index fa271fe..1cd964d 100755
--- a/configure
+++ b/configure
@@ -13773,6 +13773,74 @@ _ACEOF
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __int128" >&5
+$as_echo_n "checking for __int128... " >&6; }
+if ${pgac_cv_have___int128+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ # If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(sizeof(__int128) == 16)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_have___int128=yes
+else
+ pgac_cv_have___int128=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does_int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+main() {
+ exit(! does_int128_work());
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ pgac_cv_have___int128=yes
+else
+ pgac_cv_have___int128=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_have___int128" >&5
+$as_echo "$pgac_cv_have___int128" >&6; }
+
+if test x"$pgac_cv_have___int128" = xyes ; then
+
+$as_echo "#define HAVE___INT128 1" >>confdefs.h
+
+fi
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "#include <signal.h>
diff --git a/configure.in b/configure.in
index e6a49d1..2ef7870 100644
--- a/configure.in
+++ b/configure.in
@@ -1761,6 +1761,8 @@ AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX_ALIGNOF, [Define as the maximum alignme
AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
[#include <stdio.h>])
+PGAC_HAVE___INT128
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 715917b..7b7d7b5 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -403,6 +403,9 @@ static void apply_typmod(NumericVar *var, int32 typmod);
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
static void int8_to_numericvar(int64 val, NumericVar *var);
+#ifdef HAVE_INT128
+static void int16_to_numericvar(int128 val, NumericVar *var);
+#endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
@@ -2660,6 +2663,9 @@ 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.
*
+ * On platforms which support 128-bit integers some aggergates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
@@ -2918,34 +2924,107 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(state);
}
+#ifdef HAVE_INT128
+typedef struct Int128AggState
+{
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+} Int128AggState;
+
+/*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+static Int128AggState *
+makeInt128AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+{
+ Int128AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int128AggState *) palloc0(sizeof(Int128AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
+
+/*
+ * Accumulate a new input value for 128-bit aggregate functions.
+ */
+static void
+do_int128_accum(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+}
+
+/*
+ * Remove an input value from the aggregated state.
+ */
+static void
+do_int128_discard(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+}
+
+typedef Int128AggState PolyNumAggState;
+#define makePolyNumAggState makeInt128AggState
+#else
+typedef NumericAggState PolyNumAggState;
+#define makePolyNumAggState makeNumericAggState
+#endif
/*
- * Integer data types all use Numeric accumulators to share code and
- * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
+ * Integer data types use Numeric accumulators to share code and avoid
+ * risk of overflow. For int2 and int4 inputs, Numeric accumulation
* is overkill for the N and sum(X) values, but definitely not overkill
* for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
* for stddev/variance --- there are faster special-purpose accumulator
* routines for SUM and AVG of these datatypes.
+ *
+ * Similarily we can, where available, use 128-bit integer accumulators
+ * for sum(X) for int8 and sum(X*X) for int2 and int4, but not sum(X*X)
+ * for int8.
*/
Datum
int2_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -2954,21 +3033,25 @@ int2_accum(PG_FUNCTION_ARGS)
Datum
int4_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3003,21 +3086,25 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, false);
+ state = makePolyNumAggState(fcinfo, false);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT64(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3031,9 +3118,9 @@ int8_avg_accum(PG_FUNCTION_ARGS)
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3041,6 +3128,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT16(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
@@ -3049,6 +3139,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3057,9 +3148,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3067,6 +3158,9 @@ int4_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
@@ -3075,6 +3169,7 @@ int4_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3107,6 +3202,94 @@ int8_accum_inv(PG_FUNCTION_ARGS)
}
Datum
+int8_avg_accum_inv(PG_FUNCTION_ARGS)
+{
+ PolyNumAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ {
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT64(1));
+#else
+ 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");
+#endif
+ }
+
+ PG_RETURN_POINTER(state);
+}
+
+Datum
+numeric_int16_sum(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_sum(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_avg(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int16_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+#else
+ return numeric_avg(fcinfo);
+#endif
+}
+
+Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
@@ -3308,6 +3491,124 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
+#ifdef HAVE_INT128
+static Numeric
+numeric_int16_stddev_internal(Int128AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+{
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state)
+ {
+ numstate.N = state->N;
+ int16_to_numericvar(state->sumX, &numstate.sumX);
+ int16_to_numericvar(state->sumX2, &numstate.sumX2);
+ }
+ else
+ {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+}
+#endif
+
+Datum
+numeric_int16_var_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_stddev_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_var_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_pop(fcinfo);
+#endif
+}
+
+Datum
+numeric_int16_stddev_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_int16_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_pop(fcinfo);
+#endif
+}
+
/*
* SUM transition functions for integer datatypes.
*
@@ -4530,6 +4831,53 @@ int8_to_numericvar(int64 val, NumericVar *var)
var->weight = ndigits - 1;
}
+#ifdef HAVE_INT128
+/*
+ * Convert 128 bit integer to numeric.
+ */
+static void
+int16_to_numericvar(int128 val, NumericVar *var)
+{
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int16 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+}
+#endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/c.h b/src/include/c.h
index ee615ee..10e3c0f 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -297,6 +297,16 @@ typedef unsigned long long int uint64;
#define HAVE_INT64_TIMESTAMP
#endif
+/*
+ * 128-bit integers
+ */
+#if defined(HAVE___INT128)
+typedef __int128 int128;
+typedef unsigned __int128 uint128;
+
+#define HAVE_INT128
+#endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 3e28e2f..bdd8cf5 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -126,23 +126,23 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
+DATA(insert ( 2100 n 0 int8_avg_accum numeric_int16_avg int8_avg_accum int8_avg_accum_inv numeric_int16_avg f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
-DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
-DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
-DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
-DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2107 n 0 int8_avg_accum numeric_int16_sum int8_avg_accum int8_avg_accum_inv numeric_int16_sum f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
+DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
+DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
+DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
@@ -195,52 +195,52 @@ DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - f f 0 2
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
-DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2719 n 0 int4_accum numeric_int16_var_pop int4_accum int4_accum_inv numeric_int16_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2720 n 0 int2_accum numeric_int16_var_pop int2_accum int2_accum_inv numeric_int16_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
-DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2642 n 0 int4_accum numeric_int16_var_samp int4_accum int4_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2643 n 0 int2_accum numeric_int16_var_samp int2_accum int2_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
-DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2149 n 0 int4_accum numeric_int16_var_samp int4_accum int4_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2150 n 0 int2_accum numeric_int16_var_samp int2_accum int2_accum_inv numeric_int16_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
-DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2725 n 0 int4_accum numeric_int16_stddev_pop int4_accum int4_accum_inv numeric_int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2726 n 0 int2_accum numeric_int16_stddev_pop int2_accum int2_accum_inv numeric_int16_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
-DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2713 n 0 int4_accum numeric_int16_stddev_samp int4_accum int4_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2714 n 0 int2_accum numeric_int16_stddev_samp int2_accum int2_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
-DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2155 n 0 int4_accum numeric_int16_stddev_samp int4_accum int4_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2156 n 0 int2_accum numeric_int16_stddev_samp int2_accum int2_accum_inv numeric_int16_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index b8a3660..f5dc625 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2495,6 +2495,8 @@ DATA(insert OID = 3568 ( int4_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i
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 = 3387 ( int8_avg_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_avg_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_ ));
@@ -2513,6 +2515,19 @@ DATA(insert OID = 1841 ( int4_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+DATA(insert OID = 3388 ( numeric_int16_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_sum _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3389 ( numeric_int16_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_avg _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3390 ( numeric_int16_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_var_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3391 ( numeric_int16_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_var_samp _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3392 ( numeric_int16_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_stddev_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3393 ( numeric_int16_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_int16_stddev_samp _null_ _null_ _null_ ));
+DESCR("aggregate final 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_ ));
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index ece57c8..e5f6a45 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -681,6 +681,9 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#undef HAVE__VA_ARGS
+/* Define to 1 if the system has the type `__int128'. */
+#undef HAVE___INT128
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#undef INT64_MODIFIER
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 3f858c6..d7c05da 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -535,6 +535,9 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#define HAVE__VA_ARGS 1
+/* Define to 1 if the system has the type `__int128'. */
+#define HAVE___INT128 1
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#define INT64_MODIFIER "ll"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index bc4517d..4e770a3 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1027,6 +1027,12 @@ extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_sum(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_avg(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_var_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_var_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_stddev_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_int16_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
@@ -1034,6 +1040,7 @@ 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_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);
On 04/03/15 23:51, Andreas Karlsson wrote:
On 01/29/2015 12:28 AM, Peter Geoghegan wrote:
* I'm not sure about the idea of "polymorphic" catalog functions (that
return the type "internal", but the actual struct returned varying
based on build settings).I tend to think that things would be better if there was always a
uniform return type for such "internal" type returning functions, but
that *its* structure varied according to the availability of int128
(i.e. HAVE_INT128) at compile time. What we should probably do is have
a third aggregate struct, that encapsulates this idea of (say)
int2_accum() piggybacking on one of either Int128AggState or
NumericAggState directly. Maybe that would be called PolyNumAggState.
Then this common code is all that is needed on both types of build (at
the top of int4_accum(), for example):PolyNumAggState *state;
state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *)
PG_GETARG_POINTER(0);I'm not sure if I'd do this with a containing struct or a simple
"#ifdef HAVE_INT128 typedef #else ... ", but I think it's an
improvement either way.Not entirely sure exactly what I mean but I have changed to something
like this, relying on typedef, in the attached version of the patch. I
think it looks better after the changes.
I think this made the patch much better indeed.
What I am wondering is if those numeric_int16_* functions that also deal
with either the Int128AggState or NumericAggState should be renamed in
similar fashion.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 03/07/2015 07:18 PM, Petr Jelinek wrote:
What I am wondering is if those numeric_int16_* functions that also deal
with either the Int128AggState or NumericAggState should be renamed in
similar fashion.
You mean something like numeric_poly_sum instead of numeric_int16_sum? I
personally am not fond of either name. While numeric_int16_* incorrectly
implies we have a int16 SQL type numeric_poly_* does not tell us that
this is an optimized version which uses a smaller state.
The worst part of writing this patch has always been naming functions
and types. :)
Andreas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 09/03/15 13:39, Andreas Karlsson wrote:
On 03/07/2015 07:18 PM, Petr Jelinek wrote:
What I am wondering is if those numeric_int16_* functions that also deal
with either the Int128AggState or NumericAggState should be renamed in
similar fashion.You mean something like numeric_poly_sum instead of numeric_int16_sum? I
personally am not fond of either name. While numeric_int16_* incorrectly
implies we have a int16 SQL type numeric_poly_* does not tell us that
this is an optimized version which uses a smaller state.
Yes that's what I mean, since the int16 in the name is misleading given
that in at least some builds the int16 won't be used. You could always
have numeric function, int16 function and the poly function which
decides between them but that's probably overkill.
The worst part of writing this patch has always been naming functions
and types. :)
Naming is hard :)
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Mar 09, 2015 at 01:39:04PM +0100, Andreas Karlsson wrote:
On 03/07/2015 07:18 PM, Petr Jelinek wrote:
What I am wondering is if those numeric_int16_* functions that also deal
with either the Int128AggState or NumericAggState should be renamed in
similar fashion.You mean something like numeric_poly_sum instead of numeric_int16_sum? I
personally am not fond of either name. While numeric_int16_* incorrectly
implies we have a int16 SQL type numeric_poly_* does not tell us that this
is an optimized version which uses a smaller state.
Would it be simpler to write a separate patch to add an int16 SQL type
so that this implication is correct?
The worst part of writing this patch has always been naming functions and
types. :)
Cheers,
David.
--
David Fetter <david@fetter.org> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: david.fetter@gmail.com
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 09/03/15 18:39, David Fetter wrote:
On Mon, Mar 09, 2015 at 01:39:04PM +0100, Andreas Karlsson wrote:
On 03/07/2015 07:18 PM, Petr Jelinek wrote:
What I am wondering is if those numeric_int16_* functions that also deal
with either the Int128AggState or NumericAggState should be renamed in
similar fashion.You mean something like numeric_poly_sum instead of numeric_int16_sum? I
personally am not fond of either name. While numeric_int16_* incorrectly
implies we have a int16 SQL type numeric_poly_* does not tell us that this
is an optimized version which uses a smaller state.Would it be simpler to write a separate patch to add an int16 SQL type
so that this implication is correct?
No, because then you'd need to emulate the type on platforms where it
does not exist and the patch would be several times more complex for no
useful reason.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 03/07/2015 07:18 PM, Petr Jelinek wrote:
What I am wondering is if those numeric_int16_* functions that also deal
with either the Int128AggState or NumericAggState should be renamed in
similar fashion.
Here is a patch where I have renamed the functions.
int128-agg-v7.patch
- Rename numeric_int16_* to numeric_poly_*
- Rename static functions int{8,16}_to_numericvar to
int{64,128}_to_numericvar
- Fix typo in c-compile.m4 comment
--
Andreas Karlsson
Attachments:
int128-agg-v7.patchtext/x-patch; name=int128-agg-v7.patchDownload
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 509f961..48fcc68 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -125,6 +125,41 @@ undefine([Ac_cachevar])dnl
])# PGAC_TYPE_64BIT_INT
+# PGAC_HAVE___INT128
+# ------------------
+# Check if __int128 is a working 128 bit integer type and
+# define HAVE___INT128 if so.
+AC_DEFUN([PGAC_HAVE___INT128],
+[AC_CACHE_CHECK(for __int128, pgac_cv_have___int128,
+[AC_TRY_RUN([
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does_int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+main() {
+ exit(! does_int128_work());
+}],
+[pgac_cv_have___int128=yes],
+[pgac_cv_have___int128=no],
+[# If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([], [sizeof(__int128) == 16])],
+ pgac_cv_have___int128=yes,
+ pgac_cv_have___int128=no)])])
+
+if test x"$pgac_cv_have___int128" = xyes ; then
+ AC_DEFINE(HAVE___INT128, 1, [Define to 1 if the system has the type `__int128'.])
+fi])# PGAC_TYPE_64BIT_INT
+
# PGAC_C_FUNCNAME_SUPPORT
# -----------------------
diff --git a/configure b/configure
index fa271fe..1cd964d 100755
--- a/configure
+++ b/configure
@@ -13773,6 +13773,74 @@ _ACEOF
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __int128" >&5
+$as_echo_n "checking for __int128... " >&6; }
+if ${pgac_cv_have___int128+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ # If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(sizeof(__int128) == 16)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_have___int128=yes
+else
+ pgac_cv_have___int128=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does_int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+main() {
+ exit(! does_int128_work());
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ pgac_cv_have___int128=yes
+else
+ pgac_cv_have___int128=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_have___int128" >&5
+$as_echo "$pgac_cv_have___int128" >&6; }
+
+if test x"$pgac_cv_have___int128" = xyes ; then
+
+$as_echo "#define HAVE___INT128 1" >>confdefs.h
+
+fi
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "#include <signal.h>
diff --git a/configure.in b/configure.in
index e6a49d1..2ef7870 100644
--- a/configure.in
+++ b/configure.in
@@ -1761,6 +1761,8 @@ AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX_ALIGNOF, [Define as the maximum alignme
AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
[#include <stdio.h>])
+PGAC_HAVE___INT128
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 715917b..042a94e 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -402,7 +402,10 @@ static void apply_typmod(NumericVar *var, int32 typmod);
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
-static void int8_to_numericvar(int64 val, NumericVar *var);
+static void int64_to_numericvar(int64 val, NumericVar *var);
+#ifdef HAVE_INT128
+static void int128_to_numericvar(int128 val, NumericVar *var);
+#endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
@@ -1414,7 +1417,7 @@ width_bucket_numeric(PG_FUNCTION_ARGS)
init_var(&count_var);
/* Convert 'count' to a numeric, for ease of use later */
- int8_to_numericvar((int64) count, &count_var);
+ int64_to_numericvar((int64) count, &count_var);
switch (cmp_numerics(bound1, bound2))
{
@@ -2083,14 +2086,14 @@ numeric_fac(PG_FUNCTION_ARGS)
init_var(&fact);
init_var(&result);
- int8_to_numericvar(num, &result);
+ int64_to_numericvar(num, &result);
for (num = num - 1; num > 1; num--)
{
/* this loop can take awhile, so allow it to be interrupted */
CHECK_FOR_INTERRUPTS();
- int8_to_numericvar(num, &fact);
+ int64_to_numericvar(num, &fact);
mul_var(&result, &fact, &result, 0);
}
@@ -2388,7 +2391,7 @@ int4_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2454,7 +2457,7 @@ int8_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar(val, &result);
+ int64_to_numericvar(val, &result);
res = make_result(&result);
@@ -2498,7 +2501,7 @@ int2_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2660,6 +2663,9 @@ 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.
*
+ * On platforms which support 128-bit integers some aggergates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
@@ -2918,34 +2924,107 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(state);
}
+#ifdef HAVE_INT128
+typedef struct Int128AggState
+{
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+} Int128AggState;
+
+/*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+static Int128AggState *
+makeInt128AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+{
+ Int128AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int128AggState *) palloc0(sizeof(Int128AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
+
+/*
+ * Accumulate a new input value for 128-bit aggregate functions.
+ */
+static void
+do_int128_accum(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+}
+
+/*
+ * Remove an input value from the aggregated state.
+ */
+static void
+do_int128_discard(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+}
+
+typedef Int128AggState PolyNumAggState;
+#define makePolyNumAggState makeInt128AggState
+#else
+typedef NumericAggState PolyNumAggState;
+#define makePolyNumAggState makeNumericAggState
+#endif
/*
- * Integer data types all use Numeric accumulators to share code and
- * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
+ * Integer data types use Numeric accumulators to share code and avoid
+ * risk of overflow. For int2 and int4 inputs, Numeric accumulation
* is overkill for the N and sum(X) values, but definitely not overkill
* for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
* for stddev/variance --- there are faster special-purpose accumulator
* routines for SUM and AVG of these datatypes.
+ *
+ * Similarily we can, where available, use 128-bit integer accumulators
+ * for sum(X) for int8 and sum(X*X) for int2 and int4, but not sum(X*X)
+ * for int8.
*/
Datum
int2_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -2954,21 +3033,25 @@ int2_accum(PG_FUNCTION_ARGS)
Datum
int4_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3003,21 +3086,25 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, false);
+ state = makePolyNumAggState(fcinfo, false);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT64(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3031,9 +3118,9 @@ int8_avg_accum(PG_FUNCTION_ARGS)
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3041,6 +3128,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT16(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
@@ -3049,6 +3139,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3057,9 +3148,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3067,6 +3158,9 @@ int4_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
@@ -3075,6 +3169,7 @@ int4_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3107,6 +3202,94 @@ int8_accum_inv(PG_FUNCTION_ARGS)
}
Datum
+int8_avg_accum_inv(PG_FUNCTION_ARGS)
+{
+ PolyNumAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ {
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT64(1));
+#else
+ 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");
+#endif
+ }
+
+ PG_RETURN_POINTER(state);
+}
+
+Datum
+numeric_poly_sum(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_sum(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_avg(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+#else
+ return numeric_avg(fcinfo);
+#endif
+}
+
+Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
@@ -3185,7 +3368,7 @@ numeric_stddev_internal(NumericAggState *state,
init_var(&vsumX);
init_var(&vsumX2);
- int8_to_numericvar(state->N, &vN);
+ int64_to_numericvar(state->N, &vN);
set_var_from_var(&(state->sumX), &vsumX);
set_var_from_var(&(state->sumX2), &vsumX2);
@@ -3308,6 +3491,124 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
+#ifdef HAVE_INT128
+static Numeric
+numeric_poly_stddev_internal(Int128AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+{
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state)
+ {
+ numstate.N = state->N;
+ int128_to_numericvar(state->sumX, &numstate.sumX);
+ int128_to_numericvar(state->sumX2, &numstate.sumX2);
+ }
+ else
+ {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+}
+#endif
+
+Datum
+numeric_poly_var_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_var_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_pop(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_pop(fcinfo);
+#endif
+}
+
/*
* SUM transition functions for integer datatypes.
*
@@ -4489,14 +4790,14 @@ numericvar_to_int8(NumericVar *var, int64 *result)
* Convert int8 value to numeric.
*/
static void
-int8_to_numericvar(int64 val, NumericVar *var)
+int64_to_numericvar(int64 val, NumericVar *var)
{
uint64 uval,
newuval;
NumericDigit *ptr;
int ndigits;
- /* int8 can require at most 19 decimal digits; add one for safety */
+ /* int64 can require at most 19 decimal digits; add one for safety */
alloc_var(var, 20 / DEC_DIGITS);
if (val < 0)
{
@@ -4530,6 +4831,53 @@ int8_to_numericvar(int64 val, NumericVar *var)
var->weight = ndigits - 1;
}
+#ifdef HAVE_INT128
+/*
+ * Convert 128 bit integer to numeric.
+ */
+static void
+int128_to_numericvar(int128 val, NumericVar *var)
+{
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int128 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+}
+#endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/c.h b/src/include/c.h
index ee615ee..10e3c0f 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -297,6 +297,16 @@ typedef unsigned long long int uint64;
#define HAVE_INT64_TIMESTAMP
#endif
+/*
+ * 128-bit integers
+ */
+#if defined(HAVE___INT128)
+typedef __int128 int128;
+typedef unsigned __int128 uint128;
+
+#define HAVE_INT128
+#endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 3e28e2f..b6b6988 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -126,23 +126,23 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
+DATA(insert ( 2100 n 0 int8_avg_accum numeric_poly_avg int8_avg_accum int8_avg_accum_inv numeric_poly_avg f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
-DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
-DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
-DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
-DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2107 n 0 int8_avg_accum numeric_poly_sum int8_avg_accum int8_avg_accum_inv numeric_poly_sum f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
+DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
+DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
+DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
@@ -195,52 +195,52 @@ DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - f f 0 2
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
-DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2719 n 0 int4_accum numeric_poly_var_pop int4_accum int4_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2720 n 0 int2_accum numeric_poly_var_pop int2_accum int2_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
-DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2642 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2643 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
-DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2149 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2150 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
-DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2725 n 0 int4_accum numeric_poly_stddev_pop int4_accum int4_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2726 n 0 int2_accum numeric_poly_stddev_pop int2_accum int2_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
-DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2713 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2714 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
-DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2155 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2156 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index b8a3660..c0ad48d 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2495,6 +2495,8 @@ DATA(insert OID = 3568 ( int4_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i
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 = 3387 ( int8_avg_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_avg_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_ ));
@@ -2513,6 +2515,19 @@ DATA(insert OID = 1841 ( int4_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+DATA(insert OID = 3388 ( numeric_poly_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_sum _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3389 ( numeric_poly_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_avg _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3390 ( numeric_poly_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3391 ( numeric_poly_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_samp _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3392 ( numeric_poly_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3393 ( numeric_poly_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_samp _null_ _null_ _null_ ));
+DESCR("aggregate final 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_ ));
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index ece57c8..e5f6a45 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -681,6 +681,9 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#undef HAVE__VA_ARGS
+/* Define to 1 if the system has the type `__int128'. */
+#undef HAVE___INT128
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#undef INT64_MODIFIER
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 3f858c6..d7c05da 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -535,6 +535,9 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#define HAVE__VA_ARGS 1
+/* Define to 1 if the system has the type `__int128'. */
+#define HAVE___INT128 1
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#define INT64_MODIFIER "ll"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index bc4517d..6310641 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1027,6 +1027,12 @@ extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_sum(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_avg(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
@@ -1034,6 +1040,7 @@ 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_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);
On Mon, Mar 9, 2015 at 5:37 PM, Andreas Karlsson <andreas@proxel.se> wrote:
int128-agg-v7.patch
I see a spelling error:
"+ * On platforms which support 128-bit integers some aggergates instead use a"
Other than that, the patch looks pretty good to me. You're
generalizing from the example of existing routines for
int128_to_numericvar(), and other such code in a fairly mechanical
way. The performance improvements are pretty real and tangible.
You say:
/*
* Integer data types use Numeric accumulators to share code and avoid
* risk of overflow. For int2 and int4 inputs, Numeric accumulation
* is overkill for the N and sum(X) values, but definitely not overkill
* for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
* for stddev/variance --- there are faster special-purpose accumulator
* routines for SUM and AVG of these datatypes.
*
* Similarily we can, where available, use 128-bit integer accumulators
* for sum(X) for int8 and sum(X*X) for int2 and int4, but not sum(X*X)
* for int8.
*/
I think you should talk about the new thing first (just after the
extant, first sentence "Integer data types use Numeric..."). Refer to
where 128-bit integers are used and how, and only then the other stuff
(exceptions). After that, put the PolyNumAggState struct definition
and basic functions. Then int2_accum() and so on.
--
Peter Geoghegan
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 03/10/2015 02:26 AM, Peter Geoghegan wrote:
On Mon, Mar 9, 2015 at 5:37 PM, Andreas Karlsson <andreas@proxel.se> wrote:
int128-agg-v7.patch
I see a spelling error:
"+ * On platforms which support 128-bit integers some aggergates instead use a"
Fixed.
I think you should talk about the new thing first (just after the
extant, first sentence "Integer data types use Numeric..."). Refer to
where 128-bit integers are used and how, and only then the other stuff
(exceptions). After that, put the PolyNumAggState struct definition
and basic functions. Then int2_accum() and so on.
Good idea! Do you think the rewritten comment is clear enough, or do I
need to go into more detail?
/*
* Integer data types use Numeric accumulators to share code and avoid risk
* of overflow. To speed up aggregation 128-bit integer accumulators are
* used instead where sum(X) or sum(X*X) fit into 128-bits, and there is
* platform support.
*
* For int2 and int4 inputs sum(X) will fit into a 64-bit accumulator,
hence
* we use faster special-purpose accumulator routines for SUM and AVG of
* these datatypes.
*/
#ifdef HAVE_INT128
typedef struct Int128AggState
--
Andreas Karlsson
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Mar 12, 2015 at 6:23 PM, Andreas Karlsson <andreas@proxel.se> wrote:
Fixed.
Did you intend to attach a patch here?
I think you should talk about the new thing first (just after the
extant, first sentence "Integer data types use Numeric..."). Refer to
where 128-bit integers are used and how, and only then the other stuff
(exceptions). After that, put the PolyNumAggState struct definition
and basic functions. Then int2_accum() and so on.Good idea! Do you think the rewritten comment is clear enough, or do I need
to go into more detail?/*
* Integer data types use Numeric accumulators to share code and avoid risk
* of overflow. To speed up aggregation 128-bit integer accumulators are
* used instead where sum(X) or sum(X*X) fit into 128-bits, and there is
* platform support.
*
* For int2 and int4 inputs sum(X) will fit into a 64-bit accumulator, hence
* we use faster special-purpose accumulator routines for SUM and AVG of
* these datatypes.
*/#ifdef HAVE_INT128
typedef struct Int128AggState
Not quite. Refer to the 128-bit integer accumulators as
"special-purpose accumulator routines" instead. Then, in the case of
the extant 64-bit accumulators, refer to them by the shorthand
"integer accumulators". Otherwise it's the wrong way around.
--
Peter Geoghegan
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 03/13/2015 10:22 PM, Peter Geoghegan wrote:
On Thu, Mar 12, 2015 at 6:23 PM, Andreas Karlsson <andreas@proxel.se> wrote:
/*
* Integer data types use Numeric accumulators to share code and avoid risk
* of overflow. To speed up aggregation 128-bit integer accumulators are
* used instead where sum(X) or sum(X*X) fit into 128-bits, and there is
* platform support.
*
* For int2 and int4 inputs sum(X) will fit into a 64-bit accumulator, hence
* we use faster special-purpose accumulator routines for SUM and AVG of
* these datatypes.
*/#ifdef HAVE_INT128
typedef struct Int128AggStateNot quite. Refer to the 128-bit integer accumulators as
"special-purpose accumulator routines" instead. Then, in the case of
the extant 64-bit accumulators, refer to them by the shorthand
"integer accumulators". Otherwise it's the wrong way around.
I disagree. The term "integer accumulators" is confusing. Right now I do
not have any better ideas for how to write that comment, so I submit the
next version of the patch with the comment as I wrote it above. Feel
free to come up with a better wording, my English is not always up to
par when writing technical texts.
--
Andreas Karlsson
Attachments:
int128-agg-v8.patchtext/x-patch; name=int128-agg-v8.patchDownload
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 509f961..48fcc68 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -125,6 +125,41 @@ undefine([Ac_cachevar])dnl
])# PGAC_TYPE_64BIT_INT
+# PGAC_HAVE___INT128
+# ------------------
+# Check if __int128 is a working 128 bit integer type and
+# define HAVE___INT128 if so.
+AC_DEFUN([PGAC_HAVE___INT128],
+[AC_CACHE_CHECK(for __int128, pgac_cv_have___int128,
+[AC_TRY_RUN([
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does_int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+main() {
+ exit(! does_int128_work());
+}],
+[pgac_cv_have___int128=yes],
+[pgac_cv_have___int128=no],
+[# If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([], [sizeof(__int128) == 16])],
+ pgac_cv_have___int128=yes,
+ pgac_cv_have___int128=no)])])
+
+if test x"$pgac_cv_have___int128" = xyes ; then
+ AC_DEFINE(HAVE___INT128, 1, [Define to 1 if the system has the type `__int128'.])
+fi])# PGAC_TYPE_64BIT_INT
+
# PGAC_C_FUNCNAME_SUPPORT
# -----------------------
diff --git a/configure b/configure
index fa271fe..1cd964d 100755
--- a/configure
+++ b/configure
@@ -13773,6 +13773,74 @@ _ACEOF
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __int128" >&5
+$as_echo_n "checking for __int128... " >&6; }
+if ${pgac_cv_have___int128+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ # If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(sizeof(__int128) == 16)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_have___int128=yes
+else
+ pgac_cv_have___int128=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does_int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+main() {
+ exit(! does_int128_work());
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ pgac_cv_have___int128=yes
+else
+ pgac_cv_have___int128=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_have___int128" >&5
+$as_echo "$pgac_cv_have___int128" >&6; }
+
+if test x"$pgac_cv_have___int128" = xyes ; then
+
+$as_echo "#define HAVE___INT128 1" >>confdefs.h
+
+fi
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "#include <signal.h>
diff --git a/configure.in b/configure.in
index e6a49d1..2ef7870 100644
--- a/configure.in
+++ b/configure.in
@@ -1761,6 +1761,8 @@ AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX_ALIGNOF, [Define as the maximum alignme
AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
[#include <stdio.h>])
+PGAC_HAVE___INT128
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 715917b..1fe3d69 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -402,7 +402,10 @@ static void apply_typmod(NumericVar *var, int32 typmod);
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
-static void int8_to_numericvar(int64 val, NumericVar *var);
+static void int64_to_numericvar(int64 val, NumericVar *var);
+#ifdef HAVE_INT128
+static void int128_to_numericvar(int128 val, NumericVar *var);
+#endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
@@ -1414,7 +1417,7 @@ width_bucket_numeric(PG_FUNCTION_ARGS)
init_var(&count_var);
/* Convert 'count' to a numeric, for ease of use later */
- int8_to_numericvar((int64) count, &count_var);
+ int64_to_numericvar((int64) count, &count_var);
switch (cmp_numerics(bound1, bound2))
{
@@ -2083,14 +2086,14 @@ numeric_fac(PG_FUNCTION_ARGS)
init_var(&fact);
init_var(&result);
- int8_to_numericvar(num, &result);
+ int64_to_numericvar(num, &result);
for (num = num - 1; num > 1; num--)
{
/* this loop can take awhile, so allow it to be interrupted */
CHECK_FOR_INTERRUPTS();
- int8_to_numericvar(num, &fact);
+ int64_to_numericvar(num, &fact);
mul_var(&result, &fact, &result, 0);
}
@@ -2388,7 +2391,7 @@ int4_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2454,7 +2457,7 @@ int8_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar(val, &result);
+ int64_to_numericvar(val, &result);
res = make_result(&result);
@@ -2498,7 +2501,7 @@ int2_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2660,6 +2663,9 @@ 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.
*
+ * On platforms which support 128-bit integers some aggregates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
@@ -2918,34 +2924,105 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(state);
}
+/*
+ * Integer data types use Numeric accumulators to share code and avoid risk
+ * of overflow. To speed up aggregation 128-bit integer accumulators are
+ * used instead where sum(X) or sum(X*X) fit into 128-bits, and there is
+ * platform support.
+ *
+ * For int2 and int4 inputs sum(X) will fit into a 64-bit accumulator, hence
+ * we use faster special-purpose accumulator routines for SUM and AVG of
+ * these datatypes.
+ */
+
+#ifdef HAVE_INT128
+typedef struct Int128AggState
+{
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+} Int128AggState;
+
+/*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+static Int128AggState *
+makeInt128AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+{
+ Int128AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int128AggState *) palloc0(sizeof(Int128AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
+
+/*
+ * Accumulate a new input value for 128-bit aggregate functions.
+ */
+static void
+do_int128_accum(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+}
/*
- * Integer data types all use Numeric accumulators to share code and
- * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
- * is overkill for the N and sum(X) values, but definitely not overkill
- * for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
- * for stddev/variance --- there are faster special-purpose accumulator
- * routines for SUM and AVG of these datatypes.
+ * Remove an input value from the aggregated state.
*/
+static void
+do_int128_discard(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+}
+
+typedef Int128AggState PolyNumAggState;
+#define makePolyNumAggState makeInt128AggState
+#else
+typedef NumericAggState PolyNumAggState;
+#define makePolyNumAggState makeNumericAggState
+#endif
Datum
int2_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -2954,21 +3031,25 @@ int2_accum(PG_FUNCTION_ARGS)
Datum
int4_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3003,21 +3084,25 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, false);
+ state = makePolyNumAggState(fcinfo, false);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT64(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3031,9 +3116,9 @@ int8_avg_accum(PG_FUNCTION_ARGS)
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3041,6 +3126,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT16(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
@@ -3049,6 +3137,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3057,9 +3146,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3067,6 +3156,9 @@ int4_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
@@ -3075,6 +3167,7 @@ int4_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3107,6 +3200,94 @@ int8_accum_inv(PG_FUNCTION_ARGS)
}
Datum
+int8_avg_accum_inv(PG_FUNCTION_ARGS)
+{
+ PolyNumAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ {
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT64(1));
+#else
+ 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");
+#endif
+ }
+
+ PG_RETURN_POINTER(state);
+}
+
+Datum
+numeric_poly_sum(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_sum(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_avg(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+#else
+ return numeric_avg(fcinfo);
+#endif
+}
+
+Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
@@ -3185,7 +3366,7 @@ numeric_stddev_internal(NumericAggState *state,
init_var(&vsumX);
init_var(&vsumX2);
- int8_to_numericvar(state->N, &vN);
+ int64_to_numericvar(state->N, &vN);
set_var_from_var(&(state->sumX), &vsumX);
set_var_from_var(&(state->sumX2), &vsumX2);
@@ -3308,6 +3489,124 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
+#ifdef HAVE_INT128
+static Numeric
+numeric_poly_stddev_internal(Int128AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+{
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state)
+ {
+ numstate.N = state->N;
+ int128_to_numericvar(state->sumX, &numstate.sumX);
+ int128_to_numericvar(state->sumX2, &numstate.sumX2);
+ }
+ else
+ {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+}
+#endif
+
+Datum
+numeric_poly_var_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_var_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_pop(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_pop(fcinfo);
+#endif
+}
+
/*
* SUM transition functions for integer datatypes.
*
@@ -4489,14 +4788,14 @@ numericvar_to_int8(NumericVar *var, int64 *result)
* Convert int8 value to numeric.
*/
static void
-int8_to_numericvar(int64 val, NumericVar *var)
+int64_to_numericvar(int64 val, NumericVar *var)
{
uint64 uval,
newuval;
NumericDigit *ptr;
int ndigits;
- /* int8 can require at most 19 decimal digits; add one for safety */
+ /* int64 can require at most 19 decimal digits; add one for safety */
alloc_var(var, 20 / DEC_DIGITS);
if (val < 0)
{
@@ -4530,6 +4829,53 @@ int8_to_numericvar(int64 val, NumericVar *var)
var->weight = ndigits - 1;
}
+#ifdef HAVE_INT128
+/*
+ * Convert 128 bit integer to numeric.
+ */
+static void
+int128_to_numericvar(int128 val, NumericVar *var)
+{
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int128 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+}
+#endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/c.h b/src/include/c.h
index a2d4a2c..ee07b0d 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -293,6 +293,16 @@ typedef unsigned long long int uint64;
#define HAVE_INT64_TIMESTAMP
#endif
+/*
+ * 128-bit integers
+ */
+#if defined(HAVE___INT128)
+typedef __int128 int128;
+typedef unsigned __int128 uint128;
+
+#define HAVE_INT128
+#endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 3e28e2f..b6b6988 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -126,23 +126,23 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
+DATA(insert ( 2100 n 0 int8_avg_accum numeric_poly_avg int8_avg_accum int8_avg_accum_inv numeric_poly_avg f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
-DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
-DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
-DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
-DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2107 n 0 int8_avg_accum numeric_poly_sum int8_avg_accum int8_avg_accum_inv numeric_poly_sum f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
+DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
+DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
+DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
@@ -195,52 +195,52 @@ DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - f f 0 2
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
-DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2719 n 0 int4_accum numeric_poly_var_pop int4_accum int4_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2720 n 0 int2_accum numeric_poly_var_pop int2_accum int2_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
-DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2642 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2643 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
-DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2149 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2150 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
-DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2725 n 0 int4_accum numeric_poly_stddev_pop int4_accum int4_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2726 n 0 int2_accum numeric_poly_stddev_pop int2_accum int2_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
-DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2713 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2714 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
-DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2155 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2156 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index b8a3660..c0ad48d 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2495,6 +2495,8 @@ DATA(insert OID = 3568 ( int4_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i
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 = 3387 ( int8_avg_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_avg_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_ ));
@@ -2513,6 +2515,19 @@ DATA(insert OID = 1841 ( int4_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+DATA(insert OID = 3388 ( numeric_poly_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_sum _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3389 ( numeric_poly_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_avg _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3390 ( numeric_poly_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3391 ( numeric_poly_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_samp _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3392 ( numeric_poly_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3393 ( numeric_poly_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_samp _null_ _null_ _null_ ));
+DESCR("aggregate final 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_ ));
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index ece57c8..e5f6a45 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -681,6 +681,9 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#undef HAVE__VA_ARGS
+/* Define to 1 if the system has the type `__int128'. */
+#undef HAVE___INT128
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#undef INT64_MODIFIER
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 3f858c6..d7c05da 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -535,6 +535,9 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#define HAVE__VA_ARGS 1
+/* Define to 1 if the system has the type `__int128'. */
+#define HAVE___INT128 1
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#define INT64_MODIFIER "ll"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index bc4517d..6310641 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1027,6 +1027,12 @@ extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_sum(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_avg(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
@@ -1034,6 +1040,7 @@ 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_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);
On 14/03/15 04:17, Andreas Karlsson wrote:
On 03/13/2015 10:22 PM, Peter Geoghegan wrote:
On Thu, Mar 12, 2015 at 6:23 PM, Andreas Karlsson <andreas@proxel.se>
wrote:/*
* Integer data types use Numeric accumulators to share code and
avoid risk
* of overflow. To speed up aggregation 128-bit integer
accumulators are
* used instead where sum(X) or sum(X*X) fit into 128-bits, and
there is
* platform support.
*
* For int2 and int4 inputs sum(X) will fit into a 64-bit
accumulator, hence
* we use faster special-purpose accumulator routines for SUM and
AVG of
* these datatypes.
*/#ifdef HAVE_INT128
typedef struct Int128AggStateNot quite. Refer to the 128-bit integer accumulators as
"special-purpose accumulator routines" instead. Then, in the case of
the extant 64-bit accumulators, refer to them by the shorthand
"integer accumulators". Otherwise it's the wrong way around.I disagree. The term "integer accumulators" is confusing. Right now I do
not have any better ideas for how to write that comment, so I submit the
next version of the patch with the comment as I wrote it above. Feel
free to come up with a better wording, my English is not always up to
par when writing technical texts.
I don't like the term "integer accumulators" either as "integer" is
platform specific. I would phase it like this:
/*
* Integer data types in general use Numeric accumulators to share code
* and avoid risk of overflow.
*
* However for performance reasons some of the optimized special-purpose
* accumulator routines are used when possible.
*
* On platforms with 128-bit integer support, the 128-bit routines will be
* used when sum(X) or sum(X*X) fit into 128-bit.
*
* For int2 and int4 inputs, the N and sum(X) fit into 64-bit so the 64-bit
* accumulators will be used for SUM and AVG of these data types.
*/
It's almost the same thing as you wrote but the 128 bit and 64 bit
optimizations are put on the same "level" of optimized routines.
But this is nitpicking at this point, I am happy with the patch as it
stands right now.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 03/15/2015 09:47 PM, Petr Jelinek wrote:
It's almost the same thing as you wrote but the 128 bit and 64 bit
optimizations are put on the same "level" of optimized routines.But this is nitpicking at this point, I am happy with the patch as it
stands right now.
Do you think it is ready for committer?
New version with altered comment is attached.
--
Andreas Karlsson
Attachments:
int128-agg-v9.patchtext/x-patch; name=int128-agg-v9.patchDownload
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 509f961..48fcc68 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -125,6 +125,41 @@ undefine([Ac_cachevar])dnl
])# PGAC_TYPE_64BIT_INT
+# PGAC_HAVE___INT128
+# ------------------
+# Check if __int128 is a working 128 bit integer type and
+# define HAVE___INT128 if so.
+AC_DEFUN([PGAC_HAVE___INT128],
+[AC_CACHE_CHECK(for __int128, pgac_cv_have___int128,
+[AC_TRY_RUN([
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does_int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+main() {
+ exit(! does_int128_work());
+}],
+[pgac_cv_have___int128=yes],
+[pgac_cv_have___int128=no],
+[# If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([], [sizeof(__int128) == 16])],
+ pgac_cv_have___int128=yes,
+ pgac_cv_have___int128=no)])])
+
+if test x"$pgac_cv_have___int128" = xyes ; then
+ AC_DEFINE(HAVE___INT128, 1, [Define to 1 if the system has the type `__int128'.])
+fi])# PGAC_TYPE_64BIT_INT
+
# PGAC_C_FUNCNAME_SUPPORT
# -----------------------
diff --git a/configure b/configure
index 379dab1..b60f55f 100755
--- a/configure
+++ b/configure
@@ -13789,6 +13789,74 @@ _ACEOF
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __int128" >&5
+$as_echo_n "checking for __int128... " >&6; }
+if ${pgac_cv_have___int128+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ # If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(sizeof(__int128) == 16)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_have___int128=yes
+else
+ pgac_cv_have___int128=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does_int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+main() {
+ exit(! does_int128_work());
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ pgac_cv_have___int128=yes
+else
+ pgac_cv_have___int128=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_have___int128" >&5
+$as_echo "$pgac_cv_have___int128" >&6; }
+
+if test x"$pgac_cv_have___int128" = xyes ; then
+
+$as_echo "#define HAVE___INT128 1" >>confdefs.h
+
+fi
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "#include <signal.h>
diff --git a/configure.in b/configure.in
index ca29e93..823abaa 100644
--- a/configure.in
+++ b/configure.in
@@ -1767,6 +1767,8 @@ AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX_ALIGNOF, [Define as the maximum alignme
AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
[#include <stdio.h>])
+PGAC_HAVE___INT128
+
# We also check for sig_atomic_t, which *should* be defined per ANSI
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 715917b..9b70f36 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -402,7 +402,10 @@ static void apply_typmod(NumericVar *var, int32 typmod);
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
-static void int8_to_numericvar(int64 val, NumericVar *var);
+static void int64_to_numericvar(int64 val, NumericVar *var);
+#ifdef HAVE_INT128
+static void int128_to_numericvar(int128 val, NumericVar *var);
+#endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
@@ -1414,7 +1417,7 @@ width_bucket_numeric(PG_FUNCTION_ARGS)
init_var(&count_var);
/* Convert 'count' to a numeric, for ease of use later */
- int8_to_numericvar((int64) count, &count_var);
+ int64_to_numericvar((int64) count, &count_var);
switch (cmp_numerics(bound1, bound2))
{
@@ -2083,14 +2086,14 @@ numeric_fac(PG_FUNCTION_ARGS)
init_var(&fact);
init_var(&result);
- int8_to_numericvar(num, &result);
+ int64_to_numericvar(num, &result);
for (num = num - 1; num > 1; num--)
{
/* this loop can take awhile, so allow it to be interrupted */
CHECK_FOR_INTERRUPTS();
- int8_to_numericvar(num, &fact);
+ int64_to_numericvar(num, &fact);
mul_var(&result, &fact, &result, 0);
}
@@ -2388,7 +2391,7 @@ int4_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2454,7 +2457,7 @@ int8_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar(val, &result);
+ int64_to_numericvar(val, &result);
res = make_result(&result);
@@ -2498,7 +2501,7 @@ int2_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2660,6 +2663,9 @@ 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.
*
+ * On platforms which support 128-bit integers some aggregates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
@@ -2920,32 +2926,107 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
/*
- * Integer data types all use Numeric accumulators to share code and
- * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
- * is overkill for the N and sum(X) values, but definitely not overkill
- * for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
- * for stddev/variance --- there are faster special-purpose accumulator
- * routines for SUM and AVG of these datatypes.
+ * Integer data types in general use Numeric accumulators to share code
+ * and avoid risk of overflow.
+ *
+ * However for performance reasons optimized special-purpose accumulator
+ * routines are used when possible.
+ *
+ * On platforms with 128-bit integer support, the 128-bit routines will be
+ * used when sum(X) or sum(X*X) fit into 128-bit.
+ *
+ * For int2 and int4 inputs, the N and sum(X) fit into 64-bit so the 64-bit
+ * accumulators will be used for SUM and AVG of these data types.
+ */
+
+#ifdef HAVE_INT128
+typedef struct Int128AggState
+{
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+} Int128AggState;
+
+/*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+static Int128AggState *
+makeInt128AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+{
+ Int128AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int128AggState *) palloc0(sizeof(Int128AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
+
+/*
+ * Accumulate a new input value for 128-bit aggregate functions.
*/
+static void
+do_int128_accum(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+}
+
+/*
+ * Remove an input value from the aggregated state.
+ */
+static void
+do_int128_discard(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+}
+
+typedef Int128AggState PolyNumAggState;
+#define makePolyNumAggState makeInt128AggState
+#else
+typedef NumericAggState PolyNumAggState;
+#define makePolyNumAggState makeNumericAggState
+#endif
Datum
int2_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -2954,21 +3035,25 @@ int2_accum(PG_FUNCTION_ARGS)
Datum
int4_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3003,21 +3088,25 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, false);
+ state = makePolyNumAggState(fcinfo, false);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT64(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3031,9 +3120,9 @@ int8_avg_accum(PG_FUNCTION_ARGS)
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3041,6 +3130,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT16(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
@@ -3049,6 +3141,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3057,9 +3150,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3067,6 +3160,9 @@ int4_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
@@ -3075,6 +3171,7 @@ int4_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3107,6 +3204,94 @@ int8_accum_inv(PG_FUNCTION_ARGS)
}
Datum
+int8_avg_accum_inv(PG_FUNCTION_ARGS)
+{
+ PolyNumAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ {
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT64(1));
+#else
+ 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");
+#endif
+ }
+
+ PG_RETURN_POINTER(state);
+}
+
+Datum
+numeric_poly_sum(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_sum(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_avg(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+#else
+ return numeric_avg(fcinfo);
+#endif
+}
+
+Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
@@ -3185,7 +3370,7 @@ numeric_stddev_internal(NumericAggState *state,
init_var(&vsumX);
init_var(&vsumX2);
- int8_to_numericvar(state->N, &vN);
+ int64_to_numericvar(state->N, &vN);
set_var_from_var(&(state->sumX), &vsumX);
set_var_from_var(&(state->sumX2), &vsumX2);
@@ -3308,6 +3493,124 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
+#ifdef HAVE_INT128
+static Numeric
+numeric_poly_stddev_internal(Int128AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+{
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state)
+ {
+ numstate.N = state->N;
+ int128_to_numericvar(state->sumX, &numstate.sumX);
+ int128_to_numericvar(state->sumX2, &numstate.sumX2);
+ }
+ else
+ {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+}
+#endif
+
+Datum
+numeric_poly_var_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_var_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_pop(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ Int128AggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_pop(fcinfo);
+#endif
+}
+
/*
* SUM transition functions for integer datatypes.
*
@@ -4489,14 +4792,14 @@ numericvar_to_int8(NumericVar *var, int64 *result)
* Convert int8 value to numeric.
*/
static void
-int8_to_numericvar(int64 val, NumericVar *var)
+int64_to_numericvar(int64 val, NumericVar *var)
{
uint64 uval,
newuval;
NumericDigit *ptr;
int ndigits;
- /* int8 can require at most 19 decimal digits; add one for safety */
+ /* int64 can require at most 19 decimal digits; add one for safety */
alloc_var(var, 20 / DEC_DIGITS);
if (val < 0)
{
@@ -4530,6 +4833,53 @@ int8_to_numericvar(int64 val, NumericVar *var)
var->weight = ndigits - 1;
}
+#ifdef HAVE_INT128
+/*
+ * Convert 128 bit integer to numeric.
+ */
+static void
+int128_to_numericvar(int128 val, NumericVar *var)
+{
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int128 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+}
+#endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/c.h b/src/include/c.h
index a2d4a2c..ee07b0d 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -293,6 +293,16 @@ typedef unsigned long long int uint64;
#define HAVE_INT64_TIMESTAMP
#endif
+/*
+ * 128-bit integers
+ */
+#if defined(HAVE___INT128)
+typedef __int128 int128;
+typedef unsigned __int128 uint128;
+
+#define HAVE_INT128
+#endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 3e28e2f..b6b6988 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -126,23 +126,23 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
+DATA(insert ( 2100 n 0 int8_avg_accum numeric_poly_avg int8_avg_accum int8_avg_accum_inv numeric_poly_avg f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
-DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
-DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
-DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
-DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2107 n 0 int8_avg_accum numeric_poly_sum int8_avg_accum int8_avg_accum_inv numeric_poly_sum f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
+DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
+DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
+DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
@@ -195,52 +195,52 @@ DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - f f 0 2
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
-DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2719 n 0 int4_accum numeric_poly_var_pop int4_accum int4_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2720 n 0 int2_accum numeric_poly_var_pop int2_accum int2_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
-DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2642 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2643 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
-DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2149 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2150 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
-DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2725 n 0 int4_accum numeric_poly_stddev_pop int4_accum int4_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2726 n 0 int2_accum numeric_poly_stddev_pop int2_accum int2_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
-DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2713 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2714 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
-DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2155 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2156 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index b8a3660..c0ad48d 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2495,6 +2495,8 @@ DATA(insert OID = 3568 ( int4_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i
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 = 3387 ( int8_avg_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_avg_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_ ));
@@ -2513,6 +2515,19 @@ DATA(insert OID = 1841 ( int4_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+DATA(insert OID = 3388 ( numeric_poly_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_sum _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3389 ( numeric_poly_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_avg _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3390 ( numeric_poly_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3391 ( numeric_poly_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_samp _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3392 ( numeric_poly_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3393 ( numeric_poly_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_samp _null_ _null_ _null_ ));
+DESCR("aggregate final 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_ ));
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index ece57c8..e5f6a45 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -681,6 +681,9 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#undef HAVE__VA_ARGS
+/* Define to 1 if the system has the type `__int128'. */
+#undef HAVE___INT128
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#undef INT64_MODIFIER
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 3f858c6..d7c05da 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -535,6 +535,9 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#define HAVE__VA_ARGS 1
+/* Define to 1 if the system has the type `__int128'. */
+#define HAVE___INT128 1
+
/* Define to the appropriate snprintf length modifier for 64-bit ints. */
#define INT64_MODIFIER "ll"
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index bc4517d..6310641 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1027,6 +1027,12 @@ extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_sum(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_avg(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
@@ -1034,6 +1040,7 @@ 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_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);
On 16/03/15 00:37, Andreas Karlsson wrote:
On 03/15/2015 09:47 PM, Petr Jelinek wrote:
It's almost the same thing as you wrote but the 128 bit and 64 bit
optimizations are put on the same "level" of optimized routines.But this is nitpicking at this point, I am happy with the patch as it
stands right now.Do you think it is ready for committer?
In my opinion, yes.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Mar 16, 2015 at 6:22 AM, Petr Jelinek <petr@2ndquadrant.com> wrote:
Do you think it is ready for committer?
In my opinion, yes.
If it wasn't for the autoconf parts of this, I'd probably agree with
you. I need to go over that more carefully.
--
Peter Geoghegan
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-03-17 20:50:48 -0700, Peter Geoghegan wrote:
On Mon, Mar 16, 2015 at 6:22 AM, Petr Jelinek <petr@2ndquadrant.com> wrote:
Do you think it is ready for committer?
In my opinion, yes.
If it wasn't for the autoconf parts of this, I'd probably agree with
you. I need to go over that more carefully.
I think it's a pretty direct copy of the 64bit code. I'm not entirely
sure why this needs a AC_TRY_RUN with a compile fallback (for cross) and
why a AC_TRY_LINK isn't sufficient? But then, you just copied that
decision.
Tom, it seems you have added the 64bit check to configure. All, the way
back in 1998 ;). C.f. 07ae591c87. Do you see a reason why we need to
actually run code?
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Mar 18, 2015 at 1:05 AM, Andres Freund <andres@2ndquadrant.com> wrote:
I think it's a pretty direct copy of the 64bit code. I'm not entirely
sure why this needs a AC_TRY_RUN with a compile fallback (for cross) and
why a AC_TRY_LINK isn't sufficient? But then, you just copied that
decision.
Good point.
Anyway, I think that it's not quite the same. For one thing, we're
talking about a GCC extension, not a type described by C99. We don't
care about snprintf support, for example. For another, Andreas has
chosen to lump together __int128 and unsigned __int128 into one test,
where the latter really doesn't receive coverage. This only makes
sense from the point of view of this optimization, since we need both
anyway, as int128_to_numericvar() uses the uint128 type. I think it's
fine to only use int128/uint128 for this optimization, and similar
optimizations, and consequently I think it's fine to lump the two
types together, but lets be clear that that's all we mean to do.
I'm going to keep things that way, and try and test unsigned __int128
too (but as part of the same, single configure test). It's not merely
a matter of mechanically copying what we do for int64 (or uint64),
though.
--
Peter Geoghegan
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-03-18 14:00:51 -0700, Peter Geoghegan wrote:
Anyway, I think that it's not quite the same. For one thing, we're
talking about a GCC extension, not a type described by C99. We don't
care about snprintf support, for example.
I don't see that that has any consequence wrt Andreas' test.
For another, Andreas has chosen to lump together __int128 and unsigned
__int128 into one test, where the latter really doesn't receive
coverage.
On my urging actually. It's pretty darn unlikely that only one variant
will work. Useless configure tests just cost time. We're testing a gcc
extension here, as you point out, it'll not just stop working for
unsigned vs signed.
The reason we need a link test (vs just a compile test) is that gcc
links to helper functions to do math - even if they're not present on
the target platform. Compiling will succeed, but linking won't.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Mar 18, 2015 at 3:16 PM, Andres Freund <andres@2ndquadrant.com> wrote:
For another, Andreas has chosen to lump together __int128 and unsigned
__int128 into one test, where the latter really doesn't receive
coverage.On my urging actually. It's pretty darn unlikely that only one variant
will work.
I think that makes sense. Since we're targeting GCC here, and we're
comfortable with that, I guess that's okay after all.
The reason we need a link test (vs just a compile test) is that gcc
links to helper functions to do math - even if they're not present on
the target platform. Compiling will succeed, but linking won't.
Okay. Attached revision has a few tweaks that reflect the status of
int128/uint128 as specialized types that are basically only useful for
this optimization, or other similar optimizations on compilers that
either are GCC, or aim to be compatible with it. I don't think
Andreas' V9 reflected that sufficiently.
Also, I now always use PolyNumAggState (the typedef), even for #define
HAVE_INT128 code, which I think is a bit clearer. Note that I have
generated a minimal diff, without the machine generated changes that
are ordinarily included in the final commit when autoconf tests are
added, mostly because I do not have the exact version of autoconf on
my development machine required to do this without creating irrelevant
cruft.
Marked "Ready for committer".
A committer that has the exact right version of autoconf (GNU Autoconf
2.69), or perhaps Andreas can build the machine generated parts.
Andres may wish to take another look at the autoconf changes.
--
Peter Geoghegan
Attachments:
int128-agg-v10.patchtext/x-patch; charset=US-ASCII; name=int128-agg-v10.patchDownload
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 509f961..2db04ab 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -125,6 +125,43 @@ undefine([Ac_cachevar])dnl
])# PGAC_TYPE_64BIT_INT
+# PGAC_HAVE_GCC__INT128
+# ---------------------
+# Check if __int128 is a working 128 bit integer type, and if so define
+# HAVE_GCC__INT128. This is a GCC extension, unlike the other integer types,
+# which C99 defines.
+AC_DEFUN([PGAC_HAVE_GCC__INT128],
+[AC_CACHE_CHECK(for __int128, pgac_cv_have_gcc__int128,
+[AC_TRY_RUN([
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does__int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+
+main() {
+ exit(! does__int128_work());
+}],
+[pgac_cv_have_gcc__int128=yes],
+[pgac_cv_have_gcc__int128=no],
+[# If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([], [sizeof(__int128) == 16])],
+ pgac_cv_have_gcc__int128=yes,
+ pgac_cv_have_gcc__int128=no)])])
+
+if test x"$pgac_cv_have_gcc__int128" = xyes ; then
+ AC_DEFINE(HAVE_GCC__INT128, 1, [Define to 1 if the system has the type `__int128'.])
+fi])# PGAC_HAVE_GCC__INT128
+
# PGAC_C_FUNCNAME_SUPPORT
# -----------------------
diff --git a/configure.in b/configure.in
index ca29e93..6b1c251 100644
--- a/configure.in
+++ b/configure.in
@@ -1771,6 +1771,10 @@ AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
+# Check for extension offering the integer scalar type __int128. This is
+# supported for targets which have an integer mode wide enough to hold 128 bits.
+PGAC_HAVE_GCC__INT128
+
# Check for various atomic operations now that we have checked how to declare
# 64bit integers.
PGAC_HAVE_GCC__SYNC_CHAR_TAS
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 715917b..b925d29 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -402,7 +402,10 @@ static void apply_typmod(NumericVar *var, int32 typmod);
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
-static void int8_to_numericvar(int64 val, NumericVar *var);
+static void int64_to_numericvar(int64 val, NumericVar *var);
+#ifdef HAVE_INT128
+static void int128_to_numericvar(int128 val, NumericVar *var);
+#endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
@@ -1414,7 +1417,7 @@ width_bucket_numeric(PG_FUNCTION_ARGS)
init_var(&count_var);
/* Convert 'count' to a numeric, for ease of use later */
- int8_to_numericvar((int64) count, &count_var);
+ int64_to_numericvar((int64) count, &count_var);
switch (cmp_numerics(bound1, bound2))
{
@@ -2083,14 +2086,14 @@ numeric_fac(PG_FUNCTION_ARGS)
init_var(&fact);
init_var(&result);
- int8_to_numericvar(num, &result);
+ int64_to_numericvar(num, &result);
for (num = num - 1; num > 1; num--)
{
/* this loop can take awhile, so allow it to be interrupted */
CHECK_FOR_INTERRUPTS();
- int8_to_numericvar(num, &fact);
+ int64_to_numericvar(num, &fact);
mul_var(&result, &fact, &result, 0);
}
@@ -2388,7 +2391,7 @@ int4_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2454,7 +2457,7 @@ int8_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar(val, &result);
+ int64_to_numericvar(val, &result);
res = make_result(&result);
@@ -2498,7 +2501,7 @@ int2_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2660,6 +2663,9 @@ 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.
*
+ * On platforms which support 128-bit integers some aggregates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
@@ -2920,32 +2926,107 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
/*
- * Integer data types all use Numeric accumulators to share code and
- * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
- * is overkill for the N and sum(X) values, but definitely not overkill
- * for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
- * for stddev/variance --- there are faster special-purpose accumulator
- * routines for SUM and AVG of these datatypes.
+ * Integer data types in general use Numeric accumulators to share code
+ * and avoid risk of overflow.
+ *
+ * However for performance reasons optimized special-purpose accumulator
+ * routines are used when possible.
+ *
+ * On platforms with 128-bit integer support, the 128-bit routines will be
+ * used when sum(X) or sum(X*X) fit into 128-bit.
+ *
+ * For int2 and int4 inputs, the N and sum(X) fit into 64-bit so the 64-bit
+ * accumulators will be used for SUM and AVG of these data types.
+ */
+
+#ifdef HAVE_INT128
+typedef struct Int128AggState
+{
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+} Int128AggState;
+
+/*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+static Int128AggState *
+makeInt128AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+{
+ Int128AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int128AggState *) palloc0(sizeof(Int128AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
+
+/*
+ * Accumulate a new input value for 128-bit aggregate functions.
+ */
+static void
+do_int128_accum(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+}
+
+/*
+ * Remove an input value from the aggregated state.
*/
+static void
+do_int128_discard(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+}
+
+typedef Int128AggState PolyNumAggState;
+#define makePolyNumAggState makeInt128AggState
+#else
+typedef NumericAggState PolyNumAggState;
+#define makePolyNumAggState makeNumericAggState
+#endif
Datum
int2_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -2954,21 +3035,25 @@ int2_accum(PG_FUNCTION_ARGS)
Datum
int4_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3003,21 +3088,25 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, false);
+ state = makePolyNumAggState(fcinfo, false);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT64(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3031,9 +3120,9 @@ int8_avg_accum(PG_FUNCTION_ARGS)
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3041,6 +3130,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT16(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
@@ -3049,6 +3141,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3057,9 +3150,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3067,6 +3160,9 @@ int4_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
@@ -3075,6 +3171,7 @@ int4_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3107,6 +3204,94 @@ int8_accum_inv(PG_FUNCTION_ARGS)
}
Datum
+int8_avg_accum_inv(PG_FUNCTION_ARGS)
+{
+ PolyNumAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ {
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT64(1));
+#else
+ 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");
+#endif
+ }
+
+ PG_RETURN_POINTER(state);
+}
+
+Datum
+numeric_poly_sum(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_sum(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_avg(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+#else
+ return numeric_avg(fcinfo);
+#endif
+}
+
+Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
@@ -3185,7 +3370,7 @@ numeric_stddev_internal(NumericAggState *state,
init_var(&vsumX);
init_var(&vsumX2);
- int8_to_numericvar(state->N, &vN);
+ int64_to_numericvar(state->N, &vN);
set_var_from_var(&(state->sumX), &vsumX);
set_var_from_var(&(state->sumX2), &vsumX2);
@@ -3308,6 +3493,124 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
+#ifdef HAVE_INT128
+static Numeric
+numeric_poly_stddev_internal(Int128AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+{
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state)
+ {
+ numstate.N = state->N;
+ int128_to_numericvar(state->sumX, &numstate.sumX);
+ int128_to_numericvar(state->sumX2, &numstate.sumX2);
+ }
+ else
+ {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+}
+#endif
+
+Datum
+numeric_poly_var_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_var_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_pop(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_pop(fcinfo);
+#endif
+}
+
/*
* SUM transition functions for integer datatypes.
*
@@ -4489,14 +4792,14 @@ numericvar_to_int8(NumericVar *var, int64 *result)
* Convert int8 value to numeric.
*/
static void
-int8_to_numericvar(int64 val, NumericVar *var)
+int64_to_numericvar(int64 val, NumericVar *var)
{
uint64 uval,
newuval;
NumericDigit *ptr;
int ndigits;
- /* int8 can require at most 19 decimal digits; add one for safety */
+ /* int64 can require at most 19 decimal digits; add one for safety */
alloc_var(var, 20 / DEC_DIGITS);
if (val < 0)
{
@@ -4530,6 +4833,53 @@ int8_to_numericvar(int64 val, NumericVar *var)
var->weight = ndigits - 1;
}
+#ifdef HAVE_INT128
+/*
+ * Convert 128 bit integer to numeric.
+ */
+static void
+int128_to_numericvar(int128 val, NumericVar *var)
+{
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int128 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+}
+#endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/c.h b/src/include/c.h
index a2d4a2c..e98085a 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -293,6 +293,22 @@ typedef unsigned long long int uint64;
#define HAVE_INT64_TIMESTAMP
#endif
+/*
+ * 128-bit signed and unsigned integers
+ * These are lumped together, since they
+ * are used only for aggregate transition
+ * state. snprintf formatting support is
+ * not required. GCC does not even
+ * support __int128 literals, so int128
+ * is likely to remain a very specialized
+ * type.
+ */
+#if defined(HAVE_GCC__INT128)
+#define HAVE_INT128
+typedef __int128 int128;
+typedef unsigned __int128 uint128;
+#endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 3e28e2f..b6b6988 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -126,23 +126,23 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
+DATA(insert ( 2100 n 0 int8_avg_accum numeric_poly_avg int8_avg_accum int8_avg_accum_inv numeric_poly_avg f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
-DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
-DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
-DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
-DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2107 n 0 int8_avg_accum numeric_poly_sum int8_avg_accum int8_avg_accum_inv numeric_poly_sum f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
+DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
+DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
+DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
@@ -195,52 +195,52 @@ DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - f f 0 2
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
-DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2719 n 0 int4_accum numeric_poly_var_pop int4_accum int4_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2720 n 0 int2_accum numeric_poly_var_pop int2_accum int2_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
-DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2642 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2643 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
-DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2149 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2150 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
-DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2725 n 0 int4_accum numeric_poly_stddev_pop int4_accum int4_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2726 n 0 int2_accum numeric_poly_stddev_pop int2_accum int2_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
-DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2713 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2714 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
-DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2155 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2156 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index b8a3660..c0ad48d 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2495,6 +2495,8 @@ DATA(insert OID = 3568 ( int4_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i
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 = 3387 ( int8_avg_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_avg_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_ ));
@@ -2513,6 +2515,19 @@ DATA(insert OID = 1841 ( int4_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+DATA(insert OID = 3388 ( numeric_poly_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_sum _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3389 ( numeric_poly_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_avg _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3390 ( numeric_poly_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3391 ( numeric_poly_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_samp _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3392 ( numeric_poly_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3393 ( numeric_poly_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_samp _null_ _null_ _null_ ));
+DESCR("aggregate final 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_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index bc4517d..6310641 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1027,6 +1027,12 @@ extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_sum(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_avg(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
@@ -1034,6 +1040,7 @@ 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_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);
On 2015-03-18 15:59:52 -0700, Peter Geoghegan wrote:
Okay. Attached revision has a few tweaks that reflect the status of
int128/uint128 as specialized types that are basically only useful for
this optimization, or other similar optimizations on compilers that
either are GCC, or aim to be compatible with it. I don't think
Andreas' V9 reflected that sufficiently.
Given that we don't rely on C99, I don't think that actually
matters. Lots of our platforms build on pre C99 compilers... I think it
makes sense to say that this currently only tests for a gcc extension
and might be extended in the future. But nothing more.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Mar 18, 2015 at 4:07 PM, Andres Freund <andres@2ndquadrant.com> wrote:
Given that we don't rely on C99, I don't think that actually
matters. Lots of our platforms build on pre C99 compilers... I think it
makes sense to say that this currently only tests for a gcc extension
and might be extended in the future. But nothing more.
Works for me.
--
Peter Geoghegan
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 03/18/2015 11:59 PM, Peter Geoghegan wrote:
Okay. Attached revision has a few tweaks that reflect the status of
int128/uint128 as specialized types that are basically only useful for
this optimization, or other similar optimizations on compilers that
either are GCC, or aim to be compatible with it. I don't think
Andreas' V9 reflected that sufficiently.Also, I now always use PolyNumAggState (the typedef), even for #define
HAVE_INT128 code, which I think is a bit clearer. Note that I have
generated a minimal diff, without the machine generated changes that
are ordinarily included in the final commit when autoconf tests are
added, mostly because I do not have the exact version of autoconf on
my development machine required to do this without creating irrelevant
Thanks,
I have attached a patch where I have ran autoconf.
--
Andreas Karlsson
Attachments:
int128-agg-v11.patchtext/x-patch; name=int128-agg-v11.patchDownload
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 509f961..2db04ab 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -125,6 +125,43 @@ undefine([Ac_cachevar])dnl
])# PGAC_TYPE_64BIT_INT
+# PGAC_HAVE_GCC__INT128
+# ---------------------
+# Check if __int128 is a working 128 bit integer type, and if so define
+# HAVE_GCC__INT128. This is a GCC extension, unlike the other integer types,
+# which C99 defines.
+AC_DEFUN([PGAC_HAVE_GCC__INT128],
+[AC_CACHE_CHECK(for __int128, pgac_cv_have_gcc__int128,
+[AC_TRY_RUN([
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does__int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+
+main() {
+ exit(! does__int128_work());
+}],
+[pgac_cv_have_gcc__int128=yes],
+[pgac_cv_have_gcc__int128=no],
+[# If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([], [sizeof(__int128) == 16])],
+ pgac_cv_have_gcc__int128=yes,
+ pgac_cv_have_gcc__int128=no)])])
+
+if test x"$pgac_cv_have_gcc__int128" = xyes ; then
+ AC_DEFINE(HAVE_GCC__INT128, 1, [Define to 1 if the system has the type `__int128'.])
+fi])# PGAC_HAVE_GCC__INT128
+
# PGAC_C_FUNCNAME_SUPPORT
# -----------------------
diff --git a/configure b/configure
index 379dab1..f61d980 100755
--- a/configure
+++ b/configure
@@ -13803,6 +13803,77 @@ _ACEOF
fi
+# Check for extension offering the integer scalar type __int128. This is
+# supported for targets which have an integer mode wide enough to hold 128 bits.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __int128" >&5
+$as_echo_n "checking for __int128... " >&6; }
+if ${pgac_cv_have_gcc__int128+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ # If cross-compiling, check the size reported by the compiler and
+# trust that the arithmetic works.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+static int test_array [1 - 2 * !(sizeof(__int128) == 16)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_have_gcc__int128=yes
+else
+ pgac_cv_have_gcc__int128=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+__int128 a = 200000000001;
+__int128 b = 400000000005;
+
+int does__int128_work()
+{
+ __int128 c,d;
+
+ c = a * b;
+ d = (c + b) / b;
+ if (d != a+1)
+ return 0;
+ return 1;
+}
+
+main() {
+ exit(! does__int128_work());
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ pgac_cv_have_gcc__int128=yes
+else
+ pgac_cv_have_gcc__int128=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_have_gcc__int128" >&5
+$as_echo "$pgac_cv_have_gcc__int128" >&6; }
+
+if test x"$pgac_cv_have_gcc__int128" = xyes ; then
+
+$as_echo "#define HAVE_GCC__INT128 1" >>confdefs.h
+
+fi
+
# Check for various atomic operations now that we have checked how to declare
# 64bit integers.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __sync char locking functions" >&5
diff --git a/configure.in b/configure.in
index ca29e93..6b1c251 100644
--- a/configure.in
+++ b/configure.in
@@ -1771,6 +1771,10 @@ AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
+# Check for extension offering the integer scalar type __int128. This is
+# supported for targets which have an integer mode wide enough to hold 128 bits.
+PGAC_HAVE_GCC__INT128
+
# Check for various atomic operations now that we have checked how to declare
# 64bit integers.
PGAC_HAVE_GCC__SYNC_CHAR_TAS
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 715917b..b925d29 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -402,7 +402,10 @@ static void apply_typmod(NumericVar *var, int32 typmod);
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
-static void int8_to_numericvar(int64 val, NumericVar *var);
+static void int64_to_numericvar(int64 val, NumericVar *var);
+#ifdef HAVE_INT128
+static void int128_to_numericvar(int128 val, NumericVar *var);
+#endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
@@ -1414,7 +1417,7 @@ width_bucket_numeric(PG_FUNCTION_ARGS)
init_var(&count_var);
/* Convert 'count' to a numeric, for ease of use later */
- int8_to_numericvar((int64) count, &count_var);
+ int64_to_numericvar((int64) count, &count_var);
switch (cmp_numerics(bound1, bound2))
{
@@ -2083,14 +2086,14 @@ numeric_fac(PG_FUNCTION_ARGS)
init_var(&fact);
init_var(&result);
- int8_to_numericvar(num, &result);
+ int64_to_numericvar(num, &result);
for (num = num - 1; num > 1; num--)
{
/* this loop can take awhile, so allow it to be interrupted */
CHECK_FOR_INTERRUPTS();
- int8_to_numericvar(num, &fact);
+ int64_to_numericvar(num, &fact);
mul_var(&result, &fact, &result, 0);
}
@@ -2388,7 +2391,7 @@ int4_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2454,7 +2457,7 @@ int8_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar(val, &result);
+ int64_to_numericvar(val, &result);
res = make_result(&result);
@@ -2498,7 +2501,7 @@ int2_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2660,6 +2663,9 @@ 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.
*
+ * On platforms which support 128-bit integers some aggregates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
@@ -2920,32 +2926,107 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
/*
- * Integer data types all use Numeric accumulators to share code and
- * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
- * is overkill for the N and sum(X) values, but definitely not overkill
- * for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
- * for stddev/variance --- there are faster special-purpose accumulator
- * routines for SUM and AVG of these datatypes.
+ * Integer data types in general use Numeric accumulators to share code
+ * and avoid risk of overflow.
+ *
+ * However for performance reasons optimized special-purpose accumulator
+ * routines are used when possible.
+ *
+ * On platforms with 128-bit integer support, the 128-bit routines will be
+ * used when sum(X) or sum(X*X) fit into 128-bit.
+ *
+ * For int2 and int4 inputs, the N and sum(X) fit into 64-bit so the 64-bit
+ * accumulators will be used for SUM and AVG of these data types.
+ */
+
+#ifdef HAVE_INT128
+typedef struct Int128AggState
+{
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+} Int128AggState;
+
+/*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+static Int128AggState *
+makeInt128AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+{
+ Int128AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int128AggState *) palloc0(sizeof(Int128AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
+
+/*
+ * Accumulate a new input value for 128-bit aggregate functions.
+ */
+static void
+do_int128_accum(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+}
+
+/*
+ * Remove an input value from the aggregated state.
*/
+static void
+do_int128_discard(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+}
+
+typedef Int128AggState PolyNumAggState;
+#define makePolyNumAggState makeInt128AggState
+#else
+typedef NumericAggState PolyNumAggState;
+#define makePolyNumAggState makeNumericAggState
+#endif
Datum
int2_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -2954,21 +3035,25 @@ int2_accum(PG_FUNCTION_ARGS)
Datum
int4_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3003,21 +3088,25 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, false);
+ state = makePolyNumAggState(fcinfo, false);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT64(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3031,9 +3120,9 @@ int8_avg_accum(PG_FUNCTION_ARGS)
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3041,6 +3130,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT16(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
@@ -3049,6 +3141,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3057,9 +3150,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3067,6 +3160,9 @@ int4_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
@@ -3075,6 +3171,7 @@ int4_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3107,6 +3204,94 @@ int8_accum_inv(PG_FUNCTION_ARGS)
}
Datum
+int8_avg_accum_inv(PG_FUNCTION_ARGS)
+{
+ PolyNumAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ {
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT64(1));
+#else
+ 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");
+#endif
+ }
+
+ PG_RETURN_POINTER(state);
+}
+
+Datum
+numeric_poly_sum(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_sum(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_avg(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+#else
+ return numeric_avg(fcinfo);
+#endif
+}
+
+Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
@@ -3185,7 +3370,7 @@ numeric_stddev_internal(NumericAggState *state,
init_var(&vsumX);
init_var(&vsumX2);
- int8_to_numericvar(state->N, &vN);
+ int64_to_numericvar(state->N, &vN);
set_var_from_var(&(state->sumX), &vsumX);
set_var_from_var(&(state->sumX2), &vsumX2);
@@ -3308,6 +3493,124 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
+#ifdef HAVE_INT128
+static Numeric
+numeric_poly_stddev_internal(Int128AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+{
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state)
+ {
+ numstate.N = state->N;
+ int128_to_numericvar(state->sumX, &numstate.sumX);
+ int128_to_numericvar(state->sumX2, &numstate.sumX2);
+ }
+ else
+ {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+}
+#endif
+
+Datum
+numeric_poly_var_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_var_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_pop(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_pop(fcinfo);
+#endif
+}
+
/*
* SUM transition functions for integer datatypes.
*
@@ -4489,14 +4792,14 @@ numericvar_to_int8(NumericVar *var, int64 *result)
* Convert int8 value to numeric.
*/
static void
-int8_to_numericvar(int64 val, NumericVar *var)
+int64_to_numericvar(int64 val, NumericVar *var)
{
uint64 uval,
newuval;
NumericDigit *ptr;
int ndigits;
- /* int8 can require at most 19 decimal digits; add one for safety */
+ /* int64 can require at most 19 decimal digits; add one for safety */
alloc_var(var, 20 / DEC_DIGITS);
if (val < 0)
{
@@ -4530,6 +4833,53 @@ int8_to_numericvar(int64 val, NumericVar *var)
var->weight = ndigits - 1;
}
+#ifdef HAVE_INT128
+/*
+ * Convert 128 bit integer to numeric.
+ */
+static void
+int128_to_numericvar(int128 val, NumericVar *var)
+{
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int128 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+}
+#endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
diff --git a/src/include/c.h b/src/include/c.h
index a2d4a2c..e98085a 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -293,6 +293,22 @@ typedef unsigned long long int uint64;
#define HAVE_INT64_TIMESTAMP
#endif
+/*
+ * 128-bit signed and unsigned integers
+ * These are lumped together, since they
+ * are used only for aggregate transition
+ * state. snprintf formatting support is
+ * not required. GCC does not even
+ * support __int128 literals, so int128
+ * is likely to remain a very specialized
+ * type.
+ */
+#if defined(HAVE_GCC__INT128)
+#define HAVE_INT128
+typedef __int128 int128;
+typedef unsigned __int128 uint128;
+#endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 3e28e2f..b6b6988 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -126,23 +126,23 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
+DATA(insert ( 2100 n 0 int8_avg_accum numeric_poly_avg int8_avg_accum int8_avg_accum_inv numeric_poly_avg f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
-DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
-DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
-DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
-DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2107 n 0 int8_avg_accum numeric_poly_sum int8_avg_accum int8_avg_accum_inv numeric_poly_sum f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
+DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
+DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
+DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
@@ -195,52 +195,52 @@ DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - f f 0 2
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
-DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2719 n 0 int4_accum numeric_poly_var_pop int4_accum int4_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2720 n 0 int2_accum numeric_poly_var_pop int2_accum int2_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
-DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2642 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2643 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
-DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2149 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2150 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
-DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2725 n 0 int4_accum numeric_poly_stddev_pop int4_accum int4_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2726 n 0 int2_accum numeric_poly_stddev_pop int2_accum int2_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
-DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2713 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2714 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
-DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2155 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2156 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index b8a3660..c0ad48d 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2495,6 +2495,8 @@ DATA(insert OID = 3568 ( int4_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i
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 = 3387 ( int8_avg_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_avg_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_ ));
@@ -2513,6 +2515,19 @@ DATA(insert OID = 1841 ( int4_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+DATA(insert OID = 3388 ( numeric_poly_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_sum _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3389 ( numeric_poly_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_avg _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3390 ( numeric_poly_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3391 ( numeric_poly_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_samp _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3392 ( numeric_poly_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3393 ( numeric_poly_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_samp _null_ _null_ _null_ ));
+DESCR("aggregate final 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_ ));
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index ece57c8..55c1a52 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -183,6 +183,9 @@
*/
#undef HAVE_GCC__ATOMIC_INT64_CAS
+/* Define to 1 if the system has the type `__int128'. */
+#undef HAVE_GCC__INT128
+
/* Define to 1 if you have __sync_lock_test_and_set(char *) and friends. */
#undef HAVE_GCC__SYNC_CHAR_TAS
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index bc4517d..6310641 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1027,6 +1027,12 @@ extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_sum(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_avg(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
@@ -1034,6 +1040,7 @@ 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_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);
Hi,
Working on committing this:
* Converted the configure test to AC_LINK_IFELSE
* I dislike the way the configure test and the resulting HAVE_* is
named. This imo shouldn't be so gcc specific, even if it right now
only detects gcc support. Changed.
* Furthermore does the test use 64bit literals without marking them as
such. That doesn't strike me as a great idea.
* Stuff like:
static int32 numericvar_to_int4(NumericVar *var);
static bool numericvar_to_int8(NumericVar *var, int64 *result);
static void int64_to_numericvar(int64 val, NumericVar *var);
#ifdef HAVE_INT128
static void int128_to_numericvar(int128 val, NumericVar *var);
#endif
is beyond ugly. Imnsho the only int2/4/8 functions that should keep
their name are the SQL callable ones. It's surely one to have
numericvar_to_int8 and int64_to_numericvar.
* I'm not a fan at all of the c.h comment you added. That comment seems,
besides being oddly formatted, to be designed to be outdated ;) I'll
just rip it out and replace it by something shorter. This shouldn't be
so overly specific for this patch.
* This thread is long, I'm not sure who to list as reviewers. Please
check whether those are appropriate.
* I've split off the int128 support from the aggregate changes.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
Attachments:
0001-Add-optional-support-for-128bit-integers.patchtext/x-patch; charset=us-asciiDownload
>From 247c00714fc7cf8a1922f2bb37c6ec08a6e63133 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Thu, 19 Mar 2015 18:58:22 +0100
Subject: [PATCH 1/2] Add optional support for 128bit integers.
We will, for the foreseeable future, not expose 128 bit datatypes to
SQL. But being able to use 128bit math will allow us, in a later patch,
to use 128bit accumulators for some aggregates; leading to noticeable
speedups over using numeric.
So far we only detect a gcc/clang extension that supports 128bit math,
but no 128bit literals, and no *printf support. We might want to expand
this in the future to further compilers; if there are any that that
provide similar support.
Discussion: 544BB5F1.50709@proxel.se
Author: Andreas Karlsson, with modifications by me
Reviewed-By: Peter Geoghegan, Oskari Saarenmaa
---
config/c-compiler.m4 | 37 ++++++++++++++++++++++++++++++
configure | 52 +++++++++++++++++++++++++++++++++++++++++++
configure.in | 3 +++
src/include/c.h | 11 +++++++++
src/include/pg_config.h.in | 3 +++
src/include/pg_config.h.win32 | 3 +++
6 files changed, 109 insertions(+)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 509f961..38aab11 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -125,6 +125,43 @@ undefine([Ac_cachevar])dnl
])# PGAC_TYPE_64BIT_INT
+# PGAC_TYPE_128BIT_INT
+# ---------------------
+# Check if __int128 is a working 128 bit integer type, and if so
+# define PG_INT128_TYPE to that typename. This currently only detects
+# a GCC/clang extension, but support for different environments may be
+# added in the future.
+#
+# For the moment we only test for support for 128bit math; support for
+# 128bit literals and snprintf is not required.
+AC_DEFUN([PGAC_TYPE_128BIT_INT],
+[AC_CACHE_CHECK([for __int128], [pgac_cv__128bit_int],
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([
+/*
+ * These are globals to discourage the compiler from folding all the
+ * arithmetic tests down to compile-time constants. We do not have
+ * convenient support for 64bit literals at this point...
+ */
+__int128 a = 48828125;
+__int128 b = 97656255;
+],[
+__int128 c,d;
+a = (a << 12) + 1; /* 200000000001 */
+b = (b << 12) + 5; /* 400000000005 */
+/* use the most relevant arithmetic ops */
+c = a * b;
+d = (c + b) / b;
+/* return different values, to prevent optimizations */
+if (d != a+1)
+ return 0;
+return 1;
+])],
+[pgac_cv__128bit_int=yes],
+[pgac_cv__128bit_int=no])])
+if test x"$pgac_cv__128bit_int" = xyes ; then
+ AC_DEFINE(PG_INT128_TYPE, __int128, [Define to the name of a signed 128-bit integer type.])
+fi])# PGAC_TYPE_128BIT_INT
+
# PGAC_C_FUNCNAME_SUPPORT
# -----------------------
diff --git a/configure b/configure
index 379dab1..2c9b3a7 100755
--- a/configure
+++ b/configure
@@ -13803,6 +13803,58 @@ _ACEOF
fi
+# Check for extensions offering the integer scalar type __int128.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __int128" >&5
+$as_echo_n "checking for __int128... " >&6; }
+if ${pgac_cv__128bit_int+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/*
+ * These are globals to discourage the compiler from folding all the
+ * arithmetic tests down to compile-time constants. We do not have
+ * convenient support for 64bit literals at this point...
+ */
+__int128 a = 48828125;
+__int128 b = 97656255;
+
+int
+main ()
+{
+
+__int128 c,d;
+a = (a << 12) + 1; /* 200000000001 */
+b = (b << 12) + 5; /* 400000000005 */
+/* use the most relevant arithmetic ops */
+c = a * b;
+d = (c + b) / b;
+/* return different values, to prevent optimizations */
+if (d != a+1)
+ return 0;
+return 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ pgac_cv__128bit_int=yes
+else
+ pgac_cv__128bit_int=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv__128bit_int" >&5
+$as_echo "$pgac_cv__128bit_int" >&6; }
+if test x"$pgac_cv__128bit_int" = xyes ; then
+
+$as_echo "#define PG_INT128_TYPE __int128" >>confdefs.h
+
+fi
+
# Check for various atomic operations now that we have checked how to declare
# 64bit integers.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __sync char locking functions" >&5
diff --git a/configure.in b/configure.in
index ca29e93..b2c1ce7 100644
--- a/configure.in
+++ b/configure.in
@@ -1771,6 +1771,9 @@ AC_CHECK_TYPES([int8, uint8, int64, uint64], [], [],
# C, but is missing on some old platforms.
AC_CHECK_TYPES(sig_atomic_t, [], [], [#include <signal.h>])
+# Check for extensions offering the integer scalar type __int128.
+PGAC_TYPE_128BIT_INT
+
# Check for various atomic operations now that we have checked how to declare
# 64bit integers.
PGAC_HAVE_GCC__SYNC_CHAR_TAS
diff --git a/src/include/c.h b/src/include/c.h
index a2d4a2c..7447218 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -293,6 +293,17 @@ typedef unsigned long long int uint64;
#define HAVE_INT64_TIMESTAMP
#endif
+/*
+ * 128-bit signed and unsigned integers
+ * There currently is only a limited support for the type. E.g. 128bit
+ * literals and snprintf are not supported; but math is.
+ */
+#if defined(PG_INT128_TYPE)
+#define HAVE_INT128
+typedef PG_INT128_TYPE int128;
+typedef unsigned PG_INT128_TYPE uint128;
+#endif
+
/* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index ece57c8..202c51a 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -711,6 +711,9 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
+/* Define to the name of a signed 128-bit integer type. */
+#undef PG_INT128_TYPE
+
/* Define to the name of a signed 64-bit integer type. */
#undef PG_INT64_TYPE
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 3f858c6..1baf64f 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -562,6 +562,9 @@
/* Define to the version of this package. */
#define PACKAGE_VERSION "9.5devel"
+/* Define to the name of a signed 128-bit integer type. */
+#undef PG_INT128_TYPE
+
/* Define to the name of a signed 64-bit integer type. */
#define PG_INT64_TYPE long long int
--
2.3.0.149.gf3f4077
0002-Use-128-bit-math-to-accelerate-some-aggregation-func.patchtext/x-patch; charset=us-asciiDownload
>From 4b5ef817dfde7d423810521f088c99c0af5437d0 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Thu, 19 Mar 2015 18:58:22 +0100
Subject: [PATCH 2/2] Use 128-bit math to accelerate some aggregation
functions.
On platforms where we support 128bit integers, use them to implement
faster transition functions for sum(int8), avg(int8),
var_*(int2/int4),stdev_*(int2/int4). Where not supported continue to use
numeric as a transition type.
In some synthetic benchmarks this has been shown to provide significant
speedups.
Bumps catversion.
Discussion: 544BB5F1.50709@proxel.se
Author: Andreas Karlsson
Reviewed-By: Peter Geoghegan, Petr Jelinek, Andres Freund, Oskari Saarenmaa
---
src/backend/utils/adt/numeric.c | 428 +++++++++++++++++++++++++++++++++----
src/include/catalog/catversion.h | 2 +-
src/include/catalog/pg_aggregate.h | 102 ++++-----
src/include/catalog/pg_proc.h | 15 ++
src/include/utils/builtins.h | 7 +
5 files changed, 463 insertions(+), 91 deletions(-)
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 715917b..ff9bfcc 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -400,9 +400,12 @@ static Numeric make_result(NumericVar *var);
static void apply_typmod(NumericVar *var, int32 typmod);
-static int32 numericvar_to_int4(NumericVar *var);
-static bool numericvar_to_int8(NumericVar *var, int64 *result);
-static void int8_to_numericvar(int64 val, NumericVar *var);
+static int32 numericvar_to_int32(NumericVar *var);
+static bool numericvar_to_int64(NumericVar *var, int64 *result);
+static void int64_to_numericvar(int64 val, NumericVar *var);
+#ifdef HAVE_INT128
+static void int128_to_numericvar(int128 val, NumericVar *var);
+#endif
static double numeric_to_double_no_overflow(Numeric num);
static double numericvar_to_double_no_overflow(NumericVar *var);
@@ -1414,7 +1417,7 @@ width_bucket_numeric(PG_FUNCTION_ARGS)
init_var(&count_var);
/* Convert 'count' to a numeric, for ease of use later */
- int8_to_numericvar((int64) count, &count_var);
+ int64_to_numericvar((int64) count, &count_var);
switch (cmp_numerics(bound1, bound2))
{
@@ -1447,7 +1450,7 @@ width_bucket_numeric(PG_FUNCTION_ARGS)
}
/* if result exceeds the range of a legal int4, we ereport here */
- result = numericvar_to_int4(&result_var);
+ result = numericvar_to_int32(&result_var);
free_var(&count_var);
free_var(&result_var);
@@ -2083,14 +2086,14 @@ numeric_fac(PG_FUNCTION_ARGS)
init_var(&fact);
init_var(&result);
- int8_to_numericvar(num, &result);
+ int64_to_numericvar(num, &result);
for (num = num - 1; num > 1; num--)
{
/* this loop can take awhile, so allow it to be interrupted */
CHECK_FOR_INTERRUPTS();
- int8_to_numericvar(num, &fact);
+ int64_to_numericvar(num, &fact);
mul_var(&result, &fact, &result, 0);
}
@@ -2388,7 +2391,7 @@ int4_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2413,7 +2416,7 @@ numeric_int4(PG_FUNCTION_ARGS)
/* Convert to variable format, then convert to int4 */
init_var_from_num(num, &x);
- result = numericvar_to_int4(&x);
+ result = numericvar_to_int32(&x);
PG_RETURN_INT32(result);
}
@@ -2423,12 +2426,12 @@ numeric_int4(PG_FUNCTION_ARGS)
* ereport(). The input NumericVar is *not* free'd.
*/
static int32
-numericvar_to_int4(NumericVar *var)
+numericvar_to_int32(NumericVar *var)
{
int32 result;
int64 val;
- if (!numericvar_to_int8(var, &val))
+ if (!numericvar_to_int64(var, &val))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
@@ -2454,7 +2457,7 @@ int8_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar(val, &result);
+ int64_to_numericvar(val, &result);
res = make_result(&result);
@@ -2480,7 +2483,7 @@ numeric_int8(PG_FUNCTION_ARGS)
/* Convert to variable format and thence to int8 */
init_var_from_num(num, &x);
- if (!numericvar_to_int8(&x, &result))
+ if (!numericvar_to_int64(&x, &result))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
@@ -2498,7 +2501,7 @@ int2_numeric(PG_FUNCTION_ARGS)
init_var(&result);
- int8_to_numericvar((int64) val, &result);
+ int64_to_numericvar((int64) val, &result);
res = make_result(&result);
@@ -2525,7 +2528,7 @@ numeric_int2(PG_FUNCTION_ARGS)
/* Convert to variable format and thence to int8 */
init_var_from_num(num, &x);
- if (!numericvar_to_int8(&x, &val))
+ if (!numericvar_to_int64(&x, &val))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
@@ -2660,6 +2663,9 @@ 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.
*
+ * On platforms which support 128-bit integers some aggregates instead use a
+ * 128-bit integer based transition datatype to speed up calculations.
+ *
* ----------------------------------------------------------------------
*/
@@ -2920,32 +2926,107 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
/*
- * Integer data types all use Numeric accumulators to share code and
- * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
- * is overkill for the N and sum(X) values, but definitely not overkill
- * for the sum(X*X) value. Hence, we use int2_accum and int4_accum only
- * for stddev/variance --- there are faster special-purpose accumulator
- * routines for SUM and AVG of these datatypes.
+ * Integer data types in general use Numeric accumulators to share code
+ * and avoid risk of overflow.
+ *
+ * However for performance reasons optimized special-purpose accumulator
+ * routines are used when possible.
+ *
+ * On platforms with 128-bit integer support, the 128-bit routines will be
+ * used when sum(X) or sum(X*X) fit into 128-bit.
+ *
+ * For 16 and 32 bit inputs, the N and sum(X) fit into 64-bit so the 64-bit
+ * accumulators will be used for SUM and AVG of these data types.
+ */
+
+#ifdef HAVE_INT128
+typedef struct Int128AggState
+{
+ bool calcSumX2; /* if true, calculate sumX2 */
+ int64 N; /* count of processed numbers */
+ int128 sumX; /* sum of processed numbers */
+ int128 sumX2; /* sum of squares of processed numbers */
+} Int128AggState;
+
+/*
+ * Prepare state data for a 128-bit aggregate function that needs to compute
+ * sum, count and optionally sum of squares of the input.
+ */
+static Int128AggState *
+makeInt128AggState(FunctionCallInfo fcinfo, bool calcSumX2)
+{
+ Int128AggState *state;
+ MemoryContext agg_context;
+ MemoryContext old_context;
+
+ if (!AggCheckCallContext(fcinfo, &agg_context))
+ elog(ERROR, "aggregate function called in non-aggregate context");
+
+ old_context = MemoryContextSwitchTo(agg_context);
+
+ state = (Int128AggState *) palloc0(sizeof(Int128AggState));
+ state->calcSumX2 = calcSumX2;
+
+ MemoryContextSwitchTo(old_context);
+
+ return state;
+}
+
+/*
+ * Accumulate a new input value for 128-bit aggregate functions.
+ */
+static void
+do_int128_accum(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 += newval * newval;
+
+ state->sumX += newval;
+ state->N++;
+}
+
+/*
+ * Remove an input value from the aggregated state.
*/
+static void
+do_int128_discard(Int128AggState *state, int128 newval)
+{
+ if (state->calcSumX2)
+ state->sumX2 -= newval * newval;
+
+ state->sumX -= newval;
+ state->N--;
+}
+
+typedef Int128AggState PolyNumAggState;
+#define makePolyNumAggState makeInt128AggState
+#else
+typedef NumericAggState PolyNumAggState;
+#define makePolyNumAggState makeNumericAggState
+#endif
Datum
int2_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -2954,21 +3035,25 @@ int2_accum(PG_FUNCTION_ARGS)
Datum
int4_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, true);
+ state = makePolyNumAggState(fcinfo, true);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3003,21 +3088,25 @@ int8_accum(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makeNumericAggState(fcinfo, false);
+ state = makePolyNumAggState(fcinfo, false);
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_accum(state, (int128) PG_GETARG_INT64(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
PG_GETARG_DATUM(1)));
do_numeric_accum(state, newval);
+#endif
}
PG_RETURN_POINTER(state);
@@ -3031,9 +3120,9 @@ int8_avg_accum(PG_FUNCTION_ARGS)
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3041,6 +3130,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT16(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric,
@@ -3049,6 +3141,7 @@ int2_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3057,9 +3150,9 @@ int2_accum_inv(PG_FUNCTION_ARGS)
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
- NumericAggState *state;
+ PolyNumAggState *state;
- state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
@@ -3067,6 +3160,9 @@ int4_accum_inv(PG_FUNCTION_ARGS)
if (!PG_ARGISNULL(1))
{
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT32(1));
+#else
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
@@ -3075,6 +3171,7 @@ int4_accum_inv(PG_FUNCTION_ARGS)
/* Should never fail, all inputs have dscale 0 */
if (!do_numeric_discard(state, newval))
elog(ERROR, "do_numeric_discard failed unexpectedly");
+#endif
}
PG_RETURN_POINTER(state);
@@ -3107,6 +3204,94 @@ int8_accum_inv(PG_FUNCTION_ARGS)
}
Datum
+int8_avg_accum_inv(PG_FUNCTION_ARGS)
+{
+ PolyNumAggState *state;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* Should not get here with no state */
+ if (state == NULL)
+ elog(ERROR, "int8_avg_accum_inv called with NULL state");
+
+ if (!PG_ARGISNULL(1))
+ {
+#ifdef HAVE_INT128
+ do_int128_discard(state, (int128) PG_GETARG_INT64(1));
+#else
+ 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");
+#endif
+ }
+
+ PG_RETURN_POINTER(state);
+}
+
+Datum
+numeric_poly_sum(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ NumericVar result;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ res = make_result(&result);
+
+ free_var(&result);
+
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_sum(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_avg(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ NumericVar result;
+ Datum countd, sumd;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ /* If there were no non-null inputs, return NULL */
+ if (state == NULL || state->N == 0)
+ PG_RETURN_NULL();
+
+ init_var(&result);
+
+ int128_to_numericvar(state->sumX, &result);
+
+ countd = DirectFunctionCall1(int8_numeric,
+ Int64GetDatumFast(state->N));
+ sumd = NumericGetDatum(make_result(&result));
+
+ free_var(&result);
+
+ PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
+#else
+ return numeric_avg(fcinfo);
+#endif
+}
+
+Datum
numeric_avg(PG_FUNCTION_ARGS)
{
NumericAggState *state;
@@ -3185,7 +3370,7 @@ numeric_stddev_internal(NumericAggState *state,
init_var(&vsumX);
init_var(&vsumX2);
- int8_to_numericvar(state->N, &vN);
+ int64_to_numericvar(state->N, &vN);
set_var_from_var(&(state->sumX), &vsumX);
set_var_from_var(&(state->sumX2), &vsumX2);
@@ -3308,6 +3493,124 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
+#ifdef HAVE_INT128
+static Numeric
+numeric_poly_stddev_internal(Int128AggState *state,
+ bool variance, bool sample,
+ bool *is_null)
+{
+ NumericAggState numstate;
+ Numeric res;
+
+ init_var(&numstate.sumX);
+ init_var(&numstate.sumX2);
+ numstate.NaNcount = 0;
+ numstate.agg_context = NULL;
+
+ if (state)
+ {
+ numstate.N = state->N;
+ int128_to_numericvar(state->sumX, &numstate.sumX);
+ int128_to_numericvar(state->sumX2, &numstate.sumX2);
+ }
+ else
+ {
+ numstate.N = 0;
+ }
+
+ res = numeric_stddev_internal(&numstate, variance, sample, is_null);
+
+ free_var(&numstate.sumX);
+ free_var(&numstate.sumX2);
+
+ return res;
+}
+#endif
+
+Datum
+numeric_poly_var_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_samp(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, true, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_samp(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_var_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, true, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_var_pop(fcinfo);
+#endif
+}
+
+Datum
+numeric_poly_stddev_pop(PG_FUNCTION_ARGS)
+{
+#ifdef HAVE_INT128
+ PolyNumAggState *state;
+ Numeric res;
+ bool is_null;
+
+ state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+
+ res = numeric_poly_stddev_internal(state, false, false, &is_null);
+
+ if (is_null)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_NUMERIC(res);
+#else
+ return numeric_stddev_pop(fcinfo);
+#endif
+}
+
/*
* SUM transition functions for integer datatypes.
*
@@ -4418,7 +4721,7 @@ apply_typmod(NumericVar *var, int32 typmod)
* If overflow, return FALSE (no error is raised). Return TRUE if okay.
*/
static bool
-numericvar_to_int8(NumericVar *var, int64 *result)
+numericvar_to_int64(NumericVar *var, int64 *result)
{
NumericDigit *digits;
int ndigits;
@@ -4489,14 +4792,14 @@ numericvar_to_int8(NumericVar *var, int64 *result)
* Convert int8 value to numeric.
*/
static void
-int8_to_numericvar(int64 val, NumericVar *var)
+int64_to_numericvar(int64 val, NumericVar *var)
{
uint64 uval,
newuval;
NumericDigit *ptr;
int ndigits;
- /* int8 can require at most 19 decimal digits; add one for safety */
+ /* int64 can require at most 19 decimal digits; add one for safety */
alloc_var(var, 20 / DEC_DIGITS);
if (val < 0)
{
@@ -4530,6 +4833,53 @@ int8_to_numericvar(int64 val, NumericVar *var)
var->weight = ndigits - 1;
}
+#ifdef HAVE_INT128
+/*
+ * Convert 128 bit integer to numeric.
+ */
+static void
+int128_to_numericvar(int128 val, NumericVar *var)
+{
+ uint128 uval,
+ newuval;
+ NumericDigit *ptr;
+ int ndigits;
+
+ /* int128 can require at most 39 decimal digits; add one for safety */
+ alloc_var(var, 40 / DEC_DIGITS);
+ if (val < 0)
+ {
+ var->sign = NUMERIC_NEG;
+ uval = -val;
+ }
+ else
+ {
+ var->sign = NUMERIC_POS;
+ uval = val;
+ }
+ var->dscale = 0;
+ if (val == 0)
+ {
+ var->ndigits = 0;
+ var->weight = 0;
+ return;
+ }
+ ptr = var->digits + var->ndigits;
+ ndigits = 0;
+ do
+ {
+ ptr--;
+ ndigits++;
+ newuval = uval / NBASE;
+ *ptr = uval - newuval * NBASE;
+ uval = newuval;
+ } while (uval);
+ var->digits = ptr;
+ var->ndigits = ndigits;
+ var->weight = ndigits - 1;
+}
+#endif
+
/*
* Convert numeric to float8; if out of range, return +/- HUGE_VAL
*/
@@ -6136,7 +6486,7 @@ power_var(NumericVar *base, NumericVar *exp, NumericVar *result)
/* exact integer, but does it fit in int? */
int64 expval64;
- if (numericvar_to_int8(exp, &expval64))
+ if (numericvar_to_int64(exp, &expval64))
{
int expval = (int) expval64;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 0c435c2..da6035f 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201503181
+#define CATALOG_VERSION_NO 201503191
#endif
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 3e28e2f..b6b6988 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -126,23 +126,23 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
*/
/* avg */
-DATA(insert ( 2100 n 0 int8_avg_accum numeric_avg int8_avg_accum int8_accum_inv numeric_avg f f 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 f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
+DATA(insert ( 2100 n 0 int8_avg_accum numeric_poly_avg int8_avg_accum int8_avg_accum_inv numeric_poly_avg f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2101 n 0 int4_avg_accum int8_avg int4_avg_accum int4_avg_accum_inv int8_avg f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2104 n 0 float4_accum float8_avg - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2105 n 0 float8_accum float8_avg - - - f f 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 f f 0 1187 0 1187 0 "{0 second,0 second}" "{0 second,0 second}" ));
/* sum */
-DATA(insert ( 2107 n 0 int8_avg_accum numeric_sum int8_avg_accum int8_accum_inv numeric_sum f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
-DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
-DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
-DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
-DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2107 n 0 int8_avg_accum numeric_poly_sum int8_avg_accum int8_avg_accum_inv numeric_poly_sum f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2108 n 0 int4_sum - int4_avg_accum int4_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2109 n 0 int2_sum - int2_avg_accum int2_avg_accum_inv int2int4_sum f f 0 20 0 1016 0 _null_ "{0,0}" ));
+DATA(insert ( 2110 n 0 float4pl - - - - f f 0 700 0 0 0 _null_ _null_ ));
+DATA(insert ( 2111 n 0 float8pl - - - - f f 0 701 0 0 0 _null_ _null_ ));
+DATA(insert ( 2112 n 0 cash_pl - cash_pl cash_mi - f f 0 790 0 790 0 _null_ _null_ ));
+DATA(insert ( 2113 n 0 interval_pl - interval_pl interval_mi - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* max */
DATA(insert ( 2115 n 0 int8larger - - - - f f 413 20 0 0 0 _null_ _null_ ));
@@ -195,52 +195,52 @@ DATA(insert ( 2147 n 0 int8inc_any - int8inc_any int8dec_any - f f 0 2
DATA(insert ( 2803 n 0 int8inc - int8inc int8dec - f f 0 20 0 20 0 "0" "0" ));
/* var_pop */
-DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2718 n 0 int8_accum numeric_var_pop int8_accum int8_accum_inv numeric_var_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2719 n 0 int4_accum numeric_poly_var_pop int4_accum int4_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2720 n 0 int2_accum numeric_poly_var_pop int2_accum int2_accum_inv numeric_poly_var_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2721 n 0 float4_accum float8_var_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2722 n 0 float8_accum float8_var_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* var_samp */
-DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2641 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2642 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2643 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2644 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2645 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* variance: historical Postgres syntax for var_samp */
-DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2148 n 0 int8_accum numeric_var_samp int8_accum int8_accum_inv numeric_var_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2149 n 0 int4_accum numeric_poly_var_samp int4_accum int4_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2150 n 0 int2_accum numeric_poly_var_samp int2_accum int2_accum_inv numeric_poly_var_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2151 n 0 float4_accum float8_var_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2152 n 0 float8_accum float8_var_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_pop */
-DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2724 n 0 int8_accum numeric_stddev_pop int8_accum int8_accum_inv numeric_stddev_pop f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2725 n 0 int4_accum numeric_poly_stddev_pop int4_accum int4_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2726 n 0 int2_accum numeric_poly_stddev_pop int2_accum int2_accum_inv numeric_poly_stddev_pop f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2727 n 0 float4_accum float8_stddev_pop - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2728 n 0 float8_accum float8_stddev_pop - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev_samp */
-DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2712 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2713 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2714 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2715 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2716 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* stddev: historical Postgres syntax for stddev_samp */
-DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 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 f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
-DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
-DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2154 n 0 int8_accum numeric_stddev_samp int8_accum int8_accum_inv numeric_stddev_samp f f 0 2281 128 2281 128 _null_ _null_ ));
+DATA(insert ( 2155 n 0 int4_accum numeric_poly_stddev_samp int4_accum int4_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2156 n 0 int2_accum numeric_poly_stddev_samp int2_accum int2_accum_inv numeric_poly_stddev_samp f f 0 2281 48 2281 48 _null_ _null_ ));
+DATA(insert ( 2157 n 0 float4_accum float8_stddev_samp - - - f f 0 1022 0 0 0 "{0,0,0}" _null_ ));
+DATA(insert ( 2158 n 0 float8_accum float8_stddev_samp - - - f f 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 f f 0 2281 128 2281 128 _null_ _null_ ));
/* SQL2003 binary regression aggregates */
DATA(insert ( 2818 n 0 int8inc_float8_float8 - - - - f f 0 20 0 0 0 "0" _null_ ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 6a757f3..3c218a3 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2501,6 +2501,8 @@ DATA(insert OID = 3568 ( int4_accum_inv PGNSP PGUID 12 1 0 0 0 f f f f f f i
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 = 3387 ( int8_avg_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_avg_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_ ));
@@ -2519,6 +2521,19 @@ DATA(insert OID = 1841 ( int4_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0
DESCR("aggregate transition function");
DATA(insert OID = 1842 ( int8_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 1700 "1700 20" _null_ _null_ _null_ _null_ int8_sum _null_ _null_ _null_ ));
DESCR("aggregate transition function");
+DATA(insert OID = 3388 ( numeric_poly_sum PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_sum _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3389 ( numeric_poly_avg PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_avg _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3390 ( numeric_poly_var_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3391 ( numeric_poly_var_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_var_samp _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3392 ( numeric_poly_stddev_pop PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_pop _null_ _null_ _null_ ));
+DESCR("aggregate final function");
+DATA(insert OID = 3393 ( numeric_poly_stddev_samp PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 1700 "2281" _null_ _null_ _null_ _null_ numeric_poly_stddev_samp _null_ _null_ _null_ ));
+DESCR("aggregate final 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_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index bc4517d..6310641 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1027,6 +1027,12 @@ extern Datum numeric_var_pop(PG_FUNCTION_ARGS);
extern Datum numeric_var_samp(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_pop(PG_FUNCTION_ARGS);
extern Datum numeric_stddev_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_sum(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_avg(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_var_samp(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_pop(PG_FUNCTION_ARGS);
+extern Datum numeric_poly_stddev_samp(PG_FUNCTION_ARGS);
extern Datum int2_sum(PG_FUNCTION_ARGS);
extern Datum int4_sum(PG_FUNCTION_ARGS);
extern Datum int8_sum(PG_FUNCTION_ARGS);
@@ -1034,6 +1040,7 @@ 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_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);
--
2.3.0.149.gf3f4077
On 03/19/2015 07:08 PM, Andres Freund wrote:
Working on committing this:
Nice fixes. Sorry about forgetting numericvar_to_int*.
As for the reviewers those lists look pretty much correct. David Rowley
should probably be added to the second patch for his early review and
benchmarking.
--
Andreas Karlsson
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Mar 19, 2015 at 4:49 PM, Andreas Karlsson <andreas@proxel.se> wrote:
Nice fixes. Sorry about forgetting numericvar_to_int*.
As for the reviewers those lists look pretty much correct. David Rowley
should probably be added to the second patch for his early review and
benchmarking.
This also seems fine to me.
--
Peter Geoghegan
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-03-20 00:49:07 +0100, Andreas Karlsson wrote:
On 03/19/2015 07:08 PM, Andres Freund wrote:
Working on committing this:
Nice fixes. Sorry about forgetting numericvar_to_int*.
As for the reviewers those lists look pretty much correct. David Rowley
should probably be added to the second patch for his early review and
benchmarking.
Pushed with that additional change. Let's see if the buildfarm thinks.
Thanks for the feature.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 03/20/2015 10:32 AM, Andres Freund wrote:
Pushed with that additional change. Let's see if the buildfarm thinks.
Thanks for the feature.
Thanks to you and all the reviewers for helping me out with it.
Andreas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Mar 20, 2015 at 2:39 AM, Andreas Karlsson <andreas@proxel.se> wrote:
On 03/20/2015 10:32 AM, Andres Freund wrote:
Pushed with that additional change. Let's see if the buildfarm thinks.
Thanks for the feature.
Thanks to you and all the reviewers for helping me out with it.
Indeed. Thanks for your efforts, Andreas.
--
Peter Geoghegan
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@2ndquadrant.com> writes:
Pushed with that additional change. Let's see if the buildfarm thinks.
jacana, apparently alone among buildfarm members, does not like it.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Mar 22, 2015 at 12:32 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Andres Freund <andres@2ndquadrant.com> writes:
Pushed with that additional change. Let's see if the buildfarm thinks.
jacana, apparently alone among buildfarm members, does not like it.
All the windows nodes don't pass tests with this patch, the difference
is in the exponential precision: e+000 instead of e+00.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Mar 22, 2015 at 2:17 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
On Sun, Mar 22, 2015 at 12:32 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Andres Freund <andres@2ndquadrant.com> writes:
Pushed with that additional change. Let's see if the buildfarm thinks.
jacana, apparently alone among buildfarm members, does not like it.
All the windows nodes don't pass tests with this patch, the difference
is in the exponential precision: e+000 instead of e+00.
Useless noise from my side, the error is in the test windows.sql like here:
http://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=jacana&dt=2015-03-21%2003%3A01%3A21
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 22 March 2015 at 18:17, Michael Paquier <michael.paquier@gmail.com>
wrote:
On Sun, Mar 22, 2015 at 12:32 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Andres Freund <andres@2ndquadrant.com> writes:
Pushed with that additional change. Let's see if the buildfarm thinks.
jacana, apparently alone among buildfarm members, does not like it.
All the windows nodes don't pass tests with this patch, the difference
is in the exponential precision: e+000 instead of e+00.
It looks like there's some other problems there too, but for the
exponential issue, I posted a patch here:
/messages/by-id/CAApHDvoRDz8kCdfYzgRCPDEfLMqK0F6U_78nJ-JajxyJ7ufvHA@mail.gmail.com
On March 22, 2015 6:17:28 AM GMT+01:00, Michael Paquier <michael.paquier@gmail.com> wrote:
On Sun, Mar 22, 2015 at 12:32 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Andres Freund <andres@2ndquadrant.com> writes:
Pushed with that additional change. Let's see if the buildfarm
thinks.
jacana, apparently alone among buildfarm members, does not like it.
All the windows nodes don't pass tests with this patch, the difference
is in the exponential precision: e+000 instead of e+00.
That's due to a different patch though, right? When I checked earlier only jacana had problems due to this, and it looked like random memory was being output. It's interesting that that's on the one windows (not cygwin) critter that does the 128bit dance...
--
Please excuse brevity and formatting - I am writing this on my mobile phone.
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Mar 22, 2015 at 6:22 PM, Andres Freund <andres@2ndquadrant.com> wrote:
On March 22, 2015 6:17:28 AM GMT+01:00, Michael Paquier <michael.paquier@gmail.com> wrote:
On Sun, Mar 22, 2015 at 12:32 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Andres Freund <andres@2ndquadrant.com> writes:
Pushed with that additional change. Let's see if the buildfarm
thinks.
jacana, apparently alone among buildfarm members, does not like it.
All the windows nodes don't pass tests with this patch, the difference
is in the exponential precision: e+000 instead of e+00.That's due to a different patch though, right? When I checked earlier only jacana had problems due to this, and it looked like random memory was being output. It's interesting that that's on the one windows (not cygwin) critter that does the 128bit dance...
Yes, sorry, the e+000 stuff is from 959277a. This patch has visibly broken that:
http://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=jacana&dt=2015-03-21%2003%3A01%3A21
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 22 March 2015 at 22:22, Andres Freund <andres@2ndquadrant.com> wrote:
On March 22, 2015 6:17:28 AM GMT+01:00, Michael Paquier <
michael.paquier@gmail.com> wrote:On Sun, Mar 22, 2015 at 12:32 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Andres Freund <andres@2ndquadrant.com> writes:
Pushed with that additional change. Let's see if the buildfarm
thinks.
jacana, apparently alone among buildfarm members, does not like it.
All the windows nodes don't pass tests with this patch, the difference
is in the exponential precision: e+000 instead of e+00.That's due to a different patch though, right?
Yes this is due to cc0d90b.
When I checked earlier only jacana had problems due to this, and it looked
like random memory was being output. It's interesting that that's on the
one windows (not cygwin) critter that does the 128bit dance...
Yeah, I can't recreate the issue locally on my windows machine, but I may
try with gcc if I can get some time.
Regards
David Rowley
On March 22, 2015 10:34:04 AM GMT+01:00, Michael Paquier <michael.paquier@gmail.com> wrote:
On Sun, Mar 22, 2015 at 6:22 PM, Andres Freund <andres@2ndquadrant.com>
wrote:On March 22, 2015 6:17:28 AM GMT+01:00, Michael Paquier
<michael.paquier@gmail.com> wrote:
On Sun, Mar 22, 2015 at 12:32 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Andres Freund <andres@2ndquadrant.com> writes:
Pushed with that additional change. Let's see if the buildfarm
thinks.
jacana, apparently alone among buildfarm members, does not like it.
All the windows nodes don't pass tests with this patch, the
difference
is in the exponential precision: e+000 instead of e+00.
That's due to a different patch though, right? When I checked earlier
only jacana had problems due to this, and it looked like random memory
was being output. It's interesting that that's on the one windows (not
cygwin) critter that does the 128bit dance...Yes, sorry, the e+000 stuff is from 959277a. This patch has visibly
broken that:
http://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=jacana&dt=2015-03-21%2003%3A01%3A21
That's the stuff looking like random memory that I talk about above...
--
Please excuse brevity and formatting - I am writing this on my mobile phone.
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sun, Mar 22, 2015 at 6:34 PM, David Rowley <dgrowleyml@gmail.com> wrote:
On 22 March 2015 at 22:22, Andres Freund <andres@2ndquadrant.com> wrote:
On March 22, 2015 6:17:28 AM GMT+01:00, Michael Paquier
<michael.paquier@gmail.com> wrote:On Sun, Mar 22, 2015 at 12:32 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Andres Freund <andres@2ndquadrant.com> writes:
Pushed with that additional change. Let's see if the buildfarm
thinks.
jacana, apparently alone among buildfarm members, does not like it.
All the windows nodes don't pass tests with this patch, the difference
is in the exponential precision: e+000 instead of e+00.That's due to a different patch though, right?
Yes this is due to cc0d90b.
Err, yes. This exp error is caused by the to_char patch (and that's
what I meant X)), bad copy-paste from here...
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 22/03/15 10:35, Andres Freund wrote:
On March 22, 2015 10:34:04 AM GMT+01:00, Michael Paquier <michael.paquier@gmail.com> wrote:
On Sun, Mar 22, 2015 at 6:22 PM, Andres Freund <andres@2ndquadrant.com>
That's due to a different patch though, right? When I checked earlier
only jacana had problems due to this, and it looked like random memory
was being output. It's interesting that that's on the one windows (not
cygwin) critter that does the 128bit dance...Yes, sorry, the e+000 stuff is from 959277a. This patch has visibly
broken that:
http://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=jacana&dt=2015-03-21%2003%3A01%3A21That's the stuff looking like random memory that I talk about above...
If you look at it closely, it's actually not random memory. At least in
the first 2 failing tests which are not obfuscated by aggregates on top
of aggregates. It looks like first NumericDigit is ok and the second one
is corrupted (there are only 2 NumericDigits in those numbers). Of
course the conversion to Numeric is done from the end so it looks like
only the last computation/pointer change/something stays ok while the
rest got corrupted.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 03/22/2015 11:47 AM, Petr Jelinek wrote:
On 22/03/15 10:35, Andres Freund wrote:
http://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=jacana&dt=2015-03-21%2003%3A01%3A21
That's the stuff looking like random memory that I talk about above...
If you look at it closely, it's actually not random memory. At least in
the first 2 failing tests which are not obfuscated by aggregates on top
of aggregates. It looks like first NumericDigit is ok and the second one
is corrupted (there are only 2 NumericDigits in those numbers). Of
course the conversion to Numeric is done from the end so it looks like
only the last computation/pointer change/something stays ok while the
rest got corrupted.
Would this mean the bug is most likely somewhere in
int128_to_numericvar()? Maybe that version of gcc has a bug in some
__int128 operator or I messed up the code there somehow.
Andreas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 22/03/15 13:59, Andreas Karlsson wrote:
On 03/22/2015 11:47 AM, Petr Jelinek wrote:
On 22/03/15 10:35, Andres Freund wrote:
http://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=jacana&dt=2015-03-21%2003%3A01%3A21
That's the stuff looking like random memory that I talk about above...
If you look at it closely, it's actually not random memory. At least in
the first 2 failing tests which are not obfuscated by aggregates on top
of aggregates. It looks like first NumericDigit is ok and the second one
is corrupted (there are only 2 NumericDigits in those numbers). Of
course the conversion to Numeric is done from the end so it looks like
only the last computation/pointer change/something stays ok while the
rest got corrupted.Would this mean the bug is most likely somewhere in
int128_to_numericvar()? Maybe that version of gcc has a bug in some
__int128 operator or I messed up the code there somehow.
Yeah that's what I was thinking also, and I went through the function
and didn't find anything suspicious (besides it's same as the 64 bit
version except for the int128 use).
It really might be some combination of arithmetic + the conversion to
16bit uint bug in the compiler. Would be worth to try to produce test
case and try it standalone maybe?
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-03-22 22:00:13 +0100, Petr Jelinek wrote:
On 22/03/15 13:59, Andreas Karlsson wrote:
Would this mean the bug is most likely somewhere in
int128_to_numericvar()? Maybe that version of gcc has a bug in some
__int128 operator or I messed up the code there somehow.
Yes, or a compiler bug. I looked through the code again and found and
fixed one minor bug, but that doesnt' explain the problem.
Yeah that's what I was thinking also, and I went through the function and
didn't find anything suspicious (besides it's same as the 64 bit version
except for the int128 use).It really might be some combination of arithmetic + the conversion to 16bit
uint bug in the compiler. Would be worth to try to produce test case and try
it standalone maybe?
A compiler bug looks like a not unreasonable bet at this point. I've
asked Andrew to recompile without optimizations... We'll see whether
that makes a difference. Jacana is the only compiler with gcc 4.8.1 (or
is it 4.8.0? there's conflicting output). There've been a number of bugs
fixed that affect loop unrolling and such.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 03/22/2015 10:20 PM, Andres Freund wrote:
Yes, or a compiler bug. I looked through the code again and found and
fixed one minor bug, but that doesnt' explain the problem.
Strangely enough the bug looks like it has been fixed at jacana after
your fix of my copypasto. Maybe the bug is random, or your fix really
fixed it.
http://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=jacana&dt=2015-03-22%2020%3A41%3A54
Andreas
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-03-22 22:20:49 +0100, Andres Freund wrote:
A compiler bug looks like a not unreasonable bet at this point. I've
asked Andrew to recompile without optimizations... We'll see whether
that makes a difference. Jacana is the only compiler with gcc 4.8.1 (or
is it 4.8.0? there's conflicting output). There've been a number of bugs
fixed that affect loop unrolling and such.
And indeed, a run of jacana with -O0 fixed it. As you can see in
http://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=jacana&dt=2015-03-22%2020%3A41%3A54
, it still fails, but just because of the exp problem.
My guess it's
http://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=jacana&dt=2015-03-22%2020%3A41%3A54
Do we feel the need to find a workaround if this if it's indeed 4.8.0
and 4.8.1 (and some other releases at the same time) that are
problematic? Given that gcc 4.8.2 was released October 16, 2013 I'm
inclined not to.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2015-03-22 22:28:01 +0100, Andreas Karlsson wrote:
On 03/22/2015 10:20 PM, Andres Freund wrote:
Yes, or a compiler bug. I looked through the code again and found and
fixed one minor bug, but that doesnt' explain the problem.Strangely enough the bug looks like it has been fixed at jacana after your
fix of my copypasto. Maybe the bug is random, or your fix really fixed it.
I bet it's actually the -O0 Andrew added at my behest.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers