postgres.c

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

C
2,390
字号
	List	   *querytree_list;	ListCell   *list_item;	/*	 * (1) parse the request string into a list of raw parse trees.	 */	raw_parsetree_list = pg_parse_query(query_string);	/*	 * (2) Do parse analysis and rule rewrite.	 */	querytree_list = NIL;	foreach(list_item, raw_parsetree_list)	{		Node	   *parsetree = (Node *) lfirst(list_item);		querytree_list = list_concat(querytree_list,									 pg_analyze_and_rewrite(parsetree,															paramTypes,															numParams));	}	return querytree_list;}/* * Do raw parsing (only). * * A list of parsetrees is returned, since there might be multiple * commands in the given string. * * NOTE: for interactive queries, it is important to keep this routine * separate from the analysis & rewrite stages.  Analysis and rewriting * cannot be done in an aborted transaction, since they require access to * database tables.  So, we rely on the raw parser to determine whether * we've seen a COMMIT or ABORT command; when we are in abort state, other * commands are not processed any further than the raw parse stage. */List *pg_parse_query(const char *query_string){	List	   *raw_parsetree_list;	if (log_parser_stats)		ResetUsage();	raw_parsetree_list = raw_parser(query_string);	if (log_parser_stats)		ShowUsage("PARSER STATISTICS");	return raw_parsetree_list;}static boollog_after_parse(List *raw_parsetree_list, const char *query_string,				char **prepare_string){	ListCell   *parsetree_item;	bool		log_this_statement = (log_statement == LOGSTMT_ALL);	*prepare_string = NULL;	/* Check if we need to log the statement, and get prepare_string. */	foreach(parsetree_item, raw_parsetree_list)	{		Node	   *parsetree = (Node *) lfirst(parsetree_item);		const char *commandTag;		if (IsA(parsetree, ExplainStmt) &&			((ExplainStmt *) parsetree)->analyze)			parsetree = (Node *) (((ExplainStmt *) parsetree)->query);		if (IsA(parsetree, PrepareStmt))			parsetree = (Node *) (((PrepareStmt *) parsetree)->query);		if (IsA(parsetree, SelectStmt) &&			((SelectStmt *) parsetree)->into == NULL)			continue;			/* optimization for frequent command */		if (log_statement == LOGSTMT_MOD &&			(IsA(parsetree, InsertStmt) ||			 IsA(parsetree, UpdateStmt) ||			 IsA(parsetree, DeleteStmt) ||			 IsA(parsetree, TruncateStmt) ||			 (IsA(parsetree, CopyStmt) &&			  ((CopyStmt *) parsetree)->is_from)))		/* COPY FROM */			log_this_statement = true;		commandTag = CreateCommandTag(parsetree);		if ((log_statement == LOGSTMT_MOD ||			 log_statement == LOGSTMT_DDL) &&			(strncmp(commandTag, "CREATE ", strlen("CREATE ")) == 0 ||			 IsA(parsetree, SelectStmt) ||		/* SELECT INTO, CREATE AS */			 strncmp(commandTag, "ALTER ", strlen("ALTER ")) == 0 ||			 strncmp(commandTag, "DROP ", strlen("DROP ")) == 0 ||			 IsA(parsetree, GrantStmt) ||		/* GRANT or REVOKE */			 IsA(parsetree, CommentStmt)))			log_this_statement = true;		/*		 * For the first EXECUTE we find, record the client statement used by		 * the PREPARE.  PREPARE doesn't save the parse tree so we have no		 * way to conditionally output based on the type of query prepared.		 */		if (IsA(parsetree, ExecuteStmt))		{			ExecuteStmt *stmt = (ExecuteStmt *) parsetree;			PreparedStatement *entry;			if (*prepare_string == NULL &&				(entry = FetchPreparedStatement(stmt->name, false)) != NULL &&				entry->query_string)			{				*prepare_string = palloc(strlen(entry->query_string) +									  strlen("  [PREPARE:  %s]") - 2 + 1);				sprintf(*prepare_string, "  [PREPARE:  %s]",						entry->query_string);			}		}	}	if (log_this_statement)	{		ereport(LOG,				(errmsg("statement: %s%s", query_string,						*prepare_string ? *prepare_string : "")));		return true;	}	else		return false;}/* * Given a raw parsetree (gram.y output), and optionally information about * types of parameter symbols ($n), perform parse analysis and rule rewriting. * * A list of Query nodes is returned, since either the analyzer or the * rewriter might expand one query to several. * * NOTE: for reasons mentioned above, this must be separate from raw parsing. */List *pg_analyze_and_rewrite(Node *parsetree, Oid *paramTypes, int numParams){	List	   *querytree_list;	/*	 * (1) Perform parse analysis.	 */	if (log_parser_stats)		ResetUsage();	querytree_list = parse_analyze(parsetree, paramTypes, numParams);	if (log_parser_stats)		ShowUsage("PARSE ANALYSIS STATISTICS");	/*	 * (2) Rewrite the queries, as necessary	 */	querytree_list = pg_rewrite_queries(querytree_list);	return querytree_list;}/* * Perform rewriting of a list of queries produced by parse analysis. * * Note: queries must just have come from the parser, because we do not do * AcquireRewriteLocks() on them. */static List *pg_rewrite_queries(List *querytree_list){	List	   *new_list = NIL;	ListCell   *list_item;	if (log_parser_stats)		ResetUsage();	/*	 * rewritten queries are collected in new_list.  Note there may be more or	 * fewer than in the original list.	 */	foreach(list_item, querytree_list)	{		Query	   *querytree = (Query *) lfirst(list_item);		if (Debug_print_parse)			elog_node_display(DEBUG1, "parse tree", querytree,							  Debug_pretty_print);		if (querytree->commandType == CMD_UTILITY)		{			/* don't rewrite utilities, just dump 'em into new_list */			new_list = lappend(new_list, querytree);		}		else		{			/* rewrite regular queries */			List	   *rewritten = QueryRewrite(querytree);			new_list = list_concat(new_list, rewritten);		}	}	querytree_list = new_list;	if (log_parser_stats)		ShowUsage("REWRITER STATISTICS");#ifdef COPY_PARSE_PLAN_TREES	/*	 * Optional debugging check: pass querytree output through copyObject()	 */	new_list = (List *) copyObject(querytree_list);	/* This checks both copyObject() and the equal() routines... */	if (!equal(new_list, querytree_list))		elog(WARNING, "copyObject() failed to produce an equal parse tree");	else		querytree_list = new_list;#endif	if (Debug_print_rewritten)		elog_node_display(DEBUG1, "rewritten parse tree", querytree_list,						  Debug_pretty_print);	return querytree_list;}/* Generate a plan for a single already-rewritten query. */Plan *pg_plan_query(Query *querytree, ParamListInfo boundParams){	Plan	   *plan;	/* Utility commands have no plans. */	if (querytree->commandType == CMD_UTILITY)		return NULL;	if (log_planner_stats)		ResetUsage();	/* call the optimizer */	plan = planner(querytree, false, 0, boundParams);	if (log_planner_stats)		ShowUsage("PLANNER STATISTICS");#ifdef COPY_PARSE_PLAN_TREES	/* Optional debugging check: pass plan output through copyObject() */	{		Plan	   *new_plan = (Plan *) copyObject(plan);		/*		 * equal() currently does not have routines to compare Plan nodes, so		 * don't try to test equality here.  Perhaps fix someday?		 */#ifdef NOT_USED		/* This checks both copyObject() and the equal() routines... */		if (!equal(new_plan, plan))			elog(WARNING, "copyObject() failed to produce an equal plan tree");		else#endif			plan = new_plan;	}#endif	/*	 * Print plan if debugging.	 */	if (Debug_print_plan)		elog_node_display(DEBUG1, "plan", plan, Debug_pretty_print);	return plan;}/* * Generate plans for a list of already-rewritten queries. * * If needSnapshot is TRUE, we haven't yet set a snapshot for the current * query.  A snapshot must be set before invoking the planner, since it * might try to evaluate user-defined functions.  But we must not set a * snapshot if the list contains only utility statements, because some * utility statements depend on not having frozen the snapshot yet. * (We assume that such statements cannot appear together with plannable * statements in the rewriter's output.) */List *pg_plan_queries(List *querytrees, ParamListInfo boundParams,				bool needSnapshot){	List	   *plan_list = NIL;	ListCell   *query_list;	foreach(query_list, querytrees)	{		Query	   *query = (Query *) lfirst(query_list);		Plan	   *plan;		if (query->commandType == CMD_UTILITY)		{			/* Utility commands have no plans. */			plan = NULL;		}		else		{			if (needSnapshot)			{				ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());				needSnapshot = false;			}			plan = pg_plan_query(query, boundParams);		}		plan_list = lappend(plan_list, plan);	}	return plan_list;}/* * exec_simple_query * * Execute a "simple Query" protocol message. */static voidexec_simple_query(const char *query_string){	CommandDest dest = whereToSendOutput;	MemoryContext oldcontext;	List	   *parsetree_list;	ListCell   *parsetree_item;	struct timeval start_t,				stop_t;	bool		save_log_duration = log_duration;	int			save_log_min_duration_statement = log_min_duration_statement;	bool		save_log_statement_stats = log_statement_stats;	char	   *prepare_string = NULL;	bool		was_logged = false;	/*	 * Report query to various monitoring facilities.	 */	debug_query_string = query_string;	pgstat_report_activity(query_string);	/*	 * We use save_log_* so "SET log_duration = true"  and "SET	 * log_min_duration_statement = true" don't report incorrect time because	 * gettimeofday() wasn't called. Similarly, log_statement_stats has to be	 * captured once.	 */	if (save_log_duration || save_log_min_duration_statement != -1)		gettimeofday(&start_t, NULL);	if (save_log_statement_stats)		ResetUsage();	/*	 * Start up a transaction command.	All queries generated by the	 * query_string will be in this same command block, *unless* we find a	 * BEGIN/COMMIT/ABORT statement; we have to force a new xact command after	 * one of those, else bad things will happen in xact.c. (Note that this	 * will normally change current memory context.)	 */	start_xact_command();	/*	 * Zap any pre-existing unnamed statement.	(While not strictly necessary,	 * it seems best to define simple-Query mode as if it used the unnamed	 * statement and portal; this ensures we recover any storage used by prior	 * unnamed operations.)	 */	unnamed_stmt_pstmt = NULL;	if (unnamed_stmt_context)	{		DropDependentPortals(unnamed_stmt_context);		MemoryContextDelete(unnamed_stmt_context);	}	unnamed_stmt_context = NULL;	/*	 * Switch to appropriate context for constructing parsetrees.	 */	oldcontext = MemoryContextSwitchTo(MessageContext);	QueryContext = CurrentMemoryContext;	/*	 * Do basic parsing of the query or queries (this should be safe even if	 * we are in aborted transaction state!)	 */	parsetree_list = pg_parse_query(query_string);	if (log_statement != LOGSTMT_NONE || save_log_min_duration_statement != -1)		was_logged = log_after_parse(parsetree_list, query_string,									 &prepare_string);	/*	 * Switch back to transaction context to enter the loop.	 */	MemoryContextSwitchTo(oldcontext);	/*	 * Run through the raw parsetree(s) and process each one.	 */	foreach(parsetree_item, parsetree_list)	{		Node	   *parsetree = (Node *) lfirst(parsetree_item);		const char *commandTag;		char		completionTag[COMPLETION_TAG_BUFSIZE];		List	   *querytree_list,				   *plantree_list;		Portal		portal;		DestReceiver *receiver;		int16		format;		/*		 * Get the command name for use in status display (it also becomes the		 * default completion tag, down inside PortalRun).	Set ps_status and		 * do any special start-of-SQL-command processing needed by the		 * destination.		 */		commandTag = CreateCommandTag(parsetree);		set_ps_display(commandTag);		BeginCommand(commandTag, dest);		/*		 * If we are in an aborted transaction, reject all commands except		 * COMMIT/ABORT.  It is important that this test occur before we try		 * to do parse analysis, rewrite, or planning, since all those phases		 * try to do database accesses, which may fail in abort state. (It		 * might be safe to allow some additional utility commands in this		 * state, but not many...)		 */		if (IsAbortedTransactionBlockState() &&			!IsTransactionExitStmt(parsetree))			ereport(ERROR,					(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),					 errmsg("current transaction is aborted, "						"commands ignored until end of transaction block")));		/* Make sure we are in a transaction command */		start_xact_command();		/* If we got a cancel signal in parsing or prior command, quit */		CHECK_FOR_INTERRUPTS();		/*		 * OK to analyze, rewrite, and plan this query.		 *		 * Switch to appropriate context for constructing querytrees (again,		 * these must outlive the execution context).		 */		oldcontext = MemoryContextSwitchTo(MessageContext);		querytree_list = pg_analyze_and_rewrite(parsetree, NULL, 0);		plantree_list = pg_plan_queries(querytree_list, NULL, true);		/* If we got a cancel signal in analysis or planning, quit */		CHECK_FOR_INTERRUPTS();		/*		 * Create unnamed portal to run the query or queries in. If there		 * already is one, silently drop it.		 */		portal = CreatePortal("", true, true);

⌨️ 快捷键说明

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