diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/parse_agg.c | 80 | ||||
-rw-r--r-- | src/backend/parser/parse_coerce.c | 74 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 5 | ||||
-rw-r--r-- | src/backend/parser/parse_func.c | 357 | ||||
-rw-r--r-- | src/backend/parser/parse_node.c | 11 | ||||
-rw-r--r-- | src/backend/parser/parse_oper.c | 5 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 18 |
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, ¤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... */ - } + 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; } |