for (i = 0; i < attr_cnt; i++)
{
Operator func_operator;
- Form_pg_operator pgopform;
VacAttrStats *stats;
stats = &vacattrstats[i];
stats->best_cnt = stats->guess1_cnt = stats->guess1_hits = stats->guess2_hits = 0;
stats->max_cnt = stats->min_cnt = stats->null_cnt = stats->nonnull_cnt = 0;
- func_operator = oper("=", stats->attr->atttypid, stats->attr->atttypid, true);
+ func_operator = compatible_oper("=",
+ stats->attr->atttypid,
+ stats->attr->atttypid,
+ true);
if (func_operator != NULL)
{
- pgopform = (Form_pg_operator) GETSTRUCT(func_operator);
- fmgr_info(pgopform->oprcode, &(stats->f_cmpeq));
+ fmgr_info(oprfuncid(func_operator), &(stats->f_cmpeq));
ReleaseSysCache(func_operator);
}
else
stats->f_cmpeq.fn_addr = NULL;
- func_operator = oper("<", stats->attr->atttypid, stats->attr->atttypid, true);
+ func_operator = compatible_oper("<",
+ stats->attr->atttypid,
+ stats->attr->atttypid,
+ true);
if (func_operator != NULL)
{
- pgopform = (Form_pg_operator) GETSTRUCT(func_operator);
- fmgr_info(pgopform->oprcode, &(stats->f_cmplt));
+ fmgr_info(oprfuncid(func_operator), &(stats->f_cmplt));
stats->op_cmplt = oprid(func_operator);
ReleaseSysCache(func_operator);
}
stats->op_cmplt = InvalidOid;
}
- func_operator = oper(">", stats->attr->atttypid, stats->attr->atttypid, true);
+ func_operator = compatible_oper(">",
+ stats->attr->atttypid,
+ stats->attr->atttypid,
+ true);
if (func_operator != NULL)
{
- pgopform = (Form_pg_operator) GETSTRUCT(func_operator);
- fmgr_info(pgopform->oprcode, &(stats->f_cmpgt));
+ fmgr_info(oprfuncid(func_operator), &(stats->f_cmpgt));
ReleaseSysCache(func_operator);
}
else
/* 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;
}
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
/* 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.
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;
}
/* 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.
*
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);
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.
/* 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.
*
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,
/* 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.
*
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,
/*-------------------------------------------------------------------------
*
- * catalog_utils.h
+ * parse_oper.h
*
*
*
typedef HeapTuple Operator;
+/* Routines to find operators matching a name and given input types */
+/* NB: the selected operator may require coercion of the input types! */
extern Operator oper(char *op, Oid arg1, Oid arg2, bool noError);
extern Operator right_oper(char *op, Oid arg);
extern Operator left_oper(char *op, Oid arg);
-extern Oid oper_oid(char *op, Oid arg1, Oid arg2, bool noError);
-extern Oid oprid(Operator op);
+/* Routines to find operators that DO NOT require coercion --- ie, their */
+/* input types are either exactly as given, or binary-compatible */
+extern Operator compatible_oper(char *op, Oid arg1, Oid arg2, bool noError);
+/* currently no need for compatible_left_oper/compatible_right_oper */
+
+/* Convenience routines that call compatible_oper() and return either */
+/* the operator OID or the underlying function OID, or InvalidOid if fail */
+extern Oid compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError);
+extern Oid compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError);
-extern Oid any_ordering_op(Oid restype);
+/* Convenience routine that packages a specific call on compatible_oper */
+extern Oid any_ordering_op(Oid argtype);
+
+/* Extract operator OID or underlying-function OID from an Operator tuple */
+extern Oid oprid(Operator op);
+extern Oid oprfuncid(Operator op);
#endif /* PARSE_OPER_H */