diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index f3030fb2c70c460f617424f374fed42741210d02..9c51166b40a5b83ec8e6479191fd48850390e830 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -391,9 +391,13 @@ pgthreadlock_t pg_g_threadlock = default_threadlock; * Close any physical connection to the server, and reset associated * state inside the connection object. We don't release state that * would be needed to reconnect, though. + * + * We can always flush the output buffer, since there's no longer any hope + * of sending that data. However, unprocessed input data might still be + * valuable, so the caller must tell us whether to flush that or not. */ void -pqDropConnection(PGconn *conn) +pqDropConnection(PGconn *conn, bool flushInput) { /* Drop any SSL state */ pqsecure_close(conn); @@ -401,8 +405,10 @@ pqDropConnection(PGconn *conn) if (conn->sock != PGINVALID_SOCKET) closesocket(conn->sock); conn->sock = PGINVALID_SOCKET; - /* Discard any unread/unsent data */ - conn->inStart = conn->inCursor = conn->inEnd = 0; + /* Optionally discard any unread data */ + if (flushInput) + conn->inStart = conn->inCursor = conn->inEnd = 0; + /* Always discard any unsent data */ conn->outCount = 0; } @@ -1510,7 +1516,7 @@ connectDBStart(PGconn *conn) return 1; connect_errReturn: - pqDropConnection(conn); + pqDropConnection(conn, true); conn->status = CONNECTION_BAD; return 0; } @@ -1732,7 +1738,7 @@ keep_going: /* We will come back to here until there is { if (!connectNoDelay(conn)) { - pqDropConnection(conn); + pqDropConnection(conn, true); conn->addr_cur = addr_cur->ai_next; continue; } @@ -1742,7 +1748,7 @@ keep_going: /* We will come back to here until there is appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to nonblocking mode: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - pqDropConnection(conn); + pqDropConnection(conn, true); conn->addr_cur = addr_cur->ai_next; continue; } @@ -1753,7 +1759,7 @@ keep_going: /* We will come back to here until there is appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to close-on-exec mode: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); - pqDropConnection(conn); + pqDropConnection(conn, true); conn->addr_cur = addr_cur->ai_next; continue; } @@ -1800,7 +1806,7 @@ keep_going: /* We will come back to here until there is if (err) { - pqDropConnection(conn); + pqDropConnection(conn, true); conn->addr_cur = addr_cur->ai_next; continue; } @@ -1887,7 +1893,7 @@ keep_going: /* We will come back to here until there is * failure and keep going if there are more addresses. */ connectFailureMessage(conn, SOCK_ERRNO); - pqDropConnection(conn); + pqDropConnection(conn, true); /* * Try the next address, if any. @@ -1932,7 +1938,7 @@ keep_going: /* We will come back to here until there is * error message. */ connectFailureMessage(conn, optval); - pqDropConnection(conn); + pqDropConnection(conn, true); /* * If more addresses remain, keep trying, just as in the @@ -2220,7 +2226,7 @@ keep_going: /* We will come back to here until there is /* only retry once */ conn->allow_ssl_try = false; /* Must drop the old connection */ - pqDropConnection(conn); + pqDropConnection(conn, true); conn->status = CONNECTION_NEEDED; goto keep_going; } @@ -2331,7 +2337,7 @@ keep_going: /* We will come back to here until there is { conn->pversion = PG_PROTOCOL(2, 0); /* Must drop the old connection */ - pqDropConnection(conn); + pqDropConnection(conn, true); conn->status = CONNECTION_NEEDED; goto keep_going; } @@ -2397,7 +2403,7 @@ keep_going: /* We will come back to here until there is /* only retry once */ conn->wait_ssl_try = false; /* Must drop the old connection */ - pqDropConnection(conn); + pqDropConnection(conn, true); conn->status = CONNECTION_NEEDED; goto keep_going; } @@ -2413,7 +2419,7 @@ keep_going: /* We will come back to here until there is /* only retry once */ conn->allow_ssl_try = false; /* Must drop the old connection */ - pqDropConnection(conn); + pqDropConnection(conn, true); conn->status = CONNECTION_NEEDED; goto keep_going; } @@ -2574,7 +2580,7 @@ keep_going: /* We will come back to here until there is PQclear(res); conn->send_appname = false; /* Must drop the old connection */ - pqDropConnection(conn); + pqDropConnection(conn, true); conn->status = CONNECTION_NEEDED; goto keep_going; } @@ -2971,7 +2977,7 @@ closePGconn(PGconn *conn) /* * Close the connection, reset all transient state, flush I/O buffers. */ - pqDropConnection(conn); + pqDropConnection(conn, true); conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just * absent */ conn->asyncStatus = PGASYNC_IDLE; diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 07c433552116082e29ba72280f6fdca2a78b987b..f71df324bd50a820683e84cd375f312c96085ec2 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -1553,8 +1553,10 @@ sendFailed: /* * pqHandleSendFailure: try to clean up after failure to send command. * - * Primarily, what we want to accomplish here is to process any messages that - * the backend might have sent just before it died. + * Primarily, what we want to accomplish here is to process any ERROR or + * NOTICE messages that the backend might have sent just before it died. + * Since we're in IDLE state, all such messages will get sent to the notice + * processor. * * NOTE: this routine should only be called in PGASYNC_IDLE state. */ @@ -1562,16 +1564,17 @@ void pqHandleSendFailure(PGconn *conn) { /* - * Accept and parse any available input data. 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. + * Accept and parse any available input data, ignoring I/O 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) parseInput(conn); /* - * Make one attempt to parse available input messages even if we read no - * data. + * Be sure to parse available input messages even if we read no data. + * (Note: calling parseInput within the above loop isn't really necessary, + * but it prevents buffer bloat if there's a lot of data available.) */ parseInput(conn); } diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 0dbcf7322270f0085d6fb9f8661fee1d716fd926..b7b53d3a71ca78ee4945b37f608b07fd5e82cf6e 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -815,7 +815,8 @@ definitelyEOF: /* Come here if lower-level code already set a suitable errorMessage */ definitelyFailed: - pqDropConnection(conn); + /* Do *not* drop any already-read data; caller still wants it */ + pqDropConnection(conn, false); conn->status = CONNECTION_BAD; /* No more connection to backend */ return -1; } diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 641804cb0680448f4e9779e60974668aae97bff9..f67e12c7dbebec5a2e988f6457d93ad44753a5ff 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -446,8 +446,8 @@ handleSyncLoss(PGconn *conn, char id, int msgLength) /* build an error result holding the error message */ pqSaveErrorResult(conn); conn->asyncStatus = PGASYNC_READY; /* drop out of GetResult wait loop */ - - pqDropConnection(conn); + /* flush input data since we're giving up on processing it */ + pqDropConnection(conn, true); conn->status = CONNECTION_BAD; /* No more connection to backend */ } diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 04d056e6a61465ee4f515eeb12657b5ecd32004a..4b69c1216dbe6baaf3d2905d7ce65648cdf0a2ef 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -515,7 +515,7 @@ extern char *const pgresStatus[]; /* === in fe-connect.c === */ -extern void pqDropConnection(PGconn *conn); +extern void pqDropConnection(PGconn *conn, bool flushInput); extern int pqPacketSend(PGconn *conn, char pack_type, const void *buf, size_t buf_len); extern bool pqGetHomeDirectory(char *buf, int bufsize);