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

📄 parse_expr.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
	{		/* ALL, ANY, or MULTIEXPR: generate operator list */		List	   *left_list = sublink->lefthand;		List	   *right_list = qtree->targetList;		int			row_length = list_length(left_list);		bool		needNot = false;		List	   *op = sublink->operName;		char	   *opname = strVal(llast(op));		ListCell   *l;		ListCell   *ll_item;		/* transform lefthand expressions */		foreach(l, left_list)			lfirst(l) = transformExpr(pstate, lfirst(l));		/*		 * If the expression is "<> ALL" (with unqualified opname) then		 * convert it to "NOT IN".	This is a hack to improve efficiency of		 * expressions output by pre-7.4 Postgres.		 */		if (sublink->subLinkType == ALL_SUBLINK &&			list_length(op) == 1 && strcmp(opname, "<>") == 0)		{			sublink->subLinkType = ANY_SUBLINK;			opname = pstrdup("=");			op = list_make1(makeString(opname));			sublink->operName = op;			needNot = true;		}		/* Set useOr if op is "<>" (possibly qualified) */		if (strcmp(opname, "<>") == 0)			sublink->useOr = TRUE;		else			sublink->useOr = FALSE;		/* Combining operators other than =/<> is dubious... */		if (row_length != 1 &&			strcmp(opname, "=") != 0 &&			strcmp(opname, "<>") != 0)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("row comparison cannot use operator %s",							opname)));		/*		 * To build the list of combining operator OIDs, we must scan		 * subquery's targetlist to find values that will be matched against		 * lefthand values.  We need to ignore resjunk targets, so doing the		 * outer iteration over right_list is easier than doing it over		 * left_list.		 */		sublink->operOids = NIL;		ll_item = list_head(left_list);		foreach(l, right_list)		{			TargetEntry *tent = (TargetEntry *) lfirst(l);			Node	   *lexpr;			Operator	optup;			Form_pg_operator opform;			if (tent->resjunk)				continue;			if (ll_item == NULL)				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),						 errmsg("subquery has too many columns")));			lexpr = lfirst(ll_item);			ll_item = lnext(ll_item);			/*			 * It's OK to use oper() not compatible_oper() here, because			 * make_subplan() will insert type coercion calls if needed.			 */			optup = oper(op,						 exprType(lexpr),						 exprType((Node *) tent->expr),						 false);			opform = (Form_pg_operator) GETSTRUCT(optup);			if (opform->oprresult != BOOLOID)				ereport(ERROR,						(errcode(ERRCODE_DATATYPE_MISMATCH),				  errmsg("operator %s must return type boolean, not type %s",						 opname,						 format_type_be(opform->oprresult)),						 errhint("The operator of a quantified predicate subquery must return type boolean.")));			if (get_func_retset(opform->oprcode))				ereport(ERROR,						(errcode(ERRCODE_DATATYPE_MISMATCH),						 errmsg("operator %s must not return a set",								opname),						 errhint("The operator of a quantified predicate subquery must return type boolean.")));			sublink->operOids = lappend_oid(sublink->operOids,											oprid(optup));			ReleaseSysCache(optup);		}		if (ll_item != NULL)			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),					 errmsg("subquery has too few columns")));		if (needNot)		{			result = coerce_to_boolean(pstate, result, "NOT");			result = (Node *) makeBoolExpr(NOT_EXPR,										   list_make1(result));		}	}	return result;}static Node *transformArrayExpr(ParseState *pstate, ArrayExpr *a){	ArrayExpr  *newa = makeNode(ArrayExpr);	List	   *newelems = NIL;	List	   *newcoercedelems = NIL;	List	   *typeids = NIL;	ListCell   *element;	Oid			array_type;	Oid			element_type;	/* Transform the element expressions */	foreach(element, a->elements)	{		Node	   *e = (Node *) lfirst(element);		Node	   *newe;		newe = transformExpr(pstate, e);		newelems = lappend(newelems, newe);		typeids = lappend_oid(typeids, exprType(newe));	}	/* Select a common type for the elements */	element_type = select_common_type(typeids, "ARRAY");	/* Coerce arguments to common type if necessary */	foreach(element, newelems)	{		Node	   *e = (Node *) lfirst(element);		Node	   *newe;		newe = coerce_to_common_type(pstate, e,									 element_type,									 "ARRAY");		newcoercedelems = lappend(newcoercedelems, newe);	}	/* Do we have an array type to use? */	array_type = get_array_type(element_type);	if (array_type != InvalidOid)	{		/* Elements are presumably of scalar type */		newa->multidims = false;	}	else	{		/* Must be nested array expressions */		newa->multidims = true;		array_type = element_type;		element_type = get_element_type(array_type);		if (!OidIsValid(element_type))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("could not find array type for data type %s",							format_type_be(array_type))));	}	newa->array_typeid = array_type;	newa->element_typeid = element_type;	newa->elements = newcoercedelems;	return (Node *) newa;}static Node *transformRowExpr(ParseState *pstate, RowExpr *r){	RowExpr    *newr = makeNode(RowExpr);	List	   *newargs = NIL;	ListCell   *arg;	/* Transform the field expressions */	foreach(arg, r->args)	{		Node	   *e = (Node *) lfirst(arg);		Node	   *newe;		newe = transformExpr(pstate, e);		newargs = lappend(newargs, newe);	}	newr->args = newargs;	/* Barring later casting, we consider the type RECORD */	newr->row_typeid = RECORDOID;	newr->row_format = COERCE_IMPLICIT_CAST;	return (Node *) newr;}static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c){	CoalesceExpr *newc = makeNode(CoalesceExpr);	List	   *newargs = NIL;	List	   *newcoercedargs = NIL;	List	   *typeids = NIL;	ListCell   *args;	foreach(args, c->args)	{		Node	   *e = (Node *) lfirst(args);		Node	   *newe;		newe = transformExpr(pstate, e);		newargs = lappend(newargs, newe);		typeids = lappend_oid(typeids, exprType(newe));	}	newc->coalescetype = select_common_type(typeids, "COALESCE");	/* Convert arguments if necessary */	foreach(args, newargs)	{		Node	   *e = (Node *) lfirst(args);		Node	   *newe;		newe = coerce_to_common_type(pstate, e,									 newc->coalescetype,									 "COALESCE");		newcoercedargs = lappend(newcoercedargs, newe);	}	newc->args = newcoercedargs;	return (Node *) newc;}static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m){	MinMaxExpr *newm = makeNode(MinMaxExpr);	List	   *newargs = NIL;	List	   *newcoercedargs = NIL;	List	   *typeids = NIL;	ListCell   *args;	newm->op = m->op;	foreach(args, m->args)	{		Node	   *e = (Node *) lfirst(args);		Node	   *newe;		newe = transformExpr(pstate, e);		newargs = lappend(newargs, newe);		typeids = lappend_oid(typeids, exprType(newe));	}	newm->minmaxtype = select_common_type(typeids, "GREATEST/LEAST");	/* Convert arguments if necessary */	foreach(args, newargs)	{		Node	   *e = (Node *) lfirst(args);		Node	   *newe;		newe = coerce_to_common_type(pstate, e,									 newm->minmaxtype,									 "GREATEST/LEAST");		newcoercedargs = lappend(newcoercedargs, newe);	}	newm->args = newcoercedargs;	return (Node *) newm;}static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b){	const char *clausename;	switch (b->booltesttype)	{		case IS_TRUE:			clausename = "IS TRUE";			break;		case IS_NOT_TRUE:			clausename = "IS NOT TRUE";			break;		case IS_FALSE:			clausename = "IS FALSE";			break;		case IS_NOT_FALSE:			clausename = "IS NOT FALSE";			break;		case IS_UNKNOWN:			clausename = "IS UNKNOWN";			break;		case IS_NOT_UNKNOWN:			clausename = "IS NOT UNKNOWN";			break;		default:			elog(ERROR, "unrecognized booltesttype: %d",				 (int) b->booltesttype);			clausename = NULL;	/* keep compiler quiet */	}	b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg);	b->arg = (Expr *) coerce_to_boolean(pstate,										(Node *) b->arg,										clausename);	return (Node *) b;}/* * Construct a whole-row reference to represent the notation "relation.*". * * A whole-row reference is a Var with varno set to the correct range * table entry, and varattno == 0 to signal that it references the whole * tuple.  (Use of zero here is unclean, since it could easily be confused * with error cases, but it's not worth changing now.)  The vartype indicates * a rowtype; either a named composite type, or RECORD. */static Node *transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname){	Node	   *result;	RangeTblEntry *rte;	int			vnum;	int			sublevels_up;	Oid			toid;	/* Look up the referenced RTE, creating it if needed */	rte = refnameRangeTblEntry(pstate, schemaname, relname,							   &sublevels_up);	if (rte == NULL)		rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname));	vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);	/* Build the appropriate referencing node */	switch (rte->rtekind)	{		case RTE_RELATION:			/* relation: the rowtype is a named composite type */			toid = get_rel_type_id(rte->relid);			if (!OidIsValid(toid))				elog(ERROR, "could not find type OID for relation %u",					 rte->relid);			result = (Node *) makeVar(vnum,									  InvalidAttrNumber,									  toid,									  -1,									  sublevels_up);			break;		case RTE_FUNCTION:			toid = exprType(rte->funcexpr);			if (toid == RECORDOID || get_typtype(toid) == 'c')			{				/* func returns composite; same as relation case */				result = (Node *) makeVar(vnum,										  InvalidAttrNumber,										  toid,										  -1,										  sublevels_up);			}			else			{				/*				 * func returns scalar; instead of making a whole-row Var,				 * just reference the function's scalar output.  (XXX this				 * seems a tad inconsistent, especially if "f.*" was				 * explicitly written ...)				 */				result = (Node *) makeVar(vnum,										  1,										  toid,										  -1,										  sublevels_up);			}			break;		default:			/*			 * RTE is a join or subselect.	We represent this as a whole-row			 * Var of RECORD type.	(Note that in most cases the Var will be			 * expanded to a RowExpr during planning, but that is not our			 * concern here.)			 */			result = (Node *) makeVar(vnum,									  InvalidAttrNumber,									  RECORDOID,									  -1,									  sublevels_up);			break;	}	return result;}/* *	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 *) linitial(qtree->targetList);					Assert(IsA(tent, TargetEntry));					Assert(!tent->resjunk);					type = exprType((Node *) tent->expr);					if (sublink->subLinkType == ARRAY_SUBLINK)					{						type = get_array_type(type);						if (!OidIsValid(type))							ereport(ERROR,									(errcode(ERRCODE_UNDEFINED_OBJECT),									 errmsg("could not find array type for data type %s",							format_type_be(exprType((Node *) tent->expr)))));					}				}				else				{					/* for all other sublink types, result is boolean */					type = BOOLOID;				}			}			break;		case T_SubPlan:			{				/*

⌨️ 快捷键说明

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