]> granicus.if.org Git - postgresql/commitdiff
Teach grammar and parser about aggregate(DISTINCT ...). No implementation
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Dec 1999 07:37:35 +0000 (07:37 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Dec 1999 07:37:35 +0000 (07:37 +0000)
yet, but at least we can give a better error message:
regression=> select count(distinct f1) from int4_tbl;
ERROR:  aggregate(DISTINCT ...) is not implemented yet
instead of 'parser: parse error at or near distinct'.

src/backend/nodes/outfuncs.c
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/backend/parser/parse_agg.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/parser/parse_target.c
src/include/nodes/parsenodes.h
src/include/parser/parse_agg.h
src/include/parser/parse_func.h

index 789faad772c739468bd9feec0d0c147867da54f5..78bda61b30fc72e4e2e8f674ab5860e8d274dc68 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *     $Id: outfuncs.c,v 1.98 1999/11/23 20:06:53 momjian Exp $
+ *     $Id: outfuncs.c,v 1.99 1999/12/10 07:37:31 tgl Exp $
  *
  * NOTES
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -114,8 +114,12 @@ _outSelectStmt(StringInfo str, SelectStmt *node)
 static void
 _outFuncCall(StringInfo str, FuncCall *node)
 {
-       appendStringInfo(str, "FUNCTION %s :args ", stringStringInfo(node->funcname));
+       appendStringInfo(str, "FUNCTION %s :args ",
+                                        stringStringInfo(node->funcname));
        _outNode(str, node->args);
+       appendStringInfo(str, " :agg_star %s :agg_distinct %s ",
+                                        node->agg_star ? "true" : "false",
+                                        node->agg_distinct ? "true" : "false");
 }
 
 static void
index e93bd13d9a11c6842c64782f5c2224141494d1ed..2162bbff315c77b8121e422b38567be9b54be411 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *     $Id: analyze.c,v 1.125 1999/12/06 18:02:42 wieck Exp $
+ *     $Id: analyze.c,v 1.126 1999/12/10 07:37:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -624,6 +624,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
                                        funccallnode = makeNode(FuncCall);
                                        funccallnode->funcname = "nextval";
                                        funccallnode->args = lcons(snamenode, NIL);
+                                       funccallnode->agg_star = false;
+                                       funccallnode->agg_distinct = false;
 
                                        constraint = makeNode(Constraint);
                                        constraint->contype = CONSTR_DEFAULT;
index 4352bb327a75ce9ead948e9232fccf57730c0d43..d3fb6291806aaa7652c05705cd0850a128b299aa 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.120 1999/12/10 05:17:13 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.121 1999/12/10 07:37:35 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -246,7 +246,7 @@ static Node *doNegate(Node *n);
 %type <str>            TypeId
 
 %type <node>   TableConstraint
-%type <list>   ColPrimaryKey, ColQualifier
+%type <list>   ColPrimaryKey, ColConstraintList
 %type <node>   ColConstraint, ColConstraintElem
 %type <ival>   key_actions, key_action, key_reference
 %type <str>            key_match
@@ -912,7 +912,7 @@ OptTableElement:  columnDef                                         { $$ = $1; }
                        | TableConstraint                                       { $$ = $1; }
                ;
 
-columnDef:  ColId Typename ColQualifier
+columnDef:  ColId Typename ColConstraintList
                                {
                                        ColumnDef *n = makeNode(ColumnDef);
                                        n->colname = $1;
@@ -939,14 +939,15 @@ columnDef:  ColId Typename ColQualifier
                                }
                ;
 
-ColQualifier:  ColQualifier ColConstraint
+ColConstraintList:  ColConstraintList ColConstraint
                                {
                                        if ($2 != NULL)
                                                $$ = lappend($1, $2);
                                        else
                                                $$ = $1;
                                }
-                       | /*EMPTY*/                                                     { $$ = NULL; }
+                       | /*EMPTY*/
+                               { $$ = NIL; }
                ;
 
 ColPrimaryKey:  PRIMARY KEY
@@ -3792,6 +3793,8 @@ a_expr:  com_expr
                                                FuncCall *n = makeNode(FuncCall);
                                                n->funcname = $3->name;
                                                n->args = lcons($1,NIL);
+                                               n->agg_star = false;
+                                               n->agg_distinct = false;
                                                $$ = (Node *)n;
                                        }
                                }
@@ -4037,6 +4040,8 @@ b_expr:  com_expr
                                                FuncCall *n = makeNode(FuncCall);
                                                n->funcname = $3->name;
                                                n->args = lcons($1,NIL);
+                                               n->agg_star = false;
+                                               n->agg_distinct = false;
                                                $$ = (Node *)n;
                                        }
                                }
@@ -4129,6 +4134,8 @@ com_expr:  attr
                                                FuncCall *n = makeNode(FuncCall);
                                                n->funcname = $5->name;
                                                n->args = lcons($3,NIL);
+                                               n->agg_star = false;
+                                               n->agg_distinct = false;
                                                $$ = (Node *)n;
                                        }
                                }
@@ -4139,6 +4146,8 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = $1;
                                        n->args = NIL;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                | func_name '(' expr_list ')'
@@ -4146,6 +4155,17 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = $1;
                                        n->args = $3;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
+                                       $$ = (Node *)n;
+                               }
+               | func_name '(' DISTINCT expr_list ')'
+                               {
+                                       FuncCall *n = makeNode(FuncCall);
+                                       n->funcname = $1;
+                                       n->args = $4;
+                                       n->agg_star = false;
+                                       n->agg_distinct = true;
                                        $$ = (Node *)n;
                                }
                | func_name '(' '*' ')'
@@ -4158,12 +4178,9 @@ com_expr:  attr
                                         * and there are no other aggregates in SQL92 that accept
                                         * '*' as parameter.
                                         *
-                                        * XXX really, the '*' ought to be transformed to some
-                                        * special construct that wouldn't be acceptable as the
-                                        * input of a non-aggregate function, in case the given
-                                        * func_name matches a plain function.  This would also
-                                        * support a possible extension to let user-defined
-                                        * aggregates do something special with '*' as input.
+                                        * The FuncCall node is also marked agg_star = true,
+                                        * so that later processing can detect what the argument
+                                        * really was.
                                         */
                                        FuncCall *n = makeNode(FuncCall);
                                        A_Const *star = makeNode(A_Const);
@@ -4172,6 +4189,8 @@ com_expr:  attr
                                        star->val.val.ival = 1;
                                        n->funcname = $1;
                                        n->args = lcons(star, NIL);
+                                       n->agg_star = true;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                | CURRENT_DATE
@@ -4203,6 +4222,8 @@ com_expr:  attr
 
                                        n->funcname = xlateSqlType("date");
                                        n->args = lcons(s, NIL);
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
 
                                        $$ = (Node *)n;
                                }
@@ -4226,6 +4247,8 @@ com_expr:  attr
 
                                        n->funcname = xlateSqlType("time");
                                        n->args = lcons(s, NIL);
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
 
                                        $$ = (Node *)n;
                                }
@@ -4249,6 +4272,8 @@ com_expr:  attr
 
                                        n->funcname = xlateSqlType("time");
                                        n->args = lcons(s, NIL);
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
 
                                        if ($3 != 0)
                                                elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
@@ -4275,6 +4300,8 @@ com_expr:  attr
 
                                        n->funcname = xlateSqlType("timestamp");
                                        n->args = lcons(s, NIL);
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
 
                                        $$ = (Node *)n;
                                }
@@ -4298,6 +4325,8 @@ com_expr:  attr
 
                                        n->funcname = xlateSqlType("timestamp");
                                        n->args = lcons(s, NIL);
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
 
                                        if ($3 != 0)
                                                elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
@@ -4309,6 +4338,8 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = "getpgusername";
                                        n->args = NIL;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                | USER
@@ -4316,6 +4347,8 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = "getpgusername";
                                        n->args = NIL;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                | EXTRACT '(' extract_list ')'
@@ -4323,6 +4356,8 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = "date_part";
                                        n->args = $3;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                | POSITION '(' position_list ')'
@@ -4330,6 +4365,8 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = "strpos";
                                        n->args = $3;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                | SUBSTRING '(' substr_list ')'
@@ -4337,6 +4374,8 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = "substr";
                                        n->args = $3;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
@@ -4345,6 +4384,8 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = "btrim";
                                        n->args = $4;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                | TRIM '(' LEADING trim_list ')'
@@ -4352,6 +4393,8 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = "ltrim";
                                        n->args = $4;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                | TRIM '(' TRAILING trim_list ')'
@@ -4359,6 +4402,8 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = "rtrim";
                                        n->args = $4;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                | TRIM '(' trim_list ')'
@@ -4366,6 +4411,8 @@ com_expr:  attr
                                        FuncCall *n = makeNode(FuncCall);
                                        n->funcname = "btrim";
                                        n->args = $3;
+                                       n->agg_star = false;
+                                       n->agg_distinct = false;
                                        $$ = (Node *)n;
                                }
                | '(' SubSelect ')'
index 4e30e60ca65a7b01b11ae5c2fa69c0066f7e1674..68280f7f4a0a9ea8d75ce25951921d4fdb0428c6 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.30 1999/12/09 05:58:54 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.31 1999/12/10 07:37:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -203,7 +203,8 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
 
 Aggref *
 ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
-                List *target, int precedence)
+                List *args, bool agg_star, bool agg_distinct,
+                int precedence)
 {
        HeapTuple       theAggTuple;
        Form_pg_aggregate aggform;
@@ -242,7 +243,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
        if (OidIsValid(xfn1))
        {
                basetype = aggform->aggbasetype;
-               vartype = exprType(lfirst(target));
+               vartype = exprType(lfirst(args));
                if ((basetype != vartype)
                        && (!IS_BINARY_COMPATIBLE(basetype, vartype)))
                {
@@ -261,9 +262,17 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
        aggref->aggname = pstrdup(aggname);
        aggref->basetype = aggform->aggbasetype;
        aggref->aggtype = fintype;
-       aggref->target = lfirst(target);
+       aggref->target = lfirst(args);
        aggref->usenulls = usenulls;
 
+       /*
+        * We should store agg_star and agg_distinct into the Aggref node,
+        * and let downstream processing deal with them.  Currently, agg_star
+        * is ignored and agg_distinct is not implemented...
+        */
+       if (agg_distinct)
+               elog(ERROR, "aggregate(DISTINCT ...) is not implemented yet");
+
        pstate->p_hasAggs = true;
 
        return aggref;
index 0d51f2ae0565ebb1bd718a76a2021fad5b463d8c..95315d6c8244c17a6c7163269f9818b7fe5d088c 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.25 1999/11/22 17:56:20 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.26 1999/12/10 07:37:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -99,6 +99,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId,
 
                n->funcname = typeTypeName(targetType);
                n->args = lcons(node, NIL);
+               n->agg_star = false;
+               n->agg_distinct = false;
 
                result = transformExpr(pstate, (Node *) n, EXPR_COLUMN_FIRST);
 
index 76e5f91f1a8978247d8e92f44c585196149a3e72..ee43be4195068c7c5e0e483974ac3cddc8731016 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.59 1999/11/15 02:00:10 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.60 1999/12/10 07:37:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -106,8 +106,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                                        Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
 
                                                        result = ParseFuncOrColumn(pstate,
-                                                                                 "nullvalue", lcons(lexpr, NIL),
-                                                                                                  &pstate->p_last_resno,
+                                                                                                          "nullvalue",
+                                                                                                          lcons(lexpr, NIL),
+                                                                                                          false, false,
+                                                                                                          &pstate->p_last_resno,
                                                                                                           precedence);
                                                }
                                                break;
@@ -116,8 +118,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                                        Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
 
                                                        result = ParseFuncOrColumn(pstate,
-                                                                          "nonnullvalue", lcons(lexpr, NIL),
-                                                                                                  &pstate->p_last_resno,
+                                                                                                          "nonnullvalue",
+                                                                                                          lcons(lexpr, NIL),
+                                                                                                          false, false,
+                                                                                                          &pstate->p_last_resno,
                                                                                                           precedence);
                                                }
                                                break;
@@ -192,6 +196,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                result = ParseFuncOrColumn(pstate,
                                                                                   fn->funcname,
                                                                                   fn->args,
+                                                                                  fn->agg_star,
+                                                                                  fn->agg_distinct,
                                                                                   &pstate->p_last_resno,
                                                                                   precedence);
                                break;
index aafa4e4c9cb057a25113e61b34fa1f2a3b05656b..42143746b815c77cfa5c7964eaa01e439af49308 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.63 1999/12/07 04:09:39 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.64 1999/12/10 07:37:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -87,6 +87,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
 
                retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),
                                                                   lcons(param, NIL),
+                                                                  false, false,
                                                                   curr_resno,
                                                                   precedence);
        }
@@ -98,6 +99,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
                ident->isRel = TRUE;
                retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),
                                                                   lcons(ident, NIL),
+                                                                  false, false,
                                                                   curr_resno,
                                                                   precedence);
        }
@@ -107,6 +109,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
        {
                retval = ParseFuncOrColumn(pstate, strVal(lfirst(mutator_iter)),
                                                                   lcons(retval, NIL),
+                                                                  false, false,
                                                                   curr_resno,
                                                                   precedence);
        }
@@ -219,6 +222,7 @@ agg_select_candidate(Oid typeid, CandidateList candidates)
  */
 Node *
 ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
+                                 bool agg_star, bool agg_distinct,
                                  int *curr_resno, int precedence)
 {
        Oid                     rettype = InvalidOid;
@@ -230,12 +234,13 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
        char       *refname = NULL;
        Relation        rd;
        Oid                     relid;
-       int                     nargs;
+       int                     nargs = length(fargs);
        Func       *funcnode;
        Oid                     oid_array[MAXFARGS];
        Oid                *true_oid_array;
        Node       *retval;
        bool            retset;
+       bool            must_be_agg = agg_star || agg_distinct;
        bool            attisset = false;
        Oid                     toid = InvalidOid;
        Expr       *expr;
@@ -252,11 +257,11 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
         * that argument is a relation, param, or PQ function returning a
         * complex * type, then the function could be a projection.
         */
-       /* We only have one parameter */
-       if (length(fargs) == 1)
+       /* We only have one parameter, and it's not got aggregate decoration */
+       if (nargs == 1 && !must_be_agg)
        {
-               /* Is is a plain Relation name from the parser? */
-               if (nodeTag(first_arg) == T_Ident && ((Ident *) first_arg)->isRel)
+               /* Is it a plain Relation name from the parser? */
+               if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel)
                {
                        RangeTblEntry *rte;
                        Ident      *ident = (Ident *) first_arg;
@@ -292,15 +297,10 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                                                                                 refname,
                                                                                 funcname);
                        }
-                       else
-                       {
-                               /* drop through - attr is a set */
-                               ;
-                       }
+                       /* else drop through - attr is a set */
                }
                else if (ISCOMPLEX(exprType(first_arg)))
                {
-
                        /*
                         * Attempt to handle projection of a complex argument. If
                         * ParseComplexProjection can't handle the projection, we have
@@ -325,8 +325,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                                argrelid = typeidTypeRelid(toid);
 
                                /*
-                                * A projection contains either an attribute name or the
-                                * "*".
+                                * A projection contains either an attribute name or "*".
                                 */
                                if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
                                        && strcmp(funcname, "*"))
@@ -336,76 +335,99 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                        if (retval)
                                return retval;
                }
-               else
-               {
+       }
 
-                       /*
-                        * Parsing aggregates.
-                        */
-                       Type            tp;
-                       Oid                     basetype;
-                       int                     ncandidates;
-                       CandidateList candidates;
+       if (nargs == 1 || must_be_agg)
+       {
+               /*
+                * See if it's an aggregate.
+                */
+               Oid                     basetype;
+               int                     ncandidates;
+               CandidateList candidates;
 
-                       /*
-                        * the aggregate COUNT is a special case, ignore its base
-                        * type.  Treat it as zero
-                        */
-                       if (strcmp(funcname, "count") == 0)
-                               basetype = 0;
-                       else
-                               basetype = exprType(lfirst(fargs));
+               /* We don't presently cope with, eg, foo(DISTINCT x,y) */
+               if (nargs != 1)
+                       elog(ERROR, "Aggregate functions may only have one parameter");
 
-                       /* try for exact match first... */
-                       if (SearchSysCacheTuple(AGGNAME,
-                                                                       PointerGetDatum(funcname),
-                                                                       ObjectIdGetDatum(basetype),
-                                                                       0, 0))
-                               return (Node *) ParseAgg(pstate, funcname, basetype,
-                                                                                fargs, precedence);
+               /*
+                * the aggregate COUNT is a special case, ignore its base
+                * type.  Treat it as zero.   XXX mighty ugly --- FIXME
+                */
+               if (strcmp(funcname, "count") == 0)
+                       basetype = 0;
+               else
+                       basetype = exprType(lfirst(fargs));
 
-                       /*
-                        * No exact match yet, so see if there is another entry in the
-                        * aggregate table which is compatible. - thomas 1998-12-05
-                        */
-                       ncandidates = agg_get_candidates(funcname, basetype, &candidates);
-                       if (ncandidates > 0)
-                       {
-                               Oid                     type;
+               /* try for exact match first... */
+               if (SearchSysCacheTuple(AGGNAME,
+                                                               PointerGetDatum(funcname),
+                                                               ObjectIdGetDatum(basetype),
+                                                               0, 0))
+                       return (Node *) ParseAgg(pstate, funcname, basetype,
+                                                                        fargs, agg_star, agg_distinct,
+                                                                        precedence);
 
-                               type = agg_select_candidate(basetype, candidates);
-                               if (OidIsValid(type))
-                               {
-                                       lfirst(fargs) = coerce_type(pstate, lfirst(fargs),
-                                                                                               basetype, type, -1);
-                                       basetype = type;
+               /*
+                * No exact match yet, so see if there is another entry in the
+                * aggregate table which is compatible. - thomas 1998-12-05
+                */
+               ncandidates = agg_get_candidates(funcname, basetype, &candidates);
+               if (ncandidates > 0)
+               {
+                       Oid                     type;
 
-                                       return (Node *) ParseAgg(pstate, funcname, basetype,
-                                                                                        fargs, precedence);
-                               }
-                               else
-                               {
-                                       elog(ERROR, "Unable to select an aggregate function %s(%s)",
-                                                funcname, typeidTypeName(basetype));
-                               }
+                       type = agg_select_candidate(basetype, candidates);
+                       if (OidIsValid(type))
+                       {
+                               lfirst(fargs) = coerce_type(pstate, lfirst(fargs),
+                                                                                       basetype, type, -1);
+                               basetype = type;
+                               return (Node *) ParseAgg(pstate, funcname, basetype,
+                                                                                fargs, agg_star, agg_distinct,
+                                                                                precedence);
+                       }
+                       else
+                       {
+                               /* Multiple possible matches --- give up */
+                               elog(ERROR, "Unable to select an aggregate function %s(%s)",
+                                        funcname, typeidTypeName(basetype));
                        }
+               }
 
+               if (must_be_agg)
+               {
                        /*
-                        * See if this is a single argument function with the function
-                        * name also a type name and the input argument and type name
-                        * binary compatible... This means that you are trying for a
-                        * type conversion which does not need to take place, so we'll
-                        * just pass through the argument itself. (make this clearer
-                        * with some extra brackets - thomas 1998-12-05)
+                        * No matching agg, but we had '*' or DISTINCT, so a plain
+                        * function could not have been meant.
                         */
-                       if ((HeapTupleIsValid(tp = SearchSysCacheTuple(TYPENAME,
-                                                                                          PointerGetDatum(funcname),
-                                                                                                                  0, 0, 0)))
-                               && IS_BINARY_COMPATIBLE(typeTypeId(tp), basetype))
-                               return ((Node *) lfirst(fargs));
+                       elog(ERROR, "There is no aggregate function %s(%s)",
+                                funcname, typeidTypeName(basetype));
                }
        }
 
+       /*
+        * See if this is a single argument function with the function
+        * name also a type name and the input argument and type name
+        * binary compatible... This means that you are trying for a
+        * type conversion which does not need to take place, so we'll
+        * just pass through the argument itself. (make this clearer
+        * with some extra brackets - thomas 1998-12-05)
+        */
+       if (nargs == 1)
+       {
+               Type            tp;
+
+               tp = SearchSysCacheTuple(TYPENAME,
+                                                                PointerGetDatum(funcname),
+                                                                0, 0, 0);
+               if (HeapTupleIsValid(tp) &&
+                       IS_BINARY_COMPATIBLE(typeTypeId(tp), exprType(lfirst(fargs))))
+               {
+                       /* XXX FIXME: probably need to change expression's marked type? */
+                       return (Node *) lfirst(fargs);
+               }
+       }
 
        /*
         * If we dropped through to here it's really a function (or a set,
@@ -461,14 +483,14 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                {                                               /* set functions don't have parameters */
 
                        /*
-                        * any functiona args which are typed "unknown", but aren't
+                        * any function args which are typed "unknown", but aren't
                         * constants, we don't know what to do with, because we can't
                         * cast them    - jolly
                         */
                        if (exprType(pair) == UNKNOWNOID && !IsA(pair, Const))
                                elog(ERROR, "There is no function '%s'"
                                         " with argument #%d of type UNKNOWN",
-                                        funcname, nargs);
+                                        funcname, nargs+1);
                        else
                                toid = exprType(pair);
                }
@@ -572,7 +594,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                text       *seqname;
                int32           aclcheck_result = -1;
 
-               Assert(length(fargs) == ((funcid == F_SETVAL) ? 2 : 1));
+               Assert(nargs == ((funcid == F_SETVAL) ? 2 : 1));
                seq = (Const *) lfirst(fargs);
                if (!IsA((Node *) seq, Const))
                        elog(ERROR, "Only constant sequence names are acceptable for function '%s'", funcname);
index 8cac8b417cdc9b29d4ae1580fbb3243cee8d93fc..a5e130b85431c90be6a4894dcb928a1bf87ff18f 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.49 1999/11/22 17:56:21 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.50 1999/12/10 07:37:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -337,16 +337,16 @@ SizeTargetExpr(ParseState *pstate,
 
        if (HeapTupleIsValid(ftup))
        {
-               FuncCall   *func;
-               A_Const    *cons;
+               A_Const    *cons = makeNode(A_Const);
+               FuncCall   *func = makeNode(FuncCall);
 
-               func = makeNode(FuncCall);
-               func->funcname = funcname;
-
-               cons = makeNode(A_Const);
                cons->val.type = T_Integer;
                cons->val.val.ival = attrtypmod;
+
+               func->funcname = funcname;
                func->args = lappend(lcons(expr, NIL), cons);
+               func->agg_star = false;
+               func->agg_distinct = false;
 
                expr = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
        }
index bcff7aa30066fe23b813c8570eb1ee6dcc0d55e8..df0cb5c4e54cacbc597d4530b723e9f6ce0c5b32 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.89 1999/12/10 03:56:09 momjian Exp $
+ * $Id: parsenodes.h,v 1.90 1999/12/10 07:37:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -758,6 +758,10 @@ typedef struct SelectStmt
 
 /****************************************************************************
  *     Supporting data structures for Parse Trees
+ *
+ *     Most of these node types appear in raw parsetrees output by the grammar,
+ *     and get transformed to something else by the analyzer.  A few of them
+ *     are used as-is in transformed querytrees.
  ****************************************************************************/
 
 /*
@@ -889,13 +893,20 @@ typedef struct Ident
 } Ident;
 
 /*
- * FuncCall - a function/aggregate invocation
+ * FuncCall - a function or aggregate invocation
+ *
+ * agg_star indicates we saw a 'foo(*)' construct, while agg_distinct
+ * indicates we saw 'foo(DISTINCT ...)'.  In either case, the construct
+ * *must* be an aggregate call.  Otherwise, it might be either an
+ * aggregate or some other kind of function.
  */
 typedef struct FuncCall
 {
        NodeTag         type;
        char       *funcname;           /* name of function */
        List       *args;                       /* the arguments (list of exprs) */
+       bool            agg_star;               /* argument was really '*' */
+       bool            agg_distinct;   /* arguments were labeled DISTINCT */
 } FuncCall;
 
 /*
index f1b400e9c9ac5df7590943ab991c60e0edea0c9a..cd149e1517b81898e5a08acc4738a71ec432a593 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_agg.h,v 1.12 1999/07/15 23:04:01 momjian Exp $
+ * $Id: parse_agg.h,v 1.13 1999/12/10 07:37:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,7 +18,8 @@
 extern void AddAggToParseState(ParseState *pstate, Aggref *aggref);
 extern void parseCheckAggregates(ParseState *pstate, Query *qry);
 extern Aggref *ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
-                List *target, int precedence);
+                                               List *args, bool agg_star, bool agg_distinct,
+                                               int precedence);
 extern void agg_error(char *caller, char *aggname, Oid basetypeID);
 
 #endif  /* PARSE_AGG_H */
index 1fdb8f9890da004a3da3b2283b0f2e4b91bb4715..04b9c44ec0e1890c3043f2b0f2ea928472ce7778 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_func.h,v 1.19 1999/08/21 03:49:17 tgl Exp $
+ * $Id: parse_func.h,v 1.20 1999/12/10 07:37:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,8 +42,10 @@ typedef struct _CandidateList
 
 extern Node *ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr,
                                                int *curr_resno, int precedence);
-extern Node *ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
-                                 int *curr_resno, int precedence);
+extern Node *ParseFuncOrColumn(ParseState *pstate,
+                                                          char *funcname, List *fargs,
+                                                          bool agg_star, bool agg_distinct,
+                                                          int *curr_resno, int precedence);
 
 extern List *setup_base_tlist(Oid typeid);