*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.14 1998/09/09 03:48:17 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.15 1998/12/08 06:18:56 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parse_expr.h"
#include "parser/parse_node.h"
#include "parser/parse_target.h"
+#include "parser/parse_coerce.h"
#include "utils/syscache.h"
#include "utils/lsyscache.h"
if (tle->resdom->resno == grpcl->entry->resdom->resno)
{
if (contain_agg_clause((Node *) expr))
- elog(ERROR, "parser: aggregates not allowed in GROUP BY clause");
+ elog(ERROR, "Aggregates not allowed in GROUP BY clause");
return TRUE;
}
}
* non-group column in target list may fail.)
*/
if (contain_agg_clause(qry->qual))
- elog(ERROR, "parser: aggregates not allowed in WHERE clause");
+ elog(ERROR, "Aggregates not allowed in WHERE clause");
/*
* the target list can only contain aggregates, group columns and
if (!tleIsAggOrGroupCol(tle, qry->groupClause))
elog(ERROR,
- "parser: illegal use of aggregates or non-group column in target list");
+ "Illegal use of aggregates or non-group column in target list");
}
/*
if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause))
elog(ERROR,
- "parser: illegal use of aggregates or non-group column in HAVING clause");
+ "Illegal use of aggregates or non-group column in HAVING clause");
return;
}
ObjectIdGetDatum(basetype),
0, 0);
if (!HeapTupleIsValid(theAggTuple))
- elog(ERROR, "aggregate %s does not exist", aggname);
+ elog(ERROR, "Aggregate %s does not exist", aggname);
/*
* We do a major hack for count(*) here.
else
vartype = ((Expr *) lfirst(target))->typeOid;
- if (basetype != vartype)
+ if ((basetype != vartype)
+ && (! IS_BINARY_COMPATIBLE(basetype, vartype)))
{
Type tp1,
tp2;
tp1 = typeidType(basetype);
tp2 = typeidType(vartype);
- elog(NOTICE, "Aggregate type mismatch:");
- elog(ERROR, "%s works on %s, not %s", aggname,
- typeTypeName(tp1), typeTypeName(tp2));
+ elog(ERROR, "Aggregate type mismatch"
+ "\n\t%s() works on %s, not on %s",
+ aggname, typeTypeName(tp1), typeTypeName(tp2));
}
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.31 1998/11/27 19:52:13 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.32 1998/12/08 06:18:56 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/pg_inherits.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
+#include "catalog/pg_aggregate.h"
#include "fmgr.h"
#include "lib/dllist.h"
#include "miscadmin.h"
static List *setup_base_tlist(Oid typeid);
static Oid *func_select_candidate(int nargs, Oid *input_typeids,
CandidateList candidates);
+static int agg_get_candidates(char *aggname, Oid typeId, CandidateList *candidates);
+static Oid agg_select_candidate(Oid typeid, CandidateList candidates);
#define ISCOMPLEX(type) (typeidTypeRelid(type) ? true : false)
return retval;
}
+static int
+agg_get_candidates(char *aggname,
+ Oid typeId,
+ CandidateList *candidates)
+{
+ CandidateList current_candidate;
+ Relation pg_aggregate_desc;
+ HeapScanDesc pg_aggregate_scan;
+ HeapTuple tup;
+ Form_pg_aggregate agg;
+ int ncandidates = 0;
+
+ static ScanKeyData aggKey[1] = {
+ {0, Anum_pg_aggregate_aggname, F_NAMEEQ}};
+
+ *candidates = NULL;
+
+ fmgr_info(F_NAMEEQ, (FmgrInfo *) &aggKey[0].sk_func);
+ aggKey[0].sk_argument = NameGetDatum(aggname);
+
+ pg_aggregate_desc = heap_openr(AggregateRelationName);
+ pg_aggregate_scan = heap_beginscan(pg_aggregate_desc,
+ 0,
+ SnapshotSelf, /* ??? */
+ 1,
+ aggKey);
+
+ while (HeapTupleIsValid(tup = heap_getnext(pg_aggregate_scan, 0)))
+ {
+ current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
+ current_candidate->args = (Oid *) palloc(sizeof(Oid));
+
+ agg = (Form_pg_aggregate) GETSTRUCT(tup);
+ current_candidate->args[0] = agg->aggbasetype;
+ current_candidate->next = *candidates;
+ *candidates = current_candidate;
+ ncandidates++;
+ }
+
+ heap_endscan(pg_aggregate_scan);
+ heap_close(pg_aggregate_desc);
+
+ return ncandidates;
+} /* agg_get_candidates() */
+
+/* agg_select_candidate()
+ * Try to choose only one candidate aggregate function from a list of possibles.
+ */
+static Oid
+agg_select_candidate(Oid typeid, CandidateList candidates)
+{
+ CandidateList current_candidate;
+ CandidateList last_candidate;
+ Oid current_typeid;
+ int ncandidates;
+ CATEGORY category,
+ current_category;
+
+/*
+ * Look for candidates which allow coersion and have a preferred type.
+ * Keep all candidates if none match.
+ */
+ category = TypeCategory(typeid);
+ ncandidates = 0;
+ last_candidate = NULL;
+ for (current_candidate = candidates;
+ current_candidate != NULL;
+ current_candidate = current_candidate->next)
+ {
+ current_typeid = current_candidate->args[0];
+ current_category = TypeCategory(current_typeid);
+
+ if ((current_category == category)
+ && IsPreferredType(current_category, current_typeid)
+ && can_coerce_type(1, &typeid, ¤t_typeid))
+ {
+ /* only one so far? then keep it... */
+ if (last_candidate == NULL)
+ {
+ candidates = current_candidate;
+ last_candidate = current_candidate;
+ ncandidates = 1;
+ }
+ /* otherwise, keep this one too... */
+ else
+ {
+ last_candidate->next = current_candidate;
+ last_candidate = current_candidate;
+ ncandidates++;
+ }
+ }
+ /* otherwise, don't bother keeping this one around... */
+ else
+ {
+ last_candidate->next = NULL;
+ }
+ }
+
+ return ((ncandidates == 1) ? candidates->args[0] : 0);
+} /* agg_select_candidate() */
+
+
/*
* parse function
*/
/*
* Parsing aggregates.
*/
- Type tp;
- Oid basetype;
+ Type tp;
+ Oid basetype;
+ int ncandidates;
+ CandidateList candidates;
+
/*
* the aggregate COUNT is a special case, ignore its base
basetype = 0;
else
basetype = exprType(lfirst(fargs));
+
+ /* try for exact match first... */
if (SearchSysCacheTuple(AGGNAME,
PointerGetDatum(funcname),
ObjectIdGetDatum(basetype),
return (Node *) ParseAgg(pstate, funcname, basetype,
fargs, precedence);
+ /*
+ * 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;
+
+ type = agg_select_candidate(basetype, candidates);
+ if (OidIsValid(type))
+ {
+ lfirst(fargs) = coerce_type(pstate, lfirst(fargs), basetype, type);
+ basetype = type;
+
+ return (Node *) ParseAgg(pstate, funcname, basetype,
+ fargs, precedence);
+ }
+ else
+ {
+ elog(ERROR,"Unable to select an aggregate function for type %s",
+ 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 ((HeapTupleIsValid(tp = SearchSysCacheTuple(TYPNAME,
- PointerGetDatum(funcname),
+ PointerGetDatum(funcname),
0, 0, 0)))
&& IS_BINARY_COMPATIBLE(typeTypeId(tp), basetype))
+ {
return ((Node *) lfirst(fargs));
+ }
}
}