From f0a9e64afd1d2401abc269274113e4384bf537b9 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Sat, 30 Nov 1996 17:49:02 +0000
Subject: [PATCH] As someone asked for this feature - patch for 1.09 follows.
 Now You can do queries like

select sum(some_func(x)) from ...
select min(table1.x + table2.y) from table1, table2 where ...

and so on.

Vadim
---
 src/backend/executor/nodeAgg.c       | 50 +++++++++++++++++++++++-----
 src/backend/optimizer/util/clauses.c |  5 ++-
 src/backend/parser/parser.c          | 11 +++---
 3 files changed, 52 insertions(+), 14 deletions(-)

diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 44e051a3038..bcc6bdebaf7 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -259,16 +259,33 @@ ExecAgg(Agg *node)
 	    Datum newVal;
 	    AggFuncInfo *aggfns = &aggFuncInfo[i];
 	    Datum args[2];
-
-	    newVal = aggGetAttr(outerslot,
+	    Node *tagnode;
+	    
+	    switch(nodeTag(aggregates[i]->target))
+	    {
+	    	case T_Var:
+	    		tagnode = NULL;
+			newVal = aggGetAttr(outerslot,
 				aggregates[i],
 				&isNull);
+			break;
+		case T_Expr:
+			tagnode = ((Expr*)aggregates[i]->target)->oper;
+			econtext->ecxt_scantuple = outerslot;
+			newVal = ExecEvalExpr (aggregates[i]->target, econtext,
+					&isNull, NULL);
+			break;
+		default:
+			elog(WARN, "ExecAgg: Bad Agg->Target for Agg %d", i);
+	    }
 
 	    if (isNull)
 		continue;	/* ignore this tuple for this agg */
 
 	    if (aggfns->xfn1) {
 		if (noInitValue[i]) {
+		    int byVal;
+		    
 		    /*
 		     * value1 and value2 has not been initialized. This
 		     * is the first non-NULL value. We use it as the
@@ -278,17 +295,32 @@ ExecAgg(Agg *node)
 			to make a copy of it since the tuple from which
 			it came will be freed on the next iteration 
 			of the scan */
-		    attnum = ((Var*)aggregates[i]->target)->varattno;
-		    attlen = outerslot->ttc_tupleDescriptor->attrs[attnum-1]->attlen;
+		    if ( tagnode != NULL )
+		    {
+		    	FunctionCachePtr fcache_ptr;
+		    	
+		    	if ( nodeTag(tagnode) == T_Func )
+		    	    fcache_ptr = ((Func*)tagnode)->func_fcache;
+		    	else
+		    	    fcache_ptr = ((Oper*)tagnode)->op_fcache;
+		    	attlen = fcache_ptr->typlen;
+		    	byVal = fcache_ptr->typbyval;
+		    }
+		    else
+		    {
+		    	attnum = ((Var*)aggregates[i]->target)->varattno;
+		    	attlen = outerslot->ttc_tupleDescriptor->attrs[attnum-1]->attlen;
+		    	byVal = outerslot->ttc_tupleDescriptor->attrs[attnum-1]->attbyval;
+		    }
 		    if (attlen == -1)  {
-			/* variable length */
+		    /* variable length */
 			attlen = VARSIZE((struct varlena*) newVal);
 		    }
 		    value1[i] = (Datum)palloc(attlen);
-                 if (outerslot->ttc_tupleDescriptor->attrs[attnum-1]->attbyval)
-                        value1[i] = newVal;
-                    else
-                        memmove((char*) (value1[i]), (char*) (newVal), attlen);
+		    if ( byVal )
+		    	value1[i] = newVal;
+		    else
+		        memmove((char*)(value1[i]), (char*)newVal, attlen);
 		    /* value1[i] = newVal; */
 		    noInitValue[i] = 0;
 		    nulls[i] = 0;
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 563b6130749..b690b0fdb0f 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.4 1996/11/06 09:29:22 scrappy Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.5 1996/11/30 17:48:52 momjian Exp $
  *
  * HISTORY
  *    AUTHOR		DATE		MAJOR EVENT
@@ -521,6 +521,9 @@ fix_opid(Node *clause)
 	fix_opid((Node*)get_leftop((Expr*)clause));
 	fix_opid((Node*)get_rightop((Expr*)clause));
     }
+    else if (agg_clause (clause)) {
+    	fix_opid (((Aggreg*)clause)->target);
+    }
 
 }
 
diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c
index 79bac80c115..a77007c6f4c 100644
--- a/src/backend/parser/parser.c
+++ b/src/backend/parser/parser.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.12 1996/11/25 03:03:48 momjian Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.13 1996/11/30 17:49:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -434,13 +434,16 @@ ParseAgg(char *aggname, Oid basetype, Node *target)
     fintype = aggform->aggfinaltype;
     xfn1 = aggform->aggtransfn1;
     
-    if (nodeTag(target) != T_Var)
-	elog(WARN, "parser: aggregate can only be applied on an attribute");
+    if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr)
+	elog(WARN, "parser: aggregate can only be applied on an attribute or expression");
 
     /* only aggregates with transfn1 need a base type */
     if (OidIsValid(xfn1)) {	
 	basetype = aggform->aggbasetype;
-	vartype = ((Var*)target)->vartype;
+	if (nodeTag(target) == T_Var)
+	    vartype = ((Var*)target)->vartype;
+	else
+	    vartype = ((Expr*)target)->typeOid;
 
 	if (basetype != vartype) {
 	    Type tp1, tp2, get_id_type();
-- 
GitLab