fe-exec.c

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

C
2,443
字号
	 * convert server version to a numeric form as well.	 */	if (strcmp(name, "client_encoding") == 0)		conn->client_encoding = pg_char_to_encoding(value);	else if (strcmp(name, "server_version") == 0)	{		int			cnt;		int			vmaj,					vmin,					vrev;		cnt = sscanf(value, "%d.%d.%d", &vmaj, &vmin, &vrev);		if (cnt < 2)			conn->sversion = 0;			/* unknown */		else		{			if (cnt == 2)				vrev = 0;			conn->sversion = (100 * vmaj + vmin) * 100 + vrev;		}	}}/* * PQsendQuery *	 Submit a query, but don't wait for it to finish * * Returns: 1 if successfully submitted *			0 if error (conn->errorMessage is set) */intPQsendQuery(PGconn *conn, const char *query){	if (!PQsendQueryStart(conn))		return 0;	if (!query)	{		printfPQExpBuffer(&conn->errorMessage,					libpq_gettext("command string is a null pointer\n"));		return 0;	}	/* construct the outgoing Query message */	if (pqPutMsgStart('Q', false, conn) < 0 ||		pqPuts(query, conn) < 0 ||		pqPutMsgEnd(conn) < 0)	{		pqHandleSendFailure(conn);		return 0;	}	/* remember we are using simple query protocol */	conn->ext_query = false;	/*	 * Give the data a push.  In nonblock mode, don't complain if we're	 * unable to send it all; PQgetResult() will do any additional	 * flushing needed.	 */	if (pqFlush(conn) < 0)	{		pqHandleSendFailure(conn);		return 0;	}	/* OK, it's launched! */	conn->asyncStatus = PGASYNC_BUSY;	return 1;}/* * PQsendQueryParams *		Like PQsendQuery, but use protocol 3.0 so we can pass parameters */intPQsendQueryParams(PGconn *conn,				  const char *command,				  int nParams,				  const Oid *paramTypes,				  const char *const * paramValues,				  const int *paramLengths,				  const int *paramFormats,				  int resultFormat){	if (!PQsendQueryStart(conn))		return 0;	if (!command)	{		printfPQExpBuffer(&conn->errorMessage,					libpq_gettext("command string is a null pointer\n"));		return 0;	}	return PQsendQueryGuts(conn,						   command,						   "",	/* use unnamed statement */						   nParams,						   paramTypes,						   paramValues,						   paramLengths,						   paramFormats,						   resultFormat);}/* * PQsendQueryPrepared *		Like PQsendQuery, but execute a previously prepared statement, *		using protocol 3.0 so we can pass parameters */intPQsendQueryPrepared(PGconn *conn,					const char *stmtName,					int nParams,					const char *const * paramValues,					const int *paramLengths,					const int *paramFormats,					int resultFormat){	if (!PQsendQueryStart(conn))		return 0;	if (!stmtName)	{		printfPQExpBuffer(&conn->errorMessage,						  libpq_gettext("statement name is a null pointer\n"));		return 0;	}	return PQsendQueryGuts(conn,						   NULL, /* no command to parse */						   stmtName,						   nParams,						   NULL, /* no param types */						   paramValues,						   paramLengths,						   paramFormats,						   resultFormat);}/* * Common startup code for PQsendQuery and sibling routines */static boolPQsendQueryStart(PGconn *conn){	if (!conn)		return false;	/* clear the error string */	resetPQExpBuffer(&conn->errorMessage);	/* Don't try to send if we know there's no live connection. */	if (conn->status != CONNECTION_OK)	{		printfPQExpBuffer(&conn->errorMessage,						  libpq_gettext("no connection to the server\n"));		return false;	}	/* Can't send while already busy, either. */	if (conn->asyncStatus != PGASYNC_IDLE)	{		printfPQExpBuffer(&conn->errorMessage,			  libpq_gettext("another command is already in progress\n"));		return false;	}	/* initialize async result-accumulation state */	conn->result = NULL;	conn->curTuple = NULL;	/* ready to send command message */	return true;}/* * PQsendQueryGuts *		Common code for protocol-3.0 query sending *		PQsendQueryStart should be done already * * command may be NULL to indicate we use an already-prepared statement */static intPQsendQueryGuts(PGconn *conn,				const char *command,				const char *stmtName,				int nParams,				const Oid *paramTypes,				const char *const * paramValues,				const int *paramLengths,				const int *paramFormats,				int resultFormat){	int			i;	/* This isn't gonna work on a 2.0 server */	if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)	{		printfPQExpBuffer(&conn->errorMessage,			 libpq_gettext("function requires at least protocol version 3.0\n"));		return 0;	}	/*	 * We will send Parse (if needed), Bind, Describe Portal, Execute, Sync,	 * using specified statement name and the unnamed portal.	 */	if (command)	{		/* construct the Parse message */		if (pqPutMsgStart('P', false, conn) < 0 ||			pqPuts(stmtName, conn) < 0 ||			pqPuts(command, conn) < 0)			goto sendFailed;		if (nParams > 0 && paramTypes)		{			if (pqPutInt(nParams, 2, conn) < 0)				goto sendFailed;			for (i = 0; i < nParams; i++)			{				if (pqPutInt(paramTypes[i], 4, conn) < 0)					goto sendFailed;			}		}		else		{			if (pqPutInt(0, 2, conn) < 0)				goto sendFailed;		}		if (pqPutMsgEnd(conn) < 0)			goto sendFailed;	}	/* construct the Bind message */	if (pqPutMsgStart('B', false, conn) < 0 ||		pqPuts("", conn) < 0 ||		pqPuts(stmtName, conn) < 0)		goto sendFailed;	if (nParams > 0 && paramFormats)	{		if (pqPutInt(nParams, 2, conn) < 0)			goto sendFailed;		for (i = 0; i < nParams; i++)		{			if (pqPutInt(paramFormats[i], 2, conn) < 0)				goto sendFailed;		}	}	else	{		if (pqPutInt(0, 2, conn) < 0)			goto sendFailed;	}	if (pqPutInt(nParams, 2, conn) < 0)		goto sendFailed;	for (i = 0; i < nParams; i++)	{		if (paramValues && paramValues[i])		{			int			nbytes;			if (paramFormats && paramFormats[i] != 0)			{				/* binary parameter */				nbytes = paramLengths[i];			}			else			{				/* text parameter, do not use paramLengths */				nbytes = strlen(paramValues[i]);			}			if (pqPutInt(nbytes, 4, conn) < 0 ||				pqPutnchar(paramValues[i], nbytes, conn) < 0)				goto sendFailed;		}		else		{			/* take the param as NULL */			if (pqPutInt(-1, 4, conn) < 0)				goto sendFailed;		}	}	if (pqPutInt(1, 2, conn) < 0 ||		pqPutInt(resultFormat, 2, conn))		goto sendFailed;	if (pqPutMsgEnd(conn) < 0)		goto sendFailed;	/* construct the Describe Portal message */	if (pqPutMsgStart('D', false, conn) < 0 ||		pqPutc('P', conn) < 0 ||		pqPuts("", conn) < 0 ||		pqPutMsgEnd(conn) < 0)		goto sendFailed;	/* construct the Execute message */	if (pqPutMsgStart('E', false, conn) < 0 ||		pqPuts("", conn) < 0 ||		pqPutInt(0, 4, conn) < 0 ||		pqPutMsgEnd(conn) < 0)		goto sendFailed;	/* construct the Sync message */	if (pqPutMsgStart('S', false, conn) < 0 ||		pqPutMsgEnd(conn) < 0)		goto sendFailed;	/* remember we are using extended query protocol */	conn->ext_query = true;	/*	 * Give the data a push.  In nonblock mode, don't complain if we're	 * unable to send it all; PQgetResult() will do any additional	 * flushing needed.	 */	if (pqFlush(conn) < 0)		goto sendFailed;	/* OK, it's launched! */	conn->asyncStatus = PGASYNC_BUSY;	return 1;sendFailed:	pqHandleSendFailure(conn);	return 0;}/* * pqHandleSendFailure: try to clean up after failure to send command. * * Primarily, what we want to accomplish here is to process an async * NOTICE message that the backend might have sent just before it died. * * NOTE: this routine should only be called in PGASYNC_IDLE state. */voidpqHandleSendFailure(PGconn *conn){	/*	 * Accept any available input data, ignoring errors.  Note that if	 * pqReadData decides the backend has closed the channel, it will	 * close our side of the socket --- that's just what we want here.	 */	while (pqReadData(conn) > 0)		 /* loop until no more data readable */ ;	/*	 * Parse any available input messages.	Since we are in PGASYNC_IDLE	 * state, only NOTICE and NOTIFY messages will be eaten.	 */	parseInput(conn);}/* * Consume any available input from the backend * 0 return: some kind of trouble * 1 return: no problem */intPQconsumeInput(PGconn *conn){	if (!conn)		return 0;	/*	 * for non-blocking connections try to flush the send-queue, otherwise	 * we may never get a response for something that may not have already	 * been sent because it's in our write buffer!	 */	if (pqIsnonblocking(conn))	{		if (pqFlush(conn) < 0)			return 0;	}	/*	 * Load more data, if available. We do this no matter what state we	 * are in, since we are probably getting called because the	 * application wants to get rid of a read-select condition. Note that	 * we will NOT block waiting for more input.	 */	if (pqReadData(conn) < 0)		return 0;	/* Parsing of the data waits till later. */	return 1;}/* * 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. */static voidparseInput(PGconn *conn){	if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)		pqParseInput3(conn);	else		pqParseInput2(conn);}/* * PQisBusy *	 Return TRUE if PQgetResult would block waiting for input. */intPQisBusy(PGconn *conn){	if (!conn)		return FALSE;	/* Parse any available data, if our state permits. */	parseInput(conn);	/* PQgetResult will return immediately in all states except BUSY. */	return conn->asyncStatus == PGASYNC_BUSY;}/* * PQgetResult *	  Get the next PGresult produced by a query. *	  Returns NULL if and only if no query work remains. */PGresult *PQgetResult(PGconn *conn){	PGresult   *res;	if (!conn)		return NULL;	/* Parse any available data, if our state permits. */	parseInput(conn);	/* If not ready to return something, block until we are. */	while (conn->asyncStatus == PGASYNC_BUSY)	{		int			flushResult;		/*		 * If data remains unsent, send it.  Else we might be waiting for		 * the result of a command the backend hasn't even got yet.		 */		while ((flushResult = pqFlush(conn)) > 0)		{			if (pqWait(FALSE, TRUE, conn))			{				flushResult = -1;				break;			}		}		/* Wait for some more data, and load it. */		if (flushResult ||			pqWait(TRUE, FALSE, conn) ||			pqReadData(conn) < 0)		{			/*			 * conn->errorMessage has been set by pqWait or pqReadData. We			 * want to append it to any already-received error message.			 */			pqSaveErrorResult(conn);			conn->asyncStatus = PGASYNC_IDLE;			return pqPrepareAsyncResult(conn);		}		/* Parse it. */		parseInput(conn);	}	/* Return the appropriate thing. */	switch (conn->asyncStatus)	{		case PGASYNC_IDLE:			res = NULL;			/* query is complete */			break;		case PGASYNC_READY:			res = pqPrepareAsyncResult(conn);			/* Set the state back to BUSY, allowing parsing to proceed. */			conn->asyncStatus = PGASYNC_BUSY;			break;		case PGASYNC_COPY_IN:			if (conn->result && conn->result->resultStatus == PGRES_COPY_IN)				res = pqPrepareAsyncResult(conn);			else				res = PQmakeEmptyPGresult(conn, PGRES_COPY_IN);			break;		case PGASYNC_COPY_OUT:			if (conn->result && conn->result->resultStatus == PGRES_COPY_OUT)				res = pqPrepareAsyncResult(conn);			else				res = PQmakeEmptyPGresult(conn, PGRES_COPY_OUT);			break;		default:			printfPQExpBuffer(&conn->errorMessage,						   libpq_gettext("unexpected asyncStatus: %d\n"),							  (int) conn->asyncStatus);			res = PQmakeEmptyPGresult(conn, PGRES_FATAL_ERROR);			break;	}	return res;}/* * PQexec *	  send a query to the backend and package up the result in a PGresult * * If the query was not even sent, return NULL; conn->errorMessage is set to * a relevant message. * If the query was sent, a new PGresult is returned (which could indicate * either success or failure). * The user is responsible for freeing the PGresult via PQclear() * when done with it. */PGresult *PQexec(PGconn *conn, const char *query){	if (!PQexecStart(conn))		return NULL;	if (!PQsendQuery(conn, query))		return NULL;	return PQexecFinish(conn);}/* * PQexecParams *		Like PQexec, but use protocol 3.0 so we can pass parameters */PGresult *PQexecParams(PGconn *conn,			 const char *command,			 int nParams,			 const Oid *paramTypes,			 const char *const * paramValues,			 const int *paramLengths,			 const int *paramFormats,			 int resultFormat){	if (!PQexecStart(conn))		return NULL;	if (!PQsendQueryParams(conn, command,						   nParams, paramTypes, paramValues, paramLengths,						   paramFormats, resultFormat))		return NULL;	return PQexecFinish(conn);}/* * PQexecPrepared *		Like PQexec, but execute a previously prepared statement, *		using protocol 3.0 so we can pass parameters */PGresult *PQexecPrepared(PGconn *conn,			   const char *stmtName,			   int nParams,			   const char *const * paramValues,			   const int *paramLengths,			   const int *paramFormats,			   int resultFormat){	if (!PQexecStart(conn))		return NULL;	if (!PQsendQueryPrepared(conn, stmtName,							 nParams, paramValues, paramLengths,							 paramFormats, resultFormat))		return NULL;	return PQexecFinish(conn);}/* * Common code for PQexec and sibling routines: prepare to send command */static boolPQexecStart(PGconn *conn){	PGresult   *result;	if (!conn)		return false;	/*	 * Silently discard any prior query result that application didn't	 * eat. This is probably poor design, but it's here for backward	 * compatibility.	 */	while ((result = PQgetResult(conn)) != NULL)	{		ExecStatusType resultStatus = result->resultStatus;		PQclear(result);		/* only need its status */		if (resultStatus == PGRES_COPY_IN)		{			if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)			{				/* In protocol 3, we can get out of a COPY IN state */				if (PQputCopyEnd(conn,					 libpq_gettext("COPY terminated by new PQexec")) < 0)					return false;

⌨️ 快捷键说明

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