提交 2af360ed 编写于 作者: T Tom Lane

Clean up some problems in new asynchronous-connection logic

in libpq --- mostly, poor response to error conditions.  You now actually
get to see the postmaster's 'The Data Base System is starting up' message,
which you didn't before.  I suspect the SSL code is still broken though.
上级 0e6d72db
...@@ -323,23 +323,12 @@ PostgresPollingStatusType *PQconnectPoll(PQconn *conn) ...@@ -323,23 +323,12 @@ PostgresPollingStatusType *PQconnectPoll(PQconn *conn)
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
CONNECTION_AWAITING_RESPONSE: Waiting for a response from the backend. CONNECTION_AWAITING_RESPONSE: Waiting for a response from the postmaster.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
CONNECTION_AUTH_RESPONSE: Got an authentication response; about to deal CONNECTION_AUTH_OK: Received authentication; waiting for backend startup.
with it.
</para>
</listitem>
<listitem>
<para>
CONNECTION_ERROR_RESPONSE: Got an error response; about to deal with it.
</para>
</listitem>
<listitem>
<para>
CONNECTION_AUTH_OK: Received authentication; waiting for ReadyForQuery etc.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
...@@ -373,7 +362,7 @@ PostgresPollingStatusType *PQconnectPoll(PQconn *conn) ...@@ -373,7 +362,7 @@ PostgresPollingStatusType *PQconnectPoll(PQconn *conn)
</para> </para>
<para> <para>
Note that if PQconnectStart returns a non-NULL pointer, you must call Note that if PQconnectStart returns a non-NULL pointer, you must call
PQfinish upon that, when you are finished with it, in order to dispose of PQfinish when you are finished with it, in order to dispose of
the structure and any associated memory blocks. This must be done even if a the structure and any associated memory blocks. This must be done even if a
call to PQconnectStart or PQconnectPoll failed. call to PQconnectStart or PQconnectPoll failed.
</para> </para>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.108 1999/12/02 00:26:15 tgl Exp $ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.109 2000/01/14 05:33:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -218,15 +218,15 @@ static struct EnvironmentOptions ...@@ -218,15 +218,15 @@ static struct EnvironmentOptions
* You should call PQfinish (if conn is not NULL) regardless of whether this * You should call PQfinish (if conn is not NULL) regardless of whether this
* call succeeded. * call succeeded.
* *
* ---------------- */ * ----------------
*/
PGconn * PGconn *
PQconnectdb(const char *conninfo) PQconnectdb(const char *conninfo)
{ {
PGconn *conn = PQconnectStart(conninfo); PGconn *conn = PQconnectStart(conninfo);
(void)(!conn || (conn->status == CONNECTION_BAD) || if (conn && conn->status != CONNECTION_BAD)
!connectDBComplete(conn)); (void) connectDBComplete(conn);
return conn; return conn;
} }
...@@ -250,8 +250,8 @@ PQconnectdb(const char *conninfo) ...@@ -250,8 +250,8 @@ PQconnectdb(const char *conninfo)
* *
* See PQconnectPoll for more info. * See PQconnectPoll for more info.
* *
* ---------------- */ * ----------------
*/
PGconn * PGconn *
PQconnectStart(const char *conninfo) PQconnectStart(const char *conninfo)
{ {
...@@ -306,7 +306,7 @@ PQconnectStart(const char *conninfo) ...@@ -306,7 +306,7 @@ PQconnectStart(const char *conninfo)
*/ */
if (!connectDBStart(conn)) if (!connectDBStart(conn))
{ {
/* Just in case we failed to set it in connectDBStart */ /* Just in case we failed to set it in connectDBStart */
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
} }
...@@ -374,15 +374,13 @@ PQconndefaults(void) ...@@ -374,15 +374,13 @@ PQconndefaults(void)
* ---------------- * ----------------
*/ */
PGconn * PGconn *
PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName, const char *login, const char *pwd) PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
const char *pgtty, const char *dbName, const char *login,
const char *pwd)
{ {
PGconn *conn; PGconn *conn;
char *tmp; char *tmp; /* An error message from some service we call. */
bool error = FALSE; /* We encountered an error. */
/* An error message from some service we call. */
bool error = FALSE;
/* We encountered an error that prevents successful completion */
int i; int i;
conn = makeEmptyPGconn(); conn = makeEmptyPGconn();
...@@ -484,7 +482,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, cons ...@@ -484,7 +482,8 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, cons
} }
else else
{ {
(void)(!connectDBStart(conn) || !connectDBComplete(conn)); if (connectDBStart(conn))
(void) connectDBComplete(conn);
} }
return conn; return conn;
...@@ -676,8 +675,6 @@ connectDBStart(PGconn *conn) ...@@ -676,8 +675,6 @@ connectDBStart(PGconn *conn)
#ifdef USE_SSL #ifdef USE_SSL
StartupPacket np; /* Used to negotiate SSL connection */ StartupPacket np; /* Used to negotiate SSL connection */
char SSLok; char SSLok;
static int allow_ssl_try = 1; /* Allowed to do SSL negotiation */
int tried_ssl = 0; /* Set if SSL negotiation was tried */
#endif #endif
if (!conn) if (!conn)
...@@ -797,12 +794,11 @@ connectDBStart(PGconn *conn) ...@@ -797,12 +794,11 @@ connectDBStart(PGconn *conn)
#endif #endif
#ifdef USE_SSL #ifdef USE_SSL
/* This needs to be done before we set into nonblocking, since SSL negotiation /* This needs to be done before we set into nonblocking, since SSL
* does not like that mode */ * negotiation does not like that mode */
/* Attempt to negotiate SSL usage */ /* Attempt to negotiate SSL usage */
if (allow_ssl_try) { if (conn->allow_ssl_try) {
tried_ssl = 1;
memset((char *)&np, 0, sizeof(np)); memset((char *)&np, 0, sizeof(np));
np.protoVersion = htonl(NEGOTIATE_SSL_CODE); np.protoVersion = htonl(NEGOTIATE_SSL_CODE);
if (pqPacketSend(conn, (char *) &np, sizeof(StartupPacket)) != STATUS_OK) if (pqPacketSend(conn, (char *) &np, sizeof(StartupPacket)) != STATUS_OK)
...@@ -812,9 +808,9 @@ connectDBStart(PGconn *conn) ...@@ -812,9 +808,9 @@ connectDBStart(PGconn *conn)
errno, strerror(errno)); errno, strerror(errno));
goto connect_errReturn; goto connect_errReturn;
} }
/* Now receive the backends response */ /* Now receive the postmasters response */
if (recv(conn->sock, &SSLok, 1, 0) != 1) { if (recv(conn->sock, &SSLok, 1, 0) != 1) {
sprintf(conn->errorMessage, "PQconnectDB() -- couldn't read backend response: errno=%d\n%s\n", sprintf(conn->errorMessage, "PQconnectDB() -- couldn't read postmaster response: errno=%d\n%s\n",
errno, strerror(errno)); errno, strerror(errno));
goto connect_errReturn; goto connect_errReturn;
} }
...@@ -845,9 +841,9 @@ connectDBStart(PGconn *conn) ...@@ -845,9 +841,9 @@ connectDBStart(PGconn *conn)
else if (SSLok == 'E') { else if (SSLok == 'E') {
/* Received error - probably protocol mismatch */ /* Received error - probably protocol mismatch */
if (conn->Pfdebug) if (conn->Pfdebug)
fprintf(conn->Pfdebug, "Backend reports error, attempting fallback to pre-6.6.\n"); fprintf(conn->Pfdebug, "Postmaster reports error, attempting fallback to pre-6.6.\n");
close(conn->sock); close(conn->sock);
allow_ssl_try = 0; conn->allow_ssl_try = FALSE;
return connectDBStart(conn); return connectDBStart(conn);
} }
else if (SSLok != 'N') { else if (SSLok != 'N') {
...@@ -856,8 +852,6 @@ connectDBStart(PGconn *conn) ...@@ -856,8 +852,6 @@ connectDBStart(PGconn *conn)
goto connect_errReturn; goto connect_errReturn;
} }
} }
else
allow_ssl_try = 1; /* We'll allow an attempt to use SSL next time */
#endif #endif
/* ---------- /* ----------
...@@ -884,8 +878,8 @@ connectDBStart(PGconn *conn) ...@@ -884,8 +878,8 @@ connectDBStart(PGconn *conn)
/* Something's gone wrong */ /* Something's gone wrong */
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
"connectDBStart() -- connect() failed: %s\n" "connectDBStart() -- connect() failed: %s\n"
"Is the postmaster running%s at '%s' " "\tIs the postmaster running%s at '%s'\n"
"and accepting connections on %s '%s'?\n", "\tand accepting connections on %s '%s'?\n",
strerror(errno), strerror(errno),
(family == AF_INET) ? " (with -i)" : "", (family == AF_INET) ? " (with -i)" : "",
conn->pghost ? conn->pghost : "localhost", conn->pghost ? conn->pghost : "localhost",
...@@ -938,33 +932,31 @@ static int ...@@ -938,33 +932,31 @@ static int
connectDBComplete(PGconn *conn) connectDBComplete(PGconn *conn)
{ {
PostgresPollingStatusType flag; PostgresPollingStatusType flag;
int r = 0, w = 1;
do for (;;) {
{ flag = PQconnectPoll(conn);
if(pqWait(r, w, conn)) switch (flag)
{
conn->status = CONNECTION_BAD;
return 0;
}
again:
switch(flag = PQconnectPoll(conn))
{ {
case PGRES_POLLING_ACTIVE: case PGRES_POLLING_ACTIVE:
goto again; break;
case PGRES_POLLING_OK: case PGRES_POLLING_OK:
break; return 1; /* success! */
case PGRES_POLLING_READING: case PGRES_POLLING_READING:
r = 1; if (pqWait(1, 0, conn))
w = 0; {
conn->status = CONNECTION_BAD;
return 0;
}
break; break;
case PGRES_POLLING_WRITING: case PGRES_POLLING_WRITING:
r = 0; if (pqWait(0, 1, conn))
w = 1; {
conn->status = CONNECTION_BAD;
return 0;
}
break; break;
default: default:
...@@ -972,12 +964,9 @@ connectDBComplete(PGconn *conn) ...@@ -972,12 +964,9 @@ connectDBComplete(PGconn *conn)
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
return 0; return 0;
} }
} while (flag != PGRES_POLLING_OK); }
return 1;
} }
/* ---------------- /* ----------------
* PQconnectPoll * PQconnectPoll
* *
...@@ -993,17 +982,18 @@ connectDBComplete(PGconn *conn) ...@@ -993,17 +982,18 @@ connectDBComplete(PGconn *conn)
* there are a number of caveats: * there are a number of caveats:
* *
* o If you call PQtrace, ensure that the stream object into which you trace * o If you call PQtrace, ensure that the stream object into which you trace
will not block. * will not block.
* o If you do not supply an IP address for the remote host (i.e. you * o If you do not supply an IP address for the remote host (i.e. you
* supply a host name instead) then this function will block on * supply a host name instead) then this function will block on
* gethostbyname. You will be fine if using UDP (i.e. by supplying * gethostbyname. You will be fine if using Unix sockets (i.e. by
* neither a host name nor a host address). * supplying neither a host name nor a host address).
* o If your backend wants to use Kerberos authentication then you must * o If your backend wants to use Kerberos authentication then you must
* supply both a host name and a host address, otherwise this function * supply both a host name and a host address, otherwise this function
* may block on gethostname. * may block on gethostname.
* o This function will block if compiled with USE_SSL. * o This function will block if compiled with USE_SSL.
* *
* ---------------- */ * ----------------
*/
PostgresPollingStatusType PostgresPollingStatusType
PQconnectPoll(PGconn *conn) PQconnectPoll(PGconn *conn)
{ {
...@@ -1024,8 +1014,6 @@ PQconnectPoll(PGconn *conn) ...@@ -1024,8 +1014,6 @@ PQconnectPoll(PGconn *conn)
/* These are reading states */ /* These are reading states */
case CONNECTION_AWAITING_RESPONSE: case CONNECTION_AWAITING_RESPONSE:
case CONNECTION_AUTH_RESPONSE:
case CONNECTION_ERROR_RESPONSE:
case CONNECTION_AUTH_OK: case CONNECTION_AUTH_OK:
{ {
/* Load waiting data */ /* Load waiting data */
...@@ -1083,10 +1071,21 @@ PQconnectPoll(PGconn *conn) ...@@ -1083,10 +1071,21 @@ PQconnectPoll(PGconn *conn)
} }
else if (optval != 0) else if (optval != 0)
{ {
/*
* When using a nonblocking connect, we will typically see
* connect failures at this point, so provide a friendly
* error message.
*/
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
"PQconnectPoll() -- " "PQconnectPoll() -- connect() failed: %s\n"
"socket has error condition %d: %s.\n", "\tIs the postmaster running%s at '%s'\n"
optval, strerror(optval)); "\tand accepting connections on %s '%s'?\n",
strerror(optval),
(conn->raddr.sa.sa_family == AF_INET) ? " (with -i)" : "",
conn->pghost ? conn->pghost : "localhost",
(conn->raddr.sa.sa_family == AF_INET) ?
"TCP/IP port" : "Unix socket",
conn->pgport);
goto error_return; goto error_return;
} }
...@@ -1124,7 +1123,11 @@ PQconnectPoll(PGconn *conn) ...@@ -1124,7 +1123,11 @@ PQconnectPoll(PGconn *conn)
if (conn->pgoptions) if (conn->pgoptions)
strncpy(sp.options, conn->pgoptions, SM_OPTIONS); strncpy(sp.options, conn->pgoptions, SM_OPTIONS);
/* Send the startup packet. */ /* Send the startup packet.
*
* Theoretically, this could block, but it really shouldn't
* since we only got here if the socket is write-ready.
*/
if (pqPacketSend(conn, (char *) &sp, if (pqPacketSend(conn, (char *) &sp,
sizeof(StartupPacket)) != STATUS_OK) sizeof(StartupPacket)) != STATUS_OK)
...@@ -1141,16 +1144,19 @@ PQconnectPoll(PGconn *conn) ...@@ -1141,16 +1144,19 @@ PQconnectPoll(PGconn *conn)
return PGRES_POLLING_READING; return PGRES_POLLING_READING;
} }
/* /*
* Handle the authentication exchange: wait for backend messages * Handle the authentication exchange: wait for postmaster messages
* and respond as necessary. * and respond as necessary.
*/ */
case CONNECTION_AWAITING_RESPONSE: case CONNECTION_AWAITING_RESPONSE:
{ {
char beresp; char beresp;
AuthRequest areq;
/* Scan the message */ /* Scan the message from current point (note that if we find
* the message is incomplete, we will return without advancing
* inStart, and resume here next time).
*/
conn->inCursor = conn->inStart; conn->inCursor = conn->inStart;
if (pqGetc(&beresp, conn)) if (pqGetc(&beresp, conn))
...@@ -1162,28 +1168,29 @@ PQconnectPoll(PGconn *conn) ...@@ -1162,28 +1168,29 @@ PQconnectPoll(PGconn *conn)
/* Handle errors. */ /* Handle errors. */
if (beresp == 'E') if (beresp == 'E')
{ {
conn->status = CONNECTION_ERROR_RESPONSE; if (pqGets(&conn->errorMessage, conn))
goto keep_going; {
/* We'll come back when there are more data */
return PGRES_POLLING_READING;
}
/* OK, we read the message; mark data consumed */
conn->inStart = conn->inCursor;
/* The postmaster typically won't end its message with a
* newline, so add one to conform to libpq conventions.
*/
appendPQExpBufferChar(&conn->errorMessage, '\n');
goto error_return;
} }
/* Otherwise it should be an authentication request. */ /* Otherwise it should be an authentication request. */
if (beresp != 'R') if (beresp != 'R')
{ {
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
"PQconnectPoll() -- expected authentication " "PQconnectPoll() -- expected "
"request\n"); "authentication request\n");
goto error_return; goto error_return;
} }
/* Got an authentication request, so that's OK */
conn->status = CONNECTION_AUTH_RESPONSE;
goto keep_going;
}
case CONNECTION_AUTH_RESPONSE:
{
AuthRequest areq;
/* Get the type of request. */ /* Get the type of request. */
if (pqGetInt((int *) &areq, 4, conn)) if (pqGetInt((int *) &areq, 4, conn))
{ {
...@@ -1205,7 +1212,7 @@ PQconnectPoll(PGconn *conn) ...@@ -1205,7 +1212,7 @@ PQconnectPoll(PGconn *conn)
conn->inStart = conn->inCursor; conn->inStart = conn->inCursor;
/* Respond to the request if necessary. */ /* Respond to the request if necessary. */
/* Note that conn->pghost must be non-NULL if we are going /* Note that conn->pghost must be non-NULL if we are going to
* avoid the Kerberos code doing a hostname look-up. */ * avoid the Kerberos code doing a hostname look-up. */
/* XXX fe-auth.c has not been fixed to support PQExpBuffers, so: */ /* XXX fe-auth.c has not been fixed to support PQExpBuffers, so: */
if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass, if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
...@@ -1216,10 +1223,10 @@ PQconnectPoll(PGconn *conn) ...@@ -1216,10 +1223,10 @@ PQconnectPoll(PGconn *conn)
} }
conn->errorMessage.len = strlen(conn->errorMessage.data); conn->errorMessage.len = strlen(conn->errorMessage.data);
/* This function has a section near the end that looks like it /* Just make sure that any data sent by fe_sendauth is flushed
* should block. I think that it will be OK though, since the * out. Although this theoretically could block, it really
* socket is non-blocking, and thus the data should get out * shouldn't since we don't send large auth responses.
* as quickly as possible. */ */
if (pqFlush(conn)) if (pqFlush(conn))
goto error_return; goto error_return;
...@@ -1230,21 +1237,12 @@ PQconnectPoll(PGconn *conn) ...@@ -1230,21 +1237,12 @@ PQconnectPoll(PGconn *conn)
/* Set asyncStatus so that PQsetResult will think that what /* Set asyncStatus so that PQsetResult will think that what
* comes back next is the result of a query. See below. */ * comes back next is the result of a query. See below. */
conn->asyncStatus = PGASYNC_BUSY; conn->asyncStatus = PGASYNC_BUSY;
goto keep_going;
} }
conn->status = CONNECTION_AWAITING_RESPONSE; /* Look to see if we have more data yet. */
return PGRES_POLLING_READING; goto keep_going;
} }
case CONNECTION_ERROR_RESPONSE:
if (pqGets(&conn->errorMessage, conn))
{
/* We'll come back when there are more data */
return PGRES_POLLING_READING;
}
goto error_return;
case CONNECTION_AUTH_OK: case CONNECTION_AUTH_OK:
{ {
/* ---------- /* ----------
...@@ -1254,14 +1252,12 @@ PQconnectPoll(PGconn *conn) ...@@ -1254,14 +1252,12 @@ PQconnectPoll(PGconn *conn)
* messages indicating nonfatal warnings are also allowed by * messages indicating nonfatal warnings are also allowed by
* the protocol, as is a BackendKeyData message.) Easiest way * the protocol, as is a BackendKeyData message.) Easiest way
* to handle this is to let PQgetResult() read the messages. We * to handle this is to let PQgetResult() read the messages. We
* just have to fake it out about the state of the connection. * just have to fake it out about the state of the connection,
* by setting asyncStatus = PGASYNC_BUSY (done above).
*---------- *----------
*/ */
if (!PQconsumeInput(conn)) if (PQisBusy(conn))
goto error_return;
if(PQisBusy(conn))
return PGRES_POLLING_READING; return PGRES_POLLING_READING;
res = PQgetResult(conn); res = PQgetResult(conn);
...@@ -1273,13 +1269,21 @@ PQconnectPoll(PGconn *conn) ...@@ -1273,13 +1269,21 @@ PQconnectPoll(PGconn *conn)
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
"PQconnectPoll() -- unexpected message " "PQconnectPoll() -- unexpected message "
"during startup\n"); "during startup\n");
/* if the resultStatus is FATAL, then conn->errorMessage
* already has a copy of the error; needn't copy it back.
* But add a newline if it's not there already, since
* postmaster error messages may not have one.
*/
if (conn->errorMessage.len <= 0 ||
conn->errorMessage.data[conn->errorMessage.len-1] != '\n')
appendPQExpBufferChar(&conn->errorMessage, '\n');
PQclear(res); PQclear(res);
goto error_return; goto error_return;
} }
/* /*
* Post-connection housekeeping. Send environment variables * Post-connection housekeeping. Prepare to send environment
* to server. * variables to server.
*/ */
if ((conn->setenv_handle = PQsetenvStart(conn)) == NULL) if ((conn->setenv_handle = PQsetenvStart(conn)) == NULL)
...@@ -1292,10 +1296,10 @@ PQconnectPoll(PGconn *conn) ...@@ -1292,10 +1296,10 @@ PQconnectPoll(PGconn *conn)
case CONNECTION_SETENV: case CONNECTION_SETENV:
/* We pretend that the connection is OK for the duration of /* We pretend that the connection is OK for the duration of
theses queries. */ these queries. */
conn->status = CONNECTION_OK; conn->status = CONNECTION_OK;
switch(PQsetenvPoll(conn->setenv_handle)) switch (PQsetenvPoll(conn->setenv_handle))
{ {
case PGRES_POLLING_OK: /* Success */ case PGRES_POLLING_OK: /* Success */
conn->status = CONNECTION_OK; conn->status = CONNECTION_OK;
...@@ -1318,8 +1322,7 @@ PQconnectPoll(PGconn *conn) ...@@ -1318,8 +1322,7 @@ PQconnectPoll(PGconn *conn)
default: default:
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
"PQconnectPoll() -- unknown connection state - " "PQconnectPoll() -- unknown connection state - "
"probably indicative of memory corruption!\n", "probably indicative of memory corruption!\n");
sizeof(conn->errorMessage));
goto error_return; goto error_return;
} }
...@@ -1378,12 +1381,13 @@ PQsetenvStart(PGconn *conn) ...@@ -1378,12 +1381,13 @@ PQsetenvStart(PGconn *conn)
* Polls the process of passing the values of a standard set of environment * Polls the process of passing the values of a standard set of environment
* variables to the backend. * variables to the backend.
* *
* ---------------- */ * ----------------
*/
PostgresPollingStatusType PostgresPollingStatusType
PQsetenvPoll(PGsetenvHandle handle) PQsetenvPoll(PGsetenvHandle handle)
{ {
#ifdef MULTIBYTE #ifdef MULTIBYTE
const char envname[] = "PGCLIENTENCODING"; static const char envname[] = "PGCLIENTENCODING";
#endif #endif
if (!handle || handle->state == SETENV_STATE_FAILED) if (!handle || handle->state == SETENV_STATE_FAILED)
...@@ -1451,9 +1455,6 @@ PQsetenvPoll(PGsetenvHandle handle) ...@@ -1451,9 +1455,6 @@ PQsetenvPoll(PGsetenvHandle handle)
{ {
const char *encoding = 0; const char *encoding = 0;
if (!PQconsumeInput(handle->conn))
goto error_return;
if (PQisBusy(handle->conn)) if (PQisBusy(handle->conn))
return PGRES_POLLING_READING; return PGRES_POLLING_READING;
...@@ -1535,9 +1536,6 @@ PQsetenvPoll(PGsetenvHandle handle) ...@@ -1535,9 +1536,6 @@ PQsetenvPoll(PGsetenvHandle handle)
case SETENV_STATE_OPTION_WAIT: case SETENV_STATE_OPTION_WAIT:
{ {
if (!PQconsumeInput(handle->conn))
goto error_return;
if (PQisBusy(handle->conn)) if (PQisBusy(handle->conn))
return PGRES_POLLING_READING; return PGRES_POLLING_READING;
...@@ -1593,7 +1591,8 @@ PQsetenvPoll(PGsetenvHandle handle) ...@@ -1593,7 +1591,8 @@ PQsetenvPoll(PGsetenvHandle handle)
* Aborts the process of passing the values of a standard set of environment * Aborts the process of passing the values of a standard set of environment
* variables to the backend. * variables to the backend.
* *
* ---------------- */ * ----------------
*/
void void
PQsetenvAbort(PGsetenvHandle handle) PQsetenvAbort(PGsetenvHandle handle)
{ {
...@@ -1619,54 +1618,51 @@ PQsetenvAbort(PGsetenvHandle handle) ...@@ -1619,54 +1618,51 @@ PQsetenvAbort(PGsetenvHandle handle)
* compatibility problems caused by giving it a return value, especially as * compatibility problems caused by giving it a return value, especially as
* this function has not been documented previously. * this function has not been documented previously.
* *
* ---------------- */ * ----------------
*/
int int
PQsetenv(PGconn *conn) PQsetenv(PGconn *conn)
{ {
PostgresPollingStatusType flag;
PGsetenvHandle handle; PGsetenvHandle handle;
int r = 0, w = 1; PostgresPollingStatusType flag;
if((handle = PQsetenvStart(conn)) == NULL)
return 0;
do if ((handle = PQsetenvStart(conn)) == NULL)
{ return 0;
if(pqWait(r, w, conn))
{
/* XXX This is not a good sign - perhaps we should mark the
connection as bad here... */
return 0;
}
again: for (;;) {
switch(flag = PQsetenvPoll(handle)) flag = PQsetenvPoll(handle);
switch (flag)
{ {
case PGRES_POLLING_ACTIVE: case PGRES_POLLING_ACTIVE:
goto again; break;
case PGRES_POLLING_OK: case PGRES_POLLING_OK:
break; return 1; /* success! */
case PGRES_POLLING_READING: case PGRES_POLLING_READING:
r = 1; if (pqWait(1, 0, conn))
w = 0; {
conn->status = CONNECTION_BAD;
return 0;
}
break; break;
case PGRES_POLLING_WRITING: case PGRES_POLLING_WRITING:
r = 0; if (pqWait(0, 1, conn))
w = 1; {
conn->status = CONNECTION_BAD;
return 0;
}
break; break;
default: /* Failed */ default:
/* Just in case we failed to set it in PQconnectPoll */
conn->status = CONNECTION_BAD;
return 0; return 0;
} }
} while (flag != PGRES_POLLING_OK); }
return 1;
} }
/* /*
* makeEmptyPGconn * makeEmptyPGconn
* - create a PGconn data structure with (as yet) no interesting data * - create a PGconn data structure with (as yet) no interesting data
...@@ -1679,7 +1675,7 @@ makeEmptyPGconn(void) ...@@ -1679,7 +1675,7 @@ makeEmptyPGconn(void)
if (conn == NULL) if (conn == NULL)
return conn; return conn;
/* Zero all pointers */ /* Zero all pointers and booleans */
MemSet((char *) conn, 0, sizeof(PGconn)); MemSet((char *) conn, 0, sizeof(PGconn));
conn->noticeHook = defaultNoticeProcessor; conn->noticeHook = defaultNoticeProcessor;
...@@ -1687,6 +1683,10 @@ makeEmptyPGconn(void) ...@@ -1687,6 +1683,10 @@ makeEmptyPGconn(void)
conn->asyncStatus = PGASYNC_IDLE; conn->asyncStatus = PGASYNC_IDLE;
conn->notifyList = DLNewList(); conn->notifyList = DLNewList();
conn->sock = -1; conn->sock = -1;
#ifdef USE_SSL
conn->allow_ssl_try = TRUE;
#endif
/* /*
* The output buffer size is set to 8K, which is the usual size of pipe * The output buffer size is set to 8K, which is the usual size of pipe
* buffers on Unix systems. That way, when we are sending a large * buffers on Unix systems. That way, when we are sending a large
...@@ -1709,6 +1709,7 @@ makeEmptyPGconn(void) ...@@ -1709,6 +1709,7 @@ makeEmptyPGconn(void)
conn->errorMessage.data == NULL || conn->errorMessage.data == NULL ||
conn->workBuffer.data == NULL) conn->workBuffer.data == NULL)
{ {
/* out of memory already :-( */
freePGconn(conn); freePGconn(conn);
conn = NULL; conn = NULL;
} }
...@@ -1841,10 +1842,9 @@ PQreset(PGconn *conn) ...@@ -1841,10 +1842,9 @@ PQreset(PGconn *conn)
{ {
closePGconn(conn); closePGconn(conn);
(void)(!connectDBStart(conn) || !connectDBComplete(conn)); if (connectDBStart(conn))
(void) connectDBComplete(conn);
} }
return;
} }
...@@ -1863,7 +1863,7 @@ PQresetStart(PGconn *conn) ...@@ -1863,7 +1863,7 @@ PQresetStart(PGconn *conn)
return connectDBStart(conn); return connectDBStart(conn);
} }
return 1; return 0;
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: libpq-fe.h,v 1.53 1999/11/30 03:08:19 momjian Exp $ * $Id: libpq-fe.h,v 1.54 2000/01/14 05:33:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -41,16 +41,9 @@ extern "C" ...@@ -41,16 +41,9 @@ extern "C"
CONNECTION_STARTED, /* Waiting for connection to be made. */ CONNECTION_STARTED, /* Waiting for connection to be made. */
CONNECTION_MADE, /* Connection OK; waiting to send. */ CONNECTION_MADE, /* Connection OK; waiting to send. */
CONNECTION_AWAITING_RESPONSE, /* Waiting for a response CONNECTION_AWAITING_RESPONSE, /* Waiting for a response
from the backend. */ from the postmaster. */
CONNECTION_AUTH_RESPONSE, /* Got an authentication
response; about to deal
with it. */
CONNECTION_ERROR_RESPONSE, /* Got an error
response; about to deal
with it. */
CONNECTION_AUTH_OK, /* Received authentication; CONNECTION_AUTH_OK, /* Received authentication;
waiting for ReadyForQuery waiting for backend startup. */
etc. */
CONNECTION_SETENV /* Negotiating environment. */ CONNECTION_SETENV /* Negotiating environment. */
} ConnStatusType; } ConnStatusType;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: libpq-int.h,v 1.14 1999/11/30 03:08:19 momjian Exp $ * $Id: libpq-int.h,v 1.15 2000/01/14 05:33:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,10 +27,9 @@ ...@@ -27,10 +27,9 @@
/* include stuff found in fe only */ /* include stuff found in fe only */
#include "pqexpbuffer.h" #include "pqexpbuffer.h"
#ifdef USE_SSL #ifdef USE_SSL
#include "openssl/ssl.h" #include <openssl/ssl.h>
#include "openssl/err.h" #include <openssl/err.h>
#endif #endif
/* libpq supports this version of the frontend/backend protocol. /* libpq supports this version of the frontend/backend protocol.
...@@ -63,7 +62,7 @@ ...@@ -63,7 +62,7 @@
/* Subsidiary-storage management structure for PGresult. /* Subsidiary-storage management structure for PGresult.
* See space management routines in fe-exec.c for details. * See space management routines in fe-exec.c for details.
* Note that space[k] refers to the k'th byte starting from the physical * Note that space[k] refers to the k'th byte starting from the physical
* head of the block. * head of the block --- it's a union, not a struct!
*/ */
typedef union pgresult_data PGresult_data; typedef union pgresult_data PGresult_data;
...@@ -228,7 +227,8 @@ struct pg_conn ...@@ -228,7 +227,8 @@ struct pg_conn
PGsetenvHandle setenv_handle; PGsetenvHandle setenv_handle;
#ifdef USE_SSL #ifdef USE_SSL
SSL *ssl; bool allow_ssl_try; /* Allowed to try SSL negotiation */
SSL *ssl; /* SSL status, if have SSL connection */
#endif #endif
/* Buffer for current error message */ /* Buffer for current error message */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册