Handle errors that are discovered during abort

pull/1979/head
Marco Slot 2018-01-26 18:35:18 +01:00
parent d9c5c4a8f1
commit 6051aae56e
3 changed files with 31 additions and 11 deletions

View File

@ -58,7 +58,7 @@ IsResponseOK(PGresult *result)
* ForgetResults clears a connection from pending activity. * ForgetResults clears a connection from pending activity.
* *
* Note that this might require network IO. If that's not acceptable, use * Note that this might require network IO. If that's not acceptable, use
* NonblockingForgetResults(). * ClearResultsIfReady().
* *
* ClearResults is variant of this function which can also raise errors. * ClearResults is variant of this function which can also raise errors.
*/ */
@ -93,7 +93,7 @@ ForgetResults(MultiConnection *connection)
* is marked critical. * is marked critical.
* *
* Note that this might require network IO. If that's not acceptable, use * Note that this might require network IO. If that's not acceptable, use
* NonblockingForgetResults(). * ClearResultsIfReady().
*/ */
bool bool
ClearResults(MultiConnection *connection, bool raiseErrors) ClearResults(MultiConnection *connection, bool raiseErrors)
@ -133,12 +133,12 @@ ClearResults(MultiConnection *connection, bool raiseErrors)
/* /*
* NonblockingForgetResults clears a connection from pending activity if doing * ClearResultsIfReady clears a connection from pending activity if doing
* so does not require network IO. Returns true if successful, false * so does not require network IO. Returns true if successful, false
* otherwise. * otherwise.
*/ */
bool bool
NonblockingForgetResults(MultiConnection *connection) ClearResultsIfReady(MultiConnection *connection)
{ {
PGconn *pgConn = connection->pgConn; PGconn *pgConn = connection->pgConn;
@ -152,6 +152,7 @@ NonblockingForgetResults(MultiConnection *connection)
while (true) while (true)
{ {
PGresult *result = NULL; PGresult *result = NULL;
ExecStatusType resultStatus;
/* just in case there's a lot of results */ /* just in case there's a lot of results */
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
@ -182,19 +183,31 @@ NonblockingForgetResults(MultiConnection *connection)
} }
result = PQgetResult(pgConn); result = PQgetResult(pgConn);
if (PQresultStatus(result) == PGRES_COPY_IN || if (result == NULL)
PQresultStatus(result) == PGRES_COPY_OUT) {
/* no more results available */
return true;
}
resultStatus = PQresultStatus(result);
/* only care about the status, can clear now */
PQclear(result);
if (resultStatus == PGRES_COPY_IN || resultStatus == PGRES_COPY_OUT)
{ {
/* in copy, can't reliably recover without blocking */ /* in copy, can't reliably recover without blocking */
return false; return false;
} }
if (result == NULL) if (!(resultStatus == PGRES_SINGLE_TUPLE || resultStatus == PGRES_TUPLES_OK ||
resultStatus == PGRES_COMMAND_OK))
{ {
return true; /* an error occcurred just when we were aborting */
return false;
} }
PQclear(result); /* check if there are more results to consume */
} }
pg_unreachable(); pg_unreachable();

View File

@ -382,7 +382,14 @@ StartRemoteTransactionAbort(MultiConnection *connection)
} }
else else
{ {
if (!NonblockingForgetResults(connection)) /*
* In case of a cancellation, the connection might still be working
* on some commands. Try to consume the results such that the
* connection can be reused, but do not want to wait for commands
* to finish. Instead we just close the connection if the command
* is still busy.
*/
if (!ClearResultsIfReady(connection))
{ {
ShutdownConnection(connection); ShutdownConnection(connection);

View File

@ -27,7 +27,7 @@ extern bool LogRemoteCommands;
extern bool IsResponseOK(struct pg_result *result); extern bool IsResponseOK(struct pg_result *result);
extern void ForgetResults(MultiConnection *connection); extern void ForgetResults(MultiConnection *connection);
extern bool ClearResults(MultiConnection *connection, bool raiseErrors); extern bool ClearResults(MultiConnection *connection, bool raiseErrors);
extern bool NonblockingForgetResults(MultiConnection *connection); extern bool ClearResultsIfReady(MultiConnection *connection);
extern bool SqlStateMatchesCategory(char *sqlStateString, int category); extern bool SqlStateMatchesCategory(char *sqlStateString, int category);
/* report errors & warnings */ /* report errors & warnings */