Turns out that Mazurkiewicz's gripe about 'function inheritance' is
authorTom Lane
Thu, 16 Mar 2000 06:35:07 +0000 (06:35 +0000)
committerTom Lane
Thu, 16 Mar 2000 06:35:07 +0000 (06:35 +0000)
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.

src/backend/parser/parse_coerce.c
src/backend/parser/parse_func.c
src/include/parser/parse_func.h
src/include/parser/parse_type.h

index ce06da2669e6d3038a27365cd453de27f948db7d..f37082a87f58d0d4986d718630fcc17c330c481a 100644 (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];
 
-           /*
-            * one of the known-good transparent conversions? then drop
-            * through...
-            */
-           if (IS_BINARY_COMPATIBLE(input_typeids[i], func_typeids[i]))
-               ;
+       /* no problem if same type */
+       if (inputTypeId == targetTypeId)
+           continue;
 
-           /* 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;
+       /*
+        * one of the known-good transparent conversions? then drop
+        * through...
+        */
+       if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
+           continue;
 
-           /*
-            * 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;
-           }
+       /* 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;
 
-           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;
+           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;
index eb4884accbbe6be6362b107d52d9e0b555445ea3..e24007a439313efd88fdce06086185b7c9250473 100644 (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.
index 9ee1720370876f13c3c23413653169a948869558..b191944ee2f3ac330fc259a37c66e7a4d0c87d04 100644 (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);
 
index 034c47b8b0b757e9ae49123fbf2e95978eef07bf..190d65db4d812b2c9736469d5d5cac7bbbc202fb 100644 (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 */