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.c149
1 files changed, 101 insertions, 48 deletions
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index e55f638765b..cd557994f17 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.46 2001/01/24 19:43:02 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.47 2001/02/16 03:16:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,15 +40,15 @@ static void unary_op_error(char *op, Oid arg, bool is_left_op);
/* Select an ordering operator for the given datatype */
Oid
-any_ordering_op(Oid restype)
+any_ordering_op(Oid argtype)
{
Oid order_opid;
- order_opid = oper_oid("<", restype, restype, true);
+ order_opid = compatible_oper_opid("<", argtype, argtype, true);
if (!OidIsValid(order_opid))
elog(ERROR, "Unable to identify an ordering operator '%s' for type '%s'"
"\n\tUse an explicit ordering operator or modify the query",
- "<", typeidTypeName(restype));
+ "<", typeidTypeName(argtype));
return order_opid;
}
@@ -59,6 +59,15 @@ oprid(Operator op)
return op->t_data->t_oid;
}
+/* given operator tuple, return the underlying function's OID */
+Oid
+oprfuncid(Operator op)
+{
+ Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(op);
+
+ return pgopform->oprcode;
+}
+
/* binary_oper_get_candidates()
* given opname, find all possible input type pairs for which an operator
@@ -119,7 +128,7 @@ binary_oper_get_candidates(char *opname,
/* oper_select_candidate()
- * Given the input argtype array and more than one 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.
@@ -593,34 +602,22 @@ oper_inexact(char *op, Oid arg1, Oid arg2)
if (ncandidates == 0)
return NULL;
- /* Or found exactly one? Then proceed... */
- else if (ncandidates == 1)
+ /* Otherwise, check for compatible datatypes, and then try to resolve
+ * the conflict if more than one candidate remains.
+ */
+ inputOids[0] = arg1;
+ inputOids[1] = arg2;
+ targetOids = oper_select_candidate(2, inputOids, candidates);
+ if (targetOids != NULL)
{
tup = SearchSysCache(OPERNAME,
PointerGetDatum(op),
- ObjectIdGetDatum(candidates->args[0]),
- ObjectIdGetDatum(candidates->args[1]),
+ ObjectIdGetDatum(targetOids[0]),
+ ObjectIdGetDatum(targetOids[1]),
CharGetDatum('b'));
- Assert(HeapTupleIsValid(tup));
}
-
- /* Otherwise, multiple operators of the desired types found... */
else
- {
- inputOids[0] = arg1;
- inputOids[1] = arg2;
- targetOids = oper_select_candidate(2, inputOids, candidates);
- if (targetOids != NULL)
- {
- tup = SearchSysCache(OPERNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(targetOids[0]),
- ObjectIdGetDatum(targetOids[1]),
- CharGetDatum('b'));
- }
- else
- tup = NULL;
- }
+ tup = NULL;
return (Operator) tup;
}
@@ -628,6 +625,10 @@ oper_inexact(char *op, Oid arg1, Oid arg2)
/* oper() -- search for a binary operator
* Given operator name, types of arg1 and arg2, return oper struct.
*
+ * IMPORTANT: the returned operator (if any) is only promised to be
+ * coercion-compatible with the input datatypes. Do not use this if
+ * you need an exact- or binary-compatible match; see compatible_oper.
+ *
* If no matching operator found, return NULL if noError is true,
* raise an error if it is false.
*
@@ -653,19 +654,51 @@ oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError)
return (Operator) NULL;
}
-/* oper_oid() -- get OID of a binary operator
+/* compatible_oper()
+ * given an opname and input datatypes, find a compatible binary operator
+ *
+ * This is tighter than oper() because it will not return an operator that
+ * requires coercion of the input datatypes (but binary-compatible operators
+ * are accepted). Otherwise, the semantics are the same.
+ */
+Operator
+compatible_oper(char *op, Oid arg1, Oid arg2, bool noError)
+{
+ Operator optup;
+ Form_pg_operator opform;
+
+ /* oper() will find the best available match */
+ optup = oper(op, arg1, arg2, noError);
+ if (optup == (Operator) NULL)
+ return (Operator) NULL; /* must be noError case */
+
+ /* but is it good enough? */
+ opform = (Form_pg_operator) GETSTRUCT(optup);
+ if ((opform->oprleft == arg1 ||
+ IS_BINARY_COMPATIBLE(opform->oprleft, arg1)) &&
+ (opform->oprright == arg2 ||
+ IS_BINARY_COMPATIBLE(opform->oprright, arg2)))
+ return optup;
+
+ if (!noError)
+ op_error(op, arg1, arg2);
+
+ return (Operator) NULL;
+}
+
+/* compatible_oper_opid() -- get OID of a binary operator
*
* This is a convenience routine that extracts only the operator OID
- * from the result of oper(). InvalidOid is returned if the lookup
- * fails and noError is true.
+ * from the result of compatible_oper(). InvalidOid is returned if the
+ * lookup fails and noError is true.
*/
Oid
-oper_oid(char *op, Oid arg1, Oid arg2, bool noError)
+compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError)
{
Operator optup;
Oid result;
- optup = oper(op, arg1, arg2, noError);
+ optup = compatible_oper(op, arg1, arg2, noError);
if (optup != NULL)
{
result = oprid(optup);
@@ -675,6 +708,28 @@ oper_oid(char *op, Oid arg1, Oid arg2, bool noError)
return InvalidOid;
}
+/* compatible_oper_funcid() -- get OID of a binary operator's function
+ *
+ * This is a convenience routine that extracts only the function OID
+ * from the result of compatible_oper(). InvalidOid is returned if the
+ * lookup fails and noError is true.
+ */
+Oid
+compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError)
+{
+ Operator optup;
+ Oid result;
+
+ optup = compatible_oper(op, arg1, arg2, noError);
+ if (optup != NULL)
+ {
+ result = oprfuncid(optup);
+ ReleaseSysCache(optup);
+ return result;
+ }
+ return InvalidOid;
+}
+
/* unary_oper_get_candidates()
* given opname, find all possible types for which
* a right/left unary operator named opname exists.
@@ -738,6 +793,10 @@ unary_oper_get_candidates(char *opname,
/* Given unary right operator (operator on right), return oper struct
*
+ * IMPORTANT: the returned operator (if any) is only promised to be
+ * coercion-compatible with the input datatype. Do not use this if
+ * you need an exact- or binary-compatible match.
+ *
* Always raises error on failure.
*
* NOTE: on success, the returned object is a syscache entry. The caller
@@ -764,16 +823,11 @@ right_oper(char *op, Oid arg)
ncandidates = unary_oper_get_candidates(op, &candidates, 'r');
if (ncandidates == 0)
unary_op_error(op, arg, FALSE);
- else if (ncandidates == 1)
- {
- tup = SearchSysCache(OPERNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(candidates->args[0]),
- ObjectIdGetDatum(InvalidOid),
- CharGetDatum('r'));
- }
else
{
+ /* We must run oper_select_candidate even if only one candidate,
+ * otherwise we may falsely return a non-type-compatible operator.
+ */
targetOid = oper_select_candidate(1, &arg, candidates);
if (targetOid != NULL)
tup = SearchSysCache(OPERNAME,
@@ -793,6 +847,10 @@ right_oper(char *op, Oid arg)
/* Given unary left operator (operator on left), return oper struct
*
+ * IMPORTANT: the returned operator (if any) is only promised to be
+ * coercion-compatible with the input datatype. Do not use this if
+ * you need an exact- or binary-compatible match.
+ *
* Always raises error on failure.
*
* NOTE: on success, the returned object is a syscache entry. The caller
@@ -819,16 +877,11 @@ left_oper(char *op, Oid arg)
ncandidates = unary_oper_get_candidates(op, &candidates, 'l');
if (ncandidates == 0)
unary_op_error(op, arg, TRUE);
- else if (ncandidates == 1)
- {
- tup = SearchSysCache(OPERNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(InvalidOid),
- ObjectIdGetDatum(candidates->args[0]),
- CharGetDatum('l'));
- }
else
{
+ /* We must run oper_select_candidate even if only one candidate,
+ * otherwise we may falsely return a non-type-compatible operator.
+ */
targetOid = oper_select_candidate(1, &arg, candidates);
if (targetOid != NULL)
tup = SearchSysCache(OPERNAME,