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

📄 parse_clause.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
	/*	 * We require user to supply an alias for a subselect, per SQL92. To relax	 * this, we'd have to be prepared to gin up a unique alias for an	 * unlabeled subselect.	 */	if (r->alias == NULL)		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),				 errmsg("subquery in FROM must have an alias")));	/*	 * Analyze and transform the subquery.	 */	parsetrees = parse_sub_analyze(r->subquery, pstate);	/*	 * Check that we got something reasonable.	Most of these conditions are	 * probably impossible given restrictions of the grammar, but check 'em	 * anyway.	 */	if (list_length(parsetrees) != 1)		elog(ERROR, "unexpected parse analysis result for subquery in FROM");	query = (Query *) linitial(parsetrees);	if (query == NULL || !IsA(query, Query))		elog(ERROR, "unexpected parse analysis result for subquery in FROM");	if (query->commandType != CMD_SELECT)		elog(ERROR, "expected SELECT query from subquery in FROM");	if (query->resultRelation != 0 || query->into != NULL)		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),				 errmsg("subquery in FROM may not have SELECT INTO")));	/*	 * The subquery cannot make use of any variables from FROM items created	 * earlier in the current query.  Per SQL92, the scope of a FROM item does	 * not include other FROM items.  Formerly we hacked the namespace so that	 * the other variables weren't even visible, but it seems more useful to	 * leave them visible and give a specific error message.	 *	 * XXX this will need further work to support SQL99's LATERAL() feature,	 * wherein such references would indeed be legal.	 *	 * We can skip groveling through the subquery if there's not anything	 * visible in the current query.  Also note that outer references are OK.	 */	if (pstate->p_relnamespace || pstate->p_varnamespace)	{		if (contain_vars_of_level((Node *) query, 1))			ereport(ERROR,					(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),					 errmsg("subquery in FROM may not refer to other relations of same query level")));	}	/*	 * OK, build an RTE for the subquery.	 */	rte = addRangeTableEntryForSubquery(pstate, query, r->alias, true);	return rte;}/* * transformRangeFunction --- transform a function call appearing in FROM */static RangeTblEntry *transformRangeFunction(ParseState *pstate, RangeFunction *r){	Node	   *funcexpr;	char	   *funcname;	RangeTblEntry *rte;	/*	 * Get function name for possible use as alias.  We use the same	 * transformation rules as for a SELECT output expression.	For a FuncCall	 * node, the result will be the function name, but it is possible for the	 * grammar to hand back other node types.	 */	funcname = FigureColname(r->funccallnode);	/*	 * Transform the raw expression.	 */	funcexpr = transformExpr(pstate, r->funccallnode);	/*	 * The function parameters cannot make use of any variables from other	 * FROM items.	(Compare to transformRangeSubselect(); the coding is	 * different though because we didn't parse as a sub-select with its own	 * level of namespace.)	 *	 * XXX this will need further work to support SQL99's LATERAL() feature,	 * wherein such references would indeed be legal.	 */	if (pstate->p_relnamespace || pstate->p_varnamespace)	{		if (contain_vars_of_level(funcexpr, 0))			ereport(ERROR,					(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),					 errmsg("function expression in FROM may not refer to other relations of same query level")));	}	/*	 * Disallow aggregate functions in the expression.	(No reason to postpone	 * this check until parseCheckAggregates.)	 */	if (pstate->p_hasAggs)	{		if (checkExprHasAggs(funcexpr))			ereport(ERROR,					(errcode(ERRCODE_GROUPING_ERROR),					 errmsg("cannot use aggregate function in function expression in FROM")));	}	/*	 * If a coldeflist is supplied, ensure it defines a legal set of names (no	 * duplicates) and datatypes (no pseudo-types, for instance).	 */	if (r->coldeflist)	{		TupleDesc	tupdesc;		tupdesc = BuildDescForRelation(r->coldeflist);		CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE);	}	/*	 * OK, build an RTE for the function.	 */	rte = addRangeTableEntryForFunction(pstate, funcname, funcexpr,										r, true);	return rte;}/* * transformFromClauseItem - *	  Transform a FROM-clause item, adding any required entries to the *	  range table list being built in the ParseState, and return the *	  transformed item ready to include in the joinlist and namespaces. *	  This routine can recurse to handle SQL92 JOIN expressions. * * The function return value is the node to add to the jointree (a * RangeTblRef or JoinExpr).  Additional output parameters are: * * *top_rte: receives the RTE corresponding to the jointree item. * (We could extract this from the function return node, but it saves cycles * to pass it back separately.) * * *top_rti: receives the rangetable index of top_rte.	(Ditto.) * * *relnamespace: receives a List of the RTEs exposed as relation names * by this item. * * *containedRels: receives a bitmap set of the rangetable indexes * of all the base and join relations represented in this jointree item. * This is needed for checking JOIN/ON conditions in higher levels. * * We do not need to pass back an explicit varnamespace value, because * in all cases the varnamespace contribution is exactly top_rte. */static Node *transformFromClauseItem(ParseState *pstate, Node *n,						RangeTblEntry **top_rte, int *top_rti,						List **relnamespace,						Relids *containedRels){	if (IsA(n, RangeVar))	{		/* Plain relation reference */		RangeTblRef *rtr;		RangeTblEntry *rte;		int			rtindex;		rte = transformTableEntry(pstate, (RangeVar *) n);		/* assume new rte is at end */		rtindex = list_length(pstate->p_rtable);		Assert(rte == rt_fetch(rtindex, pstate->p_rtable));		*top_rte = rte;		*top_rti = rtindex;		*relnamespace = list_make1(rte);		*containedRels = bms_make_singleton(rtindex);		rtr = makeNode(RangeTblRef);		rtr->rtindex = rtindex;		return (Node *) rtr;	}	else if (IsA(n, RangeSubselect))	{		/* sub-SELECT is like a plain relation */		RangeTblRef *rtr;		RangeTblEntry *rte;		int			rtindex;		rte = transformRangeSubselect(pstate, (RangeSubselect *) n);		/* assume new rte is at end */		rtindex = list_length(pstate->p_rtable);		Assert(rte == rt_fetch(rtindex, pstate->p_rtable));		*top_rte = rte;		*top_rti = rtindex;		*relnamespace = list_make1(rte);		*containedRels = bms_make_singleton(rtindex);		rtr = makeNode(RangeTblRef);		rtr->rtindex = rtindex;		return (Node *) rtr;	}	else if (IsA(n, RangeFunction))	{		/* function is like a plain relation */		RangeTblRef *rtr;		RangeTblEntry *rte;		int			rtindex;		rte = transformRangeFunction(pstate, (RangeFunction *) n);		/* assume new rte is at end */		rtindex = list_length(pstate->p_rtable);		Assert(rte == rt_fetch(rtindex, pstate->p_rtable));		*top_rte = rte;		*top_rti = rtindex;		*relnamespace = list_make1(rte);		*containedRels = bms_make_singleton(rtindex);		rtr = makeNode(RangeTblRef);		rtr->rtindex = rtindex;		return (Node *) rtr;	}	else if (IsA(n, JoinExpr))	{		/* A newfangled join expression */		JoinExpr   *j = (JoinExpr *) n;		RangeTblEntry *l_rte;		RangeTblEntry *r_rte;		int			l_rtindex;		int			r_rtindex;		Relids		l_containedRels,					r_containedRels,					my_containedRels;		List	   *l_relnamespace,				   *r_relnamespace,				   *my_relnamespace,				   *l_colnames,				   *r_colnames,				   *res_colnames,				   *l_colvars,				   *r_colvars,				   *res_colvars;		RangeTblEntry *rte;		/*		 * Recursively process the left and right subtrees		 */		j->larg = transformFromClauseItem(pstate, j->larg,										  &l_rte,										  &l_rtindex,										  &l_relnamespace,										  &l_containedRels);		j->rarg = transformFromClauseItem(pstate, j->rarg,										  &r_rte,										  &r_rtindex,										  &r_relnamespace,										  &r_containedRels);		/*		 * Check for conflicting refnames in left and right subtrees. Must do		 * this because higher levels will assume I hand back a self-		 * consistent namespace subtree.		 */		checkNameSpaceConflicts(pstate, l_relnamespace, r_relnamespace);		/*		 * Generate combined relation membership info for possible use by		 * transformJoinOnClause below.		 */		my_relnamespace = list_concat(l_relnamespace, r_relnamespace);		my_containedRels = bms_join(l_containedRels, r_containedRels);		pfree(r_relnamespace);	/* free unneeded list header */		/*		 * Extract column name and var lists from both subtrees		 *		 * Note: expandRTE returns new lists, safe for me to modify		 */		expandRTE(l_rte, l_rtindex, 0, false,				  &l_colnames, &l_colvars);		expandRTE(r_rte, r_rtindex, 0, false,				  &r_colnames, &r_colvars);		/*		 * Natural join does not explicitly specify columns; must generate		 * columns to join. Need to run through the list of columns from each		 * table or join result and match up the column names. Use the first		 * table, and check every column in the second table for a match.		 * (We'll check that the matches were unique later on.) The result of		 * this step is a list of column names just like an explicitly-written		 * USING list.		 */		if (j->isNatural)		{			List	   *rlist = NIL;			ListCell   *lx,					   *rx;			Assert(j->using == NIL);	/* shouldn't have USING() too */			foreach(lx, l_colnames)			{				char	   *l_colname = strVal(lfirst(lx));				Value	   *m_name = NULL;				foreach(rx, r_colnames)				{					char	   *r_colname = strVal(lfirst(rx));					if (strcmp(l_colname, r_colname) == 0)					{						m_name = makeString(l_colname);						break;					}				}				/* matched a right column? then keep as join column... */				if (m_name != NULL)					rlist = lappend(rlist, m_name);			}			j->using = rlist;		}		/*		 * Now transform the join qualifications, if any.		 */		res_colnames = NIL;		res_colvars = NIL;		if (j->using)		{			/*			 * JOIN/USING (or NATURAL JOIN, as transformed above). Transform			 * the list into an explicit ON-condition, and generate a list of			 * merged result columns.			 */			List	   *ucols = j->using;			List	   *l_usingvars = NIL;			List	   *r_usingvars = NIL;			ListCell   *ucol;			Assert(j->quals == NULL);	/* shouldn't have ON() too */			foreach(ucol, ucols)			{				char	   *u_colname = strVal(lfirst(ucol));				ListCell   *col;				int			ndx;				int			l_index = -1;				int			r_index = -1;				Var		   *l_colvar,						   *r_colvar;				/* Check for USING(foo,foo) */				foreach(col, res_colnames)				{					char	   *res_colname = strVal(lfirst(col));					if (strcmp(res_colname, u_colname) == 0)						ereport(ERROR,								(errcode(ERRCODE_DUPLICATE_COLUMN),								 errmsg("column name \"%s\" appears more than once in USING clause",										u_colname)));				}				/* Find it in left input */				ndx = 0;				foreach(col, l_colnames)				{					char	   *l_colname = strVal(lfirst(col));					if (strcmp(l_colname, u_colname) == 0)					{						if (l_index >= 0)							ereport(ERROR,									(errcode(ERRCODE_AMBIGUOUS_COLUMN),									 errmsg("common column name \"%s\" appears more than once in left table",											u_colname)));						l_index = ndx;					}					ndx++;				}				if (l_index < 0)					ereport(ERROR,							(errcode(ERRCODE_UNDEFINED_COLUMN),							 errmsg("column \"%s\" specified in USING clause does not exist in left table",									u_colname)));				/* Find it in right input */				ndx = 0;				foreach(col, r_colnames)				{					char	   *r_colname = strVal(lfirst(col));					if (strcmp(r_colname, u_colname) == 0)					{						if (r_index >= 0)							ereport(ERROR,									(errcode(ERRCODE_AMBIGUOUS_COLUMN),									 errmsg("common column name \"%s\" appears more than once in right table",											u_colname)));						r_index = ndx;					}					ndx++;				}				if (r_index < 0)					ereport(ERROR,							(errcode(ERRCODE_UNDEFINED_COLUMN),							 errmsg("column \"%s\" specified in USING clause does not exist in right table",									u_colname)));				l_colvar = list_nth(l_colvars, l_index);				l_usingvars = lappend(l_usingvars, l_colvar);

⌨️ 快捷键说明

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