From 5253c518aef4c906dc6c922c51c2d77b0a78bf75 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 20 Feb 2000 06:35:08 +0000 Subject: [PATCH] Fix broken list-slinging logic in func_select_candidate and agg_select_candidate, which could cause them to keep more candidates than they should and thus fail to select a single match. I had previously fixed the identical bug in oper_select_candidate, but didn't realize that the same error was repeated over here. Also, repair func_select_candidate's curious notion that it could scribble on the input type-OID vector. That was causing failure to apply necessary type coercion later on, leading to malfunction of examples such as select date('now'). --- src/backend/parser/parse_func.c | 66 ++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 06afc86790..939d7a91ec 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.69 2000/02/15 03:37:47 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.70 2000/02/20 06:35:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -45,14 +45,13 @@ static Oid **argtype_inherit(int nargs, Oid *oid_array); static int find_inheritors(Oid relid, Oid **supervec); static CandidateList func_get_candidates(char *funcname, int nargs); -static bool -func_get_detail(char *funcname, - int nargs, - Oid *oid_array, - Oid *funcid, /* return value */ - Oid *rettype, /* return value */ - bool *retset, /* return value */ - Oid **true_typeids); +static bool func_get_detail(char *funcname, + int nargs, + Oid *oid_array, + Oid *funcid, /* return value */ + Oid *rettype, /* return value */ + bool *retset, /* return value */ + Oid **true_typeids); static Oid **gen_cross_product(InhPaths *arginh, int nargs); static void make_arguments(ParseState *pstate, int nargs, @@ -228,10 +227,11 @@ agg_select_candidate(Oid typeid, CandidateList candidates) } } /* otherwise, don't bother keeping this one around... */ - else if (last_candidate != NULL) - last_candidate->next = NULL; } + if (last_candidate) /* terminate rebuilt list */ + last_candidate->next = NULL; + return ((ncandidates == 1) ? candidates->args[0] : 0); } /* agg_select_candidate() */ @@ -559,8 +559,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, } /* Most of the rest of the parser just assumes that functions do not - * have more than FUNC_MAX_ARGS parameters. We have to test here to protect - * against array overruns, etc. + * have more than FUNC_MAX_ARGS parameters. We have to test here + * to protect against array overruns, etc. */ if (nargs >= FUNC_MAX_ARGS) elog(ERROR, "Cannot pass more than %d arguments to a function", @@ -892,6 +892,7 @@ func_select_candidate(int nargs, if ((nmatch + nident) == nargs) return current_candidate->args; + /* take this one as the best choice so far? */ if ((nmatch > nbestMatch) || (last_candidate == NULL)) { nbestMatch = nmatch; @@ -899,16 +900,19 @@ func_select_candidate(int nargs, last_candidate = current_candidate; ncandidates = 1; } + /* no worse than the last choice, so keep this one too? */ else if (nmatch == nbestMatch) { last_candidate->next = current_candidate; last_candidate = current_candidate; ncandidates++; } - else - last_candidate->next = NULL; + /* otherwise, don't bother keeping this one... */ } + if (last_candidate) /* terminate rebuilt list */ + last_candidate->next = NULL; + if (ncandidates == 1) return candidates->args; @@ -922,6 +926,7 @@ func_select_candidate(int nargs, { slot_category = INVALID_TYPE; slot_type = InvalidOid; + last_candidate = NULL; for (current_candidate = candidates; current_candidate != NULL; current_candidate = current_candidate->next) @@ -935,26 +940,39 @@ func_select_candidate(int nargs, slot_category = current_category; slot_type = current_type; } - else if ((current_category != slot_category) - && IS_BUILTIN_TYPE(current_type)) + else if (current_category != slot_category) + { + /* punt if more than one category for this slot */ return NULL; + } else if (current_type != slot_type) { if (IsPreferredType(slot_category, current_type)) { slot_type = current_type; + /* forget all previous candidates */ candidates = current_candidate; + last_candidate = current_candidate; } else if (IsPreferredType(slot_category, slot_type)) - candidates->next = current_candidate->next; + { + /* forget this candidate */ + if (last_candidate) + last_candidate->next = current_candidate->next; + else + candidates = current_candidate->next; + } + else + last_candidate = current_candidate; + } + else + { + /* keep this candidate */ + last_candidate = current_candidate; } } - - if (slot_type != InvalidOid) - input_typeids[i] = slot_type; - } - else - { + if (last_candidate) /* terminate rebuilt list */ + last_candidate->next = NULL; } } -- 2.11.0