]> granicus.if.org Git - postgresql/commitdiff
As someone asked for this feature - patch for 1.09 follows.
authorBruce Momjian <bruce@momjian.us>
Sat, 30 Nov 1996 17:49:02 +0000 (17:49 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 30 Nov 1996 17:49:02 +0000 (17:49 +0000)
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
src/backend/optimizer/util/clauses.c
src/backend/parser/parser.c

index 44e051a3038db9ac1569600df43efd568b7a2763..bcc6bdebaf779cbf8b6316ad211da710f0aaa641 100644 (file)
@@ -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;
index 563b6130749feae4bfd38f77fca30adcfaeff389..b690b0fdb0f4ab9e6a3928bf1dd6f692e5d4cb4f 100644 (file)
@@ -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);
+    }
 
 }
 
index 79bac80c11532d0562d648c4d0d13058d8aaa0bb..a77007c6f4c53fe98353098f5cc6a19d7a56328e 100644 (file)
@@ -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();