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

📄 parse_coerce.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
 *		has not bothered to look this up) * 'typeId': target type to coerce to * 'cformat': coercion format * 'hideInputCoercion': if true, hide the input coercion under this one. * 'lengthCoercionDone': if true, caller already accounted for length. * * If the target type isn't a domain, the given 'arg' is returned as-is. */Node *coerce_to_domain(Node *arg, Oid baseTypeId, Oid typeId,				 CoercionForm cformat, bool hideInputCoercion,				 bool lengthCoercionDone){	CoerceToDomain *result;	/* Get the base type if it hasn't been supplied */	if (baseTypeId == InvalidOid)		baseTypeId = getBaseType(typeId);	/* If it isn't a domain, return the node as it was passed in */	if (baseTypeId == typeId)		return arg;	/* Suppress display of nested coercion steps */	if (hideInputCoercion)		hide_coercion_node(arg);	/*	 * If the domain applies a typmod to its base type, build the appropriate	 * coercion step.  Mark it implicit for display purposes, because we don't	 * want it shown separately by ruleutils.c; but the isExplicit flag passed	 * to the conversion function depends on the manner in which the domain	 * coercion is invoked, so that the semantics of implicit and explicit	 * coercion differ.  (Is that really the behavior we want?)	 *	 * NOTE: because we apply this as part of the fixed expression structure,	 * ALTER DOMAIN cannot alter the typtypmod.  But it's unclear that that	 * would be safe to do anyway, without lots of knowledge about what the	 * base type thinks the typmod means.	 */	if (!lengthCoercionDone)	{		int32		typmod = get_typtypmod(typeId);		if (typmod >= 0)			arg = coerce_type_typmod(arg, baseTypeId, typmod,									 COERCE_IMPLICIT_CAST,									 (cformat != COERCE_IMPLICIT_CAST),									 false);	}	/*	 * Now build the domain coercion node.	This represents run-time checking	 * of any constraints currently attached to the domain.  This also ensures	 * that the expression is properly labeled as to result type.	 */	result = makeNode(CoerceToDomain);	result->arg = (Expr *) arg;	result->resulttype = typeId;	result->resulttypmod = -1;	/* currently, always -1 for domains */	result->coercionformat = cformat;	return (Node *) result;}/* * coerce_type_typmod() *		Force a value to a particular typmod, if meaningful and possible. * * This is applied to values that are going to be stored in a relation * (where we have an atttypmod for the column) as well as values being * explicitly CASTed (where the typmod comes from the target type spec). * * The caller must have already ensured that the value is of the correct * type, typically by applying coerce_type. * * cformat determines the display properties of the generated node (if any), * while isExplicit may affect semantics.  If hideInputCoercion is true * *and* we generate a node, the input node is forced to IMPLICIT display * form, so that only the typmod coercion node will be visible when * displaying the expression. * * NOTE: this does not need to work on domain types, because any typmod * coercion for a domain is considered to be part of the type coercion * needed to produce the domain value in the first place.  So, no getBaseType. */static Node *coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,				   CoercionForm cformat, bool isExplicit,				   bool hideInputCoercion){	Oid			funcId;	/*	 * A negative typmod is assumed to mean that no coercion is wanted. Also,	 * skip coercion if already done.	 */	if (targetTypMod < 0 || targetTypMod == exprTypmod(node))		return node;	funcId = find_typmod_coercion_function(targetTypeId);	if (OidIsValid(funcId))	{		/* Suppress display of nested coercion steps */		if (hideInputCoercion)			hide_coercion_node(node);		node = build_coercion_expression(node, funcId,										 targetTypeId, targetTypMod,										 cformat, isExplicit);	}	return node;}/* * Mark a coercion node as IMPLICIT so it will never be displayed by * ruleutils.c.  We use this when we generate a nest of coercion nodes * to implement what is logically one conversion; the inner nodes are * forced to IMPLICIT_CAST format.	This does not change their semantics, * only display behavior. * * It is caller error to call this on something that doesn't have a * CoercionForm field. */static voidhide_coercion_node(Node *node){	if (IsA(node, FuncExpr))		((FuncExpr *) node)->funcformat = COERCE_IMPLICIT_CAST;	else if (IsA(node, RelabelType))		((RelabelType *) node)->relabelformat = COERCE_IMPLICIT_CAST;	else if (IsA(node, ConvertRowtypeExpr))		((ConvertRowtypeExpr *) node)->convertformat = COERCE_IMPLICIT_CAST;	else if (IsA(node, RowExpr))		((RowExpr *) node)->row_format = COERCE_IMPLICIT_CAST;	else if (IsA(node, CoerceToDomain))		((CoerceToDomain *) node)->coercionformat = COERCE_IMPLICIT_CAST;	else		elog(ERROR, "unsupported node type: %d", (int) nodeTag(node));}/* * build_coercion_expression() *		Construct a function-call expression for applying a pg_cast entry. * * This is used for both type-coercion and length-coercion functions, * since there is no difference in terms of the calling convention. */static Node *build_coercion_expression(Node *node, Oid funcId,						  Oid targetTypeId, int32 targetTypMod,						  CoercionForm cformat, bool isExplicit){	HeapTuple	tp;	Form_pg_proc procstruct;	int			nargs;	List	   *args;	Const	   *cons;	tp = SearchSysCache(PROCOID,						ObjectIdGetDatum(funcId),						0, 0, 0);	if (!HeapTupleIsValid(tp))		elog(ERROR, "cache lookup failed for function %u", funcId);	procstruct = (Form_pg_proc) GETSTRUCT(tp);	/*	 * Asserts essentially check that function is a legal coercion function.	 * We can't make the seemingly obvious tests on prorettype and	 * proargtypes[0], because of various binary-compatibility cases.	 */	/* Assert(targetTypeId == procstruct->prorettype); */	Assert(!procstruct->proretset);	Assert(!procstruct->proisagg);	nargs = procstruct->pronargs;	Assert(nargs >= 1 && nargs <= 3);	/* Assert(procstruct->proargtypes.values[0] == exprType(node)); */	Assert(nargs < 2 || procstruct->proargtypes.values[1] == INT4OID);	Assert(nargs < 3 || procstruct->proargtypes.values[2] == BOOLOID);	ReleaseSysCache(tp);	args = list_make1(node);	if (nargs >= 2)	{		/* Pass target typmod as an int4 constant */		cons = makeConst(INT4OID,						 sizeof(int32),						 Int32GetDatum(targetTypMod),						 false,						 true);		args = lappend(args, cons);	}	if (nargs == 3)	{		/* Pass it a boolean isExplicit parameter, too */		cons = makeConst(BOOLOID,						 sizeof(bool),						 BoolGetDatum(isExplicit),						 false,						 true);		args = lappend(args, cons);	}	return (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat);}/* * coerce_record_to_complex *		Coerce a RECORD to a specific composite type. * * Currently we only support this for inputs that are RowExprs or whole-row * Vars. */static Node *coerce_record_to_complex(ParseState *pstate, Node *node,						 Oid targetTypeId,						 CoercionContext ccontext,						 CoercionForm cformat){	RowExpr    *rowexpr;	TupleDesc	tupdesc;	List	   *args = NIL;	List	   *newargs;	int			i;	int			ucolno;	ListCell   *arg;	if (node && IsA(node, RowExpr))	{		/*		 * Since the RowExpr must be of type RECORD, we needn't worry about it		 * containing any dropped columns.		 */		args = ((RowExpr *) node)->args;	}	else if (node && IsA(node, Var) &&			 ((Var *) node)->varattno == InvalidAttrNumber)	{		int			rtindex = ((Var *) node)->varno;		int			sublevels_up = ((Var *) node)->varlevelsup;		RangeTblEntry *rte;		rte = GetRTEByRangeTablePosn(pstate, rtindex, sublevels_up);		expandRTE(rte, rtindex, sublevels_up, false,				  NULL, &args);	}	else		ereport(ERROR,				(errcode(ERRCODE_CANNOT_COERCE),				 errmsg("cannot cast type %s to %s",						format_type_be(RECORDOID),						format_type_be(targetTypeId))));	tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(targetTypeId, -1));	newargs = NIL;	ucolno = 1;	arg = list_head(args);	for (i = 0; i < tupdesc->natts; i++)	{		Node	   *expr;		Oid			exprtype;		/* Fill in NULLs for dropped columns in rowtype */		if (tupdesc->attrs[i]->attisdropped)		{			/*			 * can't use atttypid here, but it doesn't really matter what type			 * the Const claims to be.			 */			newargs = lappend(newargs, makeNullConst(INT4OID));			continue;		}		if (arg == NULL)			ereport(ERROR,					(errcode(ERRCODE_CANNOT_COERCE),					 errmsg("cannot cast type %s to %s",							format_type_be(RECORDOID),							format_type_be(targetTypeId)),					 errdetail("Input has too few columns.")));		expr = (Node *) lfirst(arg);		exprtype = exprType(expr);		expr = coerce_to_target_type(pstate,									 expr, exprtype,									 tupdesc->attrs[i]->atttypid,									 tupdesc->attrs[i]->atttypmod,									 ccontext,									 COERCE_IMPLICIT_CAST);		if (expr == NULL)			ereport(ERROR,					(errcode(ERRCODE_CANNOT_COERCE),					 errmsg("cannot cast type %s to %s",							format_type_be(RECORDOID),							format_type_be(targetTypeId)),					 errdetail("Cannot cast type %s to %s in column %d.",							   format_type_be(exprtype),							   format_type_be(tupdesc->attrs[i]->atttypid),							   ucolno)));		newargs = lappend(newargs, expr);		ucolno++;		arg = lnext(arg);	}	if (arg != NULL)		ereport(ERROR,				(errcode(ERRCODE_CANNOT_COERCE),				 errmsg("cannot cast type %s to %s",						format_type_be(RECORDOID),						format_type_be(targetTypeId)),				 errdetail("Input has too many columns.")));	FreeTupleDesc(tupdesc);	rowexpr = makeNode(RowExpr);	rowexpr->args = newargs;	rowexpr->row_typeid = targetTypeId;	rowexpr->row_format = cformat;	return (Node *) rowexpr;}/* coerce_to_boolean() *		Coerce an argument of a construct that requires boolean input *		(AND, OR, NOT, etc).  Also check that input is not a set. * * Returns the possibly-transformed node tree. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */Node *coerce_to_boolean(ParseState *pstate, Node *node,				  const char *constructName){	Oid			inputTypeId = exprType(node);	if (inputTypeId != BOOLOID)	{		node = coerce_to_target_type(pstate, node, inputTypeId,									 BOOLOID, -1,									 COERCION_ASSIGNMENT,									 COERCE_IMPLICIT_CAST);		if (node == NULL)			ereport(ERROR,					(errcode(ERRCODE_DATATYPE_MISMATCH),			/* translator: first %s is name of a SQL construct, eg WHERE */				   errmsg("argument of %s must be type boolean, not type %s",						  constructName, format_type_be(inputTypeId))));	}	if (expression_returns_set(node))		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),		/* translator: %s is name of a SQL construct, eg WHERE */				 errmsg("argument of %s must not return a set",						constructName)));	return node;}/* coerce_to_integer() *		Coerce an argument of a construct that requires integer input *		(LIMIT, OFFSET, etc).  Also check that input is not a set. * * Returns the possibly-transformed node tree. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */Node *coerce_to_integer(ParseState *pstate, Node *node,				  const char *constructName){	Oid			inputTypeId = exprType(node);	if (inputTypeId != INT4OID)	{		node = coerce_to_target_type(pstate, node, inputTypeId,									 INT4OID, -1,									 COERCION_ASSIGNMENT,									 COERCE_IMPLICIT_CAST);		if (node == NULL)			ereport(ERROR,					(errcode(ERRCODE_DATATYPE_MISMATCH),			/* translator: first %s is name of a SQL construct, eg LIMIT */				   errmsg("argument of %s must be type integer, not type %s",						  constructName, format_type_be(inputTypeId))));	}	if (expression_returns_set(node))		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),		/* translator: %s is name of a SQL construct, eg LIMIT */				 errmsg("argument of %s must not return a set",						constructName)));	return node;}/* select_common_type() *		Determine the common supertype of a list of input expression types. *		This is used for determining the output type of CASE and UNION *		constructs. * * typeids is a nonempty list of type OIDs.  Note that earlier items * in the list will be preferred if there is doubt. * 'context' is a phrase to use in the error message if we fail to select * a usable type. */Oidselect_common_type(List *typeids, const char *context){	Oid			ptype;	CATEGORY	pcategory;	ListCell   *type_item;	Assert(typeids != NIL);	ptype = getBaseType(linitial_oid(typeids));	pcategory = TypeCategory(ptype);	for_each_cell(type_item, lnext(list_head(typeids)))	{		Oid			ntype = getBaseType(lfirst_oid(type_item));		/* move on to next one if no new information... */		if ((ntype != InvalidOid) && (ntype != UNKNOWNOID) && (ntype != ptype))		{			if ((ptype == InvalidOid) || ptype == UNKNOWNOID)			{				/* so far, only nulls so take anything... */				ptype = ntype;				pcategory = TypeCategory(ptype);			}			else if (TypeCategory(ntype) != pcategory)			{				/*

⌨️ 快捷键说明

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