aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_oper.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2000-12-15 19:22:03 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2000-12-15 19:22:03 +0000
commit7d6af50f4341efdd9a1e693ff7297da6122f03f4 (patch)
treea9198880bd7ae30f1da33640bdeb879364d66ed3 /src/backend/parser/parse_oper.c
parentff783fbae0b76cf409b4391fe4be5524353304e0 (diff)
downloadpostgresql-7d6af50f4341efdd9a1e693ff7297da6122f03f4.tar.gz
postgresql-7d6af50f4341efdd9a1e693ff7297da6122f03f4.zip
Make algorithm for resolving UNKNOWN function/operator inputs be
insensitive to the order of arguments. Per pghackers discussion 12/10/00.
Diffstat (limited to 'src/backend/parser/parse_oper.c')
-rw-r--r--src/backend/parser/parse_oper.c190
1 files changed, 116 insertions, 74 deletions
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index a44a740dc92..dc1c267366e 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -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() */