aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_func.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>1999-12-10 07:37:35 +0000
committerTom Lane <tgl@sss.pgh.pa.us>1999-12-10 07:37:35 +0000
commit18c30002863a1a4d2c2f0da6d245f106586bc686 (patch)
treeb417e01845965594239b0f8944e1baf00688b12e /src/backend/parser/parse_func.c
parentecba5d308ca92d3a4fd0725c200452007217991b (diff)
downloadpostgresql-18c30002863a1a4d2c2f0da6d245f106586bc686.tar.gz
postgresql-18c30002863a1a4d2c2f0da6d245f106586bc686.zip
Teach grammar and parser about aggregate(DISTINCT ...). No implementation
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'.
Diffstat (limited to 'src/backend/parser/parse_func.c')
-rw-r--r--src/backend/parser/parse_func.c170
1 files changed, 96 insertions, 74 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index aafa4e4c9cb..42143746b81 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -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);