|
5 | 5 | *
|
6 | 6 | * 1998 Jan Wieck
|
7 | 7 | *
|
8 |
| - * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.42 2001/06/07 00:09:29 momjian Exp $ |
| 8 | + * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.43 2001/08/14 22:21:58 tgl Exp $ |
9 | 9 | *
|
10 | 10 | * ----------
|
11 | 11 | */
|
@@ -1772,7 +1772,11 @@ numeric_accum(PG_FUNCTION_ARGS)
|
1772 | 1772 |
|
1773 | 1773 | /*
|
1774 | 1774 | * Integer data types all use Numeric accumulators to share code and
|
1775 |
| - * avoid risk of overflow. |
| 1775 | + * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation |
| 1776 | + * is overkill for the N and sum(X) values, but definitely not overkill |
| 1777 | + * for the sum(X*X) value. Hence, we use int2_accum and int4_accum only |
| 1778 | + * for stddev/variance --- there are faster special-purpose accumulator |
| 1779 | + * routines for SUM and AVG of these datatypes. |
1776 | 1780 | */
|
1777 | 1781 |
|
1778 | 1782 | Datum
|
@@ -1979,71 +1983,74 @@ numeric_stddev(PG_FUNCTION_ARGS)
|
1979 | 1983 | /*
|
1980 | 1984 | * SUM transition functions for integer datatypes.
|
1981 | 1985 | *
|
1982 |
| - * We use a Numeric accumulator to avoid overflow. Because SQL92 defines |
1983 |
| - * the SUM() of no values to be NULL, not zero, the initial condition of |
1984 |
| - * the transition data value needs to be NULL. This means we can't rely |
1985 |
| - * on ExecAgg to automatically insert the first non-null data value into |
1986 |
| - * the transition data: it doesn't know how to do the type conversion. |
1987 |
| - * The upshot is that these routines have to be marked non-strict and |
1988 |
| - * handle substitution of the first non-null input themselves. |
| 1986 | + * To avoid overflow, we use accumulators wider than the input datatype. |
| 1987 | + * A Numeric accumulator is needed for int8 input; for int4 and int2 |
| 1988 | + * inputs, we use int8 accumulators which should be sufficient for practical |
| 1989 | + * purposes. (The latter two therefore don't really belong in this file, |
| 1990 | + * but we keep them here anyway.) |
| 1991 | + * |
| 1992 | + * Because SQL92 defines the SUM() of no values to be NULL, not zero, |
| 1993 | + * the initial condition of the transition data value needs to be NULL. This |
| 1994 | + * means we can't rely on ExecAgg to automatically insert the first non-null |
| 1995 | + * data value into the transition data: it doesn't know how to do the type |
| 1996 | + * conversion. The upshot is that these routines have to be marked non-strict |
| 1997 | + * and handle substitution of the first non-null input themselves. |
1989 | 1998 | */
|
1990 | 1999 |
|
1991 | 2000 | Datum
|
1992 | 2001 | int2_sum(PG_FUNCTION_ARGS)
|
1993 | 2002 | {
|
1994 |
| - Numeric oldsum; |
1995 |
| - Datum newval; |
| 2003 | + int64 oldsum; |
| 2004 | + int64 newval; |
1996 | 2005 |
|
1997 | 2006 | if (PG_ARGISNULL(0))
|
1998 | 2007 | {
|
1999 | 2008 | /* No non-null input seen so far... */
|
2000 | 2009 | if (PG_ARGISNULL(1))
|
2001 | 2010 | PG_RETURN_NULL(); /* still no non-null */
|
2002 | 2011 | /* This is the first non-null input. */
|
2003 |
| - newval = DirectFunctionCall1(int2_numeric, PG_GETARG_DATUM(1)); |
2004 |
| - PG_RETURN_DATUM(newval); |
| 2012 | + newval = (int64) PG_GETARG_INT16(1); |
| 2013 | + PG_RETURN_INT64(newval); |
2005 | 2014 | }
|
2006 | 2015 |
|
2007 |
| - oldsum = PG_GETARG_NUMERIC(0); |
| 2016 | + oldsum = PG_GETARG_INT64(0); |
2008 | 2017 |
|
2009 | 2018 | /* Leave sum unchanged if new input is null. */
|
2010 | 2019 | if (PG_ARGISNULL(1))
|
2011 |
| - PG_RETURN_NUMERIC(oldsum); |
| 2020 | + PG_RETURN_INT64(oldsum); |
2012 | 2021 |
|
2013 | 2022 | /* OK to do the addition. */
|
2014 |
| - newval = DirectFunctionCall1(int2_numeric, PG_GETARG_DATUM(1)); |
| 2023 | + newval = oldsum + (int64) PG_GETARG_INT16(1); |
2015 | 2024 |
|
2016 |
| - PG_RETURN_DATUM(DirectFunctionCall2(numeric_add, |
2017 |
| - NumericGetDatum(oldsum), newval)); |
| 2025 | + PG_RETURN_INT64(newval); |
2018 | 2026 | }
|
2019 | 2027 |
|
2020 | 2028 | Datum
|
2021 | 2029 | int4_sum(PG_FUNCTION_ARGS)
|
2022 | 2030 | {
|
2023 |
| - Numeric oldsum; |
2024 |
| - Datum newval; |
| 2031 | + int64 oldsum; |
| 2032 | + int64 newval; |
2025 | 2033 |
|
2026 | 2034 | if (PG_ARGISNULL(0))
|
2027 | 2035 | {
|
2028 | 2036 | /* No non-null input seen so far... */
|
2029 | 2037 | if (PG_ARGISNULL(1))
|
2030 | 2038 | PG_RETURN_NULL(); /* still no non-null */
|
2031 | 2039 | /* This is the first non-null input. */
|
2032 |
| - newval = DirectFunctionCall1(int4_numeric, PG_GETARG_DATUM(1)); |
2033 |
| - PG_RETURN_DATUM(newval); |
| 2040 | + newval = (int64) PG_GETARG_INT32(1); |
| 2041 | + PG_RETURN_INT64(newval); |
2034 | 2042 | }
|
2035 | 2043 |
|
2036 |
| - oldsum = PG_GETARG_NUMERIC(0); |
| 2044 | + oldsum = PG_GETARG_INT64(0); |
2037 | 2045 |
|
2038 | 2046 | /* Leave sum unchanged if new input is null. */
|
2039 | 2047 | if (PG_ARGISNULL(1))
|
2040 |
| - PG_RETURN_NUMERIC(oldsum); |
| 2048 | + PG_RETURN_INT64(oldsum); |
2041 | 2049 |
|
2042 | 2050 | /* OK to do the addition. */
|
2043 |
| - newval = DirectFunctionCall1(int4_numeric, PG_GETARG_DATUM(1)); |
| 2051 | + newval = oldsum + (int64) PG_GETARG_INT32(1); |
2044 | 2052 |
|
2045 |
| - PG_RETURN_DATUM(DirectFunctionCall2(numeric_add, |
2046 |
| - NumericGetDatum(oldsum), newval)); |
| 2053 | + PG_RETURN_INT64(newval); |
2047 | 2054 | }
|
2048 | 2055 |
|
2049 | 2056 | Datum
|
@@ -2076,6 +2083,90 @@ int8_sum(PG_FUNCTION_ARGS)
|
2076 | 2083 | }
|
2077 | 2084 |
|
2078 | 2085 |
|
| 2086 | +/* |
| 2087 | + * Routines for avg(int2) and avg(int4). The transition datatype |
| 2088 | + * is a two-element int8 array, holding count and sum. |
| 2089 | + */ |
| 2090 | + |
| 2091 | +typedef struct Int8TransTypeData |
| 2092 | +{ |
| 2093 | +#ifndef INT64_IS_BUSTED |
| 2094 | + int64 count; |
| 2095 | + int64 sum; |
| 2096 | +#else |
| 2097 | + /* "int64" isn't really 64 bits, so fake up properly-aligned fields */ |
| 2098 | + int32 count; |
| 2099 | + int32 pad1; |
| 2100 | + int32 sum; |
| 2101 | + int32 pad2; |
| 2102 | +#endif |
| 2103 | +} Int8TransTypeData; |
| 2104 | + |
| 2105 | +Datum |
| 2106 | +int2_avg_accum(PG_FUNCTION_ARGS) |
| 2107 | +{ |
| 2108 | + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P_COPY(0); |
| 2109 | + int16 newval = PG_GETARG_INT16(1); |
| 2110 | + Int8TransTypeData *transdata; |
| 2111 | + |
| 2112 | + /* |
| 2113 | + * We copied the input array, so it's okay to scribble on it directly. |
| 2114 | + */ |
| 2115 | + if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData)) |
| 2116 | + elog(ERROR, "int2_avg_accum: expected 2-element int8 array"); |
| 2117 | + transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); |
| 2118 | + |
| 2119 | + transdata->count++; |
| 2120 | + transdata->sum += newval; |
| 2121 | + |
| 2122 | + PG_RETURN_ARRAYTYPE_P(transarray); |
| 2123 | +} |
| 2124 | + |
| 2125 | +Datum |
| 2126 | +int4_avg_accum(PG_FUNCTION_ARGS) |
| 2127 | +{ |
| 2128 | + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P_COPY(0); |
| 2129 | + int32 newval = PG_GETARG_INT32(1); |
| 2130 | + Int8TransTypeData *transdata; |
| 2131 | + |
| 2132 | + /* |
| 2133 | + * We copied the input array, so it's okay to scribble on it directly. |
| 2134 | + */ |
| 2135 | + if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData)) |
| 2136 | + elog(ERROR, "int4_avg_accum: expected 2-element int8 array"); |
| 2137 | + transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); |
| 2138 | + |
| 2139 | + transdata->count++; |
| 2140 | + transdata->sum += newval; |
| 2141 | + |
| 2142 | + PG_RETURN_ARRAYTYPE_P(transarray); |
| 2143 | +} |
| 2144 | + |
| 2145 | +Datum |
| 2146 | +int8_avg(PG_FUNCTION_ARGS) |
| 2147 | +{ |
| 2148 | + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); |
| 2149 | + Int8TransTypeData *transdata; |
| 2150 | + Datum countd, |
| 2151 | + sumd; |
| 2152 | + |
| 2153 | + if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData)) |
| 2154 | + elog(ERROR, "int8_avg: expected 2-element int8 array"); |
| 2155 | + transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); |
| 2156 | + |
| 2157 | + /* SQL92 defines AVG of no values to be NULL */ |
| 2158 | + if (transdata->count == 0) |
| 2159 | + PG_RETURN_NULL(); |
| 2160 | + |
| 2161 | + countd = DirectFunctionCall1(int8_numeric, |
| 2162 | + Int64GetDatumFast(transdata->count)); |
| 2163 | + sumd = DirectFunctionCall1(int8_numeric, |
| 2164 | + Int64GetDatumFast(transdata->sum)); |
| 2165 | + |
| 2166 | + PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd)); |
| 2167 | +} |
| 2168 | + |
| 2169 | + |
2079 | 2170 | /* ----------------------------------------------------------------------
|
2080 | 2171 | *
|
2081 | 2172 | * Local functions follow
|
|
0 commit comments