postgres.c

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

C
2,390
字号
		PortalDefineQuery(portal,						  query_string,						  commandTag,						  querytree_list,						  plantree_list,						  MessageContext);		/*		 * Start the portal.  No parameters here.		 */		PortalStart(portal, NULL, InvalidSnapshot);		/*		 * 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) == NULL)		{			/*			 * 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);		/* Only print duration if we previously printed the statement. */		if (was_logged && 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%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,							prepare_string ? prepare_string : "")));	}	if (save_log_statement_stats)		ShowUsage("QUERY STATISTICS");	if (prepare_string != NULL)		pfree(prepare_string);	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();	if (log_statement == LOGSTMT_ALL)		ereport(LOG,				(errmsg("statement: PREPARE %s AS %s",						(*stmt_name != '\0') ? stmt_name : "<unnamed>",						query_string)));	/*	 * 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();	/*	 * Switch to appropriate context for constructing parsetrees.	 *	 * We have two strategies depending on whether the prepared statement is	 * named or not.  For a named prepared statement, we do parsing in	 * MessageContext and copy the finished trees into the prepared	 * statement's private context; then the reset of MessageContext releases	 * temporary space used by parsing and planning.  For an unnamed prepared	 * statement, we assume the statement isn't going to hang around long, so	 * getting rid of temp space quickly is probably not worth the costs of	 * copying parse/plan trees.  So in this case, we set up a special context	 * for the unnamed statement, and do all the parsing/planning therein.	 */	is_named = (stmt_name[0] != '\0');	if (is_named)	{		/* Named prepared statement --- parse in MessageContext */		oldcontext = MemoryContextSwitchTo(MessageContext);	}	else	{		/* Unnamed prepared statement --- release any prior unnamed stmt */		unnamed_stmt_pstmt = NULL;		if (unnamed_stmt_context)		{			DropDependentPortals(unnamed_stmt_context);			MemoryContextDelete(unnamed_stmt_context);		}		unnamed_stmt_context = NULL;		/* create context for parsing/planning */		unnamed_stmt_context =			AllocSetContextCreate(TopMemoryContext,								  "unnamed prepared statement",								  ALLOCSET_DEFAULT_MINSIZE,								  ALLOCSET_DEFAULT_INITSIZE,								  ALLOCSET_DEFAULT_MAXSIZE);		oldcontext = MemoryContextSwitchTo(unnamed_stmt_context);	}	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);	/*	 * We only allow a single user statement in a prepared statement. This is	 * mainly to keep the protocol simple --- otherwise we'd need to worry	 * about multiple result tupdescs and things like that.	 */	if (list_length(parsetree_list) > 1)		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),		errmsg("cannot insert multiple commands into a prepared statement")));	if (parsetree_list != NIL)	{		Node	   *parsetree = (Node *) linitial(parsetree_list);		int			i;		/*		 * Get the command name for possible use in status display.		 */		commandTag = CreateCommandTag(parsetree);		/*		 * If we are in an aborted transaction, reject all commands except		 * COMMIT/ROLLBACK.  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")));		/*		 * OK to analyze, rewrite, and plan this query.  Note that the		 * originally specified parameter set is not required to be complete,		 * so we have to use parse_analyze_varparams().		 */		if (log_parser_stats)			ResetUsage();		querytree_list = parse_analyze_varparams(parsetree,												 &paramTypes,												 &numParams);		/*		 * Check all parameter types got determined, and convert array		 * representation to a list for storage.		 */		param_list = NIL;		for (i = 0; i < numParams; i++)		{			Oid			ptype = paramTypes[i];			if (ptype == InvalidOid || ptype == UNKNOWNOID)				ereport(ERROR,						(errcode(ERRCODE_INDETERMINATE_DATATYPE),					 errmsg("could not determine data type of parameter $%d",							i + 1)));			param_list = lappend_oid(param_list, ptype);		}		if (log_parser_stats)			ShowUsage("PARSE ANALYSIS STATISTICS");		querytree_list = pg_rewrite_queries(querytree_list);		/*		 * If this is the unnamed statement and it has parameters, defer query		 * planning until Bind.  Otherwise do it now.		 */		if (!is_named && numParams > 0)			plantree_list = NIL;		else			plantree_list = pg_plan_queries(querytree_list, NULL, true);	}	else	{		/* Empty input string.	This is legal. */		commandTag = NULL;		querytree_list = NIL;		plantree_list = NIL;		param_list = NIL;	}	/* If we got a cancel signal in analysis or planning, quit */	CHECK_FOR_INTERRUPTS();	/*	 * Store the query as a prepared statement.  See above comments.	 */	if (is_named)	{		StorePreparedStatement(stmt_name,							   query_string,							   commandTag,							   querytree_list,							   plantree_list,							   param_list);	}	else	{		PreparedStatement *pstmt;		pstmt = (PreparedStatement *) palloc0(sizeof(PreparedStatement));		/* query_string needs to be copied into unnamed_stmt_context */		pstmt->query_string = pstrdup(query_string);		/* the rest is there already */		pstmt->commandTag = commandTag;		pstmt->query_list = querytree_list;		pstmt->plan_list = plantree_list;		pstmt->argtype_list = param_list;		pstmt->context = unnamed_stmt_context;		/* Now the unnamed statement is complete and valid */		unnamed_stmt_pstmt = pstmt;	}	MemoryContextSwitchTo(oldcontext);	QueryContext = NULL;	/*	 * We do NOT close the open transaction command here; that only happens	 * when the client sends Sync.	Instead, do CommandCounterIncrement just	 * in case something happened during parse/plan.	 */	CommandCounterIncrement();	/*	 * Send ParseComplete.	 */	if (whereToSendOutput == DestRemote)		pq_putemptymessage('1');	if (save_log_statement_stats)		ShowUsage("PARSE MESSAGE STATISTICS");	debug_query_string = NULL;}/* * exec_bind_message * * Process a "Bind" message to create a portal from a prepared statement */static voidexec_bind_message(StringInfo input_message){	const char *portal_name;	const char *stmt_name;	int			numPFormats;	int16	   *pformats = NULL;	int			numParams;	int			numRFormats;	int16	   *rformats = NULL;	int			i;	PreparedStatement *pstmt;	Portal		portal;	ParamListInfo params;	pgstat_report_activity("<BIND>");	set_ps_display("BIND");	/*	 * Start up a transaction command so we can call functions etc. (Note that	 * this will normally change current memory context.) Nothing happens if	 * we are already in one.	 */	start_xact_command();	/* Switch back to message context */	MemoryContextSwitchTo(MessageContext);	/* Get the fixed part of the message */	portal_name = pq_getmsgstring(input_message);	stmt_name = pq_getmsgstring(input_message);	/* Get the parameter format codes */	numPFormats = pq_getmsgint(input_message, 2);	if (numPFormats > 0)	{		pformats = (int16 *) palloc(numPFormats * sizeof(int16));		for (i = 0; i < numPFormats; i++)			pformats[i] = pq_getmsgint(input_message, 2);	}	/* Get the parameter value count */	numParams = pq_getmsgint(input_message, 2);	if (numPFormats > 1 && numPFormats != numParams)		ereport(ERROR,				(errcode(ERRCODE_PROTOCOL_VIOLATION),			errmsg("bind message has %d parameter formats but %d parameters",				   numPFormats, numParams)));	/* Find prepared statement */	if (stmt_name[0] != '\0')		pstmt = FetchPreparedStatement(stmt_name, true);	else	{		/* special-case the unnamed statement */		pstmt = unnamed_stmt_pstmt;		if (!pstmt)			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_PSTATEMENT),					 errmsg("unnamed prepared statement does not exist")));	}	if (numParams != list_length(pstmt->argtype_list))		ereport(ERROR,				(errcode(ERRCODE_PROTOCOL_VIOLATION),				 errmsg("bind message supplies %d parameters, but prepared statement \"%s\" requires %d",				   numParams, stmt_name, list_length(pstmt->argtype_list))));	/*	 * If we are in aborted transaction state, the only portals we can	 * actually run are those containing COMMIT or ROLLBACK commands. We	 * disallow binding anything else to avoid problems with infrastructure	 * that expects to run inside a valid transaction.	We also disallow	 * binding any parameters, since we can't risk calling user-defined I/O	 * functions.	 */	if (IsAbortedTransactionBlockState() &&

⌨️ 快捷键说明

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