diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 5ff2bc6d81..2b0e10e4ca 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -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)); + /* + * 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; - for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--) - continue; - - /* 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; }