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

📄 parse_oper.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * parse_oper.c *		handle operator things for parser * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.82.2.1 2005/11/22 18:23:14 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_operator.h"#include "lib/stringinfo.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "parser/parse_oper.h"#include "parser/parse_type.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/lsyscache.h"#include "utils/syscache.h"#include "utils/typcache.h"static Oid binary_oper_exact(Oid arg1, Oid arg2,				  FuncCandidateList candidates);static FuncDetailCode oper_select_candidate(int nargs,					  Oid *input_typeids,					  FuncCandidateList candidates,					  Oid *operOid);static const char *op_signature_string(List *op, char oprkind,					Oid arg1, Oid arg2);static void op_error(List *op, char oprkind, Oid arg1, Oid arg2,		 FuncDetailCode fdresult);/* * LookupOperName *		Given a possibly-qualified operator name and exact input datatypes, *		look up the operator. * * Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for * a postfix op. * * If the operator name is not schema-qualified, it is sought in the current * namespace search path. * * If the operator is not found, we return InvalidOid if noError is true, * else raise an error. */OidLookupOperName(List *opername, Oid oprleft, Oid oprright, bool noError){	FuncCandidateList clist;	char		oprkind;	if (!OidIsValid(oprleft))		oprkind = 'l';	else if (!OidIsValid(oprright))		oprkind = 'r';	else		oprkind = 'b';	clist = OpernameGetCandidates(opername, oprkind);	while (clist)	{		if (clist->args[0] == oprleft && clist->args[1] == oprright)			return clist->oid;		clist = clist->next;	}	/* we don't use op_error here because only an exact match is wanted */	if (!noError)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("operator does not exist: %s",						op_signature_string(opername, oprkind,											oprleft, oprright))));	return InvalidOid;}/* * LookupOperNameTypeNames *		Like LookupOperName, but the argument types are specified by *		TypeName nodes. * * Pass oprleft = NULL for a prefix op, oprright = NULL for a postfix op. */OidLookupOperNameTypeNames(List *opername, TypeName *oprleft,						TypeName *oprright, bool noError){	Oid			leftoid,				rightoid;	if (oprleft == NULL)		leftoid = InvalidOid;	else	{		leftoid = LookupTypeName(oprleft);		if (!OidIsValid(leftoid))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("type %s does not exist",							TypeNameToString(oprleft))));	}	if (oprright == NULL)		rightoid = InvalidOid;	else	{		rightoid = LookupTypeName(oprright);		if (!OidIsValid(rightoid))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("type %s does not exist",							TypeNameToString(oprright))));	}	return LookupOperName(opername, leftoid, rightoid, noError);}/* * equality_oper - identify a suitable equality operator for a datatype * * On failure, return NULL if noError, else report a standard error */Operatorequality_oper(Oid argtype, bool noError){	TypeCacheEntry *typentry;	Oid			oproid;	Operator	optup;	/*	 * Look for an "=" operator for the datatype.  We require it to be an	 * exact or binary-compatible match, since most callers are not prepared	 * to cope with adding any run-time type coercion steps.	 */	typentry = lookup_type_cache(argtype, TYPECACHE_EQ_OPR);	oproid = typentry->eq_opr;	/*	 * If the datatype is an array, then we can use array_eq ... but only if	 * there is a suitable equality operator for the element type. (This check	 * is not in the raw typcache.c code ... should it be?)	 */	if (oproid == ARRAY_EQ_OP)	{		Oid			elem_type = get_element_type(argtype);		if (OidIsValid(elem_type))		{			optup = equality_oper(elem_type, true);			if (optup != NULL)				ReleaseSysCache(optup);			else				oproid = InvalidOid;	/* element type has no "=" */		}		else			oproid = InvalidOid;	/* bogus array type? */	}	if (OidIsValid(oproid))	{		optup = SearchSysCache(OPEROID,							   ObjectIdGetDatum(oproid),							   0, 0, 0);		if (optup == NULL)		/* should not fail */			elog(ERROR, "cache lookup failed for operator %u", oproid);		return optup;	}	if (!noError)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("could not identify an equality operator for type %s",						format_type_be(argtype))));	return NULL;}/* * ordering_oper - identify a suitable sorting operator ("<") for a datatype * * On failure, return NULL if noError, else report a standard error */Operatorordering_oper(Oid argtype, bool noError){	TypeCacheEntry *typentry;	Oid			oproid;	Operator	optup;	/*	 * Look for a "<" operator for the datatype.  We require it to be an exact	 * or binary-compatible match, since most callers are not prepared to cope	 * with adding any run-time type coercion steps.	 *	 * Note: the search algorithm used by typcache.c ensures that if a "<"	 * operator is returned, it will be consistent with the "=" operator	 * returned by equality_oper.  This is critical for sorting and grouping	 * purposes.	 */	typentry = lookup_type_cache(argtype, TYPECACHE_LT_OPR);	oproid = typentry->lt_opr;	/*	 * If the datatype is an array, then we can use array_lt ... but only if	 * there is a suitable less-than operator for the element type. (This	 * check is not in the raw typcache.c code ... should it be?)	 */	if (oproid == ARRAY_LT_OP)	{		Oid			elem_type = get_element_type(argtype);		if (OidIsValid(elem_type))		{			optup = ordering_oper(elem_type, true);			if (optup != NULL)				ReleaseSysCache(optup);			else				oproid = InvalidOid;	/* element type has no "<" */		}		else			oproid = InvalidOid;	/* bogus array type? */	}	if (OidIsValid(oproid))	{		optup = SearchSysCache(OPEROID,							   ObjectIdGetDatum(oproid),							   0, 0, 0);		if (optup == NULL)		/* should not fail */			elog(ERROR, "cache lookup failed for operator %u", oproid);		return optup;	}	if (!noError)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("could not identify an ordering operator for type %s",						format_type_be(argtype)),		 errhint("Use an explicit ordering operator or modify the query.")));	return NULL;}/* * reverse_ordering_oper - identify DESC sort operator (">") for a datatype * * On failure, return NULL if noError, else report a standard error */Operatorreverse_ordering_oper(Oid argtype, bool noError){	TypeCacheEntry *typentry;	Oid			oproid;	Operator	optup;	/*	 * Look for a ">" operator for the datatype.  We require it to be an exact	 * or binary-compatible match, since most callers are not prepared to cope	 * with adding any run-time type coercion steps.	 *	 * Note: the search algorithm used by typcache.c ensures that if a ">"	 * operator is returned, it will be consistent with the "=" operator	 * returned by equality_oper.  This is critical for sorting and grouping	 * purposes.	 */	typentry = lookup_type_cache(argtype, TYPECACHE_GT_OPR);	oproid = typentry->gt_opr;	/*	 * If the datatype is an array, then we can use array_gt ... but only if	 * there is a suitable greater-than operator for the element type. (This	 * check is not in the raw typcache.c code ... should it be?)	 */	if (oproid == ARRAY_GT_OP)	{		Oid			elem_type = get_element_type(argtype);		if (OidIsValid(elem_type))		{			optup = reverse_ordering_oper(elem_type, true);			if (optup != NULL)				ReleaseSysCache(optup);			else				oproid = InvalidOid;	/* element type has no ">" */		}		else			oproid = InvalidOid;	/* bogus array type? */	}	if (OidIsValid(oproid))	{		optup = SearchSysCache(OPEROID,							   ObjectIdGetDatum(oproid),							   0, 0, 0);		if (optup == NULL)		/* should not fail */			elog(ERROR, "cache lookup failed for operator %u", oproid);		return optup;	}	if (!noError)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("could not identify an ordering operator for type %s",						format_type_be(argtype)),		 errhint("Use an explicit ordering operator or modify the query.")));	return NULL;}/* * equality_oper_funcid - convenience routine for oprfuncid(equality_oper()) */Oidequality_oper_funcid(Oid argtype){	Operator	optup;	Oid			result;	optup = equality_oper(argtype, false);	result = oprfuncid(optup);	ReleaseSysCache(optup);	return result;}/* * ordering_oper_opid - convenience routine for oprid(ordering_oper()) * * This was formerly called any_ordering_op() */Oidordering_oper_opid(Oid argtype){	Operator	optup;	Oid			result;	optup = ordering_oper(argtype, false);	result = oprid(optup);	ReleaseSysCache(optup);	return result;}/* * reverse_ordering_oper_opid - convenience routine for oprid(reverse_ordering_oper()) */Oidreverse_ordering_oper_opid(Oid argtype){	Operator	optup;	Oid			result;	optup = reverse_ordering_oper(argtype, false);	result = oprid(optup);	ReleaseSysCache(optup);	return result;}/* given operator tuple, return the operator OID */Oidoprid(Operator op){	return HeapTupleGetOid(op);}/* given operator tuple, return the underlying function's OID */Oidoprfuncid(Operator op){	Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(op);	return pgopform->oprcode;}/* binary_oper_exact() * Check for an "exact" match to the specified operand types. * * If one operand is an unknown literal, assume it should be taken to be * the same type as the other operand for this purpose.  Also, consider * the possibility that the other operand is a domain type that needs to * be reduced to its base type to find an "exact" match. */static Oidbinary_oper_exact(Oid arg1, Oid arg2,				  FuncCandidateList candidates){	FuncCandidateList cand;	bool		was_unknown = false;	/* Unspecified type for one of the arguments? then use the other */	if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))	{		arg1 = arg2;		was_unknown = true;	}	else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))	{		arg2 = arg1;		was_unknown = true;	}	for (cand = candidates; cand != NULL; cand = cand->next)	{		if (arg1 == cand->args[0] && arg2 == cand->args[1])			return cand->oid;	}	if (was_unknown)	{		/* arg1 and arg2 are the same here, need only look at arg1 */		Oid			basetype = getBaseType(arg1);		if (basetype != arg1)		{			for (cand = candidates; cand != NULL; cand = cand->next)			{				if (basetype == cand->args[0] && basetype == cand->args[1])					return cand->oid;			}		}	}	return InvalidOid;}/* oper_select_candidate() *		Given the input argtype array and one or more candidates *		for the operator, attempt to resolve the conflict. * * Returns FUNCDETAIL_NOTFOUND, FUNCDETAIL_MULTIPLE, or FUNCDETAIL_NORMAL. * In the success case the Oid of the best candidate is stored in *operOid. * * Note that the caller has already determined that there is no candidate * exactly matching the input argtype(s).  Incompatible candidates are not yet * pruned away, however. */static FuncDetailCodeoper_select_candidate(int nargs,					  Oid *input_typeids,					  FuncCandidateList candidates,					  Oid *operOid)		/* output argument */{	int			ncandidates;	/*	 * Delete any candidates that cannot actually accept the given input	 * types, whether directly or by coercion.	 */	ncandidates = func_match_argtypes(nargs, input_typeids,									  candidates, &candidates);	/* Done if no candidate or only one candidate survives */	if (ncandidates == 0)	{		*operOid = InvalidOid;		return FUNCDETAIL_NOTFOUND;	}	if (ncandidates == 1)	{		*operOid = candidates->oid;		return FUNCDETAIL_NORMAL;	}	/*	 * Use the same heuristics as for ambiguous functions to resolve the	 * conflict.	 */	candidates = func_select_candidate(nargs, input_typeids, candidates);	if (candidates)	{		*operOid = candidates->oid;		return FUNCDETAIL_NORMAL;	}	*operOid = InvalidOid;	return FUNCDETAIL_MULTIPLE; /* failed to select a best candidate */}/* oper() -- search for a binary operator * Given operator name, types of arg1 and arg2, return oper struct. * * IMPORTANT: the returned operator (if any) is only promised to be * coercion-compatible with the input datatypes.  Do not use this if * you need an exact- or binary-compatible match; see compatible_oper. * * If no matching operator found, return NULL if noError is true, * raise an error if it is false. * * NOTE: on success, the returned object is a syscache entry.  The caller * must ReleaseSysCache() the entry when done with it. */

⌨️ 快捷键说明

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