Commit 7d6af50f authored by Tom Lane's avatar Tom Lane

Make algorithm for resolving UNKNOWN function/operator inputs be

insensitive to the order of arguments.  Per pghackers discussion 12/10/00.
parent ff783fba
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.94 2000/11/16 22:30:28 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.95 2000/12/15 19:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -759,14 +759,15 @@ func_select_candidate(int nargs,
CandidateList current_candidate;
CandidateList last_candidate;
Oid *current_typeids;
Oid current_type;
int i;
int ncandidates;
int nbestMatch,
nmatch;
CATEGORY slot_category,
CATEGORY slot_category[FUNC_MAX_ARGS],
current_category;
Oid slot_type,
current_type;
bool slot_has_preferred_type[FUNC_MAX_ARGS];
bool resolved_unknowns;
/*
* Run through all candidates and keep those with the most matches on
......@@ -911,98 +912,133 @@ func_select_candidate(int nargs,
* Still too many candidates? 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.
* We do this by examining each unknown argument position to see if we
* can determine a "type category" for it. If any candidate has an
* input datatype of STRING category, use STRING category (this bias
* towards STRING is appropriate since unknown-type literals look like
* strings). Otherwise, if all the candidates agree on the type
* category of this argument position, use that category. Otherwise,
* fail because we cannot determine a category.
*
* 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.
* XXX Hmm. How else would you do this? These candidates are here because
* they all have the same number of matches on arguments with explicit
* types, so from here on left-to-right resolution is as good as any.
* Need a counterexample to see otherwise...
* If we are able to determine a type category, also notice whether
* any of the candidates takes a preferred datatype within the category.
*
* Having completed this examination, remove candidates that accept
* the wrong category at any unknown position. Also, if at least one
* candidate accepted a preferred type at a position, remove candidates
* that accept non-preferred types.
*
* If we are down to one candidate at the end, we win.
*/
resolved_unknowns = false;
for (i = 0; i < nargs; i++)
{
if (input_typeids[i] == UNKNOWNOID)
bool have_conflict;
if (input_typeids[i] != UNKNOWNOID)
continue;
resolved_unknowns = true; /* assume we can do it */
slot_category[i] = INVALID_TYPE;
slot_has_preferred_type[i] = false;
have_conflict = false;
for (current_candidate = candidates;
current_candidate != NULL;
current_candidate = current_candidate->next)
{
slot_category = INVALID_TYPE;
slot_type = InvalidOid;
last_candidate = NULL;
for (current_candidate = candidates;
current_candidate != NULL;
current_candidate = current_candidate->next)
current_typeids = current_candidate->args;
current_type = current_typeids[i];
current_category = TypeCategory(current_type);
if (slot_category[i] == INVALID_TYPE)
{
current_typeids = current_candidate->args;
current_type = current_typeids[i];
current_category = TypeCategory(current_type);
if (slot_category == INVALID_TYPE)
/* first candidate */
slot_category[i] = current_category;
slot_has_preferred_type[i] =
IsPreferredType(current_category, current_type);
}
else if (current_category == slot_category[i])
{
/* more candidates in same category */
slot_has_preferred_type[i] |=
IsPreferredType(current_category, current_type);
}
else
{
/* category conflict! */
if (current_category == STRING_TYPE)
{
slot_category = current_category;
slot_type = current_type;
last_candidate = current_candidate;
/* STRING always wins if available */
slot_category[i] = current_category;
slot_has_preferred_type[i] =
IsPreferredType(current_category, current_type);
}
else if (current_category != slot_category)
else
{
/* started out as unknown type, so give preference to string type, if available */
if (current_category == STRING_TYPE)
{
slot_category = current_category;
slot_type = current_type;
/* forget all previous candidates */
candidates = current_candidate;
last_candidate = current_candidate;
}
else if (slot_category == STRING_TYPE)
{
/* forget this candidate */
if (last_candidate)
last_candidate->next = current_candidate->next;
else
candidates = current_candidate->next;
}
/* Remember conflict, but keep going (might find STRING) */
have_conflict = true;
}
else if (current_type != slot_type)
}
}
if (have_conflict && slot_category[i] != STRING_TYPE)
{
/* Failed to resolve category conflict at this position */
resolved_unknowns = false;
break;
}
}
if (resolved_unknowns)
{
/* Strip non-matching candidates */
ncandidates = 0;
last_candidate = NULL;
for (current_candidate = candidates;
current_candidate != NULL;
current_candidate = current_candidate->next)
{
bool keepit = true;
current_typeids = current_candidate->args;
for (i = 0; i < nargs; i++)
{
if (input_typeids[i] != UNKNOWNOID)
continue;
current_type = current_typeids[i];
current_category = TypeCategory(current_type);
if (current_category != slot_category[i])
{
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))
{
/* forget this candidate */
if (last_candidate)
last_candidate->next = current_candidate->next;
else
candidates = current_candidate->next;
}
else
last_candidate = current_candidate;
keepit = false;
break;
}
else
if (slot_has_preferred_type[i] &&
!IsPreferredType(current_category, current_type))
{
/* keep this candidate */
last_candidate = current_candidate;
keepit = false;
break;
}
}
if (last_candidate) /* terminate rebuilt list */
last_candidate->next = NULL;
if (keepit)
{
/* keep this candidate */
last_candidate = current_candidate;
ncandidates++;
}
else
{
/* forget this candidate */
if (last_candidate)
last_candidate->next = current_candidate->next;
else
candidates = current_candidate->next;
}
}
if (last_candidate) /* terminate rebuilt list */
last_candidate->next = NULL;
}
if (candidates == NULL)
return NULL; /* no remaining candidates */
if (candidates->next != NULL)
return NULL; /* more than one remaining candidate */
if (ncandidates == 1)
return candidates->args;
return candidates->args;
return NULL; /* failed to determine a unique candidate */
} /* func_select_candidate() */
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.44 2000/11/16 22:30:28 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.45 2000/12/15 19:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -176,15 +176,16 @@ oper_select_candidate(int nargs,
CandidateList current_candidate;
CandidateList last_candidate;
Oid *current_typeids;
Oid current_type;
int unknownOids;
int i;
int ncandidates;
int nbestMatch,
nmatch;
CATEGORY slot_category,
CATEGORY slot_category[FUNC_MAX_ARGS],
current_category;
Oid slot_type,
current_type;
bool slot_has_preferred_type[FUNC_MAX_ARGS];
bool resolved_unknowns;
/*
* First, delete any candidates that cannot actually accept the given
......@@ -406,94 +407,135 @@ oper_select_candidate(int nargs,
}
/*
* 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.
* Second try: same algorithm as for unknown resolution in parse_func.c.
*
* 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.
* We do this by examining each unknown argument position to see if we
* can determine a "type category" for it. If any candidate has an
* input datatype of STRING category, use STRING category (this bias
* towards STRING is appropriate since unknown-type literals look like
* strings). Otherwise, if all the candidates agree on the type
* category of this argument position, use that category. Otherwise,
* fail because we cannot determine a category.
*
* If we are able to determine a type category, also notice whether
* any of the candidates takes a preferred datatype within the category.
*
* Having completed this examination, remove candidates that accept
* the wrong category at any unknown position. Also, if at least one
* candidate accepted a preferred type at a position, remove candidates
* that accept non-preferred types.
*
* If we are down to one candidate at the end, we win.
*/
resolved_unknowns = false;
for (i = 0; i < nargs; i++)
{
if (input_typeids[i] == UNKNOWNOID)
bool have_conflict;
if (input_typeids[i] != UNKNOWNOID)
continue;
resolved_unknowns = true; /* assume we can do it */
slot_category[i] = INVALID_TYPE;
slot_has_preferred_type[i] = false;
have_conflict = false;
for (current_candidate = candidates;
current_candidate != NULL;
current_candidate = current_candidate->next)
{
slot_category = INVALID_TYPE;
slot_type = InvalidOid;
last_candidate = NULL;
for (current_candidate = candidates;
current_candidate != NULL;
current_candidate = current_candidate->next)
current_typeids = current_candidate->args;
current_type = current_typeids[i];
current_category = TypeCategory(current_type);
if (slot_category[i] == INVALID_TYPE)
{
current_typeids = current_candidate->args;
current_type = current_typeids[i];
current_category = TypeCategory(current_type);
/* first time through? Then we'll use this one for now */
if (slot_category == INVALID_TYPE)
/* first candidate */
slot_category[i] = current_category;
slot_has_preferred_type[i] =
IsPreferredType(current_category, current_type);
}
else if (current_category == slot_category[i])
{
/* more candidates in same category */
slot_has_preferred_type[i] |=
IsPreferredType(current_category, current_type);
}
else
{
/* category conflict! */
if (current_category == STRING_TYPE)
{
slot_category = current_category;
slot_type = current_type;
last_candidate = current_candidate;
/* STRING always wins if available */
slot_category[i] = current_category;
slot_has_preferred_type[i] =
IsPreferredType(current_category, current_type);
}
else if (current_category != slot_category)
else
{
/* started out as unknown type, so give preference to string type, if available */
if (current_category == STRING_TYPE)
{
slot_category = current_category;
slot_type = current_type;
/* forget all previous candidates */
candidates = current_candidate;
last_candidate = current_candidate;
}
else if (slot_category == STRING_TYPE)
{
/* forget this candidate */
if (last_candidate)
last_candidate->next = current_candidate->next;
else
candidates = current_candidate->next;
}
/* Remember conflict, but keep going (might find STRING) */
have_conflict = true;
}
else if (current_type != slot_type)
}
}
if (have_conflict && slot_category[i] != STRING_TYPE)
{
/* Failed to resolve category conflict at this position */
resolved_unknowns = false;
break;
}
}
if (resolved_unknowns)
{
/* Strip non-matching candidates */
ncandidates = 0;
last_candidate = NULL;
for (current_candidate = candidates;
current_candidate != NULL;
current_candidate = current_candidate->next)
{
bool keepit = true;
current_typeids = current_candidate->args;
for (i = 0; i < nargs; i++)
{
if (input_typeids[i] != UNKNOWNOID)
continue;
current_type = current_typeids[i];
current_category = TypeCategory(current_type);
if (current_category != slot_category[i])
{
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))
{
/* forget this candidate */
if (last_candidate)
last_candidate->next = current_candidate->next;
else
candidates = current_candidate->next;
}
else
last_candidate = current_candidate;
keepit = false;
break;
}
else
if (slot_has_preferred_type[i] &&
!IsPreferredType(current_category, current_type))
{
/* keep this candidate */
last_candidate = current_candidate;
keepit = false;
break;
}
}
if (last_candidate) /* terminate rebuilt list */
last_candidate->next = NULL;
if (keepit)
{
/* keep this candidate */
last_candidate = current_candidate;
ncandidates++;
}
else
{
/* forget this candidate */
if (last_candidate)
last_candidate->next = current_candidate->next;
else
candidates = current_candidate->next;
}
}
if (last_candidate) /* terminate rebuilt list */
last_candidate->next = NULL;
}
if (candidates == NULL)
return NULL; /* no remaining candidates */
if (candidates->next != NULL)
return NULL; /* more than one remaining candidate */
return candidates->args;
if (ncandidates == 1)
return candidates->args;
return NULL; /* failed to determine a unique candidate */
} /* oper_select_candidate() */
......
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