parse_func.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,534 行 · 第 1/3 页

C
1,534
字号
	ncandidates = 0;	nbestMatch = 0;	last_candidate = NULL;	for (current_candidate = candidates;		 current_candidate != NULL;		 current_candidate = current_candidate->next)	{		current_typeids = current_candidate->args;		nmatch = 0;		for (i = 0; i < nargs; i++)		{			if (input_base_typeids[i] != UNKNOWNOID &&				current_typeids[i] == input_base_typeids[i])				nmatch++;		}		/* take this one as the best choice so far? */		if ((nmatch > nbestMatch) || (last_candidate == NULL))		{			nbestMatch = nmatch;			candidates = current_candidate;			last_candidate = current_candidate;			ncandidates = 1;		}		/* no worse than the last choice, so keep this one too? */		else if (nmatch == nbestMatch)		{			last_candidate->next = current_candidate;			last_candidate = current_candidate;			ncandidates++;		}		/* otherwise, don't bother keeping this one... */	}	if (last_candidate)			/* terminate rebuilt list */		last_candidate->next = NULL;	if (ncandidates == 1)		return candidates;	/*	 * Still too many candidates? Now look for candidates which have	 * either exact matches or preferred types at the args that will	 * require coercion. (Restriction added in 7.4: preferred type must be	 * of same category as input type; give no preference to	 * cross-category conversions to preferred types.)	Keep all	 * candidates if none match.	 */	for (i = 0; i < nargs; i++) /* avoid multiple lookups */		slot_category[i] = TypeCategory(input_base_typeids[i]);	ncandidates = 0;	nbestMatch = 0;	last_candidate = NULL;	for (current_candidate = candidates;		 current_candidate != NULL;		 current_candidate = current_candidate->next)	{		current_typeids = current_candidate->args;		nmatch = 0;		for (i = 0; i < nargs; i++)		{			if (input_base_typeids[i] != UNKNOWNOID)			{				if (current_typeids[i] == input_base_typeids[i] ||					IsPreferredType(slot_category[i], current_typeids[i]))					nmatch++;			}		}		if ((nmatch > nbestMatch) || (last_candidate == NULL))		{			nbestMatch = nmatch;			candidates = current_candidate;			last_candidate = current_candidate;			ncandidates = 1;		}		else if (nmatch == nbestMatch)		{			last_candidate->next = current_candidate;			last_candidate = current_candidate;			ncandidates++;		}	}	if (last_candidate)			/* terminate rebuilt list */		last_candidate->next = NULL;	if (ncandidates == 1)		return candidates;	/*	 * Still too many candidates? Try assigning types for the unknown	 * columns.	 *	 * NOTE: for a binary operator with one unknown and one non-unknown	 * input, we already tried the heuristic of looking for a candidate	 * with the known input type on both sides (see binary_oper_exact()).	 * That's essentially a special case of the general algorithm we try	 * next.	 *	 * We do this by examining each unknown argument position to see if we	 * can determine a "type category" for it.	If any candidate has an	 * input datatype of STRING category, use STRING category (this bias	 * towards STRING is appropriate since unknown-type literals look like	 * strings).  Otherwise, if all the candidates agree on the type	 * category of this argument position, use that category.  Otherwise,	 * fail because we cannot determine a category.	 *	 * If we are able to determine a type category, also notice whether any	 * of the candidates takes a preferred datatype within the category.	 *	 * Having completed this examination, remove candidates that accept the	 * wrong category at any unknown position.	Also, if at least one	 * candidate accepted a preferred type at a position, remove	 * candidates that accept non-preferred types.	 *	 * If we are down to one candidate at the end, we win.	 */	resolved_unknowns = false;	for (i = 0; i < nargs; i++)	{		bool		have_conflict;		if (input_base_typeids[i] != UNKNOWNOID)			continue;		resolved_unknowns = true;		/* assume we can do it */		slot_category[i] = INVALID_TYPE;		slot_has_preferred_type[i] = false;		have_conflict = false;		for (current_candidate = candidates;			 current_candidate != NULL;			 current_candidate = current_candidate->next)		{			current_typeids = current_candidate->args;			current_type = current_typeids[i];			current_category = TypeCategory(current_type);			if (slot_category[i] == INVALID_TYPE)			{				/* first candidate */				slot_category[i] = current_category;				slot_has_preferred_type[i] =					IsPreferredType(current_category, current_type);			}			else if (current_category == slot_category[i])			{				/* more candidates in same category */				slot_has_preferred_type[i] |=					IsPreferredType(current_category, current_type);			}			else			{				/* category conflict! */				if (current_category == STRING_TYPE)				{					/* STRING always wins if available */					slot_category[i] = current_category;					slot_has_preferred_type[i] =						IsPreferredType(current_category, current_type);				}				else				{					/*					 * Remember conflict, but keep going (might find					 * STRING)					 */					have_conflict = true;				}			}		}		if (have_conflict && slot_category[i] != STRING_TYPE)		{			/* Failed to resolve category conflict at this position */			resolved_unknowns = false;			break;		}	}	if (resolved_unknowns)	{		/* Strip non-matching candidates */		ncandidates = 0;		last_candidate = NULL;		for (current_candidate = candidates;			 current_candidate != NULL;			 current_candidate = current_candidate->next)		{			bool		keepit = true;			current_typeids = current_candidate->args;			for (i = 0; i < nargs; i++)			{				if (input_base_typeids[i] != UNKNOWNOID)					continue;				current_type = current_typeids[i];				current_category = TypeCategory(current_type);				if (current_category != slot_category[i])				{					keepit = false;					break;				}				if (slot_has_preferred_type[i] &&					!IsPreferredType(current_category, current_type))				{					keepit = false;					break;				}			}			if (keepit)			{				/* keep this candidate */				last_candidate = current_candidate;				ncandidates++;			}			else			{				/* forget this candidate */				if (last_candidate)					last_candidate->next = current_candidate->next;				else					candidates = current_candidate->next;			}		}		if (last_candidate)		/* terminate rebuilt list */			last_candidate->next = NULL;	}	if (ncandidates == 1)		return candidates;	return NULL;				/* failed to select a best candidate */}	/* func_select_candidate() *//* func_get_detail() * * Find the named function in the system catalogs. * * Attempt to find the named function in the system catalogs with *	arguments exactly as specified, so that the normal case *	(exact match) is as quick as possible. * * If an exact match isn't found: *	1) check for possible interpretation as a trivial type coercion *	2) get a vector of all possible input arg type arrays constructed *	   from the superclasses of the original input arg types *	3) get a list of all possible argument type arrays to the function *	   with given name and number of arguments *	4) for each input arg type array from vector #1: *	 a) find how many of the function arg type arrays from list #2 *		it can be coerced to *	 b) if the answer is one, we have our function *	 c) if the answer is more than one, attempt to resolve the conflict *	 d) if the answer is zero, try the next array from vector #1 * * Note: we rely primarily on nargs/argtypes as the argument description. * The actual expression node list is passed in fargs so that we can check * for type coercion of a constant.  Some callers pass fargs == NIL * indicating they don't want that check made. */FuncDetailCodefunc_get_detail(List *funcname,				List *fargs,				int nargs,				Oid *argtypes,				Oid *funcid,	/* return value */				Oid *rettype,	/* return value */				bool *retset,	/* return value */				Oid **true_typeids)		/* return value */{	FuncCandidateList raw_candidates;	FuncCandidateList best_candidate;	/* Get list of possible candidates from namespace search */	raw_candidates = FuncnameGetCandidates(funcname, nargs);	/*	 * Quickly check if there is an exact match to the input datatypes	 * (there can be only one)	 */	for (best_candidate = raw_candidates;		 best_candidate != NULL;		 best_candidate = best_candidate->next)	{		if (memcmp(argtypes, best_candidate->args, nargs * sizeof(Oid)) == 0)			break;	}	if (best_candidate == NULL)	{		/*		 * If we didn't find an exact match, next consider the possibility		 * that this is really a type-coercion request: a single-argument		 * function call where the function name is a type name.  If so,		 * and if we can do the coercion trivially (no run-time function		 * call needed), then go ahead and treat the "function call" as a		 * coercion.  This interpretation needs to be given higher		 * priority than interpretations involving a type coercion		 * followed by a function call, otherwise we can produce		 * surprising results. For example, we want "text(varchar)" to be		 * interpreted as a trivial coercion, not as "text(name(varchar))"		 * which the code below this point is entirely capable of		 * selecting.		 *		 * "Trivial" coercions are ones that involve binary-compatible types		 * and ones that are coercing a previously-unknown-type literal		 * constant to a specific type.		 *		 * The reason we can restrict our check to binary-compatible		 * coercions here is that we expect non-binary-compatible		 * coercions to have an implementation function named after the		 * target type. That function will be found by normal lookup if		 * appropriate.		 *		 * NB: it's important that this code stays in sync with what		 * coerce_type can do, because the caller will try to apply		 * coerce_type if we return FUNCDETAIL_COERCION.  If we return		 * that result for something coerce_type can't handle, we'll cause		 * infinite recursion between this module and coerce_type!		 */		if (nargs == 1 && fargs != NIL)		{			Oid			targetType;			TypeName   *tn = makeNode(TypeName);			tn->names = funcname;			tn->typmod = -1;			targetType = LookupTypeName(tn);			if (OidIsValid(targetType) &&				!ISCOMPLEX(targetType))			{				Oid			sourceType = argtypes[0];				Node	   *arg1 = lfirst(fargs);				if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||					(find_coercion_pathway(targetType, sourceType,										   COERCION_EXPLICIT, funcid) &&					 *funcid == InvalidOid))				{					/* Yup, it's a type coercion */					*funcid = InvalidOid;					*rettype = targetType;					*retset = false;					*true_typeids = argtypes;					return FUNCDETAIL_COERCION;				}			}		}		/*		 * didn't find an exact match, so now try to match up		 * candidates...		 */		if (raw_candidates != NULL)		{			Oid		  **input_typeid_vector = NULL;			Oid		   *current_input_typeids;			/*			 * First we will search with the given argtypes, then with			 * variants based on replacing complex types with their			 * inheritance ancestors.  Stop as soon as any match is found.			 */			current_input_typeids = argtypes;			do			{				FuncCandidateList current_candidates;				int			ncandidates;				ncandidates = func_match_argtypes(nargs,												  current_input_typeids,												  raw_candidates,												  &current_candidates);				/* one match only? then run with it... */				if (ncandidates == 1)				{					best_candidate = current_candidates;					break;				}				/*				 * multiple candidates? then better decide or throw an				 * error...				 */				if (ncandidates > 1)				{					best_candidate = func_select_candidate(nargs,												   current_input_typeids,													 current_candidates);					/*					 * If we were able to choose a best candidate, we're					 * done.  Otherwise, ambiguous function call.					 */					if (best_candidate)						break;					return FUNCDETAIL_MULTIPLE;				}				/*				 * No match here, so try the next inherited type vector.				 * First time through, we need to compute the list of				 * vectors.				 */				if (input_typeid_vector == NULL)					input_typeid_vector = argtype_inherit(nargs, argtypes);				current_input_typeids = *input_typeid_vector++;			}			while (current_input_typeids != NULL);		}	}	if (best_candidate)	{		HeapTuple	ftup;		Form_pg_proc pform;		FuncDetailCode result;		*funcid = best_candidate->oid;		*true_typeids = best_candidate->args;		ftup = SearchSysCache(PROCOID,							  ObjectIdGetDatum(best_candidate->oid),							  0, 0, 0);		if (!HeapTupleIsValid(ftup))	/* should not happen */			elog(ERROR, "cache lookup failed for function %u",				 best_candidate->oid);		pform = (Form_pg_proc) GETSTRUCT(ftup);		*rettype = pform->prorettype;		*retset = pform->proretset;		result = pform->proisagg ? FUNCDETAIL_AGGREGATE : FUNCDETAIL_NORMAL;		ReleaseSysCache(ftup);		return result;	}	return FUNCDETAIL_NOTFOUND;}/* *	argtype_inherit() -- Construct an argtype vector reflecting the *						 inheritance properties of the supplied argv. * *		This function is used to handle resolution of function calls when *		there is no match to the given argument types, but there might be *		matches based on considering complex types as members of their *		superclass types (parent classes). * *		It takes an array of input type ids.  For each type id in the array *		that's a complex type (a class), it walks up the inheritance tree, *		finding all superclasses of that type. A vector of new Oid type *		arrays is returned to the caller, listing possible alternative *		interpretations of the input typeids as members of their superclasses *		rather than the actually given argument types.	The vector is *		terminated by a NULL pointer. * *		The order of this vector is as follows:  all superclasses of the *		rightmost complex class are explored first.  The exploration *		continues from right to left.  This policy means that we favor *		keeping the leftmost argument type as low in the inheritance tree *		as possible.  This is intentional; it is exactly what we need to *		do for method dispatch. * *		The vector does not include the case where no complex classes have *		been promoted, since that was already tried before this routine *		got called. */static Oid **argtype_inherit(int nargs, Oid *argtypes){	Oid			relid;	int			i;	InhPaths	arginh[FUNC_MAX_ARGS];	for (i = 0; i < nargs; i++)	{		arginh[i].self = argtypes[i];		if ((relid = typeidTypeRelid(argtypes[i])) != InvalidOid)			arginh[i].nsupers = find_inheritors(relid, &(arginh[i].supervec));		else		{			arginh[i].nsupers = 0;			arginh[i].supervec = (Oid *) NULL;		}	}	/* return an ordered cross-product of the classes involved */	return gen_cross_product(arginh, nargs);}/* * Look up the parent superclass(es) of the given relation. * * *supervec is set to an array of the type OIDs (not the relation OIDs) * of the parents, with nearest ancestors listed first.  It's set to NULL * if there are no parents.  The return value is the number of parents. */static intfind_inheritors(Oid relid, Oid **supervec){	Relation	inhrel;	HeapScanDesc inhscan;	ScanKeyData skey;	HeapTuple	inhtup;	Oid		   *relidvec;	int			nvisited;	List	   *visited,			   *queue;	List	   *elt;	bool		newrelid;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?