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.
This commit is contained in:
parent
0e6d72db55
commit
2af360ed1c
@ -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)
|
|||||||
</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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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
|
|||||||
* 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)
|
|||||||
*
|
*
|
||||||
* 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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
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
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
(void)(!connectDBStart(conn) || !connectDBComplete(conn));
|
if (connectDBStart(conn))
|
||||||
|
(void) connectDBComplete(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn;
|
return 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)
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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
|
|||||||
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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
|
|
||||||
/* 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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
/* 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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
* 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)
|
|||||||
* 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)
|
if ((handle = PQsetenvStart(conn)) == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
do
|
for (;;) {
|
||||||
{
|
flag = PQsetenvPoll(handle);
|
||||||
if(pqWait(r, w, conn))
|
switch (flag)
|
||||||
{
|
|
||||||
/* XXX This is not a good sign - perhaps we should mark the
|
|
||||||
connection as bad here... */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
again:
|
|
||||||
switch(flag = PQsetenvPoll(handle))
|
|
||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
closePGconn(conn);
|
closePGconn(conn);
|
||||||
|
|
||||||
(void)(!connectDBStart(conn) || !connectDBComplete(conn));
|
if (connectDBStart(conn))
|
||||||
|
(void) connectDBComplete(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1863,7 +1863,7 @@ PQresetStart(PGconn *conn)
|
|||||||
return connectDBStart(conn);
|
return connectDBStart(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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"
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
/* 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 @@
|
|||||||
/* 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
|
|||||||
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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user