Commit d14c8aab authored by Tom Lane's avatar Tom Lane

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.
parent d4a2c86e
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -103,6 +103,11 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
result = (Node *) relabel; result = (Node *) relabel;
} }
else if (typeInheritsFrom(inputTypeId, targetTypeId))
{
/* Input class type is a subclass of target, so nothing to do */
result = node;
}
else else
{ {
/* /*
...@@ -156,62 +161,69 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, ...@@ -156,62 +161,69 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
bool bool
can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids) can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
{ {
HeapTuple ftup;
int i; int i;
Type tp; HeapTuple ftup;
Oid oid_array[FUNC_MAX_ARGS]; Oid oid_array[FUNC_MAX_ARGS];
/* run through argument list... */ /* run through argument list... */
for (i = 0; i < nargs; i++) 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 */
* one of the known-good transparent conversions? then drop if (inputTypeId == targetTypeId)
* through... continue;
*/
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) * one of the known-good transparent conversions? then drop
return false; * through...
/* don't know what to do for the input type? then quit... */ */
else if (input_typeids[i] == InvalidOid) if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
return false; continue;
/* /* don't know what to do for the output type? then quit... */
* if not unknown input type, try for explicit conversion if (targetTypeId == InvalidOid)
* using functions... return false;
*/ /* don't know what to do for the input type? then quit... */
else if (input_typeids[i] != UNKNOWNOID) if (inputTypeId == InvalidOid)
{ return false;
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 input is an untyped string constant, assume we can
* convert it to anything except a class type.
*/
if (inputTypeId == UNKNOWNOID)
{
if (ISCOMPLEX(targetTypeId))
return false; 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; return true;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -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 int agg_get_candidates(char *aggname, Oid typeId, CandidateList *candidates);
static Oid agg_select_candidate(Oid typeid, CandidateList candidates); static Oid agg_select_candidate(Oid typeid, CandidateList candidates);
#define ISCOMPLEX(type) (typeidTypeRelid(type) ? true : false)
/* /*
** ParseNestedFuncOrColumn ** ParseNestedFuncOrColumn
...@@ -1360,6 +1359,40 @@ gen_cross_product(InhPaths *arginh, int nargs) ...@@ -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() /* make_arguments()
* Given the number and types of arguments to a function, and the * Given the number and types of arguments to a function, and the
* actual arguments and argument types, do the necessary typecasting. * actual arguments and argument types, do the necessary typecasting.
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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, ...@@ -47,6 +47,8 @@ extern Node *ParseFuncOrColumn(ParseState *pstate,
extern List *setup_base_tlist(Oid typeid); extern List *setup_base_tlist(Oid typeid);
extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
extern void func_error(char *caller, char *funcname, extern void func_error(char *caller, char *funcname,
int nargs, Oid *argtypes, char *msg); int nargs, Oid *argtypes, char *msg);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -35,4 +35,6 @@ extern Oid GetArrayElementType(Oid typearray);
extern Oid typeInfunc(Type typ); extern Oid typeInfunc(Type typ);
extern Oid typeOutfunc(Type typ); extern Oid typeOutfunc(Type typ);
#define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid)
#endif /* PARSE_TYPE_H */ #endif /* PARSE_TYPE_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment