aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_oper.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_oper.c')
-rw-r--r--src/backend/parser/parse_oper.c421
1 files changed, 18 insertions, 403 deletions
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 6238258ed2f..21f73994c42 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -8,18 +8,13 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.63 2003/04/29 22:13:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.64 2003/05/26 00:11:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "access/genam.h"
-#include "access/heapam.h"
-#include "catalog/catname.h"
-#include "catalog/indexing.h"
-#include "catalog/namespace.h"
#include "catalog/pg_operator.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
@@ -289,107 +284,29 @@ binary_oper_exact(Oid arg1, Oid arg2,
/* oper_select_candidate()
- * Given the input argtype array and one or more candidates
- * for the function argtype array, attempt to resolve the conflict.
- * Returns the selected argtype array if the conflict can be resolved,
- * otherwise returns NULL.
+ * Given the input argtype array and one or more candidates
+ * for the operator, attempt to resolve the conflict.
*
- * By design, this is pretty similar to func_select_candidate in parse_func.c.
- * However, we can do a couple of extra things here because we know we can
- * have no more than two args to deal with. Also, the calling convention
- * is a little different: we must prune away "candidates" that aren't actually
- * coercion-compatible with the input types, whereas in parse_func.c that
- * gets done by match_argtypes before func_select_candidate is called.
+ * Returns the OID of the selected operator if the conflict can be resolved,
+ * otherwise returns InvalidOid.
*
- * 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
- * operators with types, including allowing type coercions if necessary.
- * The important thing is that the code do as much as possible,
- * while _never_ doing the wrong thing, where "the wrong thing" would
- * be returning an operator when other better choices are available,
- * or returning an operator which is a non-intuitive possibility.
- * - thomas 1998-05-21
- *
- * The comments below came from binary_oper_select_candidate(), and
- * illustrate the issues and choices which are possible:
- * - thomas 1998-05-20
- *
- * current wisdom holds that the default operator should be one in which
- * both operands have the same type (there will only be one such
- * operator)
- *
- * 7.27.93 - I have decided not to do this; it's too hard to justify, and
- * it's easy enough to typecast explicitly - avi
- * [the rest of this routine was commented out since then - ay]
- *
- * 6/23/95 - I don't complete agree with avi. In particular, casting
- * floats is a pain for users. Whatever the rationale behind not doing
- * this is, I need the following special case to work.
- *
- * In the WHERE clause of a query, if a float is specified without
- * quotes, we treat it as float8. I added the float48* operators so
- * that we can operate on float4 and float8. But now we have more than
- * one matching operator if the right arg is unknown (eg. float
- * specified with quotes). This break some stuff in the regression
- * test where there are floats in quotes not properly casted. Below is
- * the solution. In addition to requiring the operator operates on the
- * same type for both operands [as in the code Avi originally
- * commented out], we also require that the operators be equivalent in
- * some sense. (see equivalentOpersAfterPromotion for details.)
- * - ay 6/95
+ * Note that the caller has already determined that there is no candidate
+ * exactly matching the input argtype(s). Incompatible candidates are not yet
+ * pruned away, however.
*/
static Oid
oper_select_candidate(int nargs,
Oid *input_typeids,
FuncCandidateList candidates)
{
- FuncCandidateList current_candidate;
- FuncCandidateList last_candidate;
- Oid *current_typeids;
- Oid current_type;
- int unknownOids;
- int i;
int ncandidates;
- int nbestMatch,
- nmatch;
- CATEGORY slot_category[FUNC_MAX_ARGS],
- current_category;
- bool slot_has_preferred_type[FUNC_MAX_ARGS];
- bool resolved_unknowns;
/*
- * First, delete any candidates that cannot actually accept the given
- * input types, whether directly or by coercion. (Note that
- * can_coerce_type will assume that UNKNOWN inputs are coercible to
- * anything, so candidates will not be eliminated on that basis.)
+ * Delete any candidates that cannot actually accept the given
+ * input types, whether directly or by coercion.
*/
- ncandidates = 0;
- last_candidate = NULL;
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- if (can_coerce_type(nargs, input_typeids, current_candidate->args,
- COERCION_IMPLICIT))
- {
- if (last_candidate == NULL)
- {
- candidates = current_candidate;
- last_candidate = current_candidate;
- ncandidates = 1;
- }
- else
- {
- last_candidate->next = current_candidate;
- last_candidate = current_candidate;
- ncandidates++;
- }
- }
- /* otherwise, don't bother keeping this one... */
- }
-
- if (last_candidate) /* terminate rebuilt list */
- last_candidate->next = NULL;
+ ncandidates = func_match_argtypes(nargs, input_typeids,
+ candidates, &candidates);
/* Done if no candidate or only one candidate survives */
if (ncandidates == 0)
@@ -398,317 +315,15 @@ oper_select_candidate(int nargs,
return candidates->oid;
/*
- * Run through all candidates and keep those with the most matches on
- * exact types. Keep all candidates if none match.
- */
- ncandidates = 0;
- nbestMatch = 0;
- last_candidate = NULL;
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- nmatch = 0;
- for (i = 0; i < nargs; i++)
- {
- if (input_typeids[i] != UNKNOWNOID &&
- current_typeids[i] == input_typeids[i])
- nmatch++;
- }
-
- /* take this one as the best choice so far? */
- if ((nmatch > nbestMatch) || (last_candidate == NULL))
- {
- nbestMatch = nmatch;
- candidates = current_candidate;
- 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++;
- }
- /* otherwise, don't bother keeping this one... */
- }
-
- if (last_candidate) /* terminate rebuilt list */
- last_candidate->next = NULL;
-
- if (ncandidates == 1)
- return candidates->oid;
-
- /*
- * Still too many candidates? Run through all candidates and keep
- * those with the most matches on exact types + binary-compatible
- * types. Keep all candidates if none match.
- */
- ncandidates = 0;
- nbestMatch = 0;
- last_candidate = NULL;
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- nmatch = 0;
- for (i = 0; i < nargs; i++)
- {
- if (input_typeids[i] != UNKNOWNOID)
- {
- if (IsBinaryCoercible(input_typeids[i], current_typeids[i]))
- nmatch++;
- }
- }
-
- /* take this one as the best choice so far? */
- if ((nmatch > nbestMatch) || (last_candidate == NULL))
- {
- nbestMatch = nmatch;
- candidates = current_candidate;
- 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++;
- }
- /* otherwise, don't bother keeping this one... */
- }
-
- if (last_candidate) /* terminate rebuilt list */
- last_candidate->next = NULL;
-
- if (ncandidates == 1)
- return candidates->oid;
-
- /*
- * Still too many candidates? Now look for candidates which are
- * preferred types at the args that will require coercion. Keep all
- * candidates if none match.
- */
- ncandidates = 0;
- nbestMatch = 0;
- last_candidate = NULL;
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- nmatch = 0;
- for (i = 0; i < nargs; i++)
- {
- if (input_typeids[i] != UNKNOWNOID)
- {
- current_category = TypeCategory(current_typeids[i]);
- if (current_typeids[i] == input_typeids[i] ||
- IsPreferredType(current_category, current_typeids[i]))
- nmatch++;
- }
- }
-
- if ((nmatch > nbestMatch) || (last_candidate == NULL))
- {
- nbestMatch = nmatch;
- candidates = current_candidate;
- last_candidate = current_candidate;
- ncandidates = 1;
- }
- else if (nmatch == nbestMatch)
- {
- last_candidate->next = current_candidate;
- last_candidate = current_candidate;
- ncandidates++;
- }
- }
-
- if (last_candidate) /* terminate rebuilt list */
- last_candidate->next = NULL;
-
- if (ncandidates == 1)
- return candidates->oid;
-
- /*
- * Still too many candidates? 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;
- current_type = UNKNOWNOID;
- for (i = 0; i < nargs; i++)
- {
- if ((input_typeids[i] != UNKNOWNOID)
- && (input_typeids[i] != InvalidOid))
- current_type = input_typeids[i];
- else
- unknownOids = TRUE;
- }
-
- if (unknownOids && (current_type != UNKNOWNOID))
- {
- for (current_candidate = candidates;
- current_candidate != NULL;
- current_candidate = current_candidate->next)
- {
- current_typeids = current_candidate->args;
- nmatch = 0;
- for (i = 0; i < nargs; i++)
- {
- if (current_type == current_typeids[i])
- nmatch++;
- }
- if (nmatch == nargs)
- return current_candidate->oid;
- }
- }
-
- /*
- * Second try: same algorithm as for unknown resolution in
- * parse_func.c.
- *
- * 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.
+ * Use the same heuristics as for ambiguous functions to resolve
+ * the conflict.
*/
- resolved_unknowns = false;
- for (i = 0; i < nargs; i++)
- {
- 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)
- {
- current_typeids = current_candidate->args;
- current_type = current_typeids[i];
- current_category = TypeCategory(current_type);
- if (slot_category[i] == 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)
- {
- /* STRING always wins if available */
- slot_category[i] = current_category;
- slot_has_preferred_type[i] =
- IsPreferredType(current_category, current_type);
- }
- else
- {
- /*
- * Remember conflict, but keep going (might find
- * STRING)
- */
- have_conflict = true;
- }
- }
- }
- if (have_conflict && slot_category[i] != STRING_TYPE)
- {
- /* Failed to resolve category conflict at this position */
- resolved_unknowns = false;
- break;
- }
- }
+ candidates = func_select_candidate(nargs, input_typeids, candidates);
- 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])
- {
- 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)
+ if (candidates)
return candidates->oid;
- return InvalidOid; /* failed to determine a unique candidate */
+ return InvalidOid; /* failed to select a best candidate */
} /* oper_select_candidate() */
@@ -751,7 +366,7 @@ oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError)
/*
* Unspecified type for one of the arguments? then use the
- * other
+ * other (XXX this is probably dead code?)
*/
if (rtypeId == InvalidOid)
rtypeId = ltypeId;