parse_expr.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,537 行 · 第 1/3 页

C
1,537
字号
						rv->relname = name;						rv->inhOpt = INH_DEFAULT;						node = (Node *) rv;					}					else						ereport(ERROR,								(errcode(ERRCODE_UNDEFINED_COLUMN),							errmsg("column \"%s\" does not exist", name)));				}				break;			}		case 2:			{				char	   *name1 = strVal(lfirst(cref->fields));				char	   *name2 = strVal(lsecond(cref->fields));				/* Whole-row reference? */				if (strcmp(name2, "*") == 0)				{					rv = makeNode(RangeVar);					rv->relname = name1;					rv->inhOpt = INH_DEFAULT;					node = (Node *) rv;					break;				}				/* Try to identify as a once-qualified column */				node = qualifiedNameToVar(pstate, NULL, name1, name2, true);				if (node == NULL)				{					/*					 * Not known as a column of any range-table entry, so					 * try it as a function call.  Here, we will create an					 * implicit RTE for tables not already entered.					 */					rv = makeNode(RangeVar);					rv->relname = name1;					rv->inhOpt = INH_DEFAULT;					node = ParseFuncOrColumn(pstate,											 makeList1(makeString(name2)),											 makeList1(rv),											 false, false, true);				}				break;			}		case 3:			{				char	   *name1 = strVal(lfirst(cref->fields));				char	   *name2 = strVal(lsecond(cref->fields));				char	   *name3 = strVal(lthird(cref->fields));				/* Whole-row reference? */				if (strcmp(name3, "*") == 0)				{					rv = makeNode(RangeVar);					rv->schemaname = name1;					rv->relname = name2;					rv->inhOpt = INH_DEFAULT;					node = (Node *) rv;					break;				}				/* Try to identify as a twice-qualified column */				node = qualifiedNameToVar(pstate, name1, name2, name3, true);				if (node == NULL)				{					/* Try it as a function call */					rv = makeNode(RangeVar);					rv->schemaname = name1;					rv->relname = name2;					rv->inhOpt = INH_DEFAULT;					node = ParseFuncOrColumn(pstate,											 makeList1(makeString(name3)),											 makeList1(rv),											 false, false, true);				}				break;			}		case 4:			{				char	   *name1 = strVal(lfirst(cref->fields));				char	   *name2 = strVal(lsecond(cref->fields));				char	   *name3 = strVal(lthird(cref->fields));				char	   *name4 = strVal(lfourth(cref->fields));				/*				 * We check the catalog name and then ignore it.				 */				if (strcmp(name1, get_database_name(MyDatabaseId)) != 0)					ereport(ERROR,							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),							 errmsg("cross-database references are not implemented")));				/* Whole-row reference? */				if (strcmp(name4, "*") == 0)				{					rv = makeNode(RangeVar);					rv->schemaname = name2;					rv->relname = name3;					rv->inhOpt = INH_DEFAULT;					node = (Node *) rv;					break;				}				/* Try to identify as a twice-qualified column */				node = qualifiedNameToVar(pstate, name2, name3, name4, true);				if (node == NULL)				{					/* Try it as a function call */					rv = makeNode(RangeVar);					rv->schemaname = name2;					rv->relname = name3;					rv->inhOpt = INH_DEFAULT;					node = ParseFuncOrColumn(pstate,											 makeList1(makeString(name4)),											 makeList1(rv),											 false, false, true);				}				break;			}		default:			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),			errmsg("improper qualified name (too many dotted names): %s",				   NameListToString(cref->fields))));			node = NULL;		/* keep compiler quiet */			break;	}	return transformIndirection(pstate, node, cref->indirection);}/* *	exprType - *	  returns the Oid of the type of the expression. (Used for typechecking.) */OidexprType(Node *expr){	Oid			type;	if (!expr)		return InvalidOid;	switch (nodeTag(expr))	{		case T_Var:			type = ((Var *) expr)->vartype;			break;		case T_Const:			type = ((Const *) expr)->consttype;			break;		case T_Param:			type = ((Param *) expr)->paramtype;			break;		case T_Aggref:			type = ((Aggref *) expr)->aggtype;			break;		case T_ArrayRef:			type = ((ArrayRef *) expr)->refrestype;			break;		case T_FuncExpr:			type = ((FuncExpr *) expr)->funcresulttype;			break;		case T_OpExpr:			type = ((OpExpr *) expr)->opresulttype;			break;		case T_DistinctExpr:			type = ((DistinctExpr *) expr)->opresulttype;			break;		case T_ScalarArrayOpExpr:			type = BOOLOID;			break;		case T_BoolExpr:			type = BOOLOID;			break;		case T_SubLink:			{				SubLink    *sublink = (SubLink *) expr;				if (sublink->subLinkType == EXPR_SUBLINK ||					sublink->subLinkType == ARRAY_SUBLINK)				{					/* get the type of the subselect's first target column */					Query	   *qtree = (Query *) sublink->subselect;					TargetEntry *tent;					if (!qtree || !IsA(qtree, Query))						elog(ERROR, "cannot get type for untransformed sublink");					tent = (TargetEntry *) lfirst(qtree->targetList);					Assert(IsA(tent, TargetEntry));					Assert(!tent->resdom->resjunk);					if (sublink->subLinkType == EXPR_SUBLINK)						type = tent->resdom->restype;					else/* ARRAY_SUBLINK */					{						type = get_array_type(tent->resdom->restype);						if (!OidIsValid(type))							ereport(ERROR,									(errcode(ERRCODE_UNDEFINED_OBJECT),									 errmsg("could not find array type for data type %s",								format_type_be(tent->resdom->restype))));					}				}				else				{					/* for all other sublink types, result is boolean */					type = BOOLOID;				}			}			break;		case T_SubPlan:			{				/*				 * Although the parser does not ever deal with				 * already-planned expression trees, we support SubPlan				 * nodes in this routine for the convenience of				 * ruleutils.c.				 */				SubPlan    *subplan = (SubPlan *) expr;				if (subplan->subLinkType == EXPR_SUBLINK ||					subplan->subLinkType == ARRAY_SUBLINK)				{					/* get the type of the subselect's first target column */					TargetEntry *tent;					tent = (TargetEntry *) lfirst(subplan->plan->targetlist);					Assert(IsA(tent, TargetEntry));					Assert(!tent->resdom->resjunk);					if (subplan->subLinkType == EXPR_SUBLINK)						type = tent->resdom->restype;					else/* ARRAY_SUBLINK */					{						type = get_array_type(tent->resdom->restype);						if (!OidIsValid(type))							ereport(ERROR,									(errcode(ERRCODE_UNDEFINED_OBJECT),									 errmsg("could not find array type for data type %s",								format_type_be(tent->resdom->restype))));					}				}				else				{					/* for all other subplan types, result is boolean */					type = BOOLOID;				}			}			break;		case T_FieldSelect:			type = ((FieldSelect *) expr)->resulttype;			break;		case T_RelabelType:			type = ((RelabelType *) expr)->resulttype;			break;		case T_CaseExpr:			type = ((CaseExpr *) expr)->casetype;			break;		case T_CaseWhen:			type = exprType((Node *) ((CaseWhen *) expr)->result);			break;		case T_ArrayExpr:			type = ((ArrayExpr *) expr)->array_typeid;			break;		case T_CoalesceExpr:			type = ((CoalesceExpr *) expr)->coalescetype;			break;		case T_NullIfExpr:			type = exprType((Node *) lfirst(((NullIfExpr *) expr)->args));			break;		case T_NullTest:			type = BOOLOID;			break;		case T_BooleanTest:			type = BOOLOID;			break;		case T_CoerceToDomain:			type = ((CoerceToDomain *) expr)->resulttype;			break;		case T_CoerceToDomainValue:			type = ((CoerceToDomainValue *) expr)->typeId;			break;		case T_SetToDefault:			type = ((SetToDefault *) expr)->typeId;			break;		case T_RangeVar:			/*			 * If someone uses a bare relation name in an expression, we			 * will likely first notice a problem here (see comments in			 * transformColumnRef()).  Issue an appropriate error message.			 */			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),					 errmsg("relation reference \"%s\" cannot be used in an expression",							((RangeVar *) expr)->relname)));			type = InvalidOid;	/* keep compiler quiet */			break;		default:			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));			type = InvalidOid;	/* keep compiler quiet */			break;	}	return type;}/* *	exprTypmod - *	  returns the type-specific attrmod of the expression, if it can be *	  determined.  In most cases, it can't and we return -1. */int32exprTypmod(Node *expr){	if (!expr)		return -1;	switch (nodeTag(expr))	{		case T_Var:			return ((Var *) expr)->vartypmod;		case T_Const:			{				/* Be smart about string constants... */				Const	   *con = (Const *) expr;				switch (con->consttype)				{					case BPCHAROID:						if (!con->constisnull)							return VARSIZE(DatumGetPointer(con->constvalue));						break;					default:						break;				}			}			break;		case T_FuncExpr:			{				int32		coercedTypmod;				/* Be smart about length-coercion functions... */				if (exprIsLengthCoercion(expr, &coercedTypmod))					return coercedTypmod;			}			break;		case T_FieldSelect:			return ((FieldSelect *) expr)->resulttypmod;		case T_RelabelType:			return ((RelabelType *) expr)->resulttypmod;		case T_CaseExpr:			{				/*				 * If all the alternatives agree on type/typmod, return				 * that typmod, else use -1				 */				CaseExpr   *cexpr = (CaseExpr *) expr;				Oid			casetype = cexpr->casetype;				int32		typmod;				List	   *arg;				if (!cexpr->defresult)					return -1;				if (exprType((Node *) cexpr->defresult) != casetype)					return -1;				typmod = exprTypmod((Node *) cexpr->defresult);				if (typmod < 0)					return -1;	/* no point in trying harder */				foreach(arg, cexpr->args)				{					CaseWhen   *w = (CaseWhen *) lfirst(arg);					Assert(IsA(w, CaseWhen));					if (exprType((Node *) w->result) != casetype)						return -1;					if (exprTypmod((Node *) w->result) != typmod)						return -1;				}				return typmod;			}			break;		case T_CoalesceExpr:			{				/*				 * If all the alternatives agree on type/typmod, return				 * that typmod, else use -1				 */				CoalesceExpr *cexpr = (CoalesceExpr *) expr;				Oid			coalescetype = cexpr->coalescetype;				int32		typmod;				List	   *arg;				typmod = exprTypmod((Node *) lfirst(cexpr->args));				foreach(arg, cexpr->args)				{					Node	   *e = (Node *) lfirst(arg);					if (exprType(e) != coalescetype)						return -1;					if (exprTypmod(e) != typmod)						return -1;				}				return typmod;			}			break;		case T_NullIfExpr:			{				NullIfExpr *nexpr = (NullIfExpr *) expr;				return exprTypmod((Node *) lfirst(nexpr->args));			}			break;		case T_CoerceToDomain:			return ((CoerceToDomain *) expr)->resulttypmod;		case T_CoerceToDomainValue:			return ((CoerceToDomainValue *) expr)->typeMod;		case T_SetToDefault:			return ((SetToDefault *) expr)->typeMod;		default:			break;	}	return -1;}/* * exprIsLengthCoercion *		Detect whether an expression tree is an application of a datatype's *		typmod-coercion function.  Optionally extract the result's typmod. * * If coercedTypmod is not NULL, the typmod is stored there if the expression * is a length-coercion function, else -1 is stored there. */boolexprIsLengthCoercion(Node *expr, int32 *coercedTypmod){	FuncExpr   *func;	int			nargs;	Const	   *second_arg;	if (coercedTypmod != NULL)		*coercedTypmod = -1;	/* default result on failure */	/* Is it a function-call at all? */	if (expr == NULL || !IsA(expr, FuncExpr))		return false;	func = (FuncExpr *) expr;	/*	 * If it didn't come from a coercion context, reject.	 */	if (func->funcformat != COERCE_EXPLICIT_CAST &&		func->funcformat != COERCE_IMPLICIT_CAST)		return false;	/*	 * If it's not a two-argument or three-argument function with the	 * second argument being an int4 constant, it can't have been created	 * from a length coercion (it must be a type coercion, instead).	 */	nargs = length(func->args);	if (nargs < 2 || nargs > 3)		return false;	second_arg = (Const *) lsecond(func->args);	if (!IsA(second_arg, Const) ||		second_arg->consttype != INT4OID ||		second_arg->constisnull)		return false;	/*	 * OK, it is indeed a length-coercion function.	 */	if (coercedTypmod != NULL)		*coercedTypmod = DatumGetInt32(second_arg->constvalue);	return true;}/* * Handle an explicit CAST construct. * * The given expr has already been transformed, but we need to lookup * the type name and then apply any necessary coercion function(s). */static Node *typecast_expression(ParseState *pstate, Node *expr, TypeName *typename){	Oid			inputType = exprType(expr);	Oid			targetType;	targetType = typenameTypeId(typename);	if (inputType == InvalidOid)		return expr;			/* do nothing if NULL input */	expr = coerce_to_target_type(pstate, expr, inputType,								 targetType, typename->typmod,								 COERCION_EXPLICIT,								 COERCE_EXPLICIT_CAST);	if (expr == NULL)		ereport(ERROR,				(errcode(ERRCODE_CANNOT_COERCE),				 errmsg("cannot cast type %s to %s",						format_type_be(inputType),						format_type_be(targetType))));	return expr;}

⌨️ 快捷键说明

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