Fix poorly worded error messages for unary operator type resolution
authorTom Lane
Sun, 27 Feb 2000 02:48:15 +0000 (02:48 +0000)
committerTom Lane
Sun, 27 Feb 2000 02:48:15 +0000 (02:48 +0000)
failures.  Fix some outright bugs too, including a reference to
uninitialized memory that would cause failures like this one:
select -('1234567890.1234567'::text);
ERROR:  Unable to locate type oid 2139062143 in catalog

src/backend/parser/parse_oper.c

index 21fdb2203245e4361f7e5b53639c4e8a1304e28b..426c61887e6099842aae8543dc720fc48154a583 100644 (file)
@@ -1,6 +1,6 @@
 /*-------------------------------------------------------------------------
  *
- * parse_oper.h
+ * parse_oper.c
  *     handle operator things for parser
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.35 2000/01/26 05:56:42 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.36 2000/02/27 02:48:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,6 +35,8 @@ static int unary_oper_get_candidates(char *op,
                          CandidateList *candidates,
                          char rightleft);
 static void op_error(char *op, Oid arg1, Oid arg2);
+static void unary_op_error(char *op, Oid arg, bool is_left_op);
+
 
 Oid
 any_ordering_op(Oid restype)
@@ -224,11 +226,11 @@ oper_select_candidate(int nargs,
 
    if (ncandidates <= 1)
    {
-       if (ncandidates > 0 &&
-           (!can_coerce_type(1, &input_typeids[0], &candidates->args[0]) ||
-            (nargs > 1 &&
-             !can_coerce_type(1, &input_typeids[1], &candidates->args[1]))))
-           ncandidates = 0;
+       if (ncandidates > 0)
+       {
+           if (!can_coerce_type(nargs, input_typeids, candidates->args))
+               ncandidates = 0;
+       }
        return (ncandidates == 1) ? candidates->args : NULL;
    }
 
@@ -279,11 +281,11 @@ oper_select_candidate(int nargs,
 
    if (ncandidates <= 1)
    {
-       if (ncandidates > 0 &&
-           (!can_coerce_type(1, &input_typeids[0], &candidates->args[0]) ||
-            (nargs > 1 &&
-             !can_coerce_type(1, &input_typeids[1], &candidates->args[1]))))
-           ncandidates = 0;
+       if (ncandidates > 0)
+       {
+           if (!can_coerce_type(nargs, input_typeids, candidates->args))
+               ncandidates = 0;
+       }
        return (ncandidates == 1) ? candidates->args : NULL;
    }
 
@@ -368,8 +370,7 @@ oper_select_candidate(int nargs,
         current_candidate != NULL;
         current_candidate = current_candidate->next)
    {
-       if (can_coerce_type(1, &input_typeids[0], ¤t_candidate->args[0])
-           && can_coerce_type(1, &input_typeids[1], ¤t_candidate->args[1]))
+       if (can_coerce_type(nargs, input_typeids, current_candidate->args))
        {
            ncandidates++;
            last_candidate = current_candidate;
@@ -559,6 +560,7 @@ right_oper(char *op, Oid arg)
    int         ncandidates;
    Oid        *targetOid;
 
+   /* Try for exact match */
    tup = SearchSysCacheTuple(OPERNAME,
                              PointerGetDatum(op),
                              ObjectIdGetDatum(arg),
@@ -567,44 +569,35 @@ right_oper(char *op, Oid arg)
 
    if (!HeapTupleIsValid(tup))
    {
+       /* Try for inexact matches */
        ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r');
        if (ncandidates == 0)
        {
-           elog(ERROR, "Can't find right op '%s' for type %u", op, arg);
-           return NULL;
+           unary_op_error(op, arg, FALSE);
        }
        else if (ncandidates == 1)
        {
            tup = SearchSysCacheTuple(OPERNAME,
                                      PointerGetDatum(op),
-                                  ObjectIdGetDatum(candidates->args[0]),
+                                     ObjectIdGetDatum(candidates->args[0]),
                                      ObjectIdGetDatum(InvalidOid),
                                      CharGetDatum('r'));
-           Assert(HeapTupleIsValid(tup));
        }
        else
        {
            targetOid = oper_select_candidate(1, &arg, candidates);
-
            if (targetOid != NULL)
-           {
                tup = SearchSysCacheTuple(OPERNAME,
                                          PointerGetDatum(op),
+                                         ObjectIdGetDatum(targetOid[0]),
                                          ObjectIdGetDatum(InvalidOid),
-                                         ObjectIdGetDatum(*targetOid),
                                          CharGetDatum('r'));
-           }
-           else
-               tup = NULL;
-
-           if (!HeapTupleIsValid(tup))
-           {
-               elog(ERROR, "Unable to convert right operator '%s' from type '%s'",
-                    op, typeidTypeName(arg));
-               return NULL;
-           }
        }
+
+       if (!HeapTupleIsValid(tup))
+           unary_op_error(op, arg, FALSE);
    }
+
    return (Operator) tup;
 }  /* right_oper() */
 
@@ -619,6 +612,7 @@ left_oper(char *op, Oid arg)
    int         ncandidates;
    Oid        *targetOid;
 
+   /* Try for exact match */
    tup = SearchSysCacheTuple(OPERNAME,
                              PointerGetDatum(op),
                              ObjectIdGetDatum(InvalidOid),
@@ -627,43 +621,35 @@ left_oper(char *op, Oid arg)
 
    if (!HeapTupleIsValid(tup))
    {
+       /* Try for inexact matches */
        ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l');
        if (ncandidates == 0)
        {
-           elog(ERROR, "Can't find left op '%s' for type %u", op, arg);
-           return NULL;
+           unary_op_error(op, arg, TRUE);
        }
        else if (ncandidates == 1)
        {
            tup = SearchSysCacheTuple(OPERNAME,
                                      PointerGetDatum(op),
                                      ObjectIdGetDatum(InvalidOid),
-                                  ObjectIdGetDatum(candidates->args[0]),
+                                     ObjectIdGetDatum(candidates->args[0]),
                                      CharGetDatum('l'));
-           Assert(HeapTupleIsValid(tup));
        }
        else
        {
            targetOid = oper_select_candidate(1, &arg, candidates);
            if (targetOid != NULL)
-           {
                tup = SearchSysCacheTuple(OPERNAME,
                                          PointerGetDatum(op),
                                          ObjectIdGetDatum(InvalidOid),
-                                         ObjectIdGetDatum(*targetOid),
+                                         ObjectIdGetDatum(targetOid[0]),
                                          CharGetDatum('l'));
-           }
-           else
-               tup = NULL;
-
-           if (!HeapTupleIsValid(tup))
-           {
-               elog(ERROR, "Unable to convert left operator '%s' from type '%s'",
-                    op, typeidTypeName(arg));
-               return NULL;
-           }
        }
+
+       if (!HeapTupleIsValid(tup))
+           unary_op_error(op, arg, TRUE);
    }
+
    return (Operator) tup;
 }  /* left_oper() */
 
@@ -698,3 +684,28 @@ op_error(char *op, Oid arg1, Oid arg2)
         "\n\tYou will have to retype this query using an explicit cast",
         op, typeTypeName(tp1), typeTypeName(tp2));
 }
+
+/* unary_op_error()
+ * Give a somewhat useful error message when the operator for one type
+ * is not found.
+ */
+static void
+unary_op_error(char *op, Oid arg, bool is_left_op)
+{
+   Type        tp1 = NULL;
+
+   if (typeidIsValid(arg))
+       tp1 = typeidType(arg);
+   else
+   {
+       elog(ERROR, "Argument of %s operator '%s' has an unknown type"
+            "\n\tProbably a bad attribute name",
+            (is_left_op ? "left" : "right"),
+            op);
+   }
+
+   elog(ERROR, "Unable to identify a %s operator '%s' for type '%s'"
+        "\n\tYou will have to retype this query using an explicit cast",
+        (is_left_op ? "left" : "right"),
+        op, typeTypeName(tp1));
+}