postgres.c

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

C
2,390
字号
		(!IsTransactionExitStmtList(pstmt->query_list) ||		 numParams != 0))		ereport(ERROR,				(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),				 errmsg("current transaction is aborted, "						"commands ignored until end of transaction block")));	/*	 * Create the portal.  Allow silent replacement of an existing portal only	 * if the unnamed portal is specified.	 */	if (portal_name[0] == '\0')		portal = CreatePortal(portal_name, true, true);	else		portal = CreatePortal(portal_name, false, false);	/* We need to output the parameter values someday */	if (log_statement == LOGSTMT_ALL)		ereport(LOG,				(errmsg("statement: <BIND> %s", portal_name)));	/*	 * Fetch parameters, if any, and store in the portal's memory context.	 */	if (numParams > 0)	{		ListCell   *l;		MemoryContext oldContext;		oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));		params = (ParamListInfo)			palloc0((numParams + 1) * sizeof(ParamListInfoData));		i = 0;		foreach(l, pstmt->argtype_list)		{			Oid			ptype = lfirst_oid(l);			int32		plength;			bool		isNull;			plength = pq_getmsgint(input_message, 4);			isNull = (plength == -1);			if (!isNull)			{				const char *pvalue = pq_getmsgbytes(input_message, plength);				int16		pformat;				StringInfoData pbuf;				char		csave;				if (numPFormats > 1)					pformat = pformats[i];				else if (numPFormats > 0)					pformat = pformats[0];				else					pformat = 0;	/* default = text */				/*				 * Rather than copying data around, we just set up a phony				 * StringInfo pointing to the correct portion of the message				 * buffer.	We assume we can scribble on the message buffer so				 * as to maintain the convention that StringInfos have a				 * trailing null.  This is grotty but is a big win when				 * dealing with very large parameter strings.				 */				pbuf.data = (char *) pvalue;				pbuf.maxlen = plength + 1;				pbuf.len = plength;				pbuf.cursor = 0;				csave = pbuf.data[plength];				pbuf.data[plength] = '\0';				if (pformat == 0)				{					Oid			typinput;					Oid			typioparam;					char	   *pstring;					getTypeInputInfo(ptype, &typinput, &typioparam);					/*					 * We have to do encoding conversion before calling the					 * typinput routine.					 */					pstring = pg_client_to_server(pbuf.data, plength);					params[i].value =						OidFunctionCall3(typinput,										 CStringGetDatum(pstring),										 ObjectIdGetDatum(typioparam),										 Int32GetDatum(-1));					/* Free result of encoding conversion, if any */					if (pstring != pbuf.data)						pfree(pstring);				}				else if (pformat == 1)				{					Oid			typreceive;					Oid			typioparam;					/*					 * Call the parameter type's binary input converter					 */					getTypeBinaryInputInfo(ptype, &typreceive, &typioparam);					params[i].value =						OidFunctionCall3(typreceive,										 PointerGetDatum(&pbuf),										 ObjectIdGetDatum(typioparam),										 Int32GetDatum(-1));					/* Trouble if it didn't eat the whole buffer */					if (pbuf.cursor != pbuf.len)						ereport(ERROR,							 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),							  errmsg("incorrect binary data format in bind parameter %d",									 i + 1)));				}				else				{					ereport(ERROR,							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),							 errmsg("unsupported format code: %d",									pformat)));				}				/* Restore message buffer contents */				pbuf.data[plength] = csave;			}			params[i].kind = PARAM_NUM;			params[i].id = i + 1;			params[i].ptype = ptype;			params[i].isnull = isNull;			i++;		}		params[i].kind = PARAM_INVALID;		MemoryContextSwitchTo(oldContext);	}	else		params = NULL;	/* Get the result format codes */	numRFormats = pq_getmsgint(input_message, 2);	if (numRFormats > 0)	{		rformats = (int16 *) palloc(numRFormats * sizeof(int16));		for (i = 0; i < numRFormats; i++)			rformats[i] = pq_getmsgint(input_message, 2);	}	pq_getmsgend(input_message);	/*	 * If we didn't plan the query before, do it now.  This allows the planner	 * to make use of the concrete parameter values we now have.	 *	 * This happens only for unnamed statements, and so switching into the	 * statement context for planning is correct (see notes in	 * exec_parse_message).	 */	if (pstmt->plan_list == NIL && pstmt->query_list != NIL)	{		MemoryContext oldContext = MemoryContextSwitchTo(pstmt->context);		pstmt->plan_list = pg_plan_queries(pstmt->query_list, params, true);		MemoryContextSwitchTo(oldContext);	}	/*	 * Define portal and start execution.	 */	PortalDefineQuery(portal,					  pstmt->query_string,					  pstmt->commandTag,					  pstmt->query_list,					  pstmt->plan_list,					  pstmt->context);	PortalStart(portal, params, InvalidSnapshot);	/*	 * Apply the result format requests to the portal.	 */	PortalSetResultFormat(portal, numRFormats, rformats);	/*	 * Send BindComplete.	 */	if (whereToSendOutput == DestRemote)		pq_putemptymessage('2');}/* * exec_execute_message * * Process an "Execute" message for a portal */static voidexec_execute_message(const char *portal_name, long max_rows){	CommandDest dest;	DestReceiver *receiver;	Portal		portal;	bool		completed;	char		completionTag[COMPLETION_TAG_BUFSIZE];	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;	bool		execute_is_fetch = false;	/* Adjust destination to tell printtup.c what to do */	dest = whereToSendOutput;	if (dest == DestRemote)		dest = DestRemoteExecute;	portal = GetPortalByName(portal_name);	if (!PortalIsValid(portal))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_CURSOR),				 errmsg("portal \"%s\" does not exist", portal_name)));	/*	 * If we re-issue an Execute protocol request against an existing portal,	 * then we are only fetching more rows rather than completely re-executing	 * the query from the start. atStart is never reset for a v3 portal, so we	 * are safe to use this check.	 */	if (!portal->atStart)		execute_is_fetch = true;	/*	 * If the original query was a null string, just return	 * EmptyQueryResponse.	 */	if (portal->commandTag == NULL)	{		Assert(portal->parseTrees == NIL);		NullCommand(dest);		return;	}	/* Should we display the portal names here? */	if (execute_is_fetch)	{		debug_query_string = "fetch message";		pgstat_report_activity("<FETCH>");	}	else if (portal->sourceText)	{		debug_query_string = portal->sourceText;		pgstat_report_activity(portal->sourceText);	}	else	{		debug_query_string = "execute message";		pgstat_report_activity("<EXECUTE>");	}	set_ps_display(portal->commandTag);	/*	 * 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();	if (log_statement == LOGSTMT_ALL)		/* We have the portal, so output the source query. */		ereport(LOG,				(errmsg("statement: %sEXECUTE %s  [PREPARE:  %s]",						(execute_is_fetch) ? "FETCH from " : "",						(*portal_name != '\0') ? portal_name : "<unnamed>",						portal->sourceText ? portal->sourceText : "")));	BeginCommand(portal->commandTag, dest);	/*	 * Create dest receiver in MessageContext (we don't want it in transaction	 * context, because that may get deleted if portal contains VACUUM).	 */	receiver = CreateDestReceiver(dest, portal);	/*	 * Ensure we are in a transaction command (this should normally be the	 * case already due to prior BIND).	 */	start_xact_command();	/*	 * If we are in aborted transaction state, the only portals we can	 * actually run are those containing COMMIT or ROLLBACK commands.	 */	if (IsAbortedTransactionBlockState() &&		!IsTransactionExitStmtList(portal->parseTrees))		ereport(ERROR,				(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),				 errmsg("current transaction is aborted, "						"commands ignored until end of transaction block")));	/* Check for cancel signal before we start execution */	CHECK_FOR_INTERRUPTS();	/*	 * Okay to run the portal.	 */	if (max_rows <= 0)		max_rows = FETCH_ALL;	completed = PortalRun(portal,						  max_rows,						  receiver,						  receiver,						  completionTag);	(*receiver->rDestroy) (receiver);	if (completed)	{		if (IsTransactionStmtList(portal->parseTrees))		{			/*			 * 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		{			/*			 * We need a CommandCounterIncrement after every query, except			 * those that start or end a transaction block.			 */			CommandCounterIncrement();		}		/* Send appropriate CommandComplete to client */		EndCommand(completionTag, dest);	}	else	{		/* Portal run not complete, so send PortalSuspended */		if (whereToSendOutput == DestRemote)			pq_putemptymessage('s');	}	/*	 * 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 (log_statement == LOGSTMT_ALL && 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: %sEXECUTE %s  [PREPARE:  %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,							(execute_is_fetch) ? "FETCH from " : "",						  (*portal_name != '\0') ? portal_name : "<unnamed>",							portal->sourceText ? portal->sourceText : "")));	}	if (save_log_statement_stats)		ShowUsage("QUERY STATISTICS");	debug_query_string = NULL;}/* * exec_describe_statement_message * * Process a "Describe" message for a prepared statement */static voidexec_describe_statement_message(const char *stmt_name){	PreparedStatement *pstmt;	TupleDesc	tupdesc;	ListCell   *l;	StringInfoData buf;	/*	 * Start up a transaction command. (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);	/* 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 we are in aborted transaction state, we can't safely create a result	 * tupledesc, because that needs catalog accesses.  Hence, refuse to	 * Describe statements that return data.  (We shouldn't just refuse all	 * Describes, since that might break the ability of some clients to issue	 * COMMIT or ROLLBACK commands, if they use code that blindly Describes	 * whatever it does.)  We can Describe parameters without doing anything	 * dangerous, so we don't restrict that.	 */	if (IsAbortedTransactionBlockState() &&		PreparedStatementReturnsTuples(pstmt))		ereport(ERROR,				(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),				 errmsg("current transaction is aborted, "						"commands ignored until end of transaction block")));	if (whereToSendOutput != DestRemote)		return;					/* can't actually do anything... */	/*	 * First describe the parameters...	 */	pq_beginmessage(&buf, 't'); /* parameter description message type */	pq_sendint(&buf, list_length(pstmt->argtype_list), 2);	foreach(l, pstmt->argtype_list)	{		Oid			ptype = lfirst_oid(l);		pq_sendint(&buf, (int) ptype, 4);	}	pq_endmessage(&buf);	/*	 * Next send RowDescription or NoData to describe the result...	 */	tupdesc = FetchPreparedStatementResultDesc(pstmt);

⌨️ 快捷键说明

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