mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Further fixes for bogus list-slinging, scribbling on input, etc in type
coercion code. I'm beginning to wonder why we have separate candidate selection routines for functions, operators, and aggregates --- shouldn't this code all be unified? But meanwhile, SELECT 'a' LIKE 'a'; finally works; the code for dealing with unknown input types for operators was pretty busted.
This commit is contained in:
		@@ -8,7 +8,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.72 2000/02/20 23:04:06 tgl Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.73 2000/03/11 23:17:47 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -854,11 +854,6 @@ match_argtypes(int nargs,
 | 
				
			|||||||
 * for the function argtype array, attempt to resolve the conflict.
 | 
					 * for the function argtype array, attempt to resolve the conflict.
 | 
				
			||||||
 * returns the selected argtype array if the conflict can be resolved,
 | 
					 * returns the selected argtype array if the conflict can be resolved,
 | 
				
			||||||
 * otherwise returns NULL.
 | 
					 * otherwise returns NULL.
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * If all input Oids are UNKNOWNOID, then try matching with TEXTOID.
 | 
					 | 
				
			||||||
 * Otherwise, could return first function arguments on list of candidates.
 | 
					 | 
				
			||||||
 * But for now, return NULL and make the user give a better hint.
 | 
					 | 
				
			||||||
 * - thomas 1998-03-17
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static Oid *
 | 
					static Oid *
 | 
				
			||||||
func_select_candidate(int nargs,
 | 
					func_select_candidate(int nargs,
 | 
				
			||||||
@@ -869,12 +864,10 @@ func_select_candidate(int nargs,
 | 
				
			|||||||
	CandidateList last_candidate;
 | 
						CandidateList last_candidate;
 | 
				
			||||||
	Oid		   *current_typeids;
 | 
						Oid		   *current_typeids;
 | 
				
			||||||
	int			i;
 | 
						int			i;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	int			ncandidates;
 | 
						int			ncandidates;
 | 
				
			||||||
	int			nbestMatch,
 | 
						int			nbestMatch,
 | 
				
			||||||
				nmatch,
 | 
									nmatch,
 | 
				
			||||||
				nident;
 | 
									ncompat;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	CATEGORY	slot_category,
 | 
						CATEGORY	slot_category,
 | 
				
			||||||
				current_category;
 | 
									current_category;
 | 
				
			||||||
	Oid			slot_type,
 | 
						Oid			slot_type,
 | 
				
			||||||
@@ -893,19 +886,29 @@ func_select_candidate(int nargs,
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		current_typeids = current_candidate->args;
 | 
							current_typeids = current_candidate->args;
 | 
				
			||||||
		nmatch = 0;
 | 
							nmatch = 0;
 | 
				
			||||||
		nident = 0;
 | 
							ncompat = 0;
 | 
				
			||||||
		for (i = 0; i < nargs; i++)
 | 
							for (i = 0; i < nargs; i++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if ((input_typeids[i] != UNKNOWNOID)
 | 
								if (input_typeids[i] != UNKNOWNOID)
 | 
				
			||||||
				&& (current_typeids[i] == input_typeids[i]))
 | 
								{
 | 
				
			||||||
 | 
									if (current_typeids[i] == input_typeids[i])
 | 
				
			||||||
					nmatch++;
 | 
										nmatch++;
 | 
				
			||||||
			else if (IS_BINARY_COMPATIBLE(current_typeids[i], input_typeids[i]))
 | 
									else if (IS_BINARY_COMPATIBLE(current_typeids[i],
 | 
				
			||||||
				nident++;
 | 
																  input_typeids[i]))
 | 
				
			||||||
 | 
										ncompat++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((nmatch + nident) == nargs)
 | 
							/*
 | 
				
			||||||
 | 
							 * If we find an exact match at all arg positions, we're done;
 | 
				
			||||||
 | 
							 * there can be only one such candidate.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (nmatch == nargs)
 | 
				
			||||||
			return current_candidate->args;
 | 
								return current_candidate->args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Otherwise, use match+compat as the score. */
 | 
				
			||||||
 | 
							nmatch += ncompat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* take this one as the best choice so far? */
 | 
							/* take this one as the best choice so far? */
 | 
				
			||||||
		if ((nmatch > nbestMatch) || (last_candidate == NULL))
 | 
							if ((nmatch > nbestMatch) || (last_candidate == NULL))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -933,6 +936,16 @@ func_select_candidate(int nargs,
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Still too many candidates?
 | 
					 * Still too many candidates?
 | 
				
			||||||
 * Try assigning types for the unknown columns.
 | 
					 * Try assigning types for the unknown columns.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * We do this by examining each unknown argument position to see if all the
 | 
				
			||||||
 | 
					 * candidates agree on the type category of that slot.  If so, and if some
 | 
				
			||||||
 | 
					 * candidates accept the preferred type in that category, eliminate the
 | 
				
			||||||
 | 
					 * candidates with other input types.  If we are down to one candidate
 | 
				
			||||||
 | 
					 * at the end, we win.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * XXX It's kinda bogus to do this left-to-right, isn't it?  If we eliminate
 | 
				
			||||||
 | 
					 * some candidates because they are non-preferred at the first slot, we won't
 | 
				
			||||||
 | 
					 * notice that they didn't have the same type category for a later slot.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
	for (i = 0; i < nargs; i++)
 | 
						for (i = 0; i < nargs; i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -947,12 +960,12 @@ func_select_candidate(int nargs,
 | 
				
			|||||||
			{
 | 
								{
 | 
				
			||||||
				current_typeids = current_candidate->args;
 | 
									current_typeids = current_candidate->args;
 | 
				
			||||||
				current_type = current_typeids[i];
 | 
									current_type = current_typeids[i];
 | 
				
			||||||
				current_category = TypeCategory(current_typeids[i]);
 | 
									current_category = TypeCategory(current_type);
 | 
				
			||||||
 | 
									if (slot_category == INVALID_TYPE)
 | 
				
			||||||
				if (slot_category == InvalidOid)
 | 
					 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					slot_category = current_category;
 | 
										slot_category = current_category;
 | 
				
			||||||
					slot_type = current_type;
 | 
										slot_type = current_type;
 | 
				
			||||||
 | 
										last_candidate = current_candidate;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				else if (current_category != slot_category)
 | 
									else if (current_category != slot_category)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.36 2000/02/27 02:48:15 tgl Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.37 2000/03/11 23:17:47 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -128,7 +128,7 @@ binary_oper_get_candidates(char *opname,
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * This routine is new code, replacing binary_oper_select_candidate()
 | 
					 * 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
 | 
					 * which dates from v4.2/v1.0.x days. It tries very hard to match up
 | 
				
			||||||
 * operators with types, including allowing type coersions if necessary.
 | 
					 * operators with types, including allowing type coercions if necessary.
 | 
				
			||||||
 * The important thing is that the code do as much as possible,
 | 
					 * The important thing is that the code do as much as possible,
 | 
				
			||||||
 * while _never_ doing the wrong thing, where "the wrong thing" would
 | 
					 * while _never_ doing the wrong thing, where "the wrong thing" would
 | 
				
			||||||
 * be returning an operator when other better choices are available,
 | 
					 * be returning an operator when other better choices are available,
 | 
				
			||||||
@@ -185,7 +185,7 @@ oper_select_candidate(int nargs,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Run through all candidates and keep those with the most matches
 | 
					 * Run through all candidates and keep those with the most matches
 | 
				
			||||||
 *	on explicit types. Keep all candidates if none match.
 | 
					 *	on exact types. Keep all candidates if none match.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
	ncandidates = 0;
 | 
						ncandidates = 0;
 | 
				
			||||||
	nbestMatch = 0;
 | 
						nbestMatch = 0;
 | 
				
			||||||
@@ -236,7 +236,7 @@ oper_select_candidate(int nargs,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Still too many candidates?
 | 
					 * Still too many candidates?
 | 
				
			||||||
 * Now look for candidates which allow coersion and are preferred types.
 | 
					 * Now look for candidates which allow coercion and are preferred types.
 | 
				
			||||||
 * Keep all candidates if none match.
 | 
					 * Keep all candidates if none match.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
	ncandidates = 0;
 | 
						ncandidates = 0;
 | 
				
			||||||
@@ -292,6 +292,13 @@ oper_select_candidate(int nargs,
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Still too many candidates?
 | 
					 * Still too many candidates?
 | 
				
			||||||
 * Try assigning types for the unknown columns.
 | 
					 * 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;
 | 
						unknownOids = FALSE;
 | 
				
			||||||
	current_type = UNKNOWNOID;
 | 
						current_type = UNKNOWNOID;
 | 
				
			||||||
@@ -314,53 +321,82 @@ oper_select_candidate(int nargs,
 | 
				
			|||||||
			nmatch = 0;
 | 
								nmatch = 0;
 | 
				
			||||||
			for (i = 0; i < nargs; i++)
 | 
								for (i = 0; i < nargs; i++)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (current_type == current_typeids[i] ||
 | 
									if (current_type == current_typeids[i])
 | 
				
			||||||
					IS_BINARY_COMPATIBLE(current_type, current_typeids[i]))
 | 
					 | 
				
			||||||
					nmatch++;
 | 
										nmatch++;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (nmatch == nargs)
 | 
								if (nmatch == nargs)
 | 
				
			||||||
				return candidates->args;
 | 
								{
 | 
				
			||||||
 | 
									/* coercion check here is probably redundant, but be safe */
 | 
				
			||||||
 | 
									if (can_coerce_type(nargs, input_typeids, current_typeids))
 | 
				
			||||||
 | 
										return current_typeids;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Second try: examine each unknown argument position to see if all the
 | 
				
			||||||
 | 
					 * candidates agree on the type category of that slot.  If so, and if some
 | 
				
			||||||
 | 
					 * candidates accept the preferred type in that category, eliminate the
 | 
				
			||||||
 | 
					 * candidates with other input types.  If we are down to one candidate
 | 
				
			||||||
 | 
					 * at the end, we win.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * XXX It's kinda bogus to do this left-to-right, isn't it?  If we eliminate
 | 
				
			||||||
 | 
					 * some candidates because they are non-preferred at the first slot, we won't
 | 
				
			||||||
 | 
					 * notice that they didn't have the same type category for a later slot.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
	for (i = 0; i < nargs; i++)
 | 
						for (i = 0; i < nargs; i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (input_typeids[i] == UNKNOWNOID)
 | 
							if (input_typeids[i] == UNKNOWNOID)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			slot_category = INVALID_TYPE;
 | 
								slot_category = INVALID_TYPE;
 | 
				
			||||||
			slot_type = InvalidOid;
 | 
								slot_type = InvalidOid;
 | 
				
			||||||
 | 
								last_candidate = NULL;
 | 
				
			||||||
			for (current_candidate = candidates;
 | 
								for (current_candidate = candidates;
 | 
				
			||||||
				 current_candidate != NULL;
 | 
									 current_candidate != NULL;
 | 
				
			||||||
				 current_candidate = current_candidate->next)
 | 
									 current_candidate = current_candidate->next)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				current_typeids = current_candidate->args;
 | 
									current_typeids = current_candidate->args;
 | 
				
			||||||
				current_type = current_typeids[i];
 | 
									current_type = current_typeids[i];
 | 
				
			||||||
				current_category = TypeCategory(current_typeids[i]);
 | 
									current_category = TypeCategory(current_type);
 | 
				
			||||||
				if (slot_category == InvalidOid)
 | 
									if (slot_category == INVALID_TYPE)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					slot_category = current_category;
 | 
										slot_category = current_category;
 | 
				
			||||||
					slot_type = current_type;
 | 
										slot_type = current_type;
 | 
				
			||||||
 | 
										last_candidate = current_candidate;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				else if (current_category != slot_category)
 | 
									else if (current_category != slot_category)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										/* punt if more than one category for this slot */
 | 
				
			||||||
					return NULL;
 | 
										return NULL;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				else if (current_type != slot_type)
 | 
									else if (current_type != slot_type)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					if (IsPreferredType(slot_category, current_type))
 | 
										if (IsPreferredType(slot_category, current_type))
 | 
				
			||||||
					{
 | 
										{
 | 
				
			||||||
						slot_type = current_type;
 | 
											slot_type = current_type;
 | 
				
			||||||
 | 
											/* forget all previous candidates */
 | 
				
			||||||
						candidates = current_candidate;
 | 
											candidates = current_candidate;
 | 
				
			||||||
 | 
											last_candidate = current_candidate;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else if (IsPreferredType(slot_category, slot_type))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											/* forget this candidate */
 | 
				
			||||||
 | 
											if (last_candidate)
 | 
				
			||||||
 | 
												last_candidate->next = current_candidate->next;
 | 
				
			||||||
 | 
											else
 | 
				
			||||||
 | 
												candidates = current_candidate->next;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											last_candidate = current_candidate;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
 | 
										/* keep this candidate */
 | 
				
			||||||
 | 
										last_candidate = current_candidate;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			}
 | 
								if (last_candidate)			/* terminate rebuilt list */
 | 
				
			||||||
 | 
									last_candidate->next = NULL;
 | 
				
			||||||
			if (slot_type != InvalidOid)
 | 
					 | 
				
			||||||
				input_typeids[i] = slot_type;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user