postgres.c

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

C
2,551
字号
 */List *pg_rewrite_queries(List *querytree_list){	List	   *new_list = NIL;	List	   *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 = nconc(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){	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);	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, bool needSnapshot){	List	   *plan_list = NIL;	List	   *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)			{				SetQuerySnapshot();				needSnapshot = false;			}			plan = pg_plan_query(query);		}		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,			   *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;	/*	 * 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);	/*	 * 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())		{			bool		allowit = false;			if (IsA(parsetree, TransactionStmt))			{				TransactionStmt *stmt = (TransactionStmt *) parsetree;				if (stmt->kind == TRANS_STMT_COMMIT ||					stmt->kind == TRANS_STMT_ROLLBACK)					allowit = true;			}			if (!allowit)				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, 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);		PortalDefineQuery(portal,						  query_string,						  commandTag,						  querytree_list,						  plantree_list,						  MessageContext);		/*		 * Start the portal.  No parameters here.		 */		PortalStart(portal, NULL);		/*		 * Select the appropriate output format: text unless we are doing		 * a FETCH from a binary cursor.  (Pretty grotty to have to do		 * this here --- but it avoids grottiness in other places.	Ah,		 * the joys of backward compatibility...)		 */		format = 0;				/* TEXT is default */		if (IsA(parsetree, FetchStmt))		{			FetchStmt  *stmt = (FetchStmt *) parsetree;			if (!stmt->ismove)			{				Portal		fportal = GetPortalByName(stmt->portalname);				if (PortalIsValid(fportal) &&					(fportal->cursorOptions & CURSOR_OPT_BINARY))					format = 1; /* BINARY */			}		}		PortalSetResultFormat(portal, 1, &format);		/*		 * Now we can create the destination receiver object.		 */		receiver = CreateDestReceiver(dest, portal);		/*		 * Switch back to transaction context for execution.		 */		MemoryContextSwitchTo(oldcontext);		/*		 * Run the portal to completion, and then drop it (and the		 * receiver).		 */		(void) PortalRun(portal,						 FETCH_ALL,						 receiver,						 receiver,						 completionTag);		(*receiver->rDestroy) (receiver);		PortalDrop(portal, false);		if (IsA(parsetree, TransactionStmt))		{			/*			 * If this was a transaction control statement, commit it. We			 * will start a new xact command for the next command (if			 * any).			 */			finish_xact_command();		}		else if (lnext(parsetree_item) == NIL)		{			/*			 * If this is the last parsetree of the query string, close			 * down transaction statement before reporting			 * command-complete.  This is so that any end-of-transaction			 * errors are reported before the command-complete message is			 * issued, to avoid confusing clients who will expect either a			 * command-complete message or an error, not one and then the			 * other.  But for compatibility with historical Postgres			 * behavior, we do not force a transaction boundary between			 * queries appearing in a single query string.			 */			finish_xact_command();		}		else		{			/*			 * We need a CommandCounterIncrement after every query, except			 * those that start or end a transaction block.			 */			CommandCounterIncrement();		}		/*		 * Tell client that we're done with this query.  Note we emit		 * exactly one EndCommand report for each raw parsetree, thus one		 * for each SQL command the client sent, regardless of rewriting.		 * (But a command aborted by error will not send an EndCommand		 * report at all.)		 */		EndCommand(completionTag, dest);	}							/* end loop over parsetrees */	/*	 * Close down transaction statement, if one is open.	 */	finish_xact_command();	/*	 * If there were no parsetrees, return EmptyQueryResponse message.	 */	if (!parsetree_list)		NullCommand(dest);	QueryContext = NULL;	/*	 * Combine processing here as we need to calculate the query duration	 * in both instances.	 */	if (save_log_duration || save_log_min_duration_statement != -1)	{		long		usecs;		gettimeofday(&stop_t, NULL);		if (stop_t.tv_usec < start_t.tv_usec)		{			stop_t.tv_sec--;			stop_t.tv_usec += 1000000;		}		usecs = (long) (stop_t.tv_sec - start_t.tv_sec) * 1000000 + (long) (stop_t.tv_usec - start_t.tv_usec);		if (save_log_duration)			ereport(LOG,					(errmsg("duration: %ld.%03ld ms",							(long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +							(stop_t.tv_usec - start_t.tv_usec) / 1000),							(long) (stop_t.tv_usec - start_t.tv_usec) % 1000)));		/*		 * Output a duration_statement to the log if the query has exceeded		 * the min duration, or if we are to print all durations.		 */		if (save_log_min_duration_statement == 0 ||			(save_log_min_duration_statement > 0 &&			 usecs >= save_log_min_duration_statement * 1000))			ereport(LOG,					(errmsg("duration: %ld.%03ld ms  statement: %s",							(long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +							(stop_t.tv_usec - start_t.tv_usec) / 1000),							(long) (stop_t.tv_usec - start_t.tv_usec) % 1000,							query_string)));	}	if (save_log_statement_stats)		ShowUsage("QUERY STATISTICS");	debug_query_string = NULL;}/* * exec_parse_message * * Execute a "Parse" protocol message. */static voidexec_parse_message(const char *query_string,	/* string to execute */				   const char *stmt_name,		/* name for prepared stmt */				   Oid *paramTypes,		/* parameter types */				   int numParams)		/* number of parameters */{	MemoryContext oldcontext;	List	   *parsetree_list;	const char *commandTag;	List	   *querytree_list,			   *plantree_list,			   *param_list;	bool		is_named;	bool		save_log_statement_stats = log_statement_stats;	/*	 * Report query to various monitoring facilities.	 */	debug_query_string = query_string;	pgstat_report_activity(query_string);	set_ps_display("PARSE");	if (save_log_statement_stats)		ResetUsage();	/*	 * Start up a transaction command so we can run parse analysis etc.	 * (Note that this will normally change current memory context.)	 * Nothing happens if we are already in one.	 */	start_xact_command();	/*

⌨️ 快捷键说明

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