]> granicus.if.org Git - postgresql/commitdiff
Don't generate 'zero' typeids in the output from gen_cross_product.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 25 Jun 2003 20:07:39 +0000 (20:07 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 25 Jun 2003 20:07:39 +0000 (20:07 +0000)
This is no longer necessary or appropriate since we don't use zero typeid
as a wildcard anymore, and it fixes a nasty performance problem with
functions with many parameters.  Per recent example from Reuven Lerner.

src/backend/parser/parse_func.c

index 5ff2bc6d81973adfa4d5170d1d11eabe6534e4ae..2b0e10e4ca1ff08680e6bd042508bd9d549f0ee6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.150 2003/06/24 23:14:45 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.151 2003/06/25 20:07:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -925,23 +925,29 @@ func_get_detail(List *funcname,
  *     argtype_inherit() -- Construct an argtype vector reflecting the
  *                                              inheritance properties of the supplied argv.
  *
- *             This function is used to disambiguate among functions with the
- *             same name but different signatures.  It takes an array of input
- *             type ids.  For each type id in the array that's a complex type
- *             (a class), it walks up the inheritance tree, finding all
- *             superclasses of that type.      A vector of new Oid type arrays
- *             is returned to the caller, reflecting the structure of the
- *             inheritance tree above the supplied arguments.
+ *             This function is used to handle resolution of function calls when
+ *             there is no match to the given argument types, but there might be
+ *             matches based on considering complex types as members of their
+ *             superclass types (parent classes).
+ *
+ *             It takes an array of input type ids.  For each type id in the array
+ *             that's a complex type (a class), it walks up the inheritance tree,
+ *             finding all superclasses of that type. A vector of new Oid type
+ *             arrays is returned to the caller, listing possible alternative
+ *             interpretations of the input typeids as members of their superclasses
+ *             rather than the actually given argument types.  The vector is
+ *             terminated by a NULL pointer.
  *
  *             The order of this vector is as follows:  all superclasses of the
  *             rightmost complex class are explored first.  The exploration
  *             continues from right to left.  This policy means that we favor
  *             keeping the leftmost argument type as low in the inheritance tree
  *             as possible.  This is intentional; it is exactly what we need to
- *             do for method dispatch.  The last type array we return is all
- *             zeroes.  This will match any functions for which return types are
- *             not defined.  There are lots of these (mostly builtins) in the
- *             catalogs.
+ *             do for method dispatch.
+ *
+ *             The vector does not include the case where no complex classes have
+ *             been promoted, since that was already tried before this routine
+ *             got called.
  */
 static Oid **
 argtype_inherit(int nargs, Oid *argtypes)
@@ -950,22 +956,13 @@ argtype_inherit(int nargs, Oid *argtypes)
        int                     i;
        InhPaths        arginh[FUNC_MAX_ARGS];
 
-       for (i = 0; i < FUNC_MAX_ARGS; i++)
+       for (i = 0; i < nargs; i++)
        {
-               if (i < nargs)
-               {
-                       arginh[i].self = argtypes[i];
-                       if ((relid = typeidTypeRelid(argtypes[i])) != InvalidOid)
-                               arginh[i].nsupers = find_inheritors(relid, &(arginh[i].supervec));
-                       else
-                       {
-                               arginh[i].nsupers = 0;
-                               arginh[i].supervec = (Oid *) NULL;
-                       }
-               }
+               arginh[i].self = argtypes[i];
+               if ((relid = typeidTypeRelid(argtypes[i])) != InvalidOid)
+                       arginh[i].nsupers = find_inheritors(relid, &(arginh[i].supervec));
                else
                {
-                       arginh[i].self = InvalidOid;
                        arginh[i].nsupers = 0;
                        arginh[i].supervec = (Oid *) NULL;
                }
@@ -975,6 +972,13 @@ argtype_inherit(int nargs, Oid *argtypes)
        return gen_cross_product(arginh, nargs);
 }
 
+/*
+ * Look up the parent superclass(es) of the given relation.
+ *
+ * *supervec is set to an array of the type OIDs (not the relation OIDs)
+ * of the parents, with nearest ancestors listed first.  It's set to NULL
+ * if there are no parents.  The return value is the number of parents.
+ */
 static int
 find_inheritors(Oid relid, Oid **supervec)
 {
@@ -1068,58 +1072,81 @@ find_inheritors(Oid relid, Oid **supervec)
        return nvisited;
 }
 
+/*
+ * Generate the ordered list of substitute argtype vectors to try.
+ *
+ * See comments for argtype_inherit.
+ */
 static Oid **
 gen_cross_product(InhPaths *arginh, int nargs)
 {
        int                     nanswers;
-       Oid               **result,
-                         **iter;
+       Oid               **result;
        Oid                *oneres;
        int                     i,
                                j;
        int                     cur[FUNC_MAX_ARGS];
 
+       /*
+        * At each position we want to try the original datatype, plus each
+        * supertype.  So the number of possible combinations is this:
+        */
        nanswers = 1;
        for (i = 0; i < nargs; i++)
-       {
-               nanswers *= (arginh[i].nsupers + 2);
-               cur[i] = 0;
-       }
+               nanswers *= (arginh[i].nsupers + 1);
 
-       iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers);
+       /*
+        * We also need an extra slot for the terminating NULL in the result
+        * array, but that cancels out with the fact that we don't want to
+        * generate the zero-changes case.  So we need exactly nanswers slots.
+        */
+       result = (Oid **) palloc(sizeof(Oid *) * nanswers);
+       j = 0;
+
+       /*
+        * Compute the cross product from right to left.  When cur[i] == 0,
+        * generate the original input type at position i.  When cur[i] == k
+        * for k > 0, generate its k'th supertype.
+        */
+       MemSet(cur, 0, sizeof(cur));
 
-       /* compute the cross product from right to left */
        for (;;)
        {
-               oneres = (Oid *) palloc0(FUNC_MAX_ARGS * sizeof(Oid));
-
-               for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--)
-                       continue;
+               /*
+                * Find a column we can increment.  All the columns after it get
+                * reset to zero.  (Essentially, we're adding one to the multi-
+                * digit number represented by cur[].)
+                */
+               for (i = nargs - 1; i >= 0 && cur[i] >= arginh[i].nsupers; i--)
+                       cur[i] = 0;
 
-               /* if we're done, terminate with NULL pointer */
+               /* if none, we're done */
                if (i < 0)
-               {
-                       *iter = NULL;
-                       return result;
-               }
+                       break;
 
-               /* no, increment this column and zero the ones after it */
-               cur[i] = cur[i] + 1;
-               for (j = nargs - 1; j > i; j--)
-                       cur[j] = 0;
+               /* increment this column */
+               cur[i] += 1;
+
+               /* Generate the proper output type-OID vector */
+               oneres = (Oid *) palloc0(FUNC_MAX_ARGS * sizeof(Oid));
 
                for (i = 0; i < nargs; i++)
                {
                        if (cur[i] == 0)
                                oneres[i] = arginh[i].self;
-                       else if (cur[i] > arginh[i].nsupers)
-                               oneres[i] = 0;  /* wild card */
                        else
                                oneres[i] = arginh[i].supervec[cur[i] - 1];
                }
 
-               *iter++ = oneres;
+               result[j++] = oneres;
        }
+
+       /* terminate result vector with NULL pointer */
+       result[j++] = NULL;
+
+       Assert(j == nanswers);
+
+       return result;
 }