aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/parse_agg.c80
-rw-r--r--src/backend/parser/parse_coerce.c74
-rw-r--r--src/backend/parser/parse_expr.c5
-rw-r--r--src/backend/parser/parse_func.c357
-rw-r--r--src/backend/parser/parse_node.c11
-rw-r--r--src/backend/parser/parse_oper.c5
-rw-r--r--src/backend/parser/parse_target.c18
7 files changed, 188 insertions, 362 deletions
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 3812579a4db..114296baf29 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -8,24 +8,17 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.48 2002/04/09 20:35:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.49 2002/04/11 20:00:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
-
#include "postgres.h"
-#include "catalog/namespace.h"
-#include "catalog/pg_aggregate.h"
+
#include "optimizer/clauses.h"
#include "optimizer/tlist.h"
#include "parser/parse_agg.h"
-#include "parser/parse_coerce.h"
-#include "parser/parse_expr.h"
#include "parser/parsetree.h"
-#include "parser/parse_type.h"
-#include "utils/builtins.h"
-#include "utils/lsyscache.h"
-#include "utils/syscache.h"
+
typedef struct
{
@@ -185,70 +178,3 @@ parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual)
/* Release the list storage (but not the pointed-to expressions!) */
freeList(groupClauses);
}
-
-
-Aggref *
-ParseAgg(ParseState *pstate, List *aggname, Oid basetype,
- List *args, bool agg_star, bool agg_distinct)
-{
- HeapTuple aggtuple;
- Form_pg_aggregate aggform;
- Aggref *aggref;
-
- aggtuple = SearchSysCache(AGGNAME,
- PointerGetDatum(strVal(llast(aggname))),
- ObjectIdGetDatum(basetype),
- 0, 0);
- /* shouldn't happen --- caller should have checked already */
- if (!HeapTupleIsValid(aggtuple))
- agg_error("ParseAgg", aggname, basetype);
- aggform = (Form_pg_aggregate) GETSTRUCT(aggtuple);
-
- /*
- * There used to be a really ugly hack for count(*) here.
- *
- * It's gone. Now, the grammar transforms count(*) into count(1), which
- * does the right thing. (It didn't use to do the right thing,
- * because the optimizer had the wrong ideas about semantics of
- * queries without explicit variables. Fixed as of Oct 1999 --- tgl.)
- */
-
- /*
- * We assume caller has already checked that given args are compatible
- * with the agg's basetype.
- */
-
- aggref = makeNode(Aggref);
- aggref->aggname = pstrdup(strVal(llast(aggname)));
- aggref->basetype = aggform->aggbasetype;
- aggref->aggtype = aggform->aggfinaltype;
- aggref->target = lfirst(args);
- aggref->aggstar = agg_star;
- aggref->aggdistinct = agg_distinct;
-
- ReleaseSysCache(aggtuple);
-
- pstate->p_hasAggs = true;
-
- return aggref;
-}
-
-/*
- * Error message when aggregate lookup fails that gives details of the
- * basetype
- */
-void
-agg_error(const char *caller, List *aggname, Oid basetypeID)
-{
- /*
- * basetypeID that is Invalid (zero) means aggregate over all types.
- * (count)
- */
-
- if (basetypeID == InvalidOid)
- elog(ERROR, "%s: aggregate '%s' for all types does not exist",
- caller, NameListToString(aggname));
- else
- elog(ERROR, "%s: aggregate '%s' for type %s does not exist",
- caller, NameListToString(aggname), format_type_be(basetypeID));
-}
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 4dd5777e1e1..aca5afc1243 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.69 2002/04/09 20:35:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.70 2002/04/11 20:00:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,7 +32,7 @@ Oid PromoteTypeToNext(Oid inType);
static Oid PreferredType(CATEGORY category, Oid type);
static Node *build_func_call(Oid funcid, Oid rettype, List *args);
static Oid find_coercion_function(Oid targetTypeId, Oid inputTypeId,
- Oid secondArgType);
+ Oid secondArgType, bool isExplicit);
/* coerce_type()
@@ -40,7 +40,7 @@ static Oid find_coercion_function(Oid targetTypeId, Oid inputTypeId,
*/
Node *
coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
- Oid targetTypeId, int32 atttypmod)
+ Oid targetTypeId, int32 atttypmod, bool isExplicit)
{
Node *result;
@@ -131,7 +131,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
funcId = find_coercion_function(baseTypeId,
getBaseType(inputTypeId),
- InvalidOid);
+ InvalidOid,
+ isExplicit);
if (!OidIsValid(funcId))
elog(ERROR, "coerce_type: no conversion function from %s to %s",
format_type_be(inputTypeId), format_type_be(targetTypeId));
@@ -171,13 +172,18 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
*
* There are a few types which are known apriori to be convertible.
* We will check for those cases first, and then look for possible
- * conversion functions.
+ * conversion functions.
+ *
+ * We must be told whether this is an implicit or explicit coercion
+ * (explicit being a CAST construct, explicit function call, etc).
+ * We will accept a wider set of coercion cases for an explicit coercion.
*
* Notes:
* This uses the same mechanism as the CAST() SQL construct in gram.y.
*/
bool
-can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
+can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
+ bool isExplicit)
{
int i;
@@ -230,7 +236,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
return false;
/*
- * Else, try for explicit conversion using functions: look for a
+ * Else, try for run-time conversion using functions: look for a
* single-argument function named with the target type name and
* accepting the source type.
*
@@ -238,7 +244,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
*/
funcId = find_coercion_function(getBaseType(targetTypeId),
getBaseType(inputTypeId),
- InvalidOid);
+ InvalidOid,
+ isExplicit);
if (!OidIsValid(funcId))
return false;
}
@@ -279,7 +286,8 @@ coerce_type_typmod(ParseState *pstate, Node *node,
/* If given type is a domain, use base type instead */
baseTypeId = getBaseType(targetTypeId);
- funcId = find_coercion_function(baseTypeId, baseTypeId, INT4OID);
+ /* Note this is always implicit coercion */
+ funcId = find_coercion_function(baseTypeId, baseTypeId, INT4OID, false);
if (OidIsValid(funcId))
{
@@ -321,9 +329,10 @@ coerce_to_boolean(ParseState *pstate, Node **pnode)
if (inputTypeId == BOOLOID)
return true; /* no work */
targetTypeId = BOOLOID;
- if (!can_coerce_type(1, &inputTypeId, &targetTypeId))
+ if (!can_coerce_type(1, &inputTypeId, &targetTypeId, false))
return false; /* fail, but let caller choose error msg */
- *pnode = coerce_type(pstate, *pnode, inputTypeId, targetTypeId, -1);
+ *pnode = coerce_type(pstate, *pnode, inputTypeId, targetTypeId, -1,
+ false);
return true;
}
@@ -378,7 +387,7 @@ select_common_type(List *typeids, const char *context)
}
else if (IsPreferredType(pcategory, ntype)
&& !IsPreferredType(pcategory, ptype)
- && can_coerce_type(1, &ptype, &ntype))
+ && can_coerce_type(1, &ptype, &ntype, false))
{
/*
* new one is preferred and can convert? then take it...
@@ -424,8 +433,9 @@ coerce_to_common_type(ParseState *pstate, Node *node,
if (inputTypeId == targetTypeId)
return node; /* no work */
- if (can_coerce_type(1, &inputTypeId, &targetTypeId))
- node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1);
+ if (can_coerce_type(1, &inputTypeId, &targetTypeId, false))
+ node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
+ false);
else
{
elog(ERROR, "%s unable to convert to type \"%s\"",
@@ -659,6 +669,9 @@ PreferredType(CATEGORY category, Oid type)
* A coercion function must be named after (the internal name of) its
* result type, and must accept exactly the specified input type. We
* also require it to be defined in the same namespace as its result type.
+ * Furthermore, unless we are doing explicit coercion the function must
+ * be marked as usable for implicit coercion --- this allows coercion
+ * functions to be provided that aren't implicitly invokable.
*
* This routine is also used to look for length-coercion functions, which
* are similar but accept a second argument. secondArgType is the type
@@ -668,16 +681,16 @@ PreferredType(CATEGORY category, Oid type)
* If a function is found, return its pg_proc OID; else return InvalidOid.
*/
static Oid
-find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType)
+find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType,
+ bool isExplicit)
{
+ Oid funcid = InvalidOid;
Type targetType;
char *typname;
Oid typnamespace;
Oid oid_array[FUNC_MAX_ARGS];
int nargs;
HeapTuple ftup;
- Form_pg_proc pform;
- Oid funcid;
targetType = typeidType(targetTypeId);
typname = NameStr(((Form_pg_type) GETSTRUCT(targetType))->typname);
@@ -698,21 +711,24 @@ find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType)
Int16GetDatum(nargs),
PointerGetDatum(oid_array),
ObjectIdGetDatum(typnamespace));
- if (!HeapTupleIsValid(ftup))
- {
- ReleaseSysCache(targetType);
- return InvalidOid;
- }
- /* Make sure the function's result type is as expected, too */
- pform = (Form_pg_proc) GETSTRUCT(ftup);
- if (pform->prorettype != targetTypeId)
+ if (HeapTupleIsValid(ftup))
{
+ Form_pg_proc pform = (Form_pg_proc) GETSTRUCT(ftup);
+
+ /* Make sure the function's result type is as expected */
+ if (pform->prorettype == targetTypeId && !pform->proretset &&
+ !pform->proisagg)
+ {
+ /* If needed, make sure it can be invoked implicitly */
+ if (isExplicit || pform->proimplicit)
+ {
+ /* Okay to use it */
+ funcid = ftup->t_data->t_oid;
+ }
+ }
ReleaseSysCache(ftup);
- ReleaseSysCache(targetType);
- return InvalidOid;
}
- funcid = ftup->t_data->t_oid;
- ReleaseSysCache(ftup);
+
ReleaseSysCache(targetType);
return funcid;
}
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index f8449716061..916c1da4a68 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.113 2002/04/09 20:35:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.114 2002/04/11 20:00:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1174,7 +1174,8 @@ parser_typecast_expression(ParseState *pstate,
if (inputType != targetType)
{
expr = CoerceTargetExpr(pstate, expr, inputType,
- targetType, typename->typmod);
+ targetType, typename->typmod,
+ true); /* explicit coercion */
if (expr == NULL)
elog(ERROR, "Cannot cast type '%s' to '%s'",
format_type_be(inputType),
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index a86195126ff..2ab9c9a6898 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,23 +8,18 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.125 2002/04/09 20:35:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.126 2002/04/11 20:00:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catname.h"
-#include "catalog/indexing.h"
#include "catalog/namespace.h"
-#include "catalog/pg_aggregate.h"
#include "catalog/pg_inherits.h"
-#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "nodes/makefuncs.h"
-#include "parser/parse_agg.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
@@ -35,6 +30,7 @@
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+
static Node *ParseComplexProjection(ParseState *pstate,
char *funcname,
Node *first_arg);
@@ -54,9 +50,6 @@ static int match_argtypes(int nargs,
static FieldSelect *setup_field_select(Node *input, char *attname, Oid relid);
static FuncCandidateList func_select_candidate(int nargs, Oid *input_typeids,
FuncCandidateList candidates);
-static int agg_get_candidates(List *aggname, Oid typeId,
- FuncCandidateList *candidates);
-static Oid agg_select_candidate(Oid typeid, FuncCandidateList candidates);
/*
@@ -89,14 +82,10 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
char *refname;
int nargs = length(fargs);
int argn;
- Func *funcnode;
Oid oid_array[FUNC_MAX_ARGS];
Oid *true_oid_array;
Node *retval;
bool retset;
- bool must_be_agg = agg_star || agg_distinct;
- bool could_be_agg;
- Expr *expr;
FuncDetailCode fdresult;
/*
@@ -123,7 +112,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
* then the "function call" could be a projection. We also check
* that there wasn't any aggregate decoration.
*/
- if (nargs == 1 && !must_be_agg && length(funcname) == 1)
+ if (nargs == 1 && !agg_star && !agg_distinct && length(funcname) == 1)
{
char *cname = strVal(lfirst(funcname));
@@ -152,84 +141,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
}
/*
- * See if it's an aggregate.
- */
- if (must_be_agg)
- {
- /* We don't presently cope with, eg, foo(DISTINCT x,y) */
- if (nargs != 1)
- elog(ERROR, "Aggregate functions may only have one parameter");
- /* Agg's argument can't be a relation name, either */
- if (IsA(first_arg, RangeVar))
- elog(ERROR, "Aggregate functions cannot be applied to relation names");
- could_be_agg = true;
- }
- else
- {
- /* Try to parse as an aggregate if above-mentioned checks are OK */
- could_be_agg = (nargs == 1) && !(IsA(first_arg, RangeVar));
- }
-
- if (could_be_agg)
- {
- Oid basetype = exprType(lfirst(fargs));
- int ncandidates;
- FuncCandidateList candidates;
-
- /* try for exact match first... */
- if (SearchSysCacheExists(AGGNAME,
- PointerGetDatum(strVal(llast(funcname))),
- ObjectIdGetDatum(basetype),
- 0, 0))
- return (Node *) ParseAgg(pstate, funcname, basetype,
- fargs, agg_star, agg_distinct);
-
- /* check for aggregate-that-accepts-any-type (eg, COUNT) */
- if (SearchSysCacheExists(AGGNAME,
- PointerGetDatum(strVal(llast(funcname))),
- ObjectIdGetDatum(0),
- 0, 0))
- return (Node *) ParseAgg(pstate, funcname, 0,
- fargs, agg_star, agg_distinct);
-
- /*
- * No exact match yet, so see if there is another entry in the
- * aggregate table that 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, -1);
- basetype = type;
- return (Node *) ParseAgg(pstate, funcname, basetype,
- fargs, agg_star, agg_distinct);
- }
- else
- {
- /* Multiple possible matches --- give up */
- elog(ERROR, "Unable to select an aggregate function %s(%s)",
- NameListToString(funcname), format_type_be(basetype));
- }
- }
-
- if (must_be_agg)
- {
- /*
- * No matching agg, but we had '*' or DISTINCT, so a plain
- * function could not have been meant.
- */
- elog(ERROR, "There is no aggregate function %s(%s)",
- NameListToString(funcname), format_type_be(basetype));
- }
- }
-
- /*
* Okay, it's not a column projection, so it must really be a function.
* Extract arg type info and transform RangeVar arguments into varnodes
* of the appropriate form.
@@ -321,9 +232,22 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
* these cases, so why duplicate code...
*/
return coerce_type(pstate, lfirst(fargs),
- oid_array[0], rettype, -1);
+ oid_array[0], rettype, -1, true);
}
- if (fdresult != FUNCDETAIL_NORMAL)
+ else if (fdresult == FUNCDETAIL_NORMAL)
+ {
+ /*
+ * Normal function found; was there anything indicating it must be
+ * an aggregate?
+ */
+ if (agg_star)
+ elog(ERROR, "%s(*) specified, but %s is not an aggregate function",
+ NameListToString(funcname), NameListToString(funcname));
+ if (agg_distinct)
+ elog(ERROR, "DISTINCT specified, but %s is not an aggregate function",
+ NameListToString(funcname));
+ }
+ else if (fdresult != FUNCDETAIL_AGGREGATE)
{
/*
* Oops. Time to die.
@@ -341,165 +265,62 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
"\n\tYou may need to add explicit typecasts");
}
- /* got it */
- funcnode = makeNode(Func);
- funcnode->funcid = funcid;
- funcnode->functype = rettype;
- funcnode->func_fcache = NULL;
-
/* perform the necessary typecasting of arguments */
make_arguments(pstate, nargs, fargs, oid_array, true_oid_array);
- expr = makeNode(Expr);
- expr->typeOid = rettype;
- expr->opType = FUNC_EXPR;
- expr->oper = (Node *) funcnode;
- expr->args = fargs;
- retval = (Node *) expr;
-
- /*
- * if the function returns a set of values, then we need to iterate
- * over all the returned values in the executor, so we stick an iter
- * node here. if it returns a singleton, then we don't need the iter
- * node.
- */
- if (retset)
+ /* build the appropriate output structure */
+ if (fdresult == FUNCDETAIL_NORMAL)
{
- Iter *iter = makeNode(Iter);
-
- iter->itertype = rettype;
- iter->iterexpr = retval;
- retval = (Node *) iter;
- }
+ Expr *expr = makeNode(Expr);
+ Func *funcnode = makeNode(Func);
- return retval;
-}
-
-
-static int
-agg_get_candidates(List *aggname,
- Oid typeId,
- FuncCandidateList *candidates)
-{
- Relation pg_aggregate_desc;
- SysScanDesc pg_aggregate_scan;
- HeapTuple tup;
- int ncandidates = 0;
- ScanKeyData aggKey[1];
+ funcnode->funcid = funcid;
+ funcnode->functype = rettype;
+ funcnode->func_fcache = NULL;
- *candidates = NULL;
+ expr->typeOid = rettype;
+ expr->opType = FUNC_EXPR;
+ expr->oper = (Node *) funcnode;
+ expr->args = fargs;
- ScanKeyEntryInitialize(&aggKey[0], 0,
- Anum_pg_aggregate_aggname,
- F_NAMEEQ,
- NameGetDatum(strVal(llast(aggname))));
-
- pg_aggregate_desc = heap_openr(AggregateRelationName, AccessShareLock);
- pg_aggregate_scan = systable_beginscan(pg_aggregate_desc,
- AggregateNameTypeIndex, true,
- SnapshotNow,
- 1, aggKey);
-
- while (HeapTupleIsValid(tup = systable_getnext(pg_aggregate_scan)))
- {
- Form_pg_aggregate agg = (Form_pg_aggregate) GETSTRUCT(tup);
- FuncCandidateList current_candidate;
-
- current_candidate = (FuncCandidateList)
- palloc(sizeof(struct _FuncCandidateList));
- current_candidate->args[0] = agg->aggbasetype;
- current_candidate->next = *candidates;
- *candidates = current_candidate;
- ncandidates++;
- }
-
- systable_endscan(pg_aggregate_scan);
- heap_close(pg_aggregate_desc, AccessShareLock);
-
- return ncandidates;
-} /* agg_get_candidates() */
-
-/* agg_select_candidate()
- *
- * Try to choose only one candidate aggregate function from a list of
- * possible matches. Return value is Oid of input type of aggregate
- * if successful, else InvalidOid.
- */
-static Oid
-agg_select_candidate(Oid typeid, FuncCandidateList candidates)
-{
- FuncCandidateList current_candidate;
- FuncCandidateList last_candidate;
- Oid current_typeid;
- int ncandidates;
- CATEGORY category,
- current_category;
+ retval = (Node *) expr;
- /*
- * First look for exact matches or binary compatible matches. (Of
- * course exact matches shouldn't even get here, but anyway.)
- */
- ncandidates = 0;
- last_candidate = NULL;
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeid = current_candidate->args[0];
-
- if (IsBinaryCompatible(current_typeid, typeid))
+ /*
+ * if the function returns a set of values, then we need to iterate
+ * over all the returned values in the executor, so we stick an iter
+ * node here. if it returns a singleton, then we don't need the iter
+ * node.
+ */
+ if (retset)
{
- last_candidate = current_candidate;
- ncandidates++;
+ Iter *iter = makeNode(Iter);
+
+ iter->itertype = rettype;
+ iter->iterexpr = retval;
+ retval = (Node *) iter;
}
}
- if (ncandidates == 1)
- return last_candidate->args[0];
-
- /*
- * If no luck that way, look for candidates which allow coercion 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)
+ else
{
- current_typeid = current_candidate->args[0];
- current_category = TypeCategory(current_typeid);
+ /* aggregate function */
+ Aggref *aggref = makeNode(Aggref);
- if (current_category == category
- && IsPreferredType(current_category, current_typeid)
- && can_coerce_type(1, &typeid, &current_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... */
- }
+ aggref->aggfnoid = funcid;
+ aggref->aggtype = rettype;
+ aggref->target = lfirst(fargs);
+ aggref->aggstar = agg_star;
+ aggref->aggdistinct = agg_distinct;
- if (last_candidate) /* terminate rebuilt list */
- last_candidate->next = NULL;
+ retval = (Node *) aggref;
- if (ncandidates == 1)
- return candidates->args[0];
+ if (retset)
+ elog(ERROR, "Aggregates may not return sets");
- return InvalidOid;
-} /* agg_select_candidate() */
+ pstate->p_hasAggs = true;
+ }
+
+ return retval;
+}
/* match_argtypes()
@@ -529,7 +350,8 @@ match_argtypes(int nargs,
current_candidate = next_candidate)
{
next_candidate = current_candidate->next;
- if (can_coerce_type(nargs, input_typeids, current_candidate->args))
+ if (can_coerce_type(nargs, input_typeids, current_candidate->args,
+ false))
{
current_candidate->next = *candidates;
*candidates = current_candidate;
@@ -1014,6 +836,7 @@ func_get_detail(List *funcname,
{
HeapTuple ftup;
Form_pg_proc pform;
+ FuncDetailCode result;
*funcid = best_candidate->oid;
*true_typeids = best_candidate->args;
@@ -1026,8 +849,9 @@ func_get_detail(List *funcname,
pform = (Form_pg_proc) GETSTRUCT(ftup);
*rettype = pform->prorettype;
*retset = pform->proretset;
+ result = pform->proisagg ? FUNCDETAIL_AGGREGATE : FUNCDETAIL_NORMAL;
ReleaseSysCache(ftup);
- return FUNCDETAIL_NORMAL;
+ return result;
}
return FUNCDETAIL_NOTFOUND;
@@ -1294,7 +1118,8 @@ make_arguments(ParseState *pstate,
lfirst(current_fargs) = coerce_type(pstate,
lfirst(current_fargs),
input_typeids[i],
- function_typeids[i], -1);
+ function_typeids[i], -1,
+ false);
}
}
}
@@ -1451,6 +1276,58 @@ func_error(const char *caller, List *funcname,
}
/*
+ * find_aggregate_func
+ * Convenience routine to check that a function exists and is an
+ * aggregate.
+ *
+ * Note: basetype is InvalidOid if we are looking for an aggregate on
+ * all types.
+ */
+Oid
+find_aggregate_func(const char *caller, List *aggname, Oid basetype)
+{
+ Oid oid;
+ HeapTuple ftup;
+ Form_pg_proc pform;
+
+ oid = LookupFuncName(aggname, 1, &basetype);
+
+ if (!OidIsValid(oid))
+ {
+ if (basetype == InvalidOid)
+ elog(ERROR, "%s: aggregate '%s' for all types does not exist",
+ caller, NameListToString(aggname));
+ else
+ elog(ERROR, "%s: aggregate '%s' for type %s does not exist",
+ caller, NameListToString(aggname),
+ format_type_be(basetype));
+ }
+
+ /* Make sure it's an aggregate */
+ ftup = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(oid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(ftup)) /* should not happen */
+ elog(ERROR, "function %u not found", oid);
+ pform = (Form_pg_proc) GETSTRUCT(ftup);
+
+ if (!pform->proisagg)
+ {
+ if (basetype == InvalidOid)
+ elog(ERROR, "%s: function %s(*) is not an aggregate",
+ caller, NameListToString(aggname));
+ else
+ elog(ERROR, "%s: function %s(%s) is not an aggregate",
+ caller, NameListToString(aggname),
+ format_type_be(basetype));
+ }
+
+ ReleaseSysCache(ftup);
+
+ return oid;
+}
+
+/*
* LookupFuncName
* Given a possibly-qualified function name and a set of argument types,
* look up the function. Returns InvalidOid if no such function.
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 8b259e97c1d..0868f3f0bb8 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.60 2002/03/21 16:01:07 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.61 2002/04/11 20:00:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -73,7 +73,8 @@ make_operand(char *opname,
{
/* must coerce? */
if (target_typeId != orig_typeId)
- result = coerce_type(NULL, tree, orig_typeId, target_typeId, -1);
+ result = coerce_type(NULL, tree, orig_typeId, target_typeId, -1,
+ false);
else
result = tree;
}
@@ -288,7 +289,7 @@ transformArraySubscripts(ParseState *pstate,
subexpr = transformExpr(pstate, ai->lidx);
/* If it's not int4 already, try to coerce */
subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
- INT4OID, -1);
+ INT4OID, -1, false);
if (subexpr == NULL)
elog(ERROR, "array index expressions must be integers");
}
@@ -308,7 +309,7 @@ transformArraySubscripts(ParseState *pstate,
subexpr = transformExpr(pstate, ai->uidx);
/* If it's not int4 already, try to coerce */
subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
- INT4OID, -1);
+ INT4OID, -1, false);
if (subexpr == NULL)
elog(ERROR, "array index expressions must be integers");
upperIndexpr = lappend(upperIndexpr, subexpr);
@@ -329,7 +330,7 @@ transformArraySubscripts(ParseState *pstate,
/* XXX fixme: need to get the array's atttypmod? */
assignFrom = CoerceTargetExpr(pstate, assignFrom,
typesource, typeneeded,
- -1);
+ -1, false);
if (assignFrom == NULL)
elog(ERROR, "Array assignment requires type '%s'"
" but expression is of type '%s'"
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 8495f9f9e65..028bfab4319 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.53 2002/03/20 19:44:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.54 2002/04/11 20:00:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -265,7 +265,8 @@ oper_select_candidate(int nargs,
current_candidate != NULL;
current_candidate = current_candidate->next)
{
- if (can_coerce_type(nargs, input_typeids, current_candidate->args))
+ if (can_coerce_type(nargs, input_typeids, current_candidate->args,
+ false))
{
if (last_candidate == NULL)
{
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 83c53de5d1d..9f97ab0f4cb 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.83 2002/04/09 20:35:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.84 2002/04/11 20:00:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -290,7 +290,8 @@ updateTargetListEntry(ParseState *pstate,
if (type_id != attrtype)
{
tle->expr = CoerceTargetExpr(pstate, tle->expr, type_id,
- attrtype, attrtypmod);
+ attrtype, attrtypmod,
+ false);
if (tle->expr == NULL)
elog(ERROR, "column \"%s\" is of type '%s'"
" but expression is of type '%s'"
@@ -327,10 +328,12 @@ CoerceTargetExpr(ParseState *pstate,
Node *expr,
Oid type_id,
Oid attrtype,
- int32 attrtypmod)
+ int32 attrtypmod,
+ bool isExplicit)
{
- if (can_coerce_type(1, &type_id, &attrtype))
- expr = coerce_type(pstate, expr, type_id, attrtype, attrtypmod);
+ if (can_coerce_type(1, &type_id, &attrtype, isExplicit))
+ expr = coerce_type(pstate, expr, type_id, attrtype, attrtypmod,
+ isExplicit);
#ifndef DISABLE_STRING_HACKS
@@ -345,8 +348,9 @@ CoerceTargetExpr(ParseState *pstate,
if (type_id == TEXTOID)
{
}
- else if (can_coerce_type(1, &type_id, &text_id))
- expr = coerce_type(pstate, expr, type_id, text_id, attrtypmod);
+ else if (can_coerce_type(1, &type_id, &text_id, isExplicit))
+ expr = coerce_type(pstate, expr, type_id, text_id, attrtypmod,
+ isExplicit);
else
expr = NULL;
}