diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index ce06da2669..f37082a87f 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.35 2000/03/14 23:06:32 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.36 2000/03/16 06:35:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -103,6 +103,11 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, result = (Node *) relabel; } + else if (typeInheritsFrom(inputTypeId, targetTypeId)) + { + /* Input class type is a subclass of target, so nothing to do */ + result = node; + } else { /* @@ -156,62 +161,69 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids) { - HeapTuple ftup; int i; - Type tp; + HeapTuple ftup; Oid oid_array[FUNC_MAX_ARGS]; /* run through argument list... */ for (i = 0; i < nargs; i++) { - if (input_typeids[i] != func_typeids[i]) + Oid inputTypeId = input_typeids[i]; + Oid targetTypeId = func_typeids[i]; + + /* no problem if same type */ + if (inputTypeId == targetTypeId) + continue; + + /* + * one of the known-good transparent conversions? then drop + * through... + */ + if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId)) + continue; + + /* don't know what to do for the output type? then quit... */ + if (targetTypeId == InvalidOid) + return false; + /* don't know what to do for the input type? then quit... */ + if (inputTypeId == InvalidOid) + return false; + + /* + * If input is an untyped string constant, assume we can + * convert it to anything except a class type. + */ + if (inputTypeId == UNKNOWNOID) { - - /* - * one of the known-good transparent conversions? then drop - * through... - */ - if (IS_BINARY_COMPATIBLE(input_typeids[i], func_typeids[i])) - ; - - /* don't know what to do for the output type? then quit... */ - else if (func_typeids[i] == InvalidOid) - return false; - /* don't know what to do for the input type? then quit... */ - else if (input_typeids[i] == InvalidOid) - return false; - - /* - * if not unknown input type, try for explicit conversion - * using functions... - */ - else if (input_typeids[i] != UNKNOWNOID) - { - MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid)); - oid_array[0] = input_typeids[i]; - - /* - * look for a single-argument function named with the - * target type name - */ - ftup = SearchSysCacheTuple(PROCNAME, - PointerGetDatum(typeidTypeName(func_typeids[i])), - Int32GetDatum(1), - PointerGetDatum(oid_array), - 0); - - /* - * should also check the function return type just to be - * safe... - */ - if (!HeapTupleIsValid(ftup)) - return false; - } - - tp = typeidType(input_typeids[i]); - if (typeTypeFlag(tp) == 'c') + if (ISCOMPLEX(targetTypeId)) return false; + continue; } + + /* + * If input is a class type that inherits from target, no problem + */ + if (typeInheritsFrom(inputTypeId, targetTypeId)) + continue; + + /* + * Else, try for explicit conversion using functions: + * look for a single-argument function named with the + * target type name and accepting the source type. + */ + MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid)); + oid_array[0] = inputTypeId; + + ftup = SearchSysCacheTuple(PROCNAME, + PointerGetDatum(typeidTypeName(targetTypeId)), + Int32GetDatum(1), + PointerGetDatum(oid_array), + 0); + if (!HeapTupleIsValid(ftup)) + return false; + /* + * should also check the function return type just to be safe... + */ } return true; diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index eb4884accb..e24007a439 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.74 2000/03/14 23:06:32 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.75 2000/03/16 06:35:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -68,7 +68,6 @@ static Oid *func_select_candidate(int nargs, Oid *input_typeids, 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) /* ** ParseNestedFuncOrColumn @@ -1360,6 +1359,40 @@ gen_cross_product(InhPaths *arginh, int nargs) } +/* + * Given two type OIDs, determine whether the first is a complex type + * (class type) that inherits from the second. + */ +bool +typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId) +{ + Oid relid; + Oid *supervec; + int nsupers, + i; + bool result; + + if (!ISCOMPLEX(subclassTypeId) || !ISCOMPLEX(superclassTypeId)) + return false; + relid = typeidTypeRelid(subclassTypeId); + if (relid == InvalidOid) + return false; + nsupers = find_inheritors(relid, &supervec); + result = false; + for (i = 0; i < nsupers; i++) + { + if (supervec[i] == superclassTypeId) + { + result = true; + break; + } + } + if (supervec) + pfree(supervec); + return result; +} + + /* make_arguments() * Given the number and types of arguments to a function, and the * actual arguments and argument types, do the necessary typecasting. diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h index 9ee1720370..b191944ee2 100644 --- a/src/include/parser/parse_func.h +++ b/src/include/parser/parse_func.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_func.h,v 1.22 2000/01/26 05:58:27 momjian Exp $ + * $Id: parse_func.h,v 1.23 2000/03/16 06:35:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -47,6 +47,8 @@ extern Node *ParseFuncOrColumn(ParseState *pstate, extern List *setup_base_tlist(Oid typeid); +extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId); + extern void func_error(char *caller, char *funcname, int nargs, Oid *argtypes, char *msg); diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h index 034c47b8b0..190d65db4d 100644 --- a/src/include/parser/parse_type.h +++ b/src/include/parser/parse_type.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_type.h,v 1.12 2000/01/26 05:58:27 momjian Exp $ + * $Id: parse_type.h,v 1.13 2000/03/16 06:35:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,4 +35,6 @@ extern Oid GetArrayElementType(Oid typearray); extern Oid typeInfunc(Type typ); extern Oid typeOutfunc(Type typ); +#define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid) + #endif /* PARSE_TYPE_H */