Avoid-error-during-error-recovery-loops-1.patch

application/octet-stream

Filename: Avoid-error-during-error-recovery-loops-1.patch
Type: application/octet-stream
Part: 0
Message: Re: BUG #17828: postgres_fdw leaks file descriptors on error and aborts aborted transaction in lack of fds

Patch

Format: unified
File+
contrib/postgres_fdw/connection.c 29 10
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index 4931ebf591..060eac9906 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -144,7 +144,8 @@ static bool pgfdw_exec_cleanup_query_end(PGconn *conn, const char *query,
 										 bool consume_input,
 										 bool ignore_errors);
 static bool pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime,
-									 PGresult **result, bool *timed_out);
+									 PGresult **result, bool *timed_out,
+									 bool *internal_error);
 static void pgfdw_abort_cleanup(ConnCacheEntry *entry, bool toplevel);
 static bool pgfdw_abort_cleanup_begin(ConnCacheEntry *entry, bool toplevel,
 									  List **pending_entries,
@@ -1352,6 +1353,7 @@ pgfdw_cancel_query_end(PGconn *conn, TimestampTz endtime, bool consume_input)
 {
 	PGresult   *result = NULL;
 	bool		timed_out;
+	bool		internal_error;
 
 	/*
 	 * If requested, consume whatever data is available from the socket. (Note
@@ -1369,9 +1371,13 @@ pgfdw_cancel_query_end(PGconn *conn, TimestampTz endtime, bool consume_input)
 	}
 
 	/* Get and discard the result of the query. */
-	if (pgfdw_get_cleanup_result(conn, endtime, &result, &timed_out))
+	if (pgfdw_get_cleanup_result(conn, endtime, &result, &timed_out,
+								 &internal_error))
 	{
-		if (timed_out)
+		if (internal_error)
+			ereport(WARNING,
+					(errmsg("could not get result of cancel request due to internal error")));
+		else if (timed_out)
 			ereport(WARNING,
 					(errmsg("could not get result of cancel request due to timeout")));
 		else
@@ -1442,6 +1448,7 @@ pgfdw_exec_cleanup_query_end(PGconn *conn, const char *query,
 {
 	PGresult   *result = NULL;
 	bool		timed_out;
+	bool		internal_error;
 
 	/*
 	 * If requested, consume whatever data is available from the socket. (Note
@@ -1456,9 +1463,14 @@ pgfdw_exec_cleanup_query_end(PGconn *conn, const char *query,
 	}
 
 	/* Get the result of the query. */
-	if (pgfdw_get_cleanup_result(conn, endtime, &result, &timed_out))
+	if (pgfdw_get_cleanup_result(conn, endtime, &result, &timed_out,
+								 &internal_error))
 	{
-		if (timed_out)
+		if (internal_error)
+			ereport(WARNING,
+					(errmsg("could not get query result due to internal error"),
+					 errcontext("remote SQL command: %s", query)));
+		else if (timed_out)
 			ereport(WARNING,
 					(errmsg("could not get query result due to timeout"),
 					 query ? errcontext("remote SQL command: %s", query) : 0));
@@ -1487,17 +1499,21 @@ pgfdw_exec_cleanup_query_end(PGconn *conn, const char *query,
  *
  * endtime is the time at which we should give up and assume the remote
  * side is dead.  Returns true if the timeout expired or connection trouble
- * occurred, false otherwise.  Sets *result except in case of a timeout.
- * Sets timed_out to true only when the timeout expired.
+ * occurred, false otherwise.  Sets *result except in case of a timeout or an
+ * internal error.  Sets timed_out or internal_error to true only when the
+ * timeout expired or the internal error occurred.
  */
 static bool
 pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result,
-						 bool *timed_out)
+						 bool *timed_out, bool *internal_error)
 {
 	volatile bool failed = false;
 	PGresult   *volatile last_res = NULL;
+	uint32		saveInterruptHoldoffCount = InterruptHoldoffCount;
+	MemoryContext ccxt = CurrentMemoryContext;
 
 	*timed_out = false;
+	*internal_error = false;
 
 	/* In what follows, do not leak any PGresults on an error. */
 	PG_TRY();
@@ -1558,8 +1574,11 @@ exit:	;
 	}
 	PG_CATCH();
 	{
-		PQclear(last_res);
-		PG_RE_THROW();
+		InterruptHoldoffCount = saveInterruptHoldoffCount;
+		MemoryContextSwitchTo(ccxt);
+		FlushErrorState();
+		*internal_error = true;
+		failed = true;
 	}
 	PG_END_TRY();