mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Fix poorly worded error messages for unary operator type resolution
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
			
			
This commit is contained in:
		@@ -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));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user