Turns out that Mazurkiewicz's gripe about 'function inheritance' is

actually a type-coercion problem.  If you have a function defined on
class A, and class B inherits from A, then the function ought to work
on class B as well --- but coerce_type didn't know that.  Now it does.
This commit is contained in:
Tom Lane 2000-03-16 06:35:07 +00:00
parent d4a2c86eaf
commit d14c8aab99
4 changed files with 101 additions and 52 deletions

View File

@ -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(input_typeids[i], func_typeids[i]))
;
if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
continue;
/* don't know what to do for the output type? then quit... */
else if (func_typeids[i] == InvalidOid)
if (targetTypeId == InvalidOid)
return false;
/* don't know what to do for the input type? then quit... */
else if (input_typeids[i] == InvalidOid)
if (inputTypeId == InvalidOid)
return false;
/*
* if not unknown input type, try for explicit conversion
* using functions...
* If input is an untyped string constant, assume we can
* convert it to anything except a class type.
*/
else if (input_typeids[i] != UNKNOWNOID)
if (inputTypeId == UNKNOWNOID)
{
MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
oid_array[0] = input_typeids[i];
if (ISCOMPLEX(targetTypeId))
return false;
continue;
}
/*
* look for a single-argument function named with the
* target type name
* 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(func_typeids[i])),
PointerGetDatum(typeidTypeName(targetTypeId)),
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')
return false;
}
/*
* should also check the function return type just to be safe...
*/
}
return true;

View File

@ -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.

View File

@ -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);

View File

@ -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 */