diff options
Diffstat (limited to 'src/backend/parser/parse_func.c')
-rw-r--r-- | src/backend/parser/parse_func.c | 296 |
1 files changed, 45 insertions, 251 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index dd91b4b4d33..002e15a9fa2 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.178 2005/04/14 20:03:25 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.179 2005/04/23 22:09:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,10 +34,6 @@ static Node *ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg); -static Oid **argtype_inherit(int nargs, Oid *argtypes); - -static int find_inheritors(Oid relid, Oid **supervec); -static Oid **gen_cross_product(InhPaths *arginh, int nargs); static void unknown_attribute(ParseState *pstate, Node *relref, char *attname); @@ -754,63 +750,34 @@ func_get_detail(List *funcname, */ if (raw_candidates != NULL) { - Oid **input_typeid_vector = NULL; - Oid *current_input_typeids; + FuncCandidateList current_candidates; + int ncandidates; + + ncandidates = func_match_argtypes(nargs, + argtypes, + raw_candidates, + ¤t_candidates); + + /* one match only? then run with it... */ + if (ncandidates == 1) + best_candidate = current_candidates; /* - * First we will search with the given argtypes, then with - * variants based on replacing complex types with their - * inheritance ancestors. Stop as soon as any match is found. + * multiple candidates? then better decide or throw an error... */ - current_input_typeids = argtypes; - - do + else if (ncandidates > 1) { - FuncCandidateList current_candidates; - int ncandidates; - - ncandidates = func_match_argtypes(nargs, - current_input_typeids, - raw_candidates, - ¤t_candidates); - - /* one match only? then run with it... */ - if (ncandidates == 1) - { - best_candidate = current_candidates; - break; - } + best_candidate = func_select_candidate(nargs, + argtypes, + current_candidates); /* - * multiple candidates? then better decide or throw an - * error... + * If we were able to choose a best candidate, we're + * done. Otherwise, ambiguous function call. */ - if (ncandidates > 1) - { - best_candidate = func_select_candidate(nargs, - current_input_typeids, - current_candidates); - - /* - * If we were able to choose a best candidate, we're - * done. Otherwise, ambiguous function call. - */ - if (best_candidate) - break; + if (!best_candidate) return FUNCDETAIL_MULTIPLE; - } - - /* - * No match here, so try the next inherited type vector. - * First time through, we need to compute the list of - * vectors. - */ - if (input_typeid_vector == NULL) - input_typeid_vector = argtype_inherit(nargs, argtypes); - - current_input_typeids = *input_typeid_vector++; } - while (current_input_typeids != NULL); } } @@ -840,81 +807,27 @@ func_get_detail(List *funcname, return FUNCDETAIL_NOTFOUND; } -/* - * argtype_inherit() -- Construct an argtype vector reflecting the - * inheritance properties of the supplied argv. - * - * 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 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) -{ - Oid **result; - Oid relid; - int i; - InhPaths *arginh; - - /* Set up the vector of superclass information */ - arginh = (InhPaths *) palloc(nargs * sizeof(InhPaths)); - - for (i = 0; i < nargs; i++) - { - 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 = NULL; - } - } - - /* Compute an ordered cross-product of the classes involved */ - result = gen_cross_product(arginh, nargs); - - pfree(arginh); - - return result; -} /* - * 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. + * Given two type OIDs, determine whether the first is a complex type + * (class type) that inherits from the second. */ -static int -find_inheritors(Oid relid, Oid **supervec) +bool +typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId) { + bool result = false; + Oid relid; Relation inhrel; - int nvisited; List *visited, *queue; ListCell *queue_item; + if (!ISCOMPLEX(subclassTypeId) || !ISCOMPLEX(superclassTypeId)) + return false; + relid = typeidTypeRelid(subclassTypeId); + if (relid == InvalidOid) + return false; + /* * Begin the search at the relation itself, so add relid to the queue. */ @@ -960,149 +873,30 @@ find_inheritors(Oid relid, Oid **supervec) while ((inhtup = heap_getnext(inhscan, ForwardScanDirection)) != NULL) { Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup); + Oid inhparent = inh->inhparent; + + /* If this is the target superclass, we're done */ + if (get_rel_type_id(inhparent) == superclassTypeId) + { + result = true; + break; + } - queue = lappend_oid(queue, inh->inhparent); + /* Else add to queue */ + queue = lappend_oid(queue, inhparent); } heap_endscan(inhscan); + + if (result) + break; } heap_close(inhrel, AccessShareLock); - nvisited = list_length(visited); - if (nvisited > 0) - { - Oid *relidvec; - ListCell *l; - - relidvec = (Oid *) palloc(nvisited * sizeof(*relidvec)); - *supervec = relidvec; - - foreach(l, visited) - { - /* return the type id, rather than the relation id */ - *relidvec++ = get_rel_type_id(lfirst_oid(l)); - } - } - else - *supervec = NULL; - list_free(visited); list_free(queue); - 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; - Oid *oneres; - int i, - j; - int *cur; - - /* - * 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 + 1); - - /* - * 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. - */ - cur = (int *) palloc0(nargs * sizeof(int)); - - for (;;) - { - /* - * 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 none, we're done */ - if (i < 0) - break; - - /* increment this column */ - cur[i] += 1; - - /* Generate the proper output type-OID vector */ - oneres = (Oid *) palloc(nargs * sizeof(Oid)); - - for (i = 0; i < nargs; i++) - { - if (cur[i] == 0) - oneres[i] = arginh[i].self; - else - oneres[i] = arginh[i].supervec[cur[i] - 1]; - } - - result[j++] = oneres; - } - - /* terminate result vector with NULL pointer */ - result[j++] = NULL; - - Assert(j == nanswers); - - pfree(cur); - - return result; -} - - -/* - * 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; } |