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

📄 parse_clause.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * parse_clause.c *	  handle clauses in parser * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.143.2.1 2005/11/22 18:23:13 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/heap.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/tlist.h"#include "optimizer/var.h"#include "parser/analyze.h"#include "parser/parsetree.h"#include "parser/parse_clause.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_oper.h"#include "parser/parse_relation.h"#include "parser/parse_target.h"#include "parser/parse_type.h"#include "rewrite/rewriteManip.h"#include "utils/builtins.h"#include "utils/guc.h"#define ORDER_CLAUSE 0#define GROUP_CLAUSE 1#define DISTINCT_ON_CLAUSE 2static char *clauseText[] = {"ORDER BY", "GROUP BY", "DISTINCT ON"};static void extractRemainingColumns(List *common_colnames,						List *src_colnames, List *src_colvars,						List **res_colnames, List **res_colvars);static Node *transformJoinUsingClause(ParseState *pstate,						 List *leftVars, List *rightVars);static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j,					  RangeTblEntry *l_rte,					  RangeTblEntry *r_rte,					  List *relnamespace,					  Relids containedRels);static RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r);static RangeTblEntry *transformRangeSubselect(ParseState *pstate,						RangeSubselect *r);static RangeTblEntry *transformRangeFunction(ParseState *pstate,					   RangeFunction *r);static Node *transformFromClauseItem(ParseState *pstate, Node *n,						RangeTblEntry **top_rte, int *top_rti,						List **relnamespace,						Relids *containedRels);static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,				   Var *l_colvar, Var *r_colvar);static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,					List **tlist, int clause);/* * transformFromClause - *	  Process the FROM clause and add items to the query's range table, *	  joinlist, and namespaces. * * Note: we assume that pstate's p_rtable, p_joinlist, p_relnamespace, and * p_varnamespace lists were initialized to NIL when the pstate was created. * We will add onto any entries already present --- this is needed for rule * processing, as well as for UPDATE and DELETE. * * The range table may grow still further when we transform the expressions * in the query's quals and target list. (This is possible because in * POSTQUEL, we allowed references to relations not specified in the * from-clause.  PostgreSQL keeps this extension to standard SQL.) */voidtransformFromClause(ParseState *pstate, List *frmList){	ListCell   *fl;	/*	 * The grammar will have produced a list of RangeVars, RangeSubselects,	 * RangeFunctions, and/or JoinExprs. Transform each one (possibly adding	 * entries to the rtable), check for duplicate refnames, and then add it	 * to the joinlist and namespaces.	 */	foreach(fl, frmList)	{		Node	   *n = lfirst(fl);		RangeTblEntry *rte;		int			rtindex;		List	   *relnamespace;		Relids		containedRels;		n = transformFromClauseItem(pstate, n,									&rte,									&rtindex,									&relnamespace,									&containedRels);		checkNameSpaceConflicts(pstate, pstate->p_relnamespace, relnamespace);		pstate->p_joinlist = lappend(pstate->p_joinlist, n);		pstate->p_relnamespace = list_concat(pstate->p_relnamespace,											 relnamespace);		pstate->p_varnamespace = lappend(pstate->p_varnamespace, rte);		bms_free(containedRels);	}}/* * setTargetTable *	  Add the target relation of INSERT/UPDATE/DELETE to the range table, *	  and make the special links to it in the ParseState. * *	  We also open the target relation and acquire a write lock on it. *	  This must be done before processing the FROM list, in case the target *	  is also mentioned as a source relation --- we want to be sure to grab *	  the write lock before any read lock. * *	  If alsoSource is true, add the target to the query's joinlist and *	  namespace.  For INSERT, we don't want the target to be joined to; *	  it's a destination of tuples, not a source.	For UPDATE/DELETE, *	  we do need to scan or join the target.  (NOTE: we do not bother *	  to check for namespace conflict; we assume that the namespace was *	  initially empty in these cases.) * *	  Finally, we mark the relation as requiring the permissions specified *	  by requiredPerms. * *	  Returns the rangetable index of the target relation. */intsetTargetTable(ParseState *pstate, RangeVar *relation,			   bool inh, bool alsoSource, AclMode requiredPerms){	RangeTblEntry *rte;	int			rtindex;	/* Close old target; this could only happen for multi-action rules */	if (pstate->p_target_relation != NULL)		heap_close(pstate->p_target_relation, NoLock);	/*	 * Open target rel and grab suitable lock (which we will hold till end of	 * transaction).	 *	 * analyze.c will eventually do the corresponding heap_close(), but *not*	 * release the lock.	 */	pstate->p_target_relation = heap_openrv(relation, RowExclusiveLock);	/*	 * Now build an RTE.	 */	rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,										NULL, inh, false);	pstate->p_target_rangetblentry = rte;	/* assume new rte is at end */	rtindex = list_length(pstate->p_rtable);	Assert(rte == rt_fetch(rtindex, pstate->p_rtable));	/*	 * Override addRangeTableEntry's default ACL_SELECT permissions check, and	 * instead mark target table as requiring exactly the specified	 * permissions.	 *	 * If we find an explicit reference to the rel later during parse	 * analysis, scanRTEForColumn will add the ACL_SELECT bit back again. That	 * can't happen for INSERT but it is possible for UPDATE and DELETE.	 */	rte->requiredPerms = requiredPerms;	/*	 * If UPDATE/DELETE, add table to joinlist and namespaces.	 */	if (alsoSource)		addRTEtoQuery(pstate, rte, true, true, true);	return rtindex;}/* * Simplify InhOption (yes/no/default) into boolean yes/no. * * The reason we do things this way is that we don't want to examine the * SQL_inheritance option flag until parse_analyze is run.	Otherwise, * we'd do the wrong thing with query strings that intermix SET commands * with queries. */boolinterpretInhOption(InhOption inhOpt){	switch (inhOpt)	{		case INH_NO:			return false;		case INH_YES:			return true;		case INH_DEFAULT:			return SQL_inheritance;	}	elog(ERROR, "bogus InhOption value: %d", inhOpt);	return false;				/* keep compiler quiet */}/* * Given an enum that indicates whether WITH / WITHOUT OIDS was * specified by the user, return true iff the specified table/result * set should be created with OIDs. This needs to be done after * parsing the query string because the return value can depend upon * the default_with_oids GUC var. */boolinterpretOidsOption(ContainsOids opt){	switch (opt)	{		case MUST_HAVE_OIDS:			return true;		case MUST_NOT_HAVE_OIDS:			return false;		case DEFAULT_OIDS:			return default_with_oids;	}	elog(ERROR, "bogus ContainsOids value: %d", opt);	return false;				/* keep compiler quiet */}/* * Extract all not-in-common columns from column lists of a source table */static voidextractRemainingColumns(List *common_colnames,						List *src_colnames, List *src_colvars,						List **res_colnames, List **res_colvars){	List	   *new_colnames = NIL;	List	   *new_colvars = NIL;	ListCell   *lnames,			   *lvars;	Assert(list_length(src_colnames) == list_length(src_colvars));	forboth(lnames, src_colnames, lvars, src_colvars)	{		char	   *colname = strVal(lfirst(lnames));		bool		match = false;		ListCell   *cnames;		foreach(cnames, common_colnames)		{			char	   *ccolname = strVal(lfirst(cnames));			if (strcmp(colname, ccolname) == 0)			{				match = true;				break;			}		}		if (!match)		{			new_colnames = lappend(new_colnames, lfirst(lnames));			new_colvars = lappend(new_colvars, lfirst(lvars));		}	}	*res_colnames = new_colnames;	*res_colvars = new_colvars;}/* transformJoinUsingClause() *	  Build a complete ON clause from a partially-transformed USING list. *	  We are given lists of nodes representing left and right match columns. *	  Result is a transformed qualification expression. */static Node *transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars){	Node	   *result = NULL;	ListCell   *lvars,			   *rvars;	/*	 * We cheat a little bit here by building an untransformed operator tree	 * whose leaves are the already-transformed Vars.  This is OK because	 * transformExpr() won't complain about already-transformed subnodes.	 */	forboth(lvars, leftVars, rvars, rightVars)	{		Node	   *lvar = (Node *) lfirst(lvars);		Node	   *rvar = (Node *) lfirst(rvars);		A_Expr	   *e;		e = makeSimpleA_Expr(AEXPR_OP, "=", copyObject(lvar), copyObject(rvar));		if (result == NULL)			result = (Node *) e;		else		{			A_Expr	   *a;			a = makeA_Expr(AEXPR_AND, NIL, result, (Node *) e);			result = (Node *) a;		}	}	/*	 * Since the references are already Vars, and are certainly from the input	 * relations, we don't have to go through the same pushups that	 * transformJoinOnClause() does.  Just invoke transformExpr() to fix up	 * the operators, and we're done.	 */	result = transformExpr(pstate, result);	result = coerce_to_boolean(pstate, result, "JOIN/USING");	return result;}/* transformJoinOnClause() *	  Transform the qual conditions for JOIN/ON. *	  Result is a transformed qualification expression. */static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j,					  RangeTblEntry *l_rte,					  RangeTblEntry *r_rte,					  List *relnamespace,					  Relids containedRels){	Node	   *result;	List	   *save_relnamespace;	List	   *save_varnamespace;	Relids		clause_varnos;	int			varno;	/*	 * This is a tad tricky, for two reasons.  First, the namespace that the	 * join expression should see is just the two subtrees of the JOIN plus	 * any outer references from upper pstate levels.  So, temporarily set	 * this pstate's namespace accordingly.  (We need not check for refname	 * conflicts, because transformFromClauseItem() already did.) NOTE: this	 * code is OK only because the ON clause can't legally alter the namespace	 * by causing implicit relation refs to be added.	 */	save_relnamespace = pstate->p_relnamespace;	save_varnamespace = pstate->p_varnamespace;	pstate->p_relnamespace = relnamespace;	pstate->p_varnamespace = list_make2(l_rte, r_rte);	result = transformWhereClause(pstate, j->quals, "JOIN/ON");	pstate->p_relnamespace = save_relnamespace;	pstate->p_varnamespace = save_varnamespace;	/*	 * Second, we need to check that the ON condition doesn't refer to any	 * rels outside the input subtrees of the JOIN.  It could do that despite	 * our hack on the namespace if it uses fully-qualified names. So, grovel	 * through the transformed clause and make sure there are no bogus	 * references.	(Outer references are OK, and are ignored here.)	 */	clause_varnos = pull_varnos(result);	clause_varnos = bms_del_members(clause_varnos, containedRels);	if ((varno = bms_first_member(clause_varnos)) >= 0)	{		ereport(ERROR,				(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),		 errmsg("JOIN/ON clause refers to \"%s\", which is not part of JOIN",				rt_fetch(varno, pstate->p_rtable)->eref->aliasname)));	}	bms_free(clause_varnos);	return result;}/* * transformTableEntry --- transform a RangeVar (simple relation reference) */static RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r){	RangeTblEntry *rte;	/*	 * mark this entry to indicate it comes from the FROM clause. In SQL, the	 * target list can only refer to range variables specified in the from	 * clause but we follow the more powerful POSTQUEL semantics and	 * automatically generate the range variable if not specified. However	 * there are times we need to know whether the entries are legitimate.	 */	rte = addRangeTableEntry(pstate, r, r->alias,							 interpretInhOption(r->inhOpt), true);	return rte;}/* * transformRangeSubselect --- transform a sub-SELECT appearing in FROM */static RangeTblEntry *transformRangeSubselect(ParseState *pstate, RangeSubselect *r){	List	   *parsetrees;	Query	   *query;	RangeTblEntry *rte;

⌨️ 快捷键说明

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