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

📄 parse_clause.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
				r_colvar = list_nth(r_colvars, r_index);				r_usingvars = lappend(r_usingvars, r_colvar);				res_colnames = lappend(res_colnames, lfirst(ucol));				res_colvars = lappend(res_colvars,									  buildMergedJoinVar(pstate,														 j->jointype,														 l_colvar,														 r_colvar));			}			j->quals = transformJoinUsingClause(pstate,												l_usingvars,												r_usingvars);		}		else if (j->quals)		{			/* User-written ON-condition; transform it */			j->quals = transformJoinOnClause(pstate, j,											 l_rte, r_rte,											 my_relnamespace,											 my_containedRels);		}		else		{			/* CROSS JOIN: no quals */		}		/* Add remaining columns from each side to the output columns */		extractRemainingColumns(res_colnames,								l_colnames, l_colvars,								&l_colnames, &l_colvars);		extractRemainingColumns(res_colnames,								r_colnames, r_colvars,								&r_colnames, &r_colvars);		res_colnames = list_concat(res_colnames, l_colnames);		res_colvars = list_concat(res_colvars, l_colvars);		res_colnames = list_concat(res_colnames, r_colnames);		res_colvars = list_concat(res_colvars, r_colvars);		/*		 * Check alias (AS clause), if any.		 */		if (j->alias)		{			if (j->alias->colnames != NIL)			{				if (list_length(j->alias->colnames) > list_length(res_colnames))					ereport(ERROR,							(errcode(ERRCODE_SYNTAX_ERROR),							 errmsg("column alias list for \"%s\" has too many entries",									j->alias->aliasname)));			}		}		/*		 * Now build an RTE for the result of the join		 */		rte = addRangeTableEntryForJoin(pstate,										res_colnames,										j->jointype,										res_colvars,										j->alias,										true);		/* assume new rte is at end */		j->rtindex = list_length(pstate->p_rtable);		Assert(rte == rt_fetch(j->rtindex, pstate->p_rtable));		*top_rte = rte;		*top_rti = j->rtindex;		/*		 * Prepare returned namespace list.  If the JOIN has an alias then it		 * hides the contained RTEs as far as the relnamespace goes;		 * otherwise, put the contained RTEs and *not* the JOIN into		 * relnamespace.		 */		if (j->alias)		{			*relnamespace = list_make1(rte);			list_free(my_relnamespace);		}		else			*relnamespace = my_relnamespace;		/*		 * Include join RTE in returned containedRels set		 */		*containedRels = bms_add_member(my_containedRels, j->rtindex);		return (Node *) j;	}	else		elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n));	return NULL;				/* can't get here, keep compiler quiet */}/* * buildMergedJoinVar - *	  generate a suitable replacement expression for a merged join column */static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,				   Var *l_colvar, Var *r_colvar){	Oid			outcoltype;	int32		outcoltypmod;	Node	   *l_node,			   *r_node,			   *res_node;	/*	 * Choose output type if input types are dissimilar.	 */	outcoltype = l_colvar->vartype;	outcoltypmod = l_colvar->vartypmod;	if (outcoltype != r_colvar->vartype)	{		outcoltype = select_common_type(list_make2_oid(l_colvar->vartype,													   r_colvar->vartype),										"JOIN/USING");		outcoltypmod = -1;		/* ie, unknown */	}	else if (outcoltypmod != r_colvar->vartypmod)	{		/* same type, but not same typmod */		outcoltypmod = -1;		/* ie, unknown */	}	/*	 * Insert coercion functions if needed.  Note that a difference in typmod	 * can only happen if input has typmod but outcoltypmod is -1. In that	 * case we insert a RelabelType to clearly mark that result's typmod is	 * not same as input.  We never need coerce_type_typmod.	 */	if (l_colvar->vartype != outcoltype)		l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype,							 outcoltype, outcoltypmod,							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);	else if (l_colvar->vartypmod != outcoltypmod)		l_node = (Node *) makeRelabelType((Expr *) l_colvar,										  outcoltype, outcoltypmod,										  COERCE_IMPLICIT_CAST);	else		l_node = (Node *) l_colvar;	if (r_colvar->vartype != outcoltype)		r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype,							 outcoltype, outcoltypmod,							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);	else if (r_colvar->vartypmod != outcoltypmod)		r_node = (Node *) makeRelabelType((Expr *) r_colvar,										  outcoltype, outcoltypmod,										  COERCE_IMPLICIT_CAST);	else		r_node = (Node *) r_colvar;	/*	 * Choose what to emit	 */	switch (jointype)	{		case JOIN_INNER:			/*			 * We can use either var; prefer non-coerced one if available.			 */			if (IsA(l_node, Var))				res_node = l_node;			else if (IsA(r_node, Var))				res_node = r_node;			else				res_node = l_node;			break;		case JOIN_LEFT:			/* Always use left var */			res_node = l_node;			break;		case JOIN_RIGHT:			/* Always use right var */			res_node = r_node;			break;		case JOIN_FULL:			{				/*				 * Here we must build a COALESCE expression to ensure that the				 * join output is non-null if either input is.				 */				CoalesceExpr *c = makeNode(CoalesceExpr);				c->coalescetype = outcoltype;				c->args = list_make2(l_node, r_node);				res_node = (Node *) c;				break;			}		default:			elog(ERROR, "unrecognized join type: %d", (int) jointype);			res_node = NULL;	/* keep compiler quiet */			break;	}	return res_node;}/* * transformWhereClause - *	  Transform the qualification and make sure it is of type boolean. *	  Used for WHERE and allied clauses. * * constructName does not affect the semantics, but is used in error messages */Node *transformWhereClause(ParseState *pstate, Node *clause,					 const char *constructName){	Node	   *qual;	if (clause == NULL)		return NULL;	qual = transformExpr(pstate, clause);	qual = coerce_to_boolean(pstate, qual, constructName);	return qual;}/* * transformLimitClause - *	  Transform the expression and make sure it is of type integer. *	  Used for LIMIT and allied clauses. * * constructName does not affect the semantics, but is used in error messages */Node *transformLimitClause(ParseState *pstate, Node *clause,					 const char *constructName){	Node	   *qual;	if (clause == NULL)		return NULL;	qual = transformExpr(pstate, clause);	qual = coerce_to_integer(pstate, qual, constructName);	/*	 * LIMIT can't refer to any vars or aggregates of the current query; we	 * don't allow subselects either (though that case would at least be	 * sensible)	 */	if (contain_vars_of_level(qual, 0))	{		ereport(ERROR,				(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),		/* translator: %s is name of a SQL construct, eg LIMIT */				 errmsg("argument of %s must not contain variables",						constructName)));	}	if (checkExprHasAggs(qual))	{		ereport(ERROR,				(errcode(ERRCODE_GROUPING_ERROR),		/* translator: %s is name of a SQL construct, eg LIMIT */				 errmsg("argument of %s must not contain aggregates",						constructName)));	}	if (contain_subplans(qual))	{		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),		/* translator: %s is name of a SQL construct, eg LIMIT */				 errmsg("argument of %s must not contain subqueries",						constructName)));	}	return qual;}/* *	findTargetlistEntry - *	  Returns the targetlist entry matching the given (untransformed) node. *	  If no matching entry exists, one is created and appended to the target *	  list as a "resjunk" node. * * node		the ORDER BY, GROUP BY, or DISTINCT ON expression to be matched * tlist	the target list (passed by reference so we can append to it) * clause	identifies clause type being processed */static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause){	TargetEntry *target_result = NULL;	ListCell   *tl;	Node	   *expr;	/*----------	 * Handle two special cases as mandated by the SQL92 spec:	 *	 * 1. Bare ColumnName (no qualifier or subscripts)	 *	  For a bare identifier, we search for a matching column name	 *	  in the existing target list.	Multiple matches are an error	 *	  unless they refer to identical values; for example,	 *	  we allow	SELECT a, a FROM table ORDER BY a	 *	  but not	SELECT a AS b, b FROM table ORDER BY b	 *	  If no match is found, we fall through and treat the identifier	 *	  as an expression.	 *	  For GROUP BY, it is incorrect to match the grouping item against	 *	  targetlist entries: according to SQL92, an identifier in GROUP BY	 *	  is a reference to a column name exposed by FROM, not to a target	 *	  list column.	However, many implementations (including pre-7.0	 *	  PostgreSQL) accept this anyway.  So for GROUP BY, we look first	 *	  to see if the identifier matches any FROM column name, and only	 *	  try for a targetlist name if it doesn't.  This ensures that we	 *	  adhere to the spec in the case where the name could be both.	 *	  DISTINCT ON isn't in the standard, so we can do what we like there;	 *	  we choose to make it work like ORDER BY, on the rather flimsy	 *	  grounds that ordinary DISTINCT works on targetlist entries.	 *	 * 2. IntegerConstant	 *	  This means to use the n'th item in the existing target list.	 *	  Note that it would make no sense to order/group/distinct by an	 *	  actual constant, so this does not create a conflict with our	 *	  extension to order/group by an expression.	 *	  GROUP BY column-number is not allowed by SQL92, but since	 *	  the standard has no other behavior defined for this syntax,	 *	  we may as well accept this common extension.	 *	 * Note that pre-existing resjunk targets must not be used in either case,	 * since the user didn't write them in his SELECT list.	 *	 * If neither special case applies, fall through to treat the item as	 * an expression.	 *----------	 */	if (IsA(node, ColumnRef) &&		list_length(((ColumnRef *) node)->fields) == 1)	{		char	   *name = strVal(linitial(((ColumnRef *) node)->fields));		if (clause == GROUP_CLAUSE)		{			/*			 * In GROUP BY, we must prefer a match against a FROM-clause			 * column to one against the targetlist.  Look to see if there is			 * a matching column.  If so, fall through to let transformExpr()			 * do the rest.  NOTE: if name could refer ambiguously to more			 * than one column name exposed by FROM, colNameToVar will			 * ereport(ERROR).	That's just what we want here.			 *			 * Small tweak for 7.4.3: ignore matches in upper query levels.			 * This effectively changes the search order for bare names to (1)			 * local FROM variables, (2) local targetlist aliases, (3) outer			 * FROM variables, whereas before it was (1) (3) (2). SQL92 and			 * SQL99 do not allow GROUPing BY an outer reference, so this			 * breaks no cases that are legal per spec, and it seems a more			 * self-consistent behavior.			 */			if (colNameToVar(pstate, name, true) != NULL)				name = NULL;		}		if (name != NULL)		{			foreach(tl, *tlist)			{				TargetEntry *tle = (TargetEntry *) lfirst(tl);				if (!tle->resjunk &&					strcmp(tle->resname, name) == 0)				{					if (target_result != NULL)					{						if (!equal(target_result->expr, tle->expr))							ereport(ERROR,									(errcode(ERRCODE_AMBIGUOUS_COLUMN),							/*							 * translator: first %s is name of a SQL							 * construct, eg ORDER BY							 */									 errmsg("%s \"%s\" is ambiguous",											clauseText[clause], name)));					}					else						target_result = tle;					/* Stay in loop to check for ambiguity */				}			}			if (target_result != NULL)				return target_result;	/* return the first match */		}	}	if (IsA(node, A_Const))	{		Value	   *val = &((A_Const *) node)->val;		int			targetlist_pos = 0;		int			target_pos;		if (!IsA(val, Integer))			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),			/* translator: %s is name of a SQL construct, eg ORDER BY */					 errmsg("non-integer constant in %s",							clauseText[clause])));		target_pos = intVal(val);		foreach(tl, *tlist)		{			TargetEntry *tle = (TargetEntry *) lfirst(tl);			if (!tle->resjunk)			{				if (++targetlist_pos == target_pos)					return tle; /* return the unique match */			}

⌨️ 快捷键说明

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