aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/parse_coerce.c150
-rw-r--r--src/backend/parser/parse_func.c213
-rw-r--r--src/backend/parser/parse_oper.c421
3 files changed, 221 insertions, 563 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 9dc0c7f1c19..fc35c2d6d41 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.96 2003/04/29 22:13:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.97 2003/05/26 00:11:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,7 +32,6 @@
static Node *coerce_type_typmod(Node *node,
Oid targetTypeId, int32 targetTypMod,
CoercionForm cformat, bool isExplicit);
-static Oid PreferredType(CATEGORY category, Oid type);
static Node *build_func_call(Oid funcid, Oid rettype, List *args,
CoercionForm fformat);
@@ -66,28 +65,43 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
if (can_coerce_type(1, &exprtype, &targettype, ccontext))
expr = coerce_type(pstate, expr, exprtype, targettype,
ccontext, cformat);
- /*
- * String hacks to get transparent conversions for char and varchar:
- * if a coercion to text is available, use it for forced coercions to
- * char(n) or varchar(n).
- *
- * This is pretty grotty, but seems easier to maintain than providing
- * entries in pg_cast that parallel all the ones for text.
- */
- else if (ccontext >= COERCION_ASSIGNMENT &&
- (targettype == BPCHAROID || targettype == VARCHAROID))
+ else if (ccontext >= COERCION_ASSIGNMENT)
{
- Oid text_id = TEXTOID;
+ /*
+ * String hacks to get transparent conversions for char and varchar:
+ * if a coercion to text is available, use it for forced coercions to
+ * char(n) or varchar(n) or domains thereof.
+ *
+ * This is pretty grotty, but seems easier to maintain than providing
+ * entries in pg_cast that parallel all the ones for text.
+ */
+ Oid targetbasetype = getBaseType(targettype);
- if (can_coerce_type(1, &exprtype, &text_id, ccontext))
+ if (targetbasetype == BPCHAROID || targetbasetype == VARCHAROID)
{
- expr = coerce_type(pstate, expr, exprtype, text_id,
- ccontext, cformat);
- /* Need a RelabelType if no typmod coercion is performed */
- if (targettypmod < 0)
- expr = (Node *) makeRelabelType((Expr *) expr,
- targettype, -1,
- cformat);
+ Oid text_id = TEXTOID;
+
+ if (can_coerce_type(1, &exprtype, &text_id, ccontext))
+ {
+ expr = coerce_type(pstate, expr, exprtype, text_id,
+ ccontext, cformat);
+ if (targetbasetype != targettype)
+ {
+ /* need to coerce to domain over char or varchar */
+ expr = coerce_to_domain(expr, targetbasetype, targettype,
+ cformat);
+ }
+ else
+ {
+ /* need a RelabelType if no typmod coercion will be performed */
+ if (targettypmod < 0)
+ expr = (Node *) makeRelabelType((Expr *) expr,
+ targettype, -1,
+ cformat);
+ }
+ }
+ else
+ expr = NULL;
}
else
expr = NULL;
@@ -923,7 +937,10 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
/* TypeCategory()
- * Assign a category to the specified OID.
+ * Assign a category to the specified type OID.
+ *
+ * NB: this must not return INVALID_TYPE.
+ *
* XXX This should be moved to system catalog lookups
* to allow for better type extensibility.
* - thomas 2001-09-30
@@ -1026,7 +1043,11 @@ TypeCategory(Oid inType)
/* IsPreferredType()
- * Check if this type is a preferred type.
+ * Check if this type is a preferred type for the given category.
+ *
+ * If category is INVALID_TYPE, then we'll return TRUE for preferred types
+ * of any category; otherwise, only for preferred types of that category.
+ *
* XXX This should be moved to system catalog lookups
* to allow for better type extensibility.
* - thomas 2001-09-30
@@ -1034,39 +1055,34 @@ TypeCategory(Oid inType)
bool
IsPreferredType(CATEGORY category, Oid type)
{
- return (type == PreferredType(category, type));
-} /* IsPreferredType() */
+ Oid preftype;
+ if (category == INVALID_TYPE)
+ category = TypeCategory(type);
+ else if (category != TypeCategory(type))
+ return false;
-/* PreferredType()
- * Return the preferred type OID for the specified category.
- * XXX This should be moved to system catalog lookups
- * to allow for better type extensibility.
- * - thomas 2001-09-30
- */
-static Oid
-PreferredType(CATEGORY category, Oid type)
-{
- Oid result;
-
+ /*
+ * This switch should agree with TypeCategory(), above. Note that
+ * at this point, category certainly matches the type.
+ */
switch (category)
{
- case (INVALID_TYPE):
case (UNKNOWN_TYPE):
case (GENERIC_TYPE):
- result = UNKNOWNOID;
+ preftype = UNKNOWNOID;
break;
case (BOOLEAN_TYPE):
- result = BOOLOID;
+ preftype = BOOLOID;
break;
case (STRING_TYPE):
- result = TEXTOID;
+ preftype = TEXTOID;
break;
case (BITSTRING_TYPE):
- result = VARBITOID;
+ preftype = VARBITOID;
break;
case (NUMERIC_TYPE):
@@ -1077,52 +1093,59 @@ PreferredType(CATEGORY category, Oid type)
type == REGOPERATOROID ||
type == REGCLASSOID ||
type == REGTYPEOID)
- result = OIDOID;
+ preftype = OIDOID;
else
- result = FLOAT8OID;
+ preftype = FLOAT8OID;
break;
case (DATETIME_TYPE):
if (type == DATEOID)
- result = TIMESTAMPOID;
+ preftype = TIMESTAMPOID;
else
- result = TIMESTAMPTZOID;
+ preftype = TIMESTAMPTZOID;
break;
case (TIMESPAN_TYPE):
- result = INTERVALOID;
+ preftype = INTERVALOID;
break;
case (GEOMETRIC_TYPE):
- result = type;
+ preftype = type;
break;
case (NETWORK_TYPE):
- result = INETOID;
+ preftype = INETOID;
break;
case (USER_TYPE):
- result = type;
+ preftype = type;
break;
default:
- elog(ERROR, "PreferredType: unknown category");
- result = UNKNOWNOID;
+ elog(ERROR, "IsPreferredType: unknown category");
+ preftype = UNKNOWNOID;
break;
}
- return result;
-} /* PreferredType() */
+
+ return (type == preftype);
+} /* IsPreferredType() */
/* IsBinaryCoercible()
* Check if srctype is binary-coercible to targettype.
*
* This notion allows us to cheat and directly exchange values without
- * going through the trouble of calling a conversion function.
+ * going through the trouble of calling a conversion function. Note that
+ * in general, this should only be an implementation shortcut. Before 7.4,
+ * this was also used as a heuristic for resolving overloaded functions and
+ * operators, but that's basically a bad idea.
*
* As of 7.3, binary coercibility isn't hardwired into the code anymore.
* We consider two types binary-coercible if there is an implicitly
- * invokable, no-function-needed pg_cast entry.
+ * invokable, no-function-needed pg_cast entry. Also, a domain is always
+ * binary-coercible to its base type, though *not* vice versa (in the other
+ * direction, one must apply domain constraint checks before accepting the
+ * value as legitimate).
*
* This function replaces IsBinaryCompatible(), which was an inherently
* symmetric test. Since the pg_cast entries aren't necessarily symmetric,
@@ -1139,13 +1162,11 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
if (srctype == targettype)
return true;
- /* Perhaps the types are domains; if so, look at their base types */
+ /* If srctype is a domain, reduce to its base type */
if (OidIsValid(srctype))
srctype = getBaseType(srctype);
- if (OidIsValid(targettype))
- targettype = getBaseType(targettype);
- /* Somewhat-fast path if same base type */
+ /* Somewhat-fast path for domain -> base type case */
if (srctype == targettype)
return true;
@@ -1174,8 +1195,13 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
* ccontext determines the set of available casts.
*
* If we find a suitable entry in pg_cast, return TRUE, and set *funcid
- * to the castfunc value (which may be InvalidOid for a binary-compatible
- * coercion).
+ * to the castfunc value, which may be InvalidOid for a binary-compatible
+ * coercion.
+ *
+ * NOTE: *funcid == InvalidOid does not necessarily mean that no work is
+ * needed to do the coercion; if the target is a domain then we may need to
+ * apply domain constraint checking. If you want to check for a zero-effort
+ * conversion then use IsBinaryCoercible().
*/
bool
find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
@@ -1193,7 +1219,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
if (OidIsValid(targetTypeId))
targetTypeId = getBaseType(targetTypeId);
- /* Domains are automatically binary-compatible with their base type */
+ /* Domains are always coercible to and from their base type */
if (sourceTypeId == targetTypeId)
return true;
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 058b9aad73d..e9a40e03179 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.147 2003/04/29 22:13:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.148 2003/05/26 00:11:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,7 +16,6 @@
#include "access/heapam.h"
#include "catalog/catname.h"
-#include "catalog/namespace.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_proc.h"
#include "lib/stringinfo.h"
@@ -37,13 +36,7 @@ static Oid **argtype_inherit(int nargs, Oid *argtypes);
static int find_inheritors(Oid relid, Oid **supervec);
static Oid **gen_cross_product(InhPaths *arginh, int nargs);
-static int match_argtypes(int nargs,
- Oid *input_typeids,
- FuncCandidateList function_typeids,
- FuncCandidateList *candidates);
static FieldSelect *setup_field_select(Node *input, char *attname, Oid relid);
-static FuncCandidateList func_select_candidate(int nargs, Oid *input_typeids,
- FuncCandidateList candidates);
static void unknown_attribute(const char *schemaname, const char *relname,
const char *attname);
@@ -355,21 +348,24 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
}
-/* match_argtypes()
+/* func_match_argtypes()
*
- * Given a list of possible typeid arrays to a function and an array of
- * input typeids, produce a shortlist of those function typeid arrays
- * that match the input typeids (either exactly or by coercion), and
- * return the number of such arrays.
+ * Given a list of candidate functions (having the right name and number
+ * of arguments) and an array of input datatype OIDs, produce a shortlist of
+ * those candidates that actually accept the input datatypes (either exactly
+ * or by coercion), and return the number of such candidates.
+ *
+ * Note that can_coerce_type will assume that UNKNOWN inputs are coercible to
+ * anything, so candidates will not be eliminated on that basis.
*
* NB: okay to modify input list structure, as long as we find at least
- * one match.
+ * one match. If no match at all, the list must remain unmodified.
*/
-static int
-match_argtypes(int nargs,
- Oid *input_typeids,
- FuncCandidateList function_typeids,
- FuncCandidateList *candidates) /* return value */
+int
+func_match_argtypes(int nargs,
+ Oid *input_typeids,
+ FuncCandidateList raw_candidates,
+ FuncCandidateList *candidates) /* return value */
{
FuncCandidateList current_candidate;
FuncCandidateList next_candidate;
@@ -377,7 +373,7 @@ match_argtypes(int nargs,
*candidates = NULL;
- for (current_candidate = function_typeids;
+ for (current_candidate = raw_candidates;
current_candidate != NULL;
current_candidate = next_candidate)
{
@@ -392,21 +388,65 @@ match_argtypes(int nargs,
}
return ncandidates;
-} /* match_argtypes() */
+} /* func_match_argtypes() */
/* func_select_candidate()
- * Given the input argtype array and more than one candidate
- * for the function, attempt to resolve the conflict.
+ * Given the input argtype array and more than one candidate
+ * for the function, attempt to resolve the conflict.
+ *
* Returns the selected candidate if the conflict can be resolved,
* otherwise returns NULL.
*
- * By design, this is pretty similar to oper_select_candidate in parse_oper.c.
- * However, the calling convention is a little different: we assume the caller
- * already pruned away "candidates" that aren't actually coercion-compatible
- * with the input types, whereas oper_select_candidate must do that itself.
+ * Note that the caller has already determined that there is no candidate
+ * exactly matching the input argtypes, and has pruned away any "candidates"
+ * that aren't actually coercion-compatible with the input types.
+ *
+ * This is also used for resolving ambiguous operator references. Formerly
+ * parse_oper.c had its own, essentially duplicate code for the purpose.
+ * The following comments (formerly in parse_oper.c) are kept to record some
+ * of the history of these heuristics.
+ *
+ * OLD COMMENTS:
+ *
+ * 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
*/
-static FuncCandidateList
+FuncCandidateList
func_select_candidate(int nargs,
Oid *input_typeids,
FuncCandidateList candidates)
@@ -419,59 +459,28 @@ func_select_candidate(int nargs,
int ncandidates;
int nbestMatch,
nmatch;
+ Oid input_base_typeids[FUNC_MAX_ARGS];
CATEGORY slot_category[FUNC_MAX_ARGS],
current_category;
bool slot_has_preferred_type[FUNC_MAX_ARGS];
bool resolved_unknowns;
/*
- * Run through all candidates and keep those with the most matches on
- * exact types. Keep all candidates if none match.
+ * If any input types are domains, reduce them to their base types.
+ * This ensures that we will consider functions on the base type to be
+ * "exact matches" in the exact-match heuristic; it also makes it possible
+ * to do something useful with the type-category heuristics. Note that
+ * this makes it difficult, but not impossible, to use functions declared
+ * to take a domain as an input datatype. Such a function will be
+ * selected over the base-type function only if it is an exact match at
+ * all argument positions, and so was already chosen by our caller.
*/
- 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;
+ for (i = 0; i < nargs; i++)
+ input_base_typeids[i] = getBaseType(input_typeids[i]);
/*
- * 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.
+ * Run through all candidates and keep those with the most matches on
+ * exact types. Keep all candidates if none match.
*/
ncandidates = 0;
nbestMatch = 0;
@@ -484,11 +493,9 @@ func_select_candidate(int nargs,
nmatch = 0;
for (i = 0; i < nargs; i++)
{
- if (input_typeids[i] != UNKNOWNOID)
- {
- if (IsBinaryCoercible(input_typeids[i], current_typeids[i]))
- nmatch++;
- }
+ if (input_base_typeids[i] != UNKNOWNOID &&
+ current_typeids[i] == input_base_typeids[i])
+ nmatch++;
}
/* take this one as the best choice so far? */
@@ -516,10 +523,14 @@ func_select_candidate(int nargs,
return candidates;
/*
- * 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.
+ * Still too many candidates? Now look for candidates which have either
+ * exact matches or preferred types at the args that will require coercion.
+ * (Restriction added in 7.4: preferred type must be of same category as
+ * input type; give no preference to cross-category conversions to
+ * preferred types.) Keep all candidates if none match.
*/
+ for (i = 0; i < nargs; i++) /* avoid multiple lookups */
+ slot_category[i] = TypeCategory(input_base_typeids[i]);
ncandidates = 0;
nbestMatch = 0;
last_candidate = NULL;
@@ -531,11 +542,10 @@ func_select_candidate(int nargs,
nmatch = 0;
for (i = 0; i < nargs; i++)
{
- if (input_typeids[i] != UNKNOWNOID)
+ if (input_base_typeids[i] != UNKNOWNOID)
{
- current_category = TypeCategory(current_typeids[i]);
- if (current_typeids[i] == input_typeids[i] ||
- IsPreferredType(current_category, current_typeids[i]))
+ if (current_typeids[i] == input_base_typeids[i] ||
+ IsPreferredType(slot_category[i], current_typeids[i]))
nmatch++;
}
}
@@ -565,6 +575,11 @@ func_select_candidate(int nargs,
* Still too many candidates? Try assigning types for the unknown
* columns.
*
+ * NOTE: for a binary operator with one unknown and one non-unknown input,
+ * we already tried the heuristic of looking for a candidate with the
+ * known input type on both sides (see binary_oper_exact()). That's
+ * essentially a special case of the general algorithm we try next.
+ *
* 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
@@ -588,7 +603,7 @@ func_select_candidate(int nargs,
{
bool have_conflict;
- if (input_typeids[i] != UNKNOWNOID)
+ if (input_base_typeids[i] != UNKNOWNOID)
continue;
resolved_unknowns = true; /* assume we can do it */
slot_category[i] = INVALID_TYPE;
@@ -656,7 +671,7 @@ func_select_candidate(int nargs,
current_typeids = current_candidate->args;
for (i = 0; i < nargs; i++)
{
- if (input_typeids[i] != UNKNOWNOID)
+ if (input_base_typeids[i] != UNKNOWNOID)
continue;
current_type = current_typeids[i];
current_category = TypeCategory(current_type);
@@ -694,7 +709,7 @@ func_select_candidate(int nargs,
if (ncandidates == 1)
return candidates;
- return NULL; /* failed to determine a unique candidate */
+ return NULL; /* failed to select a best candidate */
} /* func_select_candidate() */
@@ -734,16 +749,17 @@ func_get_detail(List *funcname,
bool *retset, /* return value */
Oid **true_typeids) /* return value */
{
- FuncCandidateList function_typeids;
+ FuncCandidateList raw_candidates;
FuncCandidateList best_candidate;
/* Get list of possible candidates from namespace search */
- function_typeids = FuncnameGetCandidates(funcname, nargs);
+ raw_candidates = FuncnameGetCandidates(funcname, nargs);
/*
- * See if there is an exact match
+ * Quickly check if there is an exact match to the input datatypes
+ * (there can be only one)
*/
- for (best_candidate = function_typeids;
+ for (best_candidate = raw_candidates;
best_candidate != NULL;
best_candidate = best_candidate->next)
{
@@ -815,7 +831,7 @@ func_get_detail(List *funcname,
* didn't find an exact match, so now try to match up
* candidates...
*/
- if (function_typeids != NULL)
+ if (raw_candidates != NULL)
{
Oid **input_typeid_vector = NULL;
Oid *current_input_typeids;
@@ -829,17 +845,18 @@ func_get_detail(List *funcname,
do
{
- FuncCandidateList current_function_typeids;
+ FuncCandidateList current_candidates;
int ncandidates;
- ncandidates = match_argtypes(nargs, current_input_typeids,
- function_typeids,
- &current_function_typeids);
+ ncandidates = func_match_argtypes(nargs,
+ current_input_typeids,
+ raw_candidates,
+ &current_candidates);
/* one match only? then run with it... */
if (ncandidates == 1)
{
- best_candidate = current_function_typeids;
+ best_candidate = current_candidates;
break;
}
@@ -851,7 +868,7 @@ func_get_detail(List *funcname,
{
best_candidate = func_select_candidate(nargs,
current_input_typeids,
- current_function_typeids);
+ current_candidates);
/*
* If we were able to choose a best candidate, we're
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;