analyze.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,258 行 · 第 1/5 页

C
2,258
字号
/*------------------------------------------------------------------------- * * analyze.c *	  transform the parse tree into a query tree * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *	$Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.290.2.1 2003/11/05 22:00:52 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/catname.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/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/lsyscache.h"#include "utils/relcache.h"#include "utils/syscache.h"#include "mb/pg_wchar.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	   *tables;			/* CREATE TABLE items */	List	   *views;			/* CREATE VIEW 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? */	Oid			relOid;			/* OID of table, if ALTER TABLE case */	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 *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 isAddConstraint);static void applyColumnNames(List *dst, List *src);static List *getSetColTypes(ParseState *pstate, Node *node);static void transformForUpdate(Query *qry, List *forUpdate);static void transformConstraintAttrs(List *constraintList);static void transformColumnType(ParseState *pstate, ColumnDef *column);static bool relationHasPrimaryKey(Oid relationOid);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;	List	   *listscan;	query = transformStmt(pstate, parseTree, &extras_before, &extras_after);	/* don't need to access result relation any more */	release_pstate_resources(pstate);	while (extras_before != NIL)	{		result = nconc(result,					   parse_sub_analyze(lfirst(extras_before), pstate));		extras_before = lnext(extras_before);	}	result = lappend(result, query);	while (extras_after != NIL)	{		result = nconc(result,					   parse_sub_analyze(lfirst(extras_after), pstate));		extras_after = lnext(extras_after);	}	/*	 * 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(listscan, result)	{		Query	   *q = lfirst(listscan);		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:			{				ViewStmt   *n = (ViewStmt *) parseTree;				n->query = transformStmt(pstate, (Node *) n->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 (n->aliases != NIL)				{					List	   *aliaslist = n->aliases;					List	   *targetList;					foreach(targetList, n->query->targetList)					{						TargetEntry *te = (TargetEntry *) lfirst(targetList);						Resdom	   *rd;						Assert(IsA(te, TargetEntry));						rd = te->resdom;						Assert(IsA(rd, Resdom));						/* junk columns don't get aliases */						if (rd->resjunk)							continue;						rd->resname = pstrdup(strVal(lfirst(aliaslist)));						aliaslist = lnext(aliaslist);						if (aliaslist == NIL)							break;		/* done assigning aliases */					}					if (aliaslist != NIL)						ereport(ERROR,								(errcode(ERRCODE_SYNTAX_ERROR),								 errmsg("CREATE VIEW specifies more column names than columns")));				}				result = makeNode(Query);				result->commandType = CMD_UTILITY;				result->utilityStmt = (Node *) n;			}			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;	return result;}/* * transformDeleteStmt - *	  transforms a Delete Statement */static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt){

⌨️ 快捷键说明

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