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

📄 parse_oper.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
Operatoroper(List *opname, Oid ltypeId, Oid rtypeId, bool noError){	FuncCandidateList clist;	Oid			inputOids[2];	Oid			operOid;	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;	HeapTuple	tup = NULL;	/* Get binary operators of given name */	clist = OpernameGetCandidates(opname, 'b');	/* No operators found? Then fail... */	if (clist != NULL)	{		/*		 * Check for an "exact" match.		 */		operOid = binary_oper_exact(ltypeId, rtypeId, clist);		if (!OidIsValid(operOid))		{			/*			 * Otherwise, search for the most suitable candidate.			 */			/*			 * Unspecified type for one of the arguments? then use the other			 * (XXX this is probably dead code?)			 */			if (rtypeId == InvalidOid)				rtypeId = ltypeId;			else if (ltypeId == InvalidOid)				ltypeId = rtypeId;			inputOids[0] = ltypeId;			inputOids[1] = rtypeId;			fdresult = oper_select_candidate(2, inputOids, clist, &operOid);		}		if (OidIsValid(operOid))			tup = SearchSysCache(OPEROID,								 ObjectIdGetDatum(operOid),								 0, 0, 0);	}	if (!HeapTupleIsValid(tup) && !noError)		op_error(opname, 'b', ltypeId, rtypeId, fdresult);	return (Operator) tup;}/* compatible_oper() *	given an opname and input datatypes, find a compatible binary operator * *	This is tighter than oper() because it will not return an operator that *	requires coercion of the input datatypes (but binary-compatible operators *	are accepted).	Otherwise, the semantics are the same. */Operatorcompatible_oper(List *op, Oid arg1, Oid arg2, bool noError){	Operator	optup;	Form_pg_operator opform;	/* oper() will find the best available match */	optup = oper(op, arg1, arg2, noError);	if (optup == (Operator) NULL)		return (Operator) NULL; /* must be noError case */	/* but is it good enough? */	opform = (Form_pg_operator) GETSTRUCT(optup);	if (IsBinaryCoercible(arg1, opform->oprleft) &&		IsBinaryCoercible(arg2, opform->oprright))		return optup;	/* nope... */	ReleaseSysCache(optup);	if (!noError)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("operator requires run-time type coercion: %s",						op_signature_string(op, 'b', arg1, arg2))));	return (Operator) NULL;}/* compatible_oper_opid() -- get OID of a binary operator * * This is a convenience routine that extracts only the operator OID * from the result of compatible_oper().  InvalidOid is returned if the * lookup fails and noError is true. */Oidcompatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError){	Operator	optup;	Oid			result;	optup = compatible_oper(op, arg1, arg2, noError);	if (optup != NULL)	{		result = oprid(optup);		ReleaseSysCache(optup);		return result;	}	return InvalidOid;}/* right_oper() -- search for a unary right operator (postfix operator) * Given operator name and type of arg, return oper struct. * * IMPORTANT: the returned operator (if any) is only promised to be * coercion-compatible with the input datatype.  Do not use this if * you need an exact- or binary-compatible match. * * 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. */Operatorright_oper(List *op, Oid arg, bool noError){	FuncCandidateList clist;	Oid			operOid = InvalidOid;	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;	HeapTuple	tup = NULL;	/* Find candidates */	clist = OpernameGetCandidates(op, 'r');	if (clist != NULL)	{		/*		 * First, quickly check to see if there is an exactly matching		 * operator (there can be only one such entry in the list).		 */		FuncCandidateList clisti;		for (clisti = clist; clisti != NULL; clisti = clisti->next)		{			if (arg == clisti->args[0])			{				operOid = clisti->oid;				break;			}		}		if (!OidIsValid(operOid))		{			/*			 * We must run oper_select_candidate even if only one candidate,			 * otherwise we may falsely return a non-type-compatible operator.			 */			fdresult = oper_select_candidate(1, &arg, clist, &operOid);		}		if (OidIsValid(operOid))			tup = SearchSysCache(OPEROID,								 ObjectIdGetDatum(operOid),								 0, 0, 0);	}	if (!HeapTupleIsValid(tup) && !noError)		op_error(op, 'r', arg, InvalidOid, fdresult);	return (Operator) tup;}/* left_oper() -- search for a unary left operator (prefix operator) * Given operator name and type of arg, return oper struct. * * IMPORTANT: the returned operator (if any) is only promised to be * coercion-compatible with the input datatype.  Do not use this if * you need an exact- or binary-compatible match. * * 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. */Operatorleft_oper(List *op, Oid arg, bool noError){	FuncCandidateList clist;	Oid			operOid = InvalidOid;	FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;	HeapTuple	tup = NULL;	/* Find candidates */	clist = OpernameGetCandidates(op, 'l');	if (clist != NULL)	{		/*		 * First, quickly check to see if there is an exactly matching		 * operator (there can be only one such entry in the list).		 *		 * The returned list has args in the form (0, oprright).  Move the		 * useful data into args[0] to keep oper_select_candidate simple. XXX		 * we are assuming here that we may scribble on the list!		 */		FuncCandidateList clisti;		for (clisti = clist; clisti != NULL; clisti = clisti->next)		{			clisti->args[0] = clisti->args[1];			if (arg == clisti->args[0])			{				operOid = clisti->oid;				break;			}		}		if (!OidIsValid(operOid))		{			/*			 * We must run oper_select_candidate even if only one candidate,			 * otherwise we may falsely return a non-type-compatible operator.			 */			fdresult = oper_select_candidate(1, &arg, clist, &operOid);		}		if (OidIsValid(operOid))			tup = SearchSysCache(OPEROID,								 ObjectIdGetDatum(operOid),								 0, 0, 0);	}	if (!HeapTupleIsValid(tup) && !noError)		op_error(op, 'l', InvalidOid, arg, fdresult);	return (Operator) tup;}/* * op_signature_string *		Build a string representing an operator name, including arg type(s). *		The result is something like "integer + integer". * * This is typically used in the construction of operator-not-found error * messages. */static const char *op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2){	StringInfoData argbuf;	initStringInfo(&argbuf);	if (oprkind != 'l')		appendStringInfo(&argbuf, "%s ", format_type_be(arg1));	appendStringInfoString(&argbuf, NameListToString(op));	if (oprkind != 'r')		appendStringInfo(&argbuf, " %s", format_type_be(arg2));	return argbuf.data;			/* return palloc'd string buffer */}/* * op_error - utility routine to complain about an unresolvable operator */static voidop_error(List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult){	if (fdresult == FUNCDETAIL_MULTIPLE)		ereport(ERROR,				(errcode(ERRCODE_AMBIGUOUS_FUNCTION),				 errmsg("operator is not unique: %s",						op_signature_string(op, oprkind, arg1, arg2)),				 errhint("Could not choose a best candidate operator. "						 "You may need to add explicit type casts.")));	else		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("operator does not exist: %s",						op_signature_string(op, oprkind, arg1, arg2)),		  errhint("No operator matches the given name and argument type(s). "				  "You may need to add explicit type casts.")));}/* * make_op() *		Operator expression construction. * * Transform operator expression ensuring type compatibility. * This is where some type conversion happens. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */Expr *make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree){	Oid			ltypeId,				rtypeId;	Operator	tup;	Expr	   *result;	/* Select the operator */	if (rtree == NULL)	{		/* right operator */		ltypeId = exprType(ltree);		rtypeId = InvalidOid;		tup = right_oper(opname, ltypeId, false);	}	else if (ltree == NULL)	{		/* left operator */		rtypeId = exprType(rtree);		ltypeId = InvalidOid;		tup = left_oper(opname, rtypeId, false);	}	else	{		/* otherwise, binary operator */		ltypeId = exprType(ltree);		rtypeId = exprType(rtree);		tup = oper(opname, ltypeId, rtypeId, false);	}	/* Do typecasting and build the expression tree */	result = make_op_expr(pstate, tup, ltree, rtree, ltypeId, rtypeId);	ReleaseSysCache(tup);	return result;}/* * make_scalar_array_op() *		Build expression tree for "scalar op ANY/ALL (array)" construct. */Expr *make_scalar_array_op(ParseState *pstate, List *opname,					 bool useOr,					 Node *ltree, Node *rtree){	Oid			ltypeId,				rtypeId,				atypeId,				res_atypeId;	Operator	tup;	Form_pg_operator opform;	Oid			actual_arg_types[2];	Oid			declared_arg_types[2];	List	   *args;	Oid			rettype;	ScalarArrayOpExpr *result;	ltypeId = exprType(ltree);	atypeId = exprType(rtree);	/*	 * The right-hand input of the operator will be the element type of the	 * array.  However, if we currently have just an untyped literal on the	 * right, stay with that and hope we can resolve the operator.	 */	if (atypeId == UNKNOWNOID)		rtypeId = UNKNOWNOID;	else	{		rtypeId = get_element_type(atypeId);		if (!OidIsValid(rtypeId))			ereport(ERROR,					(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("op ANY/ALL (array) requires array on right side")));	}	/* Now resolve the operator */	tup = oper(opname, ltypeId, rtypeId, false);	opform = (Form_pg_operator) GETSTRUCT(tup);	args = list_make2(ltree, rtree);	actual_arg_types[0] = ltypeId;	actual_arg_types[1] = rtypeId;	declared_arg_types[0] = opform->oprleft;	declared_arg_types[1] = opform->oprright;	/*	 * enforce consistency with ANYARRAY and ANYELEMENT argument and return	 * types, possibly adjusting return type or declared_arg_types (which will	 * be used as the cast destination by make_fn_arguments)	 */	rettype = enforce_generic_type_consistency(actual_arg_types,											   declared_arg_types,											   2,											   opform->oprresult);	/*	 * Check that operator result is boolean	 */	if (rettype != BOOLOID)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),		   errmsg("op ANY/ALL (array) requires operator to yield boolean")));	if (get_func_retset(opform->oprcode))		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),		errmsg("op ANY/ALL (array) requires operator not to return a set")));	/*	 * Now switch back to the array type on the right, arranging for any	 * needed cast to be applied.	 */	res_atypeId = get_array_type(declared_arg_types[1]);	if (!OidIsValid(res_atypeId))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("could not find array type for data type %s",						format_type_be(declared_arg_types[1]))));	actual_arg_types[1] = atypeId;	declared_arg_types[1] = res_atypeId;	/* perform the necessary typecasting of arguments */	make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);	/* and build the expression node */	result = makeNode(ScalarArrayOpExpr);	result->opno = oprid(tup);	result->opfuncid = InvalidOid;	result->useOr = useOr;	result->args = args;	ReleaseSysCache(tup);	return (Expr *) result;}/* * make_op_expr() *		Build operator expression using an already-looked-up operator. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */Expr *make_op_expr(ParseState *pstate, Operator op,			 Node *ltree, Node *rtree,			 Oid ltypeId, Oid rtypeId){	Form_pg_operator opform = (Form_pg_operator) GETSTRUCT(op);	Oid			actual_arg_types[2];	Oid			declared_arg_types[2];	int			nargs;	List	   *args;	Oid			rettype;	OpExpr	   *result;	if (rtree == NULL)	{		/* right operator */		args = list_make1(ltree);		actual_arg_types[0] = ltypeId;		declared_arg_types[0] = opform->oprleft;		nargs = 1;	}	else if (ltree == NULL)	{		/* left operator */		args = list_make1(rtree);		actual_arg_types[0] = rtypeId;		declared_arg_types[0] = opform->oprright;		nargs = 1;	}	else	{		/* otherwise, binary operator */		args = list_make2(ltree, rtree);		actual_arg_types[0] = ltypeId;		actual_arg_types[1] = rtypeId;		declared_arg_types[0] = opform->oprleft;		declared_arg_types[1] = opform->oprright;		nargs = 2;	}	/*	 * enforce consistency with ANYARRAY and ANYELEMENT argument and return	 * types, possibly adjusting return type or declared_arg_types (which will	 * be used as the cast destination by make_fn_arguments)	 */	rettype = enforce_generic_type_consistency(actual_arg_types,											   declared_arg_types,											   nargs,											   opform->oprresult);	/* perform the necessary typecasting of arguments */	make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);	/* and build the expression node */	result = makeNode(OpExpr);	result->opno = oprid(op);	result->opfuncid = InvalidOid;	result->opresulttype = rettype;	result->opretset = get_func_retset(opform->oprcode);	result->args = args;	return (Expr *) result;}

⌨️ 快捷键说明

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