From 51b2f8ba5593558312157720c3d8e1dcfd8744b3 Mon Sep 17 00:00:00 2001
From: Neil Conway <neilc@samurai.com>
Date: Mon, 4 Apr 2005 23:50:27 +0000
Subject: [PATCH] This patch changes int2_avg_accum() and int4_avg_accum() use
 the nodeAgg performance hack Tom introduced recently. This means we can avoid
 copying the transition array for each input tuple if these functions are
 invoked as aggregate transition functions.

To test the performance improvement, I created a 1 million row table
with a single int4 column. Without the patch, SELECT avg(col) FROM
table took about 4.2 seconds (after the data was cached); with the
patch, it took about 3.2 seconds. Naturally, the performance
improvement for a less trivial query (or a table with wider rows)
would be relatively smaller.
---
 src/backend/utils/adt/numeric.c | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 411891e269b..a459ca2d6e4 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -14,7 +14,7 @@
  * Copyright (c) 1998-2005, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.81 2005/01/01 05:43:07 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.82 2005/04/04 23:50:27 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2462,17 +2462,24 @@ typedef struct Int8TransTypeData
 Datum
 int2_avg_accum(PG_FUNCTION_ARGS)
 {
-	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
+	ArrayType  *transarray;
 	int16		newval = PG_GETARG_INT16(1);
 	Int8TransTypeData *transdata;
 
 	/*
-	 * We copied the input array, so it's okay to scribble on it directly.
+	 * If we're invoked by nodeAgg, we can cheat and modify our first
+	 * parameter in-place to reduce palloc overhead. Otherwise we need
+	 * to make a copy of it before scribbling on it.
 	 */
+	if (fcinfo->context && IsA(fcinfo->context, AggState))
+		transarray = PG_GETARG_ARRAYTYPE_P(0);
+	else
+		transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
+
 	if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))
 		elog(ERROR, "expected 2-element int8 array");
-	transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
 
+	transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
 	transdata->count++;
 	transdata->sum += newval;
 
@@ -2482,17 +2489,24 @@ int2_avg_accum(PG_FUNCTION_ARGS)
 Datum
 int4_avg_accum(PG_FUNCTION_ARGS)
 {
-	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
+	ArrayType  *transarray;
 	int32		newval = PG_GETARG_INT32(1);
 	Int8TransTypeData *transdata;
 
 	/*
-	 * We copied the input array, so it's okay to scribble on it directly.
+	 * If we're invoked by nodeAgg, we can cheat and modify our first
+	 * parameter in-place to reduce palloc overhead. Otherwise we need
+	 * to make a copy of it before scribbling on it.
 	 */
+	if (fcinfo->context && IsA(fcinfo->context, AggState))
+		transarray = PG_GETARG_ARRAYTYPE_P(0);
+	else
+		transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
+
 	if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))
 		elog(ERROR, "expected 2-element int8 array");
-	transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
 
+	transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
 	transdata->count++;
 	transdata->sum += newval;
 
-- 
GitLab