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

📄 analyze.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * analyze.c *	  transform the parse tree into a query tree * * Copyright (c) 1994, Regents of the University of California * *	$Id: analyze.c,v 1.110.2.1 1999/08/15 06:50:22 thomas Exp $ * *------------------------------------------------------------------------- */#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include "postgres.h"#include "access/heapam.h"#include "nodes/makefuncs.h"#include "nodes/memnodes.h"#include "nodes/pg_list.h"#include "parser/analyze.h"#include "parser/parse_agg.h"#include "parser/parse_clause.h"#include "parser/parse_node.h"#include "parser/parse_relation.h"#include "parser/parse_target.h"/***S*I***/#include "parser/parse_expr.h"#include "catalog/pg_type.h"#include "parse.h"#include "utils/builtins.h"#include "utils/mcxt.h"static Query *transformStmt(ParseState *pstate, Node *stmt);static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);static Query *transformCursorStmt(ParseState *pstate, SelectStmt *stmt);static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);static void transformForUpdate(Query *qry, List *forUpdate);void		CheckSelectForUpdate(Query *qry);List	   *extras_before = NIL;List	   *extras_after = NIL;/* * parse_analyze - *	  analyze a list of parse trees and transform them if necessary. * * Returns a list of transformed parse trees. Optimizable statements are * all transformed to Query while the rest stays the same. * */List *parse_analyze(List *pl, ParseState *parentParseState){	List	   *result = NIL;	ParseState *pstate;	Query	   *parsetree;	while (pl != NIL)	{		pstate = make_parsestate(parentParseState);		parsetree = transformStmt(pstate, lfirst(pl));		if (pstate->p_target_relation != NULL)			heap_close(pstate->p_target_relation);		while (extras_before != NIL)		{			result = lappend(result,						   transformStmt(pstate, lfirst(extras_before)));			if (pstate->p_target_relation != NULL)				heap_close(pstate->p_target_relation);			extras_before = lnext(extras_before);		}		result = lappend(result, parsetree);		while (extras_after != NIL)		{			result = lappend(result,							 transformStmt(pstate, lfirst(extras_after)));			if (pstate->p_target_relation != NULL)				heap_close(pstate->p_target_relation);			extras_after = lnext(extras_after);		}		pl = lnext(pl);		pfree(pstate);	}	return result;}/* * transformStmt - *	  transform a Parse tree. If it is an optimizable statement, turn it *	  into a Query tree. */static Query *transformStmt(ParseState *pstate, Node *parseTree){	Query	   *result = NULL;	switch (nodeTag(parseTree))	{			/*------------------------			 *	Non-optimizable statements			 *------------------------			 */		case T_CreateStmt:			result = transformCreateStmt(pstate, (CreateStmt *) parseTree);			break;		case T_IndexStmt:			result = transformIndexStmt(pstate, (IndexStmt *) parseTree);			break;		case T_ExtendStmt:			result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);			break;		case T_RuleStmt:			result = transformRuleStmt(pstate, (RuleStmt *) parseTree);			break;		case T_ViewStmt:			{				ViewStmt   *n = (ViewStmt *) parseTree;				n->query = (Query *) transformStmt(pstate, (Node *) n->query);				result = makeNode(Query);				result->commandType = CMD_UTILITY;				result->utilityStmt = (Node *) n;			}			break;		case T_VacuumStmt:			{				MemoryContext oldcontext;				/*				 * make sure that this Query is allocated in TopMemory				 * context because vacuum spans transactions and we don't				 * want to lose the vacuum Query due to end-of-transaction				 * free'ing				 */				oldcontext = MemoryContextSwitchTo(TopMemoryContext);				result = makeNode(Query);				result->commandType = CMD_UTILITY;				result->utilityStmt = (Node *) parseTree;				MemoryContextSwitchTo(oldcontext);				break;			}		case T_ExplainStmt:			{				ExplainStmt *n = (ExplainStmt *) parseTree;				result = makeNode(Query);				result->commandType = CMD_UTILITY;				n->query = transformStmt(pstate, (Node *) n->query);				result->utilityStmt = (Node *) parseTree;			}			break;			/*------------------------			 *	Optimizable statements			 *------------------------			 */		case T_InsertStmt:			result = transformInsertStmt(pstate, (InsertStmt *) parseTree);			break;		case T_DeleteStmt:			result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);			break;		case T_UpdateStmt:			result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);			break;		case T_SelectStmt:			if (!((SelectStmt *) parseTree)->portalname)			{				result = transformSelectStmt(pstate, (SelectStmt *) parseTree);				result->limitOffset = ((SelectStmt *) parseTree)->limitOffset;				result->limitCount = ((SelectStmt *) parseTree)->limitCount;			}			else				result = transformCursorStmt(pstate, (SelectStmt *) parseTree);			break;		default:			/*			 * other statments don't require any transformation-- just			 * return the original parsetree, yea!			 */			result = makeNode(Query);			result->commandType = CMD_UTILITY;			result->utilityStmt = (Node *) parseTree;			break;	}	return result;}/* * transformDeleteStmt - *	  transforms a Delete Statement */static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt){	Query	   *qry = makeNode(Query);	qry->commandType = CMD_DELETE;	/* set up a range table */	makeRangeTable(pstate, stmt->relname, NULL, NULL);	qry->uniqueFlag = NULL;	/* fix where clause */	qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL);	qry->hasSubLinks = pstate->p_hasSubLinks;	qry->rtable = pstate->p_rtable;	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);	qry->hasAggs = pstate->p_hasAggs;	if (pstate->p_hasAggs)		parseCheckAggregates(pstate, qry);	return (Query *) qry;}/* * transformInsertStmt - *	  transform an Insert Statement */static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt){	Query	   *qry = makeNode(Query);	/* make a new query tree */	List	   *icolumns;	qry->commandType = CMD_INSERT;	pstate->p_is_insert = true;	/* set up a range table */	makeRangeTable(pstate, stmt->relname, stmt->fromClause, NULL);	qry->uniqueFlag = stmt->unique;	/* fix the target list */	icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);	qry->targetList = transformTargetList(pstate, stmt->targetList);	/* DEFAULT handling */	if (length(qry->targetList) < pstate->p_target_relation->rd_att->natts &&		pstate->p_target_relation->rd_att->constr &&		pstate->p_target_relation->rd_att->constr->num_defval > 0)	{		Form_pg_attribute *att = pstate->p_target_relation->rd_att->attrs;		AttrDefault *defval = pstate->p_target_relation->rd_att->constr->defval;		int			ndef = pstate->p_target_relation->rd_att->constr->num_defval;		/*		 * if stmt->cols == NIL then makeTargetNames returns list of all		 * attrs. May have to shorten icolumns list...		 */		if (stmt->cols == NIL)		{			List	   *extrl;			int			i = length(qry->targetList);			foreach(extrl, icolumns)			{				/*				 * decrements first, so if we started with zero items it				 * will now be negative				 */				if (--i <= 0)					break;			}			/*			 * this an index into the targetList, so make sure we had one			 * to start...			 */			if (i >= 0)			{				freeList(lnext(extrl));				lnext(extrl) = NIL;			}			else				icolumns = NIL;		}		while (ndef-- > 0)		{			List	   *tl;			Ident	   *id;			TargetEntry *te;			foreach(tl, icolumns)			{				id = (Ident *) lfirst(tl);				if (namestrcmp(&(att[defval[ndef].adnum - 1]->attname), id->name) == 0)					break;			}			if (tl != NIL)		/* something given for this attr */				continue;			/*			 * Nothing given for this attr with DEFAULT expr, so add new			 * TargetEntry to qry->targetList. Note, that we set resno to			 * defval[ndef].adnum: it's what			 * transformTargetList()->make_targetlist_expr() does for			 * INSERT ... SELECT. But for INSERT ... VALUES			 * pstate->p_last_resno is used. It doesn't matter for			 * "normal" using (planner creates proper target list in			 * preptlist.c), but may break RULEs in some way. It seems			 * better to create proper target list here...			 */			te = makeTargetEntry(makeResdom(defval[ndef].adnum,								   att[defval[ndef].adnum - 1]->atttypid,								  att[defval[ndef].adnum - 1]->atttypmod,			   pstrdup(nameout(&(att[defval[ndef].adnum - 1]->attname))),											0, 0, false),							  (Node *) stringToNode(defval[ndef].adbin));			qry->targetList = lappend(qry->targetList, te);		}	}	/* fix where clause */	qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL);	/*	 * The havingQual has a similar meaning as "qual" in the where	 * statement. So we can easily use the code from the "where clause"	 * with some additional traversals done in	 * .../optimizer/plan/planner.c	 */	qry->havingQual = transformWhereClause(pstate, stmt->havingClause, NULL);	qry->hasSubLinks = pstate->p_hasSubLinks;	/* now the range table will not change */	qry->rtable = pstate->p_rtable;	qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);	qry->groupClause = transformGroupClause(pstate,											stmt->groupClause,											qry->targetList);	/* fix order clause */	qry->sortClause = transformSortClause(pstate,										  NIL,										  NIL,										  qry->targetList,										  qry->uniqueFlag);	qry->hasAggs = pstate->p_hasAggs;	if (pstate->p_hasAggs || qry->groupClause)		parseCheckAggregates(pstate, qry);	/*	 * The INSERT INTO ... SELECT ... could have a UNION in child, so	 * unionClause may be false ,	 */	qry->unionall = stmt->unionall;	/***S*I***/	/*	 * Just hand through the unionClause and intersectClause. We will	 * handle it in the function Except_Intersect_Rewrite()	 */	qry->unionClause = stmt->unionClause;	qry->intersectClause = stmt->intersectClause;	/*	 * If there is a havingQual but there are no aggregates, then there is	 * something wrong with the query because having must contain	 * aggregates in its expressions! Otherwise the query could have been	 * formulated using the where clause.	 */	if ((qry->hasAggs == false) && (qry->havingQual != NULL))	{		elog(ERROR, "SELECT/HAVING requires aggregates to be valid");		return (Query *) NIL;	}	if (stmt->forUpdate != NULL)		transformForUpdate(qry, stmt->forUpdate);	return (Query *) qry;}/* *	makeObjectName() * *	Create a name for an implicitly created index, sequence, constraint, etc. * *	The parameters are: the original table name, the original field name, and *	a "type" string (such as "seq" or "pkey").  The field name and/or type *	can be NULL if not relevant. * *	The result is a palloc'd string. * *	The basic result we want is "name1_name2_type", omitting "_name2" or *	"_type" when those parameters are NULL.  However, we must generate *	a name with less than NAMEDATALEN characters!  So, we truncate one or *	both names if necessary to make a short-enough string.  The type part *	is never truncated (so it had better be reasonably short). * *	To reduce the probability of collisions, we might someday add more *	smarts to this routine, like including some "hash" characters computed *	from the truncated characters.  Currently it seems best to keep it simple,

⌨️ 快捷键说明

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