⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parse_func.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 = linitial(fargs);				Oid			cfuncid;				if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||					(find_coercion_pathway(targetType, sourceType,										   COERCION_EXPLICIT, &cfuncid) &&					 cfuncid == 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)		{			FuncCandidateList current_candidates;			int			ncandidates;			ncandidates = func_match_argtypes(nargs,											  argtypes,											  raw_candidates,											  &current_candidates);			/* one match only? then run with it... */			if (ncandidates == 1)				best_candidate = current_candidates;			/*			 * multiple candidates? then better decide or throw an error...			 */			else if (ncandidates > 1)			{				best_candidate = func_select_candidate(nargs,													   argtypes,													   current_candidates);				/*				 * If we were able to choose a best candidate, we're done.				 * Otherwise, ambiguous function call.				 */				if (!best_candidate)					return FUNCDETAIL_MULTIPLE;			}		}	}	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;}/* * Given two type OIDs, determine whether the first is a complex type * (class type) that inherits from the second. */booltypeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)

⌨️ 快捷键说明

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