analyze.c

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

C
2,222
字号
/*------------------------------------------------------------------------- * * analyze.c *	  transform the parse tree into a query tree * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *	$PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.326.2.1 2005/11/22 18:23:12 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/heap.h"#include "catalog/index.h"#include "catalog/namespace.h"#include "catalog/pg_index.h"#include "catalog/pg_type.h"#include "commands/defrem.h"#include "commands/prepare.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/var.h"#include "parser/analyze.h"#include "parser/gramparse.h"#include "parser/parsetree.h"#include "parser/parse_agg.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 "parser/parse_expr.h"#include "rewrite/rewriteManip.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/guc.h"#include "utils/lsyscache.h"#include "utils/relcache.h"#include "utils/syscache.h"/* State shared by transformCreateSchemaStmt and its subroutines */typedef struct{	const char *stmtType;		/* "CREATE SCHEMA" or "ALTER SCHEMA" */	char	   *schemaname;		/* name of schema */	char	   *authid;			/* owner of schema */	List	   *sequences;		/* CREATE SEQUENCE items */	List	   *tables;			/* CREATE TABLE items */	List	   *views;			/* CREATE VIEW items */	List	   *indexes;		/* CREATE INDEX items */	List	   *triggers;		/* CREATE TRIGGER items */	List	   *grants;			/* GRANT items */	List	   *fwconstraints;	/* Forward referencing FOREIGN KEY constraints */	List	   *alters;			/* Generated ALTER items (from the above) */	List	   *ixconstraints;	/* index-creating constraints */	List	   *blist;			/* "before list" of things to do before								 * creating the schema */	List	   *alist;			/* "after list" of things to do after creating								 * the schema */} CreateSchemaStmtContext;/* State shared by transformCreateStmt and its subroutines */typedef struct{	const char *stmtType;		/* "CREATE TABLE" or "ALTER TABLE" */	RangeVar   *relation;		/* relation to create */	List	   *inhRelations;	/* relations to inherit from */	bool		hasoids;		/* does relation have an OID column? */	bool		isalter;		/* true if altering existing table */	List	   *columns;		/* ColumnDef items */	List	   *ckconstraints;	/* CHECK constraints */	List	   *fkconstraints;	/* FOREIGN KEY constraints */	List	   *ixconstraints;	/* index-creating constraints */	List	   *blist;			/* "before list" of things to do before								 * creating the table */	List	   *alist;			/* "after list" of things to do after creating								 * the table */	IndexStmt  *pkey;			/* PRIMARY KEY index, if any */} CreateStmtContext;typedef struct{	Oid		   *paramTypes;	int			numParams;} check_parameter_resolution_context;static List *do_parse_analyze(Node *parseTree, ParseState *pstate);static Query *transformStmt(ParseState *pstate, Node *stmt,			  List **extras_before, List **extras_after);static Query *transformViewStmt(ParseState *pstate, ViewStmt *stmt,				  List **extras_before, List **extras_after);static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt,					List **extras_before, List **extras_after);static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt,				  List **extras_before, List **extras_after);static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);static Query *transformDeclareCursorStmt(ParseState *pstate,						   DeclareCursorStmt *stmt);static Query *transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt);static Query *transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt);static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt,					List **extras_before, List **extras_after);static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,						List **extras_before, List **extras_after);static void transformColumnDefinition(ParseState *pstate,						  CreateStmtContext *cxt,						  ColumnDef *column);static void transformTableConstraint(ParseState *pstate,						 CreateStmtContext *cxt,						 Constraint *constraint);static void transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,					 InhRelation *inhrelation);static void transformIndexConstraints(ParseState *pstate,						  CreateStmtContext *cxt);static void transformFKConstraints(ParseState *pstate,					   CreateStmtContext *cxt,					   bool skipValidation,					   bool isAddConstraint);static void applyColumnNames(List *dst, List *src);static List *getSetColTypes(ParseState *pstate, Node *node);static void transformLockingClause(Query *qry, LockingClause *lc);static void transformConstraintAttrs(List *constraintList);static void transformColumnType(ParseState *pstate, ColumnDef *column);static void release_pstate_resources(ParseState *pstate);static FromExpr *makeFromExpr(List *fromlist, Node *quals);static bool check_parameter_resolution_walker(Node *node,								check_parameter_resolution_context *context);/* * parse_analyze *		Analyze a raw parse tree and transform it to Query form. * * Optionally, information about $n parameter types can be supplied. * References to $n indexes not defined by paramTypes[] are disallowed. * * The result is a List of Query nodes (we need a list since some commands * produce multiple Queries).  Optimizable statements require considerable * transformation, while many utility-type statements are simply hung off * a dummy CMD_UTILITY Query node. */List *parse_analyze(Node *parseTree, Oid *paramTypes, int numParams){	ParseState *pstate = make_parsestate(NULL);	List	   *result;	pstate->p_paramtypes = paramTypes;	pstate->p_numparams = numParams;	pstate->p_variableparams = false;	result = do_parse_analyze(parseTree, pstate);	pfree(pstate);	return result;}/* * parse_analyze_varparams * * This variant is used when it's okay to deduce information about $n * symbol datatypes from context.  The passed-in paramTypes[] array can * be modified or enlarged (via repalloc). */List *parse_analyze_varparams(Node *parseTree, Oid **paramTypes, int *numParams){	ParseState *pstate = make_parsestate(NULL);	List	   *result;	pstate->p_paramtypes = *paramTypes;	pstate->p_numparams = *numParams;	pstate->p_variableparams = true;	result = do_parse_analyze(parseTree, pstate);	*paramTypes = pstate->p_paramtypes;	*numParams = pstate->p_numparams;	pfree(pstate);	/* make sure all is well with parameter types */	if (*numParams > 0)	{		check_parameter_resolution_context context;		context.paramTypes = *paramTypes;		context.numParams = *numParams;		check_parameter_resolution_walker((Node *) result, &context);	}	return result;}/* * parse_sub_analyze *		Entry point for recursively analyzing a sub-statement. */List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState){	ParseState *pstate = make_parsestate(parentParseState);	List	   *result;	result = do_parse_analyze(parseTree, pstate);	pfree(pstate);	return result;}/* * do_parse_analyze *		Workhorse code shared by the above variants of parse_analyze. */static List *do_parse_analyze(Node *parseTree, ParseState *pstate){	List	   *result = NIL;	/* Lists to return extra commands from transformation */	List	   *extras_before = NIL;	List	   *extras_after = NIL;	Query	   *query;	ListCell   *l;	query = transformStmt(pstate, parseTree, &extras_before, &extras_after);	/* don't need to access result relation any more */	release_pstate_resources(pstate);	foreach(l, extras_before)		result = list_concat(result, parse_sub_analyze(lfirst(l), pstate));	result = lappend(result, query);	foreach(l, extras_after)		result = list_concat(result, parse_sub_analyze(lfirst(l), pstate));	/*	 * Make sure that only the original query is marked original. We have to	 * do this explicitly since recursive calls of do_parse_analyze will have	 * marked some of the added-on queries as "original".  Also mark only the	 * original query as allowed to set the command-result tag.	 */	foreach(l, result)	{		Query	   *q = lfirst(l);		if (q == query)		{			q->querySource = QSRC_ORIGINAL;			q->canSetTag = true;		}		else		{			q->querySource = QSRC_PARSER;			q->canSetTag = false;		}	}	return result;}static voidrelease_pstate_resources(ParseState *pstate){	if (pstate->p_target_relation != NULL)		heap_close(pstate->p_target_relation, NoLock);	pstate->p_target_relation = NULL;	pstate->p_target_rangetblentry = NULL;}/* * transformStmt - *	  transform a Parse tree into a Query tree. */static Query *transformStmt(ParseState *pstate, Node *parseTree,			  List **extras_before, List **extras_after){	Query	   *result = NULL;	switch (nodeTag(parseTree))	{			/*			 * Non-optimizable statements			 */		case T_CreateStmt:			result = transformCreateStmt(pstate, (CreateStmt *) parseTree,										 extras_before, extras_after);			break;		case T_IndexStmt:			result = transformIndexStmt(pstate, (IndexStmt *) parseTree);			break;		case T_RuleStmt:			result = transformRuleStmt(pstate, (RuleStmt *) parseTree,									   extras_before, extras_after);			break;		case T_ViewStmt:			result = transformViewStmt(pstate, (ViewStmt *) parseTree,									   extras_before, extras_after);			break;		case T_ExplainStmt:			{				ExplainStmt *n = (ExplainStmt *) parseTree;				result = makeNode(Query);				result->commandType = CMD_UTILITY;				n->query = transformStmt(pstate, (Node *) n->query,										 extras_before, extras_after);				result->utilityStmt = (Node *) parseTree;			}			break;		case T_AlterTableStmt:			result = transformAlterTableStmt(pstate,											 (AlterTableStmt *) parseTree,											 extras_before, extras_after);			break;		case T_PrepareStmt:			result = transformPrepareStmt(pstate, (PrepareStmt *) parseTree);			break;		case T_ExecuteStmt:			result = transformExecuteStmt(pstate, (ExecuteStmt *) parseTree);			break;			/*			 * Optimizable statements			 */		case T_InsertStmt:			result = transformInsertStmt(pstate, (InsertStmt *) parseTree,										 extras_before, extras_after);			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)->op == SETOP_NONE)				result = transformSelectStmt(pstate,											 (SelectStmt *) parseTree);			else				result = transformSetOperationStmt(pstate,												   (SelectStmt *) parseTree);			break;		case T_DeclareCursorStmt:			result = transformDeclareCursorStmt(pstate,											(DeclareCursorStmt *) parseTree);			break;		default:			/*			 * other statements don't require any transformation-- just return			 * the original parsetree, yea!			 */			result = makeNode(Query);			result->commandType = CMD_UTILITY;			result->utilityStmt = (Node *) parseTree;			break;	}	/* Mark as original query until we learn differently */	result->querySource = QSRC_ORIGINAL;	result->canSetTag = true;	/*	 * Check that we did not produce too many resnos; at the very least we	 * cannot allow more than 2^16, since that would exceed the range of a	 * AttrNumber. It seems safest to use MaxTupleAttributeNumber.	 */	if (pstate->p_next_resno - 1 > MaxTupleAttributeNumber)		ereport(ERROR,				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),				 errmsg("target lists can have at most %d entries",						MaxTupleAttributeNumber)));	return result;}static Query *transformViewStmt(ParseState *pstate, ViewStmt *stmt,				  List **extras_before, List **extras_after){	Query	   *result = makeNode(Query);	result->commandType = CMD_UTILITY;	result->utilityStmt = (Node *) stmt;	stmt->query = transformStmt(pstate, (Node *) stmt->query,								extras_before, extras_after);	/*	 * If a list of column names was given, run through and insert these into	 * the actual query tree. - thomas 2000-03-08	 *	 * Outer loop is over targetlist to make it easier to skip junk targetlist	 * entries.	 */	if (stmt->aliases != NIL)	{		ListCell   *alist_item = list_head(stmt->aliases);		ListCell   *targetList;		foreach(targetList, stmt->query->targetList)		{			TargetEntry *te = (TargetEntry *) lfirst(targetList);			Assert(IsA(te, TargetEntry));			/* junk columns don't get aliases */			if (te->resjunk)				continue;			te->resname = pstrdup(strVal(lfirst(alist_item)));			alist_item = lnext(alist_item);			if (alist_item == NULL)				break;			/* done assigning aliases */

⌨️ 快捷键说明

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