⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fe-protocol2.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * fe-protocol2.c *	  functions that are specific to frontend/backend protocol version 2 * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol2.c,v 1.19.2.1 2005/11/22 18:23:30 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres_fe.h"#include <errno.h>#include <ctype.h>#include <fcntl.h>#include "libpq-fe.h"#include "libpq-int.h"#include "mb/pg_wchar.h"#ifdef WIN32#include "win32.h"#else#include <unistd.h>#include <netinet/in.h>#ifdef HAVE_NETINET_TCP_H#include <netinet/tcp.h>#endif#include <arpa/inet.h>#endifstatic int	getRowDescriptions(PGconn *conn);static int	getAnotherTuple(PGconn *conn, bool binary);static int	pqGetErrorNotice2(PGconn *conn, bool isError);static void checkXactStatus(PGconn *conn, const char *cmdTag);static int	getNotify(PGconn *conn);/* *		pqSetenvPoll * * Polls the process of passing the values of a standard set of environment * variables to the backend. */PostgresPollingStatusTypepqSetenvPoll(PGconn *conn){	PGresult   *res;	if (conn == NULL || conn->status == CONNECTION_BAD)		return PGRES_POLLING_FAILED;	/* Check whether there are any data for us */	switch (conn->setenv_state)	{			/* These are reading states */		case SETENV_STATE_OPTION_WAIT:		case SETENV_STATE_QUERY1_WAIT:		case SETENV_STATE_QUERY2_WAIT:			{				/* Load waiting data */				int			n = pqReadData(conn);				if (n < 0)					goto error_return;				if (n == 0)					return PGRES_POLLING_READING;				break;			}			/* These are writing states, so we just proceed. */		case SETENV_STATE_OPTION_SEND:		case SETENV_STATE_QUERY1_SEND:		case SETENV_STATE_QUERY2_SEND:			break;			/* Should we raise an error if called when not active? */		case SETENV_STATE_IDLE:			return PGRES_POLLING_OK;		default:			printfPQExpBuffer(&conn->errorMessage,							  libpq_gettext(											"invalid setenv state %c, "								 "probably indicative of memory corruption\n"											),							  conn->setenv_state);			goto error_return;	}	/* We will loop here until there is nothing left to do in this call. */	for (;;)	{		switch (conn->setenv_state)		{			case SETENV_STATE_OPTION_SEND:				{					/*					 * Send SET commands for stuff directed by Environment					 * Options.  Note: we assume that SET commands won't start					 * transaction blocks, even in a 7.3 server with					 * autocommit off.					 */					char		setQuery[100];	/* note length limit in												 * sprintf below */					if (conn->next_eo->envName)					{						const char *val;						if ((val = getenv(conn->next_eo->envName)))						{							if (pg_strcasecmp(val, "default") == 0)								sprintf(setQuery, "SET %s = DEFAULT",										conn->next_eo->pgName);							else								sprintf(setQuery, "SET %s = '%.60s'",										conn->next_eo->pgName, val);#ifdef CONNECTDEBUG							fprintf(stderr,								  "Use environment variable %s to send %s\n",									conn->next_eo->envName, setQuery);#endif							if (!PQsendQuery(conn, setQuery))								goto error_return;							conn->setenv_state = SETENV_STATE_OPTION_WAIT;						}						else							conn->next_eo++;					}					else					{						/* No more options to send, so move on to querying */						conn->setenv_state = SETENV_STATE_QUERY1_SEND;					}					break;				}			case SETENV_STATE_OPTION_WAIT:				{					if (PQisBusy(conn))						return PGRES_POLLING_READING;					res = PQgetResult(conn);					if (res)					{						if (PQresultStatus(res) != PGRES_COMMAND_OK)						{							PQclear(res);							goto error_return;						}						PQclear(res);						/* Keep reading until PQgetResult returns NULL */					}					else					{						/* Query finished, so send the next option */						conn->next_eo++;						conn->setenv_state = SETENV_STATE_OPTION_SEND;					}					break;				}			case SETENV_STATE_QUERY1_SEND:				{					/*					 * Issue query to get information we need.	Here we must					 * use begin/commit in case autocommit is off by default					 * in a 7.3 server.					 *					 * Note: version() exists in all protocol-2.0-supporting					 * backends.  In 7.3 it would be safer to write					 * pg_catalog.version(), but we can't do that without					 * causing problems on older versions.					 */					if (!PQsendQuery(conn, "begin; select version(); end"))						goto error_return;					conn->setenv_state = SETENV_STATE_QUERY1_WAIT;					return PGRES_POLLING_READING;				}			case SETENV_STATE_QUERY1_WAIT:				{					if (PQisBusy(conn))						return PGRES_POLLING_READING;					res = PQgetResult(conn);					if (res)					{						char	   *val;						if (PQresultStatus(res) == PGRES_COMMAND_OK)						{							/* ignore begin/commit command results */							PQclear(res);							continue;						}						if (PQresultStatus(res) != PGRES_TUPLES_OK ||							PQntuples(res) != 1)						{							PQclear(res);							goto error_return;						}						/*						 * Extract server version and save as if						 * ParameterStatus						 */						val = PQgetvalue(res, 0, 0);						if (val && strncmp(val, "PostgreSQL ", 11) == 0)						{							char	   *ptr;							/* strip off PostgreSQL part */							val += 11;							/*							 * strip off platform part (scribbles on result,							 * naughty naughty)							 */							ptr = strchr(val, ' ');							if (ptr)								*ptr = '\0';							pqSaveParameterStatus(conn, "server_version",												  val);						}						PQclear(res);						/* Keep reading until PQgetResult returns NULL */					}					else					{						/* Query finished, move to next */						conn->setenv_state = SETENV_STATE_QUERY2_SEND;					}					break;				}			case SETENV_STATE_QUERY2_SEND:				{					const char *query;					/*					 * pg_client_encoding does not exist in pre-7.2 servers.					 * So we need to be prepared for an error here.  Do *not*					 * start a transaction block, except in 7.3 servers where					 * we need to prevent autocommit-off from starting a					 * transaction anyway.					 */					if (conn->sversion >= 70300 &&						conn->sversion < 70400)						query = "begin; select pg_catalog.pg_client_encoding(); end";					else						query = "select pg_client_encoding()";					if (!PQsendQuery(conn, query))						goto error_return;					conn->setenv_state = SETENV_STATE_QUERY2_WAIT;					return PGRES_POLLING_READING;				}			case SETENV_STATE_QUERY2_WAIT:				{					if (PQisBusy(conn))						return PGRES_POLLING_READING;					res = PQgetResult(conn);					if (res)					{						const char *val;						if (PQresultStatus(res) == PGRES_COMMAND_OK)						{							/* ignore begin/commit command results */							PQclear(res);							continue;						}						if (PQresultStatus(res) == PGRES_TUPLES_OK &&							PQntuples(res) == 1)						{							/* Extract client encoding and save it */							val = PQgetvalue(res, 0, 0);							if (val && *val)	/* null should not happen, but */								pqSaveParameterStatus(conn, "client_encoding",													  val);						}						else						{							/*							 * Error: presumably function not available, so							 * use PGCLIENTENCODING or SQL_ASCII as the							 * fallback.							 */							val = getenv("PGCLIENTENCODING");							if (val && *val)								pqSaveParameterStatus(conn, "client_encoding",													  val);							else								pqSaveParameterStatus(conn, "client_encoding",													  "SQL_ASCII");						}						PQclear(res);						/* Keep reading until PQgetResult returns NULL */					}					else					{						/* Query finished, so we're done */						conn->setenv_state = SETENV_STATE_IDLE;						return PGRES_POLLING_OK;					}					break;				}			default:				printfPQExpBuffer(&conn->errorMessage,								  libpq_gettext("invalid state %c, "							   "probably indicative of memory corruption\n"),								  conn->setenv_state);				goto error_return;		}	}	/* Unreachable */error_return:	conn->setenv_state = SETENV_STATE_IDLE;	return PGRES_POLLING_FAILED;}/* * parseInput: if appropriate, parse input data from backend * until input is exhausted or a stopping state is reached. * Note that this function will NOT attempt to read more data from the backend. */voidpqParseInput2(PGconn *conn){	char		id;	/*	 * Loop to parse successive complete messages available in the buffer.	 */	for (;;)	{		/*		 * Quit if in COPY_OUT state: we expect raw data from the server until		 * PQendcopy is called.  Don't try to parse it according to the normal		 * protocol.  (This is bogus.  The data lines ought to be part of the		 * protocol and have identifying leading characters.)		 */		if (conn->asyncStatus == PGASYNC_COPY_OUT)			return;		/*		 * OK to try to read a message type code.		 */		conn->inCursor = conn->inStart;		if (pqGetc(&id, conn))			return;		/*		 * NOTIFY and NOTICE messages can happen in any state besides COPY		 * OUT; always process them right away.		 *		 * Most other messages should only be processed while in BUSY state.		 * (In particular, in READY state we hold off further parsing until		 * the application collects the current PGresult.)		 *		 * However, if the state is IDLE then we got trouble; we need to deal		 * with the unexpected message somehow.		 */		if (id == 'A')		{			if (getNotify(conn))				return;		}		else if (id == 'N')		{			if (pqGetErrorNotice2(conn, false))				return;		}		else if (conn->asyncStatus != PGASYNC_BUSY)		{			/* If not IDLE state, just wait ... */			if (conn->asyncStatus != PGASYNC_IDLE)				return;			/*			 * Unexpected message in IDLE state; need to recover somehow.			 * ERROR messages are displayed using the notice processor;			 * anything else is just dropped on the floor after displaying a			 * suitable warning notice.  (An ERROR is very possibly the			 * backend telling us why it is about to close the connection, so			 * we don't want to just discard it...)			 */			if (id == 'E')			{				if (pqGetErrorNotice2(conn, false /* treat as notice */ ))					return;			}			else			{				pqInternalNotice(&conn->noticeHooks,						"message type 0x%02x arrived from server while idle",								 id);				/* Discard the unexpected message; good idea?? */				conn->inStart = conn->inEnd;				break;			}		}		else		{			/*			 * In BUSY state, we can process everything.			 */			switch (id)			{				case 'C':		/* command complete */					if (pqGets(&conn->workBuffer, conn))						return;					if (conn->result == NULL)					{						conn->result = PQmakeEmptyPGresult(conn,														   PGRES_COMMAND_OK);						if (!conn->result)							return;					}					strncpy(conn->result->cmdStatus, conn->workBuffer.data,							CMDSTATUS_LEN);					checkXactStatus(conn, conn->workBuffer.data);					conn->asyncStatus = PGASYNC_READY;					break;				case 'E':		/* error return */					if (pqGetErrorNotice2(conn, true))						return;					conn->asyncStatus = PGASYNC_READY;					break;				case 'Z':		/* backend is ready for new query */					conn->asyncStatus = PGASYNC_IDLE;					break;				case 'I':		/* empty query */					/* read and throw away the closing '\0' */					if (pqGetc(&id, conn))						return;					if (id != '\0')						pqInternalNotice(&conn->noticeHooks,										 "unexpected character %c following empty query response (\"I\" message)",										 id);					if (conn->result == NULL)						conn->result = PQmakeEmptyPGresult(conn,														   PGRES_EMPTY_QUERY);					conn->asyncStatus = PGASYNC_READY;					break;				case 'K':		/* secret key data from the backend */					/*					 * This is expected only during backend startup, but it's					 * just as easy to handle it as part of the main loop.					 * Save the data and continue processing.					 */					if (pqGetInt(&(conn->be_pid), 4, conn))						return;					if (pqGetInt(&(conn->be_key), 4, conn))						return;					break;

⌨️ 快捷键说明

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