fix-some-PGresult-leaks.patch
text/x-diff
Filename: fix-some-PGresult-leaks.patch
Type: text/x-diff
Part: 0
Message:
Assorted leaks of PGresults
Patch
Format: unified
| File | + | − |
|---|---|---|
| contrib/postgres_fdw/connection.c | 0 | 0 |
| src/backend/replication/libpqwalreceiver/libpqwalreceiver.c | 0 | 0 |
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index 1b691fb..9818d27 100644
*** a/contrib/postgres_fdw/connection.c
--- b/contrib/postgres_fdw/connection.c
*************** pgfdw_exec_query(PGconn *conn, const cha
*** 485,491 ****
*
* This function offers quick responsiveness by checking for any interruptions.
*
! * This function emulates the PQexec()'s behavior of returning the last result
* when there are many.
*
* Caller is responsible for the error handling on the result.
--- 485,491 ----
*
* This function offers quick responsiveness by checking for any interruptions.
*
! * This function emulates PQexec()'s behavior of returning the last result
* when there are many.
*
* Caller is responsible for the error handling on the result.
*************** pgfdw_exec_query(PGconn *conn, const cha
*** 493,532 ****
PGresult *
pgfdw_get_result(PGconn *conn, const char *query)
{
! PGresult *last_res = NULL;
! for (;;)
{
! PGresult *res;
!
! while (PQisBusy(conn))
{
! int wc;
! /* Sleep until there's something to do */
! wc = WaitLatchOrSocket(MyLatch,
! WL_LATCH_SET | WL_SOCKET_READABLE,
! PQsocket(conn),
! -1L, PG_WAIT_EXTENSION);
! ResetLatch(MyLatch);
! CHECK_FOR_INTERRUPTS();
! /* Data available in socket */
! if (wc & WL_SOCKET_READABLE)
! {
! if (!PQconsumeInput(conn))
! pgfdw_report_error(ERROR, NULL, conn, false, query);
}
- }
! res = PQgetResult(conn);
! if (res == NULL)
! break; /* query is complete */
PQclear(last_res);
! last_res = res;
}
return last_res;
}
--- 493,542 ----
PGresult *
pgfdw_get_result(PGconn *conn, const char *query)
{
! PGresult *volatile last_res = NULL;
! /* In what follows, do not leak any PGresults on an error. */
! PG_TRY();
{
! for (;;)
{
! PGresult *res;
! while (PQisBusy(conn))
! {
! int wc;
! /* Sleep until there's something to do */
! wc = WaitLatchOrSocket(MyLatch,
! WL_LATCH_SET | WL_SOCKET_READABLE,
! PQsocket(conn),
! -1L, PG_WAIT_EXTENSION);
! ResetLatch(MyLatch);
! CHECK_FOR_INTERRUPTS();
!
! /* Data available in socket? */
! if (wc & WL_SOCKET_READABLE)
! {
! if (!PQconsumeInput(conn))
! pgfdw_report_error(ERROR, NULL, conn, false, query);
! }
}
! res = PQgetResult(conn);
! if (res == NULL)
! break; /* query is complete */
+ PQclear(last_res);
+ last_res = res;
+ }
+ }
+ PG_CATCH();
+ {
PQclear(last_res);
! PG_RE_THROW();
}
+ PG_END_TRY();
return last_res;
}
*************** pgfdw_exec_cleanup_query(PGconn *conn, c
*** 1006,1011 ****
--- 1016,1022 ----
pgfdw_report_error(WARNING, result, conn, true, query);
return ignore_errors;
}
+ PQclear(result);
return true;
}
*************** pgfdw_exec_cleanup_query(PGconn *conn, c
*** 1028,1083 ****
static bool
pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
{
! PGresult *last_res = NULL;
! for (;;)
{
! PGresult *res;
!
! while (PQisBusy(conn))
{
! int wc;
! TimestampTz now = GetCurrentTimestamp();
! long secs;
! int microsecs;
! long cur_timeout;
! /* If timeout has expired, give up, else get sleep time. */
! if (now >= endtime)
! return true;
! TimestampDifference(now, endtime, &secs, µsecs);
! /* To protect against clock skew, limit sleep to one minute. */
! cur_timeout = Min(60000, secs * USECS_PER_SEC + microsecs);
! /* Sleep until there's something to do */
! wc = WaitLatchOrSocket(MyLatch,
WL_LATCH_SET | WL_SOCKET_READABLE | WL_TIMEOUT,
! PQsocket(conn),
! cur_timeout, PG_WAIT_EXTENSION);
! ResetLatch(MyLatch);
! CHECK_FOR_INTERRUPTS();
! /* Data available in socket */
! if (wc & WL_SOCKET_READABLE)
! {
! if (!PQconsumeInput(conn))
{
! *result = NULL;
! return false;
}
}
- }
! res = PQgetResult(conn);
! if (res == NULL)
! break; /* query is complete */
PQclear(last_res);
! last_res = res;
}
! *result = last_res;
! return false;
}
--- 1039,1113 ----
static bool
pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
{
! volatile bool timed_out = false;
! PGresult *volatile last_res = NULL;
! /* In what follows, do not leak any PGresults on an error. */
! PG_TRY();
{
! for (;;)
{
! PGresult *res;
! while (PQisBusy(conn))
! {
! int wc;
! TimestampTz now = GetCurrentTimestamp();
! long secs;
! int microsecs;
! long cur_timeout;
! /* If timeout has expired, give up, else get sleep time. */
! if (now >= endtime)
! {
! timed_out = true;
! goto exit;
! }
! TimestampDifference(now, endtime, &secs, µsecs);
! /* To protect against clock skew, limit sleep to one minute. */
! cur_timeout = Min(60000, secs * USECS_PER_SEC + microsecs);
!
! /* Sleep until there's something to do */
! wc = WaitLatchOrSocket(MyLatch,
WL_LATCH_SET | WL_SOCKET_READABLE | WL_TIMEOUT,
! PQsocket(conn),
! cur_timeout, PG_WAIT_EXTENSION);
! ResetLatch(MyLatch);
! CHECK_FOR_INTERRUPTS();
! /* Data available in socket? */
! if (wc & WL_SOCKET_READABLE)
{
! if (!PQconsumeInput(conn))
! {
! /* connection trouble; treat the same as a timeout */
! timed_out = true;
! goto exit;
! }
}
}
! res = PQgetResult(conn);
! if (res == NULL)
! break; /* query is complete */
+ PQclear(last_res);
+ last_res = res;
+ }
+ exit: ;
+ }
+ PG_CATCH();
+ {
PQclear(last_res);
! PG_RE_THROW();
}
+ PG_END_TRY();
! if (timed_out)
! PQclear(last_res);
! else
! *result = last_res;
! return timed_out;
}
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 7509b4f..f6fa0e4 100644
*** a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
--- b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
*************** libpqrcv_PQexec(PGconn *streamConn, cons
*** 591,603 ****
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
if (PQconsumeInput(streamConn) == 0)
! return NULL; /* trouble */
}
/*
! * Emulate the PQexec()'s behavior of returning the last result when
! * there are many. We are fine with returning just last error message.
*/
result = PQgetResult(streamConn);
if (result == NULL)
--- 591,609 ----
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
+
+ /* Consume whatever data is available from the socket */
if (PQconsumeInput(streamConn) == 0)
! {
! /* trouble; drop whatever we had and return NULL */
! PQclear(lastResult);
! return NULL;
! }
}
/*
! * Emulate PQexec()'s behavior of returning the last result when there
! * are many. We are fine with returning just last error message.
*/
result = PQgetResult(streamConn);
if (result == NULL)