parse_expr.c

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

C
1,537
字号
					sublink->useOr = FALSE;				}				else				{					/* ALL, ANY, or MULTIEXPR: generate operator list */					List	   *left_list = sublink->lefthand;					List	   *right_list = qtree->targetList;					int			row_length = length(left_list);					bool		needNot = false;					List	   *op = sublink->operName;					char	   *opname = strVal(llast(op));					List	   *elist;					/* transform lefthand expressions */					foreach(elist, left_list)						lfirst(elist) = transformExpr(pstate, lfirst(elist));					/*					 * 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 &&						length(op) == 1 && strcmp(opname, "<>") == 0)					{						sublink->subLinkType = ANY_SUBLINK;						opname = pstrdup("=");						op = makeList1(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;					while (right_list != NIL)					{						TargetEntry *tent = (TargetEntry *) lfirst(right_list);						Node	   *lexpr;						Operator	optup;						Form_pg_operator opform;						right_list = lnext(right_list);						if (tent->resdom->resjunk)							continue;						if (left_list == NIL)							ereport(ERROR,									(errcode(ERRCODE_SYNTAX_ERROR),							 errmsg("subquery has too many columns")));						lexpr = lfirst(left_list);						left_list = lnext(left_list);						/*						 * 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 = lappendo(sublink->operOids,													 oprid(optup));						ReleaseSysCache(optup);					}					if (left_list != NIL)						ereport(ERROR,								(errcode(ERRCODE_SYNTAX_ERROR),							  errmsg("subquery has too few columns")));					if (needNot)					{						expr = coerce_to_boolean(pstate, expr, "NOT");						expr = (Node *) makeBoolExpr(NOT_EXPR,													 makeList1(expr));					}				}				result = (Node *) expr;				break;			}		case T_CaseExpr:			{				CaseExpr   *c = (CaseExpr *) expr;				CaseExpr   *newc = makeNode(CaseExpr);				List	   *newargs = NIL;				List	   *typeids = NIL;				List	   *args;				Node	   *defresult;				Oid			ptype;				/* transform the list of arguments */				foreach(args, c->args)				{					CaseWhen   *w = (CaseWhen *) lfirst(args);					CaseWhen   *neww = makeNode(CaseWhen);					Node	   *warg;					Assert(IsA(w, CaseWhen));					warg = (Node *) w->expr;					if (c->arg != NULL)					{						/* shorthand form was specified, so expand... */						warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",														 (Node *) c->arg,														 warg);					}					neww->expr = (Expr *) transformExpr(pstate, warg);					neww->expr = (Expr *) coerce_to_boolean(pstate,													 (Node *) neww->expr,															"CASE/WHEN");					/*					 * result is NULL for NULLIF() construct - thomas					 * 1998-11-11					 */					warg = (Node *) w->result;					if (warg == NULL)					{						A_Const    *n = makeNode(A_Const);						n->val.type = T_Null;						warg = (Node *) n;					}					neww->result = (Expr *) transformExpr(pstate, warg);					newargs = lappend(newargs, neww);					typeids = lappendo(typeids, exprType((Node *) neww->result));				}				newc->args = newargs;				/*				 * It's not shorthand anymore, so drop the implicit				 * argument. This is necessary to keep any re-application				 * of transformExpr from doing the wrong thing.				 */				newc->arg = NULL;				/* transform the default clause */				defresult = (Node *) c->defresult;				if (defresult == NULL)				{					A_Const    *n = makeNode(A_Const);					n->val.type = T_Null;					defresult = (Node *) n;				}				newc->defresult = (Expr *) transformExpr(pstate, defresult);				/*				 * Note: default result is considered the most significant				 * type in determining preferred type.	This is how the				 * code worked before, but it seems a little bogus to me				 * --- tgl				 */				typeids = lconso(exprType((Node *) newc->defresult), typeids);				ptype = select_common_type(typeids, "CASE");				newc->casetype = ptype;				/* Convert default result clause, if necessary */				newc->defresult = (Expr *)					coerce_to_common_type(pstate,										  (Node *) newc->defresult,										  ptype,										  "CASE/ELSE");				/* Convert when-clause results, if necessary */				foreach(args, newc->args)				{					CaseWhen   *w = (CaseWhen *) lfirst(args);					w->result = (Expr *)						coerce_to_common_type(pstate,											  (Node *) w->result,											  ptype,											  "CASE/WHEN");				}				result = (Node *) newc;				break;			}		case T_ArrayExpr:			{				ArrayExpr  *a = (ArrayExpr *) expr;				ArrayExpr  *newa = makeNode(ArrayExpr);				List	   *newelems = NIL;				List	   *newcoercedelems = NIL;				List	   *typeids = NIL;				List	   *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 = lappendo(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;				result = (Node *) newa;				break;			}		case T_CoalesceExpr:			{				CoalesceExpr *c = (CoalesceExpr *) expr;				CoalesceExpr *newc = makeNode(CoalesceExpr);				List	   *newargs = NIL;				List	   *newcoercedargs = NIL;				List	   *typeids = NIL;				List	   *args;				foreach(args, c->args)				{					Node	   *e = (Node *) lfirst(args);					Node	   *newe;					newe = transformExpr(pstate, e);					newargs = lappend(newargs, newe);					typeids = lappendo(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;				result = (Node *) newc;				break;			}		case T_NullTest:			{				NullTest   *n = (NullTest *) expr;				n->arg = (Expr *) transformExpr(pstate, (Node *) n->arg);				/* the argument can be any type, so don't coerce it */				result = expr;				break;			}		case T_BooleanTest:			{				BooleanTest *b = (BooleanTest *) expr;				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);				result = expr;				break;			}			/*********************************************			 * Quietly accept node types that may be presented when we are			 * called on an already-transformed tree.			 *			 * Do any other node types need to be accepted?  For now we are			 * taking a conservative approach, and only accepting node			 * types that are demonstrably necessary to accept.			 *********************************************/		case T_Var:		case T_Const:		case T_Param:		case T_Aggref:		case T_ArrayRef:		case T_FuncExpr:		case T_OpExpr:		case T_DistinctExpr:		case T_ScalarArrayOpExpr:		case T_NullIfExpr:		case T_BoolExpr:		case T_FieldSelect:		case T_RelabelType:		case T_CoerceToDomain:		case T_CoerceToDomainValue:		case T_SetToDefault:			{				result = (Node *) expr;				break;			}		default:			/* should not reach here */			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));			break;	}	expr_depth_counter--;	return result;}static Node *transformIndirection(ParseState *pstate, Node *basenode, List *indirection){	if (indirection == NIL)		return basenode;	return (Node *) transformArraySubscripts(pstate,											 basenode,											 exprType(basenode),											 exprTypmod(basenode),											 indirection,											 false,											 NULL);}static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref){	int			numnames = length(cref->fields);	Node	   *node;	RangeVar   *rv;	int			levels_up;	/*----------	 * The allowed syntaxes are:	 *	 * A		First try to resolve as unqualified column name;	 *			if no luck, try to resolve as unqual. table name (A.*).	 * A.B		A is an unqual. table name; B is either a	 *			column or function name (trying column name first).	 * A.B.C	schema A, table B, col or func name C.	 * A.B.C.D	catalog A, schema B, table C, col or func D.	 * A.*		A is an unqual. table name; means whole-row value.	 * A.B.*	whole-row value of table B in schema A.	 * A.B.C.*	whole-row value of table C in schema B in catalog A.	 *	 * We do not need to cope with bare "*"; that will only be accepted by	 * the grammar at the top level of a SELECT list, and transformTargetList	 * will take care of it before it ever gets here.	 *	 * Currently, if a catalog name is given then it must equal the current	 * database name; we check it here and then discard it.	 *	 * For whole-row references, the result is an untransformed RangeVar,	 * which will work as the argument to a function call, but not in any	 * other context at present.  (We could instead coerce to a whole-row Var,	 * but that will fail for subselect and join RTEs, because there is no	 * pg_type entry for their rowtypes.)	 *----------	 */	switch (numnames)	{		case 1:			{				char	   *name = strVal(lfirst(cref->fields));				/* Try to identify as an unqualified column */				node = colNameToVar(pstate, name, false);				if (node == NULL)				{					/*					 * Not known as a column of any range-table entry.					 *					 * Consider the possibility that it's VALUE in a domain					 * check expression.  (We handle VALUE as a name, not					 * a keyword, to avoid breaking a lot of applications					 * that have used VALUE as a column name in the past.)					 */					if (pstate->p_value_substitute != NULL &&						strcmp(name, "value") == 0)					{						node = (Node *) copyObject(pstate->p_value_substitute);						break;					}					/*					 * Try to find the name as a relation ... but not if					 * subscripts appear.  Note also that only relations					 * already entered into the rangetable will be					 * recognized.					 *					 * This is a hack for backwards compatibility with					 * PostQUEL-inspired syntax.  The preferred form now					 * is "rel.*".					 */					if (cref->indirection == NIL &&						refnameRangeTblEntry(pstate, NULL, name,											 &levels_up) != NULL)					{						rv = makeNode(RangeVar);

⌨️ 快捷键说明

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