Make algorithm for resolving UNKNOWN function/operator inputs be
insensitive to the order of arguments. Per pghackers discussion 12/10/00.
This commit is contained in:
parent
ff783fbae0
commit
7d6af50f43
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 current_candidate;
|
||||||
CandidateList last_candidate;
|
CandidateList last_candidate;
|
||||||
Oid *current_typeids;
|
Oid *current_typeids;
|
||||||
|
Oid current_type;
|
||||||
int i;
|
int i;
|
||||||
int ncandidates;
|
int ncandidates;
|
||||||
int nbestMatch,
|
int nbestMatch,
|
||||||
nmatch;
|
nmatch;
|
||||||
CATEGORY slot_category,
|
CATEGORY slot_category[FUNC_MAX_ARGS],
|
||||||
current_category;
|
current_category;
|
||||||
Oid slot_type,
|
bool slot_has_preferred_type[FUNC_MAX_ARGS];
|
||||||
current_type;
|
bool resolved_unknowns;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run through all candidates and keep those with the most matches on
|
* 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
|
* Still too many candidates? Try assigning types for the unknown
|
||||||
* columns.
|
* columns.
|
||||||
*
|
*
|
||||||
* We do this by examining each unknown argument position to see if all
|
* We do this by examining each unknown argument position to see if we
|
||||||
* the candidates agree on the type category of that slot. If so, and
|
* can determine a "type category" for it. If any candidate has an
|
||||||
* if some candidates accept the preferred type in that category,
|
* input datatype of STRING category, use STRING category (this bias
|
||||||
* eliminate the candidates with other input types. If we are down to
|
* towards STRING is appropriate since unknown-type literals look like
|
||||||
* one candidate at the end, we win.
|
* 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
|
* If we are able to determine a type category, also notice whether
|
||||||
* eliminate some candidates because they are non-preferred at the
|
* any of the candidates takes a preferred datatype within the category.
|
||||||
* first slot, we won't notice that they didn't have the same type
|
*
|
||||||
* category for a later slot.
|
* Having completed this examination, remove candidates that accept
|
||||||
* XXX Hmm. How else would you do this? These candidates are here because
|
* the wrong category at any unknown position. Also, if at least one
|
||||||
* they all have the same number of matches on arguments with explicit
|
* candidate accepted a preferred type at a position, remove candidates
|
||||||
* types, so from here on left-to-right resolution is as good as any.
|
* that accept non-preferred types.
|
||||||
* Need a counterexample to see otherwise...
|
*
|
||||||
|
* If we are down to one candidate at the end, we win.
|
||||||
*/
|
*/
|
||||||
|
resolved_unknowns = false;
|
||||||
for (i = 0; i < nargs; i++)
|
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;
|
current_typeids = current_candidate->args;
|
||||||
slot_type = InvalidOid;
|
current_type = current_typeids[i];
|
||||||
last_candidate = NULL;
|
current_category = TypeCategory(current_type);
|
||||||
for (current_candidate = candidates;
|
if (slot_category[i] == INVALID_TYPE)
|
||||||
current_candidate != NULL;
|
|
||||||
current_candidate = current_candidate->next)
|
|
||||||
{
|
{
|
||||||
current_typeids = current_candidate->args;
|
/* first candidate */
|
||||||
current_type = current_typeids[i];
|
slot_category[i] = current_category;
|
||||||
current_category = TypeCategory(current_type);
|
slot_has_preferred_type[i] =
|
||||||
if (slot_category == INVALID_TYPE)
|
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;
|
/* STRING always wins if available */
|
||||||
slot_type = current_type;
|
slot_category[i] = current_category;
|
||||||
last_candidate = current_candidate;
|
slot_has_preferred_type[i] =
|
||||||
}
|
IsPreferredType(current_category, current_type);
|
||||||
else if (current_category != slot_category)
|
|
||||||
{
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
/* forget this candidate */
|
|
||||||
if (last_candidate)
|
|
||||||
last_candidate->next = current_candidate->next;
|
|
||||||
else
|
|
||||||
candidates = current_candidate->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
last_candidate = current_candidate;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* keep this candidate */
|
/* Remember conflict, but keep going (might find STRING) */
|
||||||
last_candidate = current_candidate;
|
have_conflict = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (last_candidate) /* terminate rebuilt list */
|
}
|
||||||
last_candidate->next = NULL;
|
if (have_conflict && slot_category[i] != STRING_TYPE)
|
||||||
|
{
|
||||||
|
/* Failed to resolve category conflict at this position */
|
||||||
|
resolved_unknowns = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (candidates == NULL)
|
if (resolved_unknowns)
|
||||||
return NULL; /* no remaining candidates */
|
{
|
||||||
if (candidates->next != NULL)
|
/* Strip non-matching candidates */
|
||||||
return NULL; /* more than one remaining candidate */
|
ncandidates = 0;
|
||||||
|
last_candidate = NULL;
|
||||||
|
for (current_candidate = candidates;
|
||||||
|
current_candidate != NULL;
|
||||||
|
current_candidate = current_candidate->next)
|
||||||
|
{
|
||||||
|
bool keepit = true;
|
||||||
|
|
||||||
return candidates->args;
|
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])
|
||||||
|
{
|
||||||
|
keepit = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (slot_has_preferred_type[i] &&
|
||||||
|
!IsPreferredType(current_category, current_type))
|
||||||
|
{
|
||||||
|
keepit = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 (ncandidates == 1)
|
||||||
|
return candidates->args;
|
||||||
|
|
||||||
|
return NULL; /* failed to determine a unique candidate */
|
||||||
} /* func_select_candidate() */
|
} /* func_select_candidate() */
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 current_candidate;
|
||||||
CandidateList last_candidate;
|
CandidateList last_candidate;
|
||||||
Oid *current_typeids;
|
Oid *current_typeids;
|
||||||
|
Oid current_type;
|
||||||
int unknownOids;
|
int unknownOids;
|
||||||
int i;
|
int i;
|
||||||
int ncandidates;
|
int ncandidates;
|
||||||
int nbestMatch,
|
int nbestMatch,
|
||||||
nmatch;
|
nmatch;
|
||||||
CATEGORY slot_category,
|
CATEGORY slot_category[FUNC_MAX_ARGS],
|
||||||
current_category;
|
current_category;
|
||||||
Oid slot_type,
|
bool slot_has_preferred_type[FUNC_MAX_ARGS];
|
||||||
current_type;
|
bool resolved_unknowns;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First, delete any candidates that cannot actually accept the given
|
* 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
|
* Second try: same algorithm as for unknown resolution in parse_func.c.
|
||||||
* 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
|
* We do this by examining each unknown argument position to see if we
|
||||||
* eliminate some candidates because they are non-preferred at the
|
* can determine a "type category" for it. If any candidate has an
|
||||||
* first slot, we won't notice that they didn't have the same type
|
* input datatype of STRING category, use STRING category (this bias
|
||||||
* category for a later slot.
|
* 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++)
|
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;
|
current_typeids = current_candidate->args;
|
||||||
slot_type = InvalidOid;
|
current_type = current_typeids[i];
|
||||||
last_candidate = NULL;
|
current_category = TypeCategory(current_type);
|
||||||
for (current_candidate = candidates;
|
if (slot_category[i] == INVALID_TYPE)
|
||||||
current_candidate != NULL;
|
|
||||||
current_candidate = current_candidate->next)
|
|
||||||
{
|
{
|
||||||
current_typeids = current_candidate->args;
|
/* first candidate */
|
||||||
current_type = current_typeids[i];
|
slot_category[i] = current_category;
|
||||||
current_category = TypeCategory(current_type);
|
slot_has_preferred_type[i] =
|
||||||
/* first time through? Then we'll use this one for now */
|
IsPreferredType(current_category, current_type);
|
||||||
if (slot_category == INVALID_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;
|
/* STRING always wins if available */
|
||||||
slot_type = current_type;
|
slot_category[i] = current_category;
|
||||||
last_candidate = current_candidate;
|
slot_has_preferred_type[i] =
|
||||||
}
|
IsPreferredType(current_category, current_type);
|
||||||
else if (current_category != slot_category)
|
|
||||||
{
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
/* forget this candidate */
|
|
||||||
if (last_candidate)
|
|
||||||
last_candidate->next = current_candidate->next;
|
|
||||||
else
|
|
||||||
candidates = current_candidate->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
last_candidate = current_candidate;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* keep this candidate */
|
/* Remember conflict, but keep going (might find STRING) */
|
||||||
last_candidate = current_candidate;
|
have_conflict = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (last_candidate) /* terminate rebuilt list */
|
}
|
||||||
last_candidate->next = NULL;
|
if (have_conflict && slot_category[i] != STRING_TYPE)
|
||||||
|
{
|
||||||
|
/* Failed to resolve category conflict at this position */
|
||||||
|
resolved_unknowns = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (candidates == NULL)
|
if (resolved_unknowns)
|
||||||
return NULL; /* no remaining candidates */
|
{
|
||||||
if (candidates->next != NULL)
|
/* Strip non-matching candidates */
|
||||||
return NULL; /* more than one remaining candidate */
|
ncandidates = 0;
|
||||||
return candidates->args;
|
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])
|
||||||
|
{
|
||||||
|
keepit = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (slot_has_preferred_type[i] &&
|
||||||
|
!IsPreferredType(current_category, current_type))
|
||||||
|
{
|
||||||
|
keepit = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 (ncandidates == 1)
|
||||||
|
return candidates->args;
|
||||||
|
|
||||||
|
return NULL; /* failed to determine a unique candidate */
|
||||||
} /* oper_select_candidate() */
|
} /* oper_select_candidate() */
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user