Commit c9f287e4 authored by Tom Lane's avatar Tom Lane

Further fixes for bogus list-slinging, scribbling on input, etc in type

coercion code.  I'm beginning to wonder why we have separate candidate
selection routines for functions, operators, and aggregates --- shouldn't
this code all be unified?  But meanwhile,
	SELECT 'a' LIKE 'a';
finally works; the code for dealing with unknown input types for operators
was pretty busted.
parent 1d752981
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.72 2000/02/20 23:04:06 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.73 2000/03/11 23:17:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -854,11 +854,6 @@ match_argtypes(int nargs, ...@@ -854,11 +854,6 @@ match_argtypes(int nargs,
* for the function argtype array, attempt to resolve the conflict. * for the function argtype array, attempt to resolve the conflict.
* returns the selected argtype array if the conflict can be resolved, * returns the selected argtype array if the conflict can be resolved,
* otherwise returns NULL. * otherwise returns NULL.
*
* If all input Oids are UNKNOWNOID, then try matching with TEXTOID.
* Otherwise, could return first function arguments on list of candidates.
* But for now, return NULL and make the user give a better hint.
* - thomas 1998-03-17
*/ */
static Oid * static Oid *
func_select_candidate(int nargs, func_select_candidate(int nargs,
...@@ -869,12 +864,10 @@ func_select_candidate(int nargs, ...@@ -869,12 +864,10 @@ func_select_candidate(int nargs,
CandidateList last_candidate; CandidateList last_candidate;
Oid *current_typeids; Oid *current_typeids;
int i; int i;
int ncandidates; int ncandidates;
int nbestMatch, int nbestMatch,
nmatch, nmatch,
nident; ncompat;
CATEGORY slot_category, CATEGORY slot_category,
current_category; current_category;
Oid slot_type, Oid slot_type,
...@@ -893,19 +886,29 @@ func_select_candidate(int nargs, ...@@ -893,19 +886,29 @@ func_select_candidate(int nargs,
{ {
current_typeids = current_candidate->args; current_typeids = current_candidate->args;
nmatch = 0; nmatch = 0;
nident = 0; ncompat = 0;
for (i = 0; i < nargs; i++) for (i = 0; i < nargs; i++)
{ {
if ((input_typeids[i] != UNKNOWNOID) if (input_typeids[i] != UNKNOWNOID)
&& (current_typeids[i] == input_typeids[i])) {
nmatch++; if (current_typeids[i] == input_typeids[i])
else if (IS_BINARY_COMPATIBLE(current_typeids[i], input_typeids[i])) nmatch++;
nident++; else if (IS_BINARY_COMPATIBLE(current_typeids[i],
input_typeids[i]))
ncompat++;
}
} }
if ((nmatch + nident) == nargs) /*
* If we find an exact match at all arg positions, we're done;
* there can be only one such candidate.
*/
if (nmatch == nargs)
return current_candidate->args; return current_candidate->args;
/* Otherwise, use match+compat as the score. */
nmatch += ncompat;
/* take this one as the best choice so far? */ /* take this one as the best choice so far? */
if ((nmatch > nbestMatch) || (last_candidate == NULL)) if ((nmatch > nbestMatch) || (last_candidate == NULL))
{ {
...@@ -933,6 +936,16 @@ func_select_candidate(int nargs, ...@@ -933,6 +936,16 @@ func_select_candidate(int nargs,
/* /*
* Still too many candidates? * Still too many candidates?
* Try assigning types for the unknown columns. * Try assigning types for the unknown columns.
*
* We do this by examining each unknown argument position to see if all the
* candidates agree on the type category of that slot. If so, and if some
* candidates accept the preferred type in that category, eliminate the
* candidates with other input types. If we are down to one candidate
* at the end, we win.
*
* XXX It's kinda bogus to do this left-to-right, isn't it? If we eliminate
* some candidates because they are non-preferred at the first slot, we won't
* notice that they didn't have the same type category for a later slot.
*/ */
for (i = 0; i < nargs; i++) for (i = 0; i < nargs; i++)
{ {
...@@ -947,12 +960,12 @@ func_select_candidate(int nargs, ...@@ -947,12 +960,12 @@ func_select_candidate(int nargs,
{ {
current_typeids = current_candidate->args; current_typeids = current_candidate->args;
current_type = current_typeids[i]; current_type = current_typeids[i];
current_category = TypeCategory(current_typeids[i]); current_category = TypeCategory(current_type);
if (slot_category == INVALID_TYPE)
if (slot_category == InvalidOid)
{ {
slot_category = current_category; slot_category = current_category;
slot_type = current_type; slot_type = current_type;
last_candidate = current_candidate;
} }
else if (current_category != slot_category) else if (current_category != slot_category)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.36 2000/02/27 02:48:15 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.37 2000/03/11 23:17:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -128,7 +128,7 @@ binary_oper_get_candidates(char *opname, ...@@ -128,7 +128,7 @@ binary_oper_get_candidates(char *opname,
* *
* This routine is new code, replacing binary_oper_select_candidate() * This routine is new code, replacing binary_oper_select_candidate()
* which dates from v4.2/v1.0.x days. It tries very hard to match up * which dates from v4.2/v1.0.x days. It tries very hard to match up
* operators with types, including allowing type coersions if necessary. * operators with types, including allowing type coercions if necessary.
* The important thing is that the code do as much as possible, * The important thing is that the code do as much as possible,
* while _never_ doing the wrong thing, where "the wrong thing" would * while _never_ doing the wrong thing, where "the wrong thing" would
* be returning an operator when other better choices are available, * be returning an operator when other better choices are available,
...@@ -185,7 +185,7 @@ oper_select_candidate(int nargs, ...@@ -185,7 +185,7 @@ oper_select_candidate(int nargs,
/* /*
* Run through all candidates and keep those with the most matches * Run through all candidates and keep those with the most matches
* on explicit types. Keep all candidates if none match. * on exact types. Keep all candidates if none match.
*/ */
ncandidates = 0; ncandidates = 0;
nbestMatch = 0; nbestMatch = 0;
...@@ -236,7 +236,7 @@ oper_select_candidate(int nargs, ...@@ -236,7 +236,7 @@ oper_select_candidate(int nargs,
/* /*
* Still too many candidates? * Still too many candidates?
* Now look for candidates which allow coersion and are preferred types. * Now look for candidates which allow coercion and are preferred types.
* Keep all candidates if none match. * Keep all candidates if none match.
*/ */
ncandidates = 0; ncandidates = 0;
...@@ -292,6 +292,13 @@ oper_select_candidate(int nargs, ...@@ -292,6 +292,13 @@ oper_select_candidate(int nargs,
/* /*
* Still too many candidates? * Still too many candidates?
* Try assigning types for the unknown columns. * Try assigning types for the unknown columns.
*
* First try: if we have an unknown and a non-unknown input, see whether
* there is a candidate all of whose input types are the same as the known
* input type (there can be at most one such candidate). If so, use that
* candidate. NOTE that this is cool only because operators can't
* have more than 2 args, so taking the last non-unknown as current_type
* can yield only one possibility if there is also an unknown.
*/ */
unknownOids = FALSE; unknownOids = FALSE;
current_type = UNKNOWNOID; current_type = UNKNOWNOID;
...@@ -314,53 +321,82 @@ oper_select_candidate(int nargs, ...@@ -314,53 +321,82 @@ oper_select_candidate(int nargs,
nmatch = 0; nmatch = 0;
for (i = 0; i < nargs; i++) for (i = 0; i < nargs; i++)
{ {
if (current_type == current_typeids[i] || if (current_type == current_typeids[i])
IS_BINARY_COMPATIBLE(current_type, current_typeids[i]))
nmatch++; nmatch++;
} }
if (nmatch == nargs) if (nmatch == nargs)
return candidates->args; {
/* coercion check here is probably redundant, but be safe */
if (can_coerce_type(nargs, input_typeids, current_typeids))
return current_typeids;
}
} }
} }
/*
* Second try: examine each unknown argument position to see if all the
* candidates agree on the type category of that slot. If so, and if some
* candidates accept the preferred type in that category, eliminate the
* candidates with other input types. If we are down to one candidate
* at the end, we win.
*
* XXX It's kinda bogus to do this left-to-right, isn't it? If we eliminate
* some candidates because they are non-preferred at the first slot, we won't
* notice that they didn't have the same type category for a later slot.
*/
for (i = 0; i < nargs; i++) for (i = 0; i < nargs; i++)
{ {
if (input_typeids[i] == UNKNOWNOID) if (input_typeids[i] == UNKNOWNOID)
{ {
slot_category = INVALID_TYPE; slot_category = INVALID_TYPE;
slot_type = InvalidOid; slot_type = InvalidOid;
last_candidate = NULL;
for (current_candidate = candidates; for (current_candidate = candidates;
current_candidate != NULL; current_candidate != NULL;
current_candidate = current_candidate->next) current_candidate = current_candidate->next)
{ {
current_typeids = current_candidate->args; current_typeids = current_candidate->args;
current_type = current_typeids[i]; current_type = current_typeids[i];
current_category = TypeCategory(current_typeids[i]); current_category = TypeCategory(current_type);
if (slot_category == InvalidOid) if (slot_category == INVALID_TYPE)
{ {
slot_category = current_category; slot_category = current_category;
slot_type = current_type; slot_type = current_type;
last_candidate = current_candidate;
} }
else if (current_category != slot_category) else if (current_category != slot_category)
{
/* punt if more than one category for this slot */
return NULL; return NULL;
}
else if (current_type != slot_type) else if (current_type != slot_type)
{ {
if (IsPreferredType(slot_category, current_type)) if (IsPreferredType(slot_category, current_type))
{ {
slot_type = current_type; slot_type = current_type;
/* forget all previous candidates */
candidates = current_candidate; candidates = current_candidate;
last_candidate = current_candidate;
} }
else else if (IsPreferredType(slot_category, slot_type))
{ {
/* 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 (last_candidate) /* terminate rebuilt list */
if (slot_type != InvalidOid) last_candidate->next = NULL;
input_typeids[i] = slot_type;
}
else
{
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment