1414 * Copyright (c) 1998-2007, PostgreSQL Global Development Group
1515 *
1616 * IDENTIFICATION
17- * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.99 2007/01/16 21:41:13 neilc Exp $
17+ * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.100 2007/02/17 00:55:57 momjian Exp $
1818 *
1919 *-------------------------------------------------------------------------
2020 */
@@ -2165,6 +2165,40 @@ do_numeric_accum(ArrayType *transarray, Numeric newval)
21652165 return result ;
21662166}
21672167
2168+ /*
2169+ * Improve avg performance by not caclulating sum(X*X).
2170+ */
2171+ static ArrayType *
2172+ do_numeric_avg_accum (ArrayType * transarray , Numeric newval )
2173+ {
2174+ Datum * transdatums ;
2175+ int ndatums ;
2176+ Datum N ,
2177+ sumX ;
2178+ ArrayType * result ;
2179+
2180+ /* We assume the input is array of numeric */
2181+ deconstruct_array (transarray ,
2182+ NUMERICOID , -1 , false, 'i' ,
2183+ & transdatums , NULL , & ndatums );
2184+ if (ndatums != 2 )
2185+ elog (ERROR , "expected 2-element numeric array" );
2186+ N = transdatums [0 ];
2187+ sumX = transdatums [1 ];
2188+
2189+ N = DirectFunctionCall1 (numeric_inc , N );
2190+ sumX = DirectFunctionCall2 (numeric_add , sumX ,
2191+ NumericGetDatum (newval ));
2192+
2193+ transdatums [0 ] = N ;
2194+ transdatums [1 ] = sumX ;
2195+
2196+ result = construct_array (transdatums , 2 ,
2197+ NUMERICOID , -1 , false, 'i' );
2198+
2199+ return result ;
2200+ }
2201+
21682202Datum
21692203numeric_accum (PG_FUNCTION_ARGS )
21702204{
@@ -2174,6 +2208,18 @@ numeric_accum(PG_FUNCTION_ARGS)
21742208 PG_RETURN_ARRAYTYPE_P (do_numeric_accum (transarray , newval ));
21752209}
21762210
2211+ /*
2212+ * Optimized case for average of numeric.
2213+ */
2214+ Datum
2215+ numeric_avg_accum (PG_FUNCTION_ARGS )
2216+ {
2217+ ArrayType * transarray = PG_GETARG_ARRAYTYPE_P (0 );
2218+ Numeric newval = PG_GETARG_NUMERIC (1 );
2219+
2220+ PG_RETURN_ARRAYTYPE_P (do_numeric_avg_accum (transarray , newval ));
2221+ }
2222+
21772223/*
21782224 * Integer data types all use Numeric accumulators to share code and
21792225 * avoid risk of overflow. For int2 and int4 inputs, Numeric accumulation
@@ -2219,6 +2265,22 @@ int8_accum(PG_FUNCTION_ARGS)
22192265 PG_RETURN_ARRAYTYPE_P (do_numeric_accum (transarray , newval ));
22202266}
22212267
2268+ /*
2269+ * Optimized case for average of int8.
2270+ */
2271+ Datum
2272+ int8_avg_accum (PG_FUNCTION_ARGS )
2273+ {
2274+ ArrayType * transarray = PG_GETARG_ARRAYTYPE_P (0 );
2275+ Datum newval8 = PG_GETARG_DATUM (1 );
2276+ Numeric newval ;
2277+
2278+ newval = DatumGetNumeric (DirectFunctionCall1 (int8_numeric , newval8 ));
2279+
2280+ PG_RETURN_ARRAYTYPE_P (do_numeric_avg_accum (transarray , newval ));
2281+ }
2282+
2283+
22222284Datum
22232285numeric_avg (PG_FUNCTION_ARGS )
22242286{
@@ -2232,11 +2294,10 @@ numeric_avg(PG_FUNCTION_ARGS)
22322294 deconstruct_array (transarray ,
22332295 NUMERICOID , -1 , false, 'i' ,
22342296 & transdatums , NULL , & ndatums );
2235- if (ndatums != 3 )
2236- elog (ERROR , "expected 3 -element numeric array" );
2297+ if (ndatums != 2 )
2298+ elog (ERROR , "expected 2 -element numeric array" );
22372299 N = DatumGetNumeric (transdatums [0 ]);
22382300 sumX = DatumGetNumeric (transdatums [1 ]);
2239- /* ignore sumX2 */
22402301
22412302 /* SQL92 defines AVG of no values to be NULL */
22422303 /* N is zero iff no digits (cf. numeric_uminus) */
0 commit comments