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

📄 parse_coerce.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * parse_coerce.c *		handle type coercions/conversions 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_coerce.c,v 2.132.2.3 2006/01/17 17:33:20 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_cast.h"#include "catalog/pg_proc.h"#include "nodes/makefuncs.h"#include "nodes/params.h"#include "optimizer/clauses.h"#include "parser/parsetree.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "parser/parse_relation.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 Node *coerce_type_typmod(Node *node,				   Oid targetTypeId, int32 targetTypMod,				   CoercionForm cformat, bool isExplicit,				   bool hideInputCoercion);static void hide_coercion_node(Node *node);static Node *build_coercion_expression(Node *node, Oid funcId,						  Oid targetTypeId, int32 targetTypMod,						  CoercionForm cformat, bool isExplicit);static Node *coerce_record_to_complex(ParseState *pstate, Node *node,						 Oid targetTypeId,						 CoercionContext ccontext,						 CoercionForm cformat);/* * coerce_to_target_type() *		Convert an expression to a target type and typmod. * * This is the general-purpose entry point for arbitrary type coercion * operations.	Direct use of the component operations can_coerce_type, * coerce_type, and coerce_type_typmod should be restricted to special * cases (eg, when the conversion is expected to succeed). * * Returns the possibly-transformed expression tree, or NULL if the type * conversion is not possible.	(We do this, rather than ereport'ing directly, * so that callers can generate custom error messages indicating context.) * * pstate - parse state (can be NULL, see coerce_type) * expr - input expression tree (already transformed by transformExpr) * exprtype - result type of expr * targettype - desired result type * targettypmod - desired result typmod * ccontext, cformat - context indicators to control coercions */Node *coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,					  Oid targettype, int32 targettypmod,					  CoercionContext ccontext,					  CoercionForm cformat){	Node	   *result;	if (!can_coerce_type(1, &exprtype, &targettype, ccontext))		return NULL;	result = coerce_type(pstate, expr, exprtype,						 targettype, targettypmod,						 ccontext, cformat);	/*	 * If the target is a fixed-length type, it may need a length coercion as	 * well as a type coercion.  If we find ourselves adding both, force the	 * inner coercion node to implicit display form.	 */	result = coerce_type_typmod(result,								targettype, targettypmod,								cformat,								(cformat != COERCE_IMPLICIT_CAST),								(result != expr && !IsA(result, Const)));	return result;}/* * coerce_type() *		Convert an expression to a different type. * * The caller should already have determined that the coercion is possible; * see can_coerce_type. * * Normally, no coercion to a typmod (length) is performed here.  The caller * must call coerce_type_typmod as well, if a typmod constraint is wanted. * (But if the target type is a domain, it may internally contain a * typmod constraint, which will be applied inside coerce_to_domain.) * In some cases pg_cast specifies a type coercion function that also * applies length conversion, and in those cases only, the result will * already be properly coerced to the specified typmod. * * pstate is only used in the case that we are able to resolve the type of * a previously UNKNOWN Param.	It is okay to pass pstate = NULL if the * caller does not want type information updated for Params. */Node *coerce_type(ParseState *pstate, Node *node,			Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,			CoercionContext ccontext, CoercionForm cformat){	Node	   *result;	Oid			funcId;	if (targetTypeId == inputTypeId ||		node == NULL)	{		/* no conversion needed */		return node;	}	if (targetTypeId == ANYOID ||		targetTypeId == ANYARRAYOID ||		targetTypeId == ANYELEMENTOID)	{		/* assume can_coerce_type verified that implicit coercion is okay */		/* NB: we do NOT want a RelabelType here */		return node;	}	if (inputTypeId == UNKNOWNOID && IsA(node, Const))	{		/*		 * Input is a string constant with previously undetermined type. Apply		 * the target type's typinput function to it to produce a constant of		 * the target type.		 *		 * NOTE: this case cannot be folded together with the other		 * constant-input case, since the typinput function does not		 * necessarily behave the same as a type conversion function. For		 * example, int4's typinput function will reject "1.2", whereas		 * float-to-int type conversion will round to integer.		 *		 * XXX if the typinput function is not immutable, we really ought to		 * postpone evaluation of the function call until runtime. But there		 * is no way to represent a typinput function call as an expression		 * tree, because C-string values are not Datums. (XXX This *is*		 * possible as of 7.3, do we want to do it?)		 */		Const	   *con = (Const *) node;		Const	   *newcon = makeNode(Const);		Type		targetType = typeidType(targetTypeId);		char		targetTyptype = typeTypType(targetType);		newcon->consttype = targetTypeId;		newcon->constlen = typeLen(targetType);		newcon->constbyval = typeByVal(targetType);		newcon->constisnull = con->constisnull;		if (!con->constisnull)		{			/*			 * We assume here that UNKNOWN's internal representation is the			 * same as CSTRING			 */			char	   *val = DatumGetCString(con->constvalue);			/*			 * We pass typmod -1 to the input routine, primarily because			 * existing input routines follow implicit-coercion semantics for			 * length checks, which is not always what we want here. Any			 * length constraint will be applied later by our caller.			 *			 * Note that we call stringTypeDatum using the domain's pg_type			 * row, if it's a domain.  This works because the domain row has			 * the same typinput and typelem as the base type --- ugly...			 */			newcon->constvalue = stringTypeDatum(targetType, val, -1);		}		result = (Node *) newcon;		/* If target is a domain, apply constraints. */		if (targetTyptype == 'd')			result = coerce_to_domain(result, InvalidOid, targetTypeId,									  cformat, false, false);		ReleaseSysCache(targetType);		return result;	}	if (inputTypeId == UNKNOWNOID && IsA(node, Param) &&		((Param *) node)->paramkind == PARAM_NUM &&		pstate != NULL && pstate->p_variableparams)	{		/*		 * Input is a Param of previously undetermined type, and we want to		 * update our knowledge of the Param's type.  Find the topmost		 * ParseState and update the state.		 */		Param	   *param = (Param *) node;		int			paramno = param->paramid;		ParseState *toppstate;		toppstate = pstate;		while (toppstate->parentParseState != NULL)			toppstate = toppstate->parentParseState;		if (paramno <= 0 ||		/* shouldn't happen, but... */			paramno > toppstate->p_numparams)			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_PARAMETER),					 errmsg("there is no parameter $%d", paramno)));		if (toppstate->p_paramtypes[paramno - 1] == UNKNOWNOID)		{			/* We've successfully resolved the type */			toppstate->p_paramtypes[paramno - 1] = targetTypeId;		}		else if (toppstate->p_paramtypes[paramno - 1] == targetTypeId)		{			/* We previously resolved the type, and it matches */		}		else		{			/* Ooops */			ereport(ERROR,					(errcode(ERRCODE_AMBIGUOUS_PARAMETER),					 errmsg("inconsistent types deduced for parameter $%d",							paramno),					 errdetail("%s versus %s",						format_type_be(toppstate->p_paramtypes[paramno - 1]),							   format_type_be(targetTypeId))));		}		param->paramtype = targetTypeId;		/* Apply domain constraints, if necessary */		return coerce_to_domain((Node *) param, InvalidOid, targetTypeId,								cformat, false, false);	}	if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,							  &funcId))	{		if (OidIsValid(funcId))		{			/*			 * Generate an expression tree representing run-time application			 * of the conversion function.	If we are dealing with a domain			 * target type, the conversion function will yield the base type,			 * and we need to extract the correct typmod to use from the			 * domain's typtypmod.			 */			Oid			baseTypeId = getBaseType(targetTypeId);			int32		baseTypeMod;			if (targetTypeId != baseTypeId)				baseTypeMod = get_typtypmod(targetTypeId);			else				baseTypeMod = targetTypeMod;			result = build_coercion_expression(node, funcId,											   baseTypeId, baseTypeMod,											   cformat,										  (cformat != COERCE_IMPLICIT_CAST));			/*			 * If domain, coerce to the domain type and relabel with domain			 * type ID.  We can skip the internal length-coercion step if the			 * selected coercion function was a type-and-length coercion.			 */			if (targetTypeId != baseTypeId)				result = coerce_to_domain(result, baseTypeId, targetTypeId,										  cformat, true,										  exprIsLengthCoercion(result,															   NULL));		}		else		{			/*			 * We don't need to do a physical conversion, but we do need to			 * attach a RelabelType node so that the expression will be seen			 * to have the intended type when inspected by higher-level code.			 *			 * Also, domains may have value restrictions beyond the base type			 * that must be accounted for.	If the destination is a domain			 * then we won't need a RelabelType node.			 */			result = coerce_to_domain(node, InvalidOid, targetTypeId,									  cformat, false, false);			if (result == node)			{				/*				 * XXX could we label result with exprTypmod(node) instead of				 * default -1 typmod, to save a possible length-coercion				 * later? Would work if both types have same interpretation of				 * typmod, which is likely but not certain.				 */				result = (Node *) makeRelabelType((Expr *) result,												  targetTypeId, -1,												  cformat);			}		}		return result;	}	if (inputTypeId == RECORDOID &&		ISCOMPLEX(targetTypeId))	{		/* Coerce a RECORD to a specific complex type */		return coerce_record_to_complex(pstate, node, targetTypeId,										ccontext, cformat);	}	if (targetTypeId == RECORDOID &&		ISCOMPLEX(inputTypeId))	{		/* Coerce a specific complex type to RECORD */		/* NB: we do NOT want a RelabelType here */		return node;	}	if (typeInheritsFrom(inputTypeId, targetTypeId))	{		/*		 * Input class type is a subclass of target, so generate an		 * appropriate runtime conversion (removing unneeded columns and		 * possibly rearranging the ones that are wanted).		 */		ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);		r->arg = (Expr *) node;		r->resulttype = targetTypeId;		r->convertformat = cformat;		return (Node *) r;	}	/* If we get here, caller blew it */	elog(ERROR, "failed to find conversion function from %s to %s",		 format_type_be(inputTypeId), format_type_be(targetTypeId));	return NULL;				/* keep compiler quiet */}/* * can_coerce_type() *		Can input_typeids be coerced to target_typeids? * * We must be told the context (CAST construct, assignment, implicit coercion) * as this determines the set of available casts. */boolcan_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,				CoercionContext ccontext){	bool		have_generics = false;	int			i;	/* run through argument list... */	for (i = 0; i < nargs; i++)	{		Oid			inputTypeId = input_typeids[i];		Oid			targetTypeId = target_typeids[i];		Oid			funcId;		/* no problem if same type */		if (inputTypeId == targetTypeId)			continue;		/* accept if target is ANY */		if (targetTypeId == ANYOID)			continue;		/* accept if target is ANYARRAY or ANYELEMENT, for now */		if (targetTypeId == ANYARRAYOID ||			targetTypeId == ANYELEMENTOID)		{			have_generics = true;		/* do more checking later */			continue;		}		/*		 * If input is an untyped string constant, assume we can convert it to		 * anything.		 */		if (inputTypeId == UNKNOWNOID)			continue;		/*		 * If pg_cast shows that we can coerce, accept.  This test now covers		 * both binary-compatible and coercion-function cases.		 */		if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,								  &funcId))			continue;		/*		 * If input is RECORD and target is a composite type, assume we can		 * coerce (may need tighter checking here)		 */		if (inputTypeId == RECORDOID &&			ISCOMPLEX(targetTypeId))			continue;		/*		 * If input is a composite type and target is RECORD, accept		 */		if (targetTypeId == RECORDOID &&			ISCOMPLEX(inputTypeId))			continue;		/*		 * If input is a class type that inherits from target, accept		 */		if (typeInheritsFrom(inputTypeId, targetTypeId))			continue;		/*		 * Else, cannot coerce at this argument position		 */		return false;	}	/* If we found any generic argument types, cross-check them */	if (have_generics)	{		if (!check_generic_type_consistency(input_typeids, target_typeids,											nargs))			return false;	}	return true;}/* * Create an expression tree to represent coercion to a domain type. * * 'arg': input expression * 'baseTypeId': base type of domain, if known (pass InvalidOid if caller

⌨️ 快捷键说明

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