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
This commit is contained in:
parent
87352726b2
commit
f0a9e64afd
@ -259,16 +259,33 @@ ExecAgg(Agg *node)
|
|||||||
Datum newVal;
|
Datum newVal;
|
||||||
AggFuncInfo *aggfns = &aggFuncInfo[i];
|
AggFuncInfo *aggfns = &aggFuncInfo[i];
|
||||||
Datum args[2];
|
Datum args[2];
|
||||||
|
Node *tagnode;
|
||||||
newVal = aggGetAttr(outerslot,
|
|
||||||
|
switch(nodeTag(aggregates[i]->target))
|
||||||
|
{
|
||||||
|
case T_Var:
|
||||||
|
tagnode = NULL;
|
||||||
|
newVal = aggGetAttr(outerslot,
|
||||||
aggregates[i],
|
aggregates[i],
|
||||||
&isNull);
|
&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)
|
if (isNull)
|
||||||
continue; /* ignore this tuple for this agg */
|
continue; /* ignore this tuple for this agg */
|
||||||
|
|
||||||
if (aggfns->xfn1) {
|
if (aggfns->xfn1) {
|
||||||
if (noInitValue[i]) {
|
if (noInitValue[i]) {
|
||||||
|
int byVal;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* value1 and value2 has not been initialized. This
|
* value1 and value2 has not been initialized. This
|
||||||
* is the first non-NULL value. We use it as the
|
* 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
|
to make a copy of it since the tuple from which
|
||||||
it came will be freed on the next iteration
|
it came will be freed on the next iteration
|
||||||
of the scan */
|
of the scan */
|
||||||
attnum = ((Var*)aggregates[i]->target)->varattno;
|
if ( tagnode != NULL )
|
||||||
attlen = outerslot->ttc_tupleDescriptor->attrs[attnum-1]->attlen;
|
{
|
||||||
|
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) {
|
if (attlen == -1) {
|
||||||
/* variable length */
|
/* variable length */
|
||||||
attlen = VARSIZE((struct varlena*) newVal);
|
attlen = VARSIZE((struct varlena*) newVal);
|
||||||
}
|
}
|
||||||
value1[i] = (Datum)palloc(attlen);
|
value1[i] = (Datum)palloc(attlen);
|
||||||
if (outerslot->ttc_tupleDescriptor->attrs[attnum-1]->attbyval)
|
if ( byVal )
|
||||||
value1[i] = newVal;
|
value1[i] = newVal;
|
||||||
else
|
else
|
||||||
memmove((char*) (value1[i]), (char*) (newVal), attlen);
|
memmove((char*)(value1[i]), (char*)newVal, attlen);
|
||||||
/* value1[i] = newVal; */
|
/* value1[i] = newVal; */
|
||||||
noInitValue[i] = 0;
|
noInitValue[i] = 0;
|
||||||
nulls[i] = 0;
|
nulls[i] = 0;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -521,6 +521,9 @@ fix_opid(Node *clause)
|
|||||||
fix_opid((Node*)get_leftop((Expr*)clause));
|
fix_opid((Node*)get_leftop((Expr*)clause));
|
||||||
fix_opid((Node*)get_rightop((Expr*)clause));
|
fix_opid((Node*)get_rightop((Expr*)clause));
|
||||||
}
|
}
|
||||||
|
else if (agg_clause (clause)) {
|
||||||
|
fix_opid (((Aggreg*)clause)->target);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
fintype = aggform->aggfinaltype;
|
||||||
xfn1 = aggform->aggtransfn1;
|
xfn1 = aggform->aggtransfn1;
|
||||||
|
|
||||||
if (nodeTag(target) != T_Var)
|
if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr)
|
||||||
elog(WARN, "parser: aggregate can only be applied on an attribute");
|
elog(WARN, "parser: aggregate can only be applied on an attribute or expression");
|
||||||
|
|
||||||
/* only aggregates with transfn1 need a base type */
|
/* only aggregates with transfn1 need a base type */
|
||||||
if (OidIsValid(xfn1)) {
|
if (OidIsValid(xfn1)) {
|
||||||
basetype = aggform->aggbasetype;
|
basetype = aggform->aggbasetype;
|
||||||
vartype = ((Var*)target)->vartype;
|
if (nodeTag(target) == T_Var)
|
||||||
|
vartype = ((Var*)target)->vartype;
|
||||||
|
else
|
||||||
|
vartype = ((Expr*)target)->typeOid;
|
||||||
|
|
||||||
if (basetype != vartype) {
|
if (basetype != vartype) {
|
||||||
Type tp1, tp2, get_id_type();
|
Type tp1, tp2, get_id_type();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user