OSDN Git Service

Turns out that Mazurkiewicz's gripe about 'function inheritance' is
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 16 Mar 2000 06:35:07 +0000 (06:35 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 ce06da2..f37082a 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 eb4884a..e24007a 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 9ee1720..b191944 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 034c47b..190d65d 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 */