diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 44e051a303..bcc6bdebaf 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 563b613074..b690b0fdb0 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 79bac80c11..a77007c6f4 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();