analyze.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,222 行 · 第 1/5 页

C
2,222
字号
		stmt->actions = newactions;	}	/* Close relation, but keep the exclusive lock */	heap_close(rel, NoLock);	return qry;}/* * transformSelectStmt - *	  transforms a Select Statement * * Note: this is also used for DECLARE CURSOR statements. */static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt){	Query	   *qry = makeNode(Query);	Node	   *qual;	qry->commandType = CMD_SELECT;	/* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */	pstate->p_locking_clause = stmt->lockingClause;	/* process the FROM clause */	transformFromClause(pstate, stmt->fromClause);	/* transform targetlist */	qry->targetList = transformTargetList(pstate, stmt->targetList);	/* handle any SELECT INTO/CREATE TABLE AS spec */	qry->into = stmt->into;	if (stmt->intoColNames)		applyColumnNames(qry->targetList, stmt->intoColNames);	qry->intoHasOids = interpretOidsOption(stmt->intoHasOids);	/* mark column origins */	markTargetListOrigins(pstate, qry->targetList);	/* transform WHERE */	qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");	/*	 * Initial processing of HAVING clause is just like WHERE clause.	 */	qry->havingQual = transformWhereClause(pstate, stmt->havingClause,										   "HAVING");	/*	 * Transform sorting/grouping stuff.  Do ORDER BY first because both	 * transformGroupClause and transformDistinctClause need the results.	 */	qry->sortClause = transformSortClause(pstate,										  stmt->sortClause,										  &qry->targetList,										  true /* fix unknowns */ );	qry->groupClause = transformGroupClause(pstate,											stmt->groupClause,											&qry->targetList,											qry->sortClause);	qry->distinctClause = transformDistinctClause(pstate,												  stmt->distinctClause,												  &qry->targetList,												  &qry->sortClause);	qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,											"OFFSET");	qry->limitCount = transformLimitClause(pstate, stmt->limitCount,										   "LIMIT");	qry->rtable = pstate->p_rtable;	qry->jointree = makeFromExpr(pstate->p_joinlist, qual);	qry->hasSubLinks = pstate->p_hasSubLinks;	qry->hasAggs = pstate->p_hasAggs;	if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)		parseCheckAggregates(pstate, qry);	if (stmt->lockingClause)		transformLockingClause(qry, stmt->lockingClause);	return qry;}/* * transformSetOperationsStmt - *	  transforms a set-operations tree * * A set-operation tree is just a SELECT, but with UNION/INTERSECT/EXCEPT * structure to it.  We must transform each leaf SELECT and build up a top- * level Query that contains the leaf SELECTs as subqueries in its rangetable. * The tree of set operations is converted into the setOperations field of * the top-level Query. */static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt){	Query	   *qry = makeNode(Query);	SelectStmt *leftmostSelect;	int			leftmostRTI;	Query	   *leftmostQuery;	SetOperationStmt *sostmt;	RangeVar   *into;	List	   *intoColNames;	List	   *sortClause;	Node	   *limitOffset;	Node	   *limitCount;	LockingClause *lockingClause;	Node	   *node;	ListCell   *left_tlist,			   *dtlist;	List	   *targetvars,			   *targetnames,			   *sv_relnamespace,			   *sv_varnamespace,			   *sv_rtable;	RangeTblEntry *jrte;	int			tllen;	qry->commandType = CMD_SELECT;	/*	 * Find leftmost leaf SelectStmt; extract the one-time-only items from it	 * and from the top-level node.	 */	leftmostSelect = stmt->larg;	while (leftmostSelect && leftmostSelect->op != SETOP_NONE)		leftmostSelect = leftmostSelect->larg;	Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&		   leftmostSelect->larg == NULL);	into = leftmostSelect->into;	intoColNames = leftmostSelect->intoColNames;	/* clear them to prevent complaints in transformSetOperationTree() */	leftmostSelect->into = NULL;	leftmostSelect->intoColNames = NIL;	/*	 * These are not one-time, exactly, but we want to process them here and	 * not let transformSetOperationTree() see them --- else it'll just	 * recurse right back here!	 */	sortClause = stmt->sortClause;	limitOffset = stmt->limitOffset;	limitCount = stmt->limitCount;	lockingClause = stmt->lockingClause;	stmt->sortClause = NIL;	stmt->limitOffset = NULL;	stmt->limitCount = NULL;	stmt->lockingClause = NULL;	/* We don't support FOR UPDATE/SHARE with set ops at the moment. */	if (lockingClause)		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));	/*	 * Recursively transform the components of the tree.	 */	sostmt = (SetOperationStmt *) transformSetOperationTree(pstate, stmt);	Assert(sostmt && IsA(sostmt, SetOperationStmt));	qry->setOperations = (Node *) sostmt;	/*	 * Re-find leftmost SELECT (now it's a sub-query in rangetable)	 */	node = sostmt->larg;	while (node && IsA(node, SetOperationStmt))		node = ((SetOperationStmt *) node)->larg;	Assert(node && IsA(node, RangeTblRef));	leftmostRTI = ((RangeTblRef *) node)->rtindex;	leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;	Assert(leftmostQuery != NULL);	/*	 * Generate dummy targetlist for outer query using column names of	 * leftmost select and common datatypes of topmost set operation. Also	 * make lists of the dummy vars and their names for use in parsing ORDER	 * BY.	 *	 * Note: we use leftmostRTI as the varno of the dummy variables. It	 * shouldn't matter too much which RT index they have, as long as they	 * have one that corresponds to a real RT entry; else funny things may	 * happen when the tree is mashed by rule rewriting.	 */	qry->targetList = NIL;	targetvars = NIL;	targetnames = NIL;	left_tlist = list_head(leftmostQuery->targetList);	foreach(dtlist, sostmt->colTypes)	{		Oid			colType = lfirst_oid(dtlist);		TargetEntry *lefttle = (TargetEntry *) lfirst(left_tlist);		char	   *colName;		TargetEntry *tle;		Expr	   *expr;		Assert(!lefttle->resjunk);		colName = pstrdup(lefttle->resname);		expr = (Expr *) makeVar(leftmostRTI,								lefttle->resno,								colType,								-1,								0);		tle = makeTargetEntry(expr,							  (AttrNumber) pstate->p_next_resno++,							  colName,							  false);		qry->targetList = lappend(qry->targetList, tle);		targetvars = lappend(targetvars, expr);		targetnames = lappend(targetnames, makeString(colName));		left_tlist = lnext(left_tlist);	}	/*	 * Handle SELECT INTO/CREATE TABLE AS.	 *	 * Any column names from CREATE TABLE AS need to be attached to both the	 * top level and the leftmost subquery.  We do not do this earlier because	 * we do *not* want the targetnames list to be affected.	 */	qry->into = into;	if (intoColNames)	{		applyColumnNames(qry->targetList, intoColNames);		applyColumnNames(leftmostQuery->targetList, intoColNames);	}	/*	 * As a first step towards supporting sort clauses that are expressions	 * using the output columns, generate a varnamespace entry that makes the	 * output columns visible.	A Join RTE node is handy for this, since we	 * can easily control the Vars generated upon matches.	 *	 * Note: we don't yet do anything useful with such cases, but at least	 * "ORDER BY upper(foo)" will draw the right error message rather than	 * "foo not found".	 */	jrte = addRangeTableEntryForJoin(NULL,									 targetnames,									 JOIN_INNER,									 targetvars,									 NULL,									 false);	sv_rtable = pstate->p_rtable;	pstate->p_rtable = list_make1(jrte);	sv_relnamespace = pstate->p_relnamespace;	pstate->p_relnamespace = NIL;		/* no qualified names allowed */	sv_varnamespace = pstate->p_varnamespace;	pstate->p_varnamespace = list_make1(jrte);	/*	 * For now, we don't support resjunk sort clauses on the output of a	 * setOperation tree --- you can only use the SQL92-spec options of	 * selecting an output column by name or number.  Enforce by checking that	 * transformSortClause doesn't add any items to tlist.	 */	tllen = list_length(qry->targetList);	qry->sortClause = transformSortClause(pstate,										  sortClause,										  &qry->targetList,										  false /* no unknowns expected */ );	pstate->p_rtable = sv_rtable;	pstate->p_relnamespace = sv_relnamespace;	pstate->p_varnamespace = sv_varnamespace;	if (tllen != list_length(qry->targetList))		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("ORDER BY on a UNION/INTERSECT/EXCEPT result must be on one of the result columns")));	qry->limitOffset = transformLimitClause(pstate, limitOffset,											"OFFSET");	qry->limitCount = transformLimitClause(pstate, limitCount,										   "LIMIT");	qry->rtable = pstate->p_rtable;	qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);	qry->hasSubLinks = pstate->p_hasSubLinks;	qry->hasAggs = pstate->p_hasAggs;	if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)		parseCheckAggregates(pstate, qry);	if (lockingClause)		transformLockingClause(qry, lockingClause);	return qry;}/* * transformSetOperationTree *		Recursively transform leaves and internal nodes of a set-op tree */static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt){	bool		isLeaf;	Assert(stmt && IsA(stmt, SelectStmt));	/*	 * Validity-check both leaf and internal SELECTs for disallowed ops.	 */	if (stmt->into)		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),				 errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));	/* We don't support FOR UPDATE/SHARE with set ops at the moment. */	if (stmt->lockingClause)		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));	/*	 * If an internal node of a set-op tree has ORDER BY, UPDATE, or LIMIT	 * clauses attached, we need to treat it like a leaf node to generate an	 * independent sub-Query tree.	Otherwise, it can be represented by a	 * SetOperationStmt node underneath the parent Query.	 */	if (stmt->op == SETOP_NONE)	{		Assert(stmt->larg == NULL && stmt->rarg == NULL);		isLeaf = true;	}	else	{		Assert(stmt->larg != NULL && stmt->rarg != NULL);		if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||			stmt->lockingClause)			isLeaf = true;		else			isLeaf = false;	}	if (isLeaf)	{		/* Process leaf SELECT */		List	   *selectList;		Query	   *selectQuery;		char		selectName[32];		RangeTblEntry *rte;		RangeTblRef *rtr;		/*		 * Transform SelectStmt into a Query.		 *		 * Note: previously transformed sub-queries don't affect the parsing		 * of this sub-query, because they are not in the toplevel pstate's		 * namespace list.		 */		selectList = parse_sub_analyze((Node *) stmt, pstate);		Assert(list_length(selectList) == 1);		selectQuery = (Query *) linitial(selectList);		Assert(IsA(selectQuery, Query));		/*		 * Check for bogus references to Vars on the current query level (but		 * upper-level references are okay). Normally this can't happen		 * because the namespace will be empty, but it could happen if we are		 * inside a rule.		 */		if (pstate->p_relnamespace || pstate->p_varnamespace)		{			if (contain_vars_of_level((Node *) selectQuery, 1))				ereport(ERROR,						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),						 errmsg("UNION/INTERSECT/EXCEPT member statement may not refer to other relations of same query level")));		}		/*		 * Make the leaf query be a subquery in the top-level rangetable.		 */		snprintf(selectName, sizeof(selectName), "*SELECT* %d",				 list_length(pstate->p_rtable) + 1);		rte = addRangeTableEntryForSubquery(pstate,											selectQuery,											makeAlias(selectName, NIL),											false);		/*		 * Return a RangeTblRef to replace the SelectStmt in the set-op tree.		 */		rtr = makeNode(RangeTblRef);		/* assume new rte is at end */		rtr->rtindex = list_length(pstate->p_rtable);		Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));		return (Node *) rtr;	}	else	{		/* Process an internal node (set operation node) */		SetOperationStmt *op = makeNode(SetOperationStmt);		List	   *lcoltypes;		List	   *rcoltypes;		ListCell   *l;		ListCell   *r;		const char *context;		context = (stmt->op == SETOP_UNION ? "UNION" :				   (stmt->op == SETOP_INTERSECT ? "INTERSECT" :					"EXCEPT"));		op->op = stmt->op;		op->all = stmt->all;		/*		 * Recursively transform the child nodes.		 */		op->larg = transformSetOperationTree(pstate, stmt->larg);		op->rarg = transformSetOperationTree(pstate, stmt->rarg);		/*		 * Verify that the two children have the same number of non-junk		 * columns, and determine the types of the merged output columns.		 */		lcoltypes = getSetColTypes(pstate, op->larg);		rcoltypes = getSetColTypes(pstate, op->rarg);		if (list_length(lcoltypes) != list_length(rcoltypes))			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),				 errmsg("each %s query must have the same number of columns",						context)));		op->colTypes = NIL;	

⌨️ 快捷键说明

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