Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a6eff54

Browse files
author
Commitfest Bot
committed
[CF 5772] v8 - Fixing memory leaks in postgres_fdw
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5772 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/2677387.1748629914@sss.pgh.pa.us Author(s): Tom Lane
2 parents 232d8ca + 2620f96 commit a6eff54

File tree

11 files changed

+936
-872
lines changed

11 files changed

+936
-872
lines changed

contrib/dblink/dblink.c

Lines changed: 114 additions & 156 deletions
Large diffs are not rendered by default.

contrib/postgres_fdw/connection.c

Lines changed: 106 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ static void
812812
do_sql_command_begin(PGconn *conn, const char *sql)
813813
{
814814
if (!PQsendQuery(conn, sql))
815-
pgfdw_report_error(ERROR, NULL, conn, false, sql);
815+
pgfdw_report_error(ERROR, NULL, conn, sql);
816816
}
817817

818818
static void
@@ -827,10 +827,10 @@ do_sql_command_end(PGconn *conn, const char *sql, bool consume_input)
827827
* would be large compared to the overhead of PQconsumeInput.)
828828
*/
829829
if (consume_input && !PQconsumeInput(conn))
830-
pgfdw_report_error(ERROR, NULL, conn, false, sql);
830+
pgfdw_report_error(ERROR, NULL, conn, sql);
831831
res = pgfdw_get_result(conn);
832832
if (PQresultStatus(res) != PGRES_COMMAND_OK)
833-
pgfdw_report_error(ERROR, res, conn, true, sql);
833+
pgfdw_report_error(ERROR, res, conn, sql);
834834
PQclear(res);
835835
}
836836

@@ -964,62 +964,55 @@ pgfdw_get_result(PGconn *conn)
964964
* Report an error we got from the remote server.
965965
*
966966
* elevel: error level to use (typically ERROR, but might be less)
967-
* res: PGresult containing the error
967+
* res: PGresult containing the error (might be NULL)
968968
* conn: connection we did the query on
969-
* clear: if true, PQclear the result (otherwise caller will handle it)
970969
* sql: NULL, or text of remote command we tried to execute
971970
*
971+
* If "res" is not NULL, it'll be PQclear'ed here (unless we throw error,
972+
* in which case memory context cleanup will clear it eventually).
973+
*
972974
* Note: callers that choose not to throw ERROR for a remote error are
973975
* responsible for making sure that the associated ConnCacheEntry gets
974976
* marked with have_error = true.
975977
*/
976978
void
977979
pgfdw_report_error(int elevel, PGresult *res, PGconn *conn,
978-
bool clear, const char *sql)
980+
const char *sql)
979981
{
980-
/* If requested, PGresult must be released before leaving this function. */
981-
PG_TRY();
982-
{
983-
char *diag_sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
984-
char *message_primary = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
985-
char *message_detail = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
986-
char *message_hint = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT);
987-
char *message_context = PQresultErrorField(res, PG_DIAG_CONTEXT);
988-
int sqlstate;
989-
990-
if (diag_sqlstate)
991-
sqlstate = MAKE_SQLSTATE(diag_sqlstate[0],
992-
diag_sqlstate[1],
993-
diag_sqlstate[2],
994-
diag_sqlstate[3],
995-
diag_sqlstate[4]);
996-
else
997-
sqlstate = ERRCODE_CONNECTION_FAILURE;
982+
char *diag_sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
983+
char *message_primary = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
984+
char *message_detail = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
985+
char *message_hint = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT);
986+
char *message_context = PQresultErrorField(res, PG_DIAG_CONTEXT);
987+
int sqlstate;
988+
989+
if (diag_sqlstate)
990+
sqlstate = MAKE_SQLSTATE(diag_sqlstate[0],
991+
diag_sqlstate[1],
992+
diag_sqlstate[2],
993+
diag_sqlstate[3],
994+
diag_sqlstate[4]);
995+
else
996+
sqlstate = ERRCODE_CONNECTION_FAILURE;
998997

999-
/*
1000-
* If we don't get a message from the PGresult, try the PGconn. This
1001-
* is needed because for connection-level failures, PQgetResult may
1002-
* just return NULL, not a PGresult at all.
1003-
*/
1004-
if (message_primary == NULL)
1005-
message_primary = pchomp(PQerrorMessage(conn));
1006-
1007-
ereport(elevel,
1008-
(errcode(sqlstate),
1009-
(message_primary != NULL && message_primary[0] != '\0') ?
1010-
errmsg_internal("%s", message_primary) :
1011-
errmsg("could not obtain message string for remote error"),
1012-
message_detail ? errdetail_internal("%s", message_detail) : 0,
1013-
message_hint ? errhint("%s", message_hint) : 0,
1014-
message_context ? errcontext("%s", message_context) : 0,
1015-
sql ? errcontext("remote SQL command: %s", sql) : 0));
1016-
}
1017-
PG_FINALLY();
1018-
{
1019-
if (clear)
1020-
PQclear(res);
1021-
}
1022-
PG_END_TRY();
998+
/*
999+
* If we don't get a message from the PGresult, try the PGconn. This is
1000+
* needed because for connection-level failures, PQgetResult may just
1001+
* return NULL, not a PGresult at all.
1002+
*/
1003+
if (message_primary == NULL)
1004+
message_primary = pchomp(PQerrorMessage(conn));
1005+
1006+
ereport(elevel,
1007+
(errcode(sqlstate),
1008+
(message_primary != NULL && message_primary[0] != '\0') ?
1009+
errmsg_internal("%s", message_primary) :
1010+
errmsg("could not obtain message string for remote error"),
1011+
message_detail ? errdetail_internal("%s", message_detail) : 0,
1012+
message_hint ? errhint("%s", message_hint) : 0,
1013+
message_context ? errcontext("%s", message_context) : 0,
1014+
sql ? errcontext("remote SQL command: %s", sql) : 0));
1015+
PQclear(res);
10231016
}
10241017

10251018
/*
@@ -1542,7 +1535,7 @@ pgfdw_exec_cleanup_query_begin(PGconn *conn, const char *query)
15421535
*/
15431536
if (!PQsendQuery(conn, query))
15441537
{
1545-
pgfdw_report_error(WARNING, NULL, conn, false, query);
1538+
pgfdw_report_error(WARNING, NULL, conn, query);
15461539
return false;
15471540
}
15481541

@@ -1567,7 +1560,7 @@ pgfdw_exec_cleanup_query_end(PGconn *conn, const char *query,
15671560
*/
15681561
if (consume_input && !PQconsumeInput(conn))
15691562
{
1570-
pgfdw_report_error(WARNING, NULL, conn, false, query);
1563+
pgfdw_report_error(WARNING, NULL, conn, query);
15711564
return false;
15721565
}
15731566

@@ -1579,15 +1572,15 @@ pgfdw_exec_cleanup_query_end(PGconn *conn, const char *query,
15791572
(errmsg("could not get query result due to timeout"),
15801573
errcontext("remote SQL command: %s", query)));
15811574
else
1582-
pgfdw_report_error(WARNING, NULL, conn, false, query);
1575+
pgfdw_report_error(WARNING, NULL, conn, query);
15831576

15841577
return false;
15851578
}
15861579

15871580
/* Issue a warning if not successful. */
15881581
if (PQresultStatus(result) != PGRES_COMMAND_OK)
15891582
{
1590-
pgfdw_report_error(WARNING, result, conn, true, query);
1583+
pgfdw_report_error(WARNING, result, conn, query);
15911584
return ignore_errors;
15921585
}
15931586
PQclear(result);
@@ -1615,103 +1608,90 @@ pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime,
16151608
PGresult **result,
16161609
bool *timed_out)
16171610
{
1618-
volatile bool failed = false;
1619-
PGresult *volatile last_res = NULL;
1611+
bool failed = false;
1612+
PGresult *last_res = NULL;
1613+
int canceldelta = RETRY_CANCEL_TIMEOUT * 2;
16201614

16211615
*result = NULL;
16221616
*timed_out = false;
1623-
1624-
/* In what follows, do not leak any PGresults on an error. */
1625-
PG_TRY();
1617+
for (;;)
16261618
{
1627-
int canceldelta = RETRY_CANCEL_TIMEOUT * 2;
1619+
PGresult *res;
16281620

1629-
for (;;)
1621+
while (PQisBusy(conn))
16301622
{
1631-
PGresult *res;
1623+
int wc;
1624+
TimestampTz now = GetCurrentTimestamp();
1625+
long cur_timeout;
16321626

1633-
while (PQisBusy(conn))
1627+
/* If timeout has expired, give up. */
1628+
if (now >= endtime)
16341629
{
1635-
int wc;
1636-
TimestampTz now = GetCurrentTimestamp();
1637-
long cur_timeout;
1638-
1639-
/* If timeout has expired, give up. */
1640-
if (now >= endtime)
1641-
{
1642-
*timed_out = true;
1643-
failed = true;
1644-
goto exit;
1645-
}
1630+
*timed_out = true;
1631+
failed = true;
1632+
goto exit;
1633+
}
16461634

1647-
/* If we need to re-issue the cancel request, do that. */
1648-
if (now >= retrycanceltime)
1649-
{
1650-
/* We ignore failure to issue the repeated request. */
1651-
(void) libpqsrv_cancel(conn, endtime);
1635+
/* If we need to re-issue the cancel request, do that. */
1636+
if (now >= retrycanceltime)
1637+
{
1638+
/* We ignore failure to issue the repeated request. */
1639+
(void) libpqsrv_cancel(conn, endtime);
16521640

1653-
/* Recompute "now" in case that took measurable time. */
1654-
now = GetCurrentTimestamp();
1641+
/* Recompute "now" in case that took measurable time. */
1642+
now = GetCurrentTimestamp();
16551643

1656-
/* Adjust re-cancel timeout in increasing steps. */
1657-
retrycanceltime = TimestampTzPlusMilliseconds(now,
1658-
canceldelta);
1659-
canceldelta += canceldelta;
1660-
}
1644+
/* Adjust re-cancel timeout in increasing steps. */
1645+
retrycanceltime = TimestampTzPlusMilliseconds(now,
1646+
canceldelta);
1647+
canceldelta += canceldelta;
1648+
}
16611649

1662-
/* If timeout has expired, give up, else get sleep time. */
1663-
cur_timeout = TimestampDifferenceMilliseconds(now,
1664-
Min(endtime,
1665-
retrycanceltime));
1666-
if (cur_timeout <= 0)
1667-
{
1668-
*timed_out = true;
1669-
failed = true;
1670-
goto exit;
1671-
}
1650+
/* If timeout has expired, give up, else get sleep time. */
1651+
cur_timeout = TimestampDifferenceMilliseconds(now,
1652+
Min(endtime,
1653+
retrycanceltime));
1654+
if (cur_timeout <= 0)
1655+
{
1656+
*timed_out = true;
1657+
failed = true;
1658+
goto exit;
1659+
}
16721660

1673-
/* first time, allocate or get the custom wait event */
1674-
if (pgfdw_we_cleanup_result == 0)
1675-
pgfdw_we_cleanup_result = WaitEventExtensionNew("PostgresFdwCleanupResult");
1661+
/* first time, allocate or get the custom wait event */
1662+
if (pgfdw_we_cleanup_result == 0)
1663+
pgfdw_we_cleanup_result = WaitEventExtensionNew("PostgresFdwCleanupResult");
16761664

1677-
/* Sleep until there's something to do */
1678-
wc = WaitLatchOrSocket(MyLatch,
1679-
WL_LATCH_SET | WL_SOCKET_READABLE |
1680-
WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
1681-
PQsocket(conn),
1682-
cur_timeout, pgfdw_we_cleanup_result);
1683-
ResetLatch(MyLatch);
1665+
/* Sleep until there's something to do */
1666+
wc = WaitLatchOrSocket(MyLatch,
1667+
WL_LATCH_SET | WL_SOCKET_READABLE |
1668+
WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
1669+
PQsocket(conn),
1670+
cur_timeout, pgfdw_we_cleanup_result);
1671+
ResetLatch(MyLatch);
16841672

1685-
CHECK_FOR_INTERRUPTS();
1673+
CHECK_FOR_INTERRUPTS();
16861674

1687-
/* Data available in socket? */
1688-
if (wc & WL_SOCKET_READABLE)
1675+
/* Data available in socket? */
1676+
if (wc & WL_SOCKET_READABLE)
1677+
{
1678+
if (!PQconsumeInput(conn))
16891679
{
1690-
if (!PQconsumeInput(conn))
1691-
{
1692-
/* connection trouble */
1693-
failed = true;
1694-
goto exit;
1695-
}
1680+
/* connection trouble */
1681+
failed = true;
1682+
goto exit;
16961683
}
16971684
}
1685+
}
16981686

1699-
res = PQgetResult(conn);
1700-
if (res == NULL)
1701-
break; /* query is complete */
1687+
res = PQgetResult(conn);
1688+
if (res == NULL)
1689+
break; /* query is complete */
17021690

1703-
PQclear(last_res);
1704-
last_res = res;
1705-
}
1706-
exit: ;
1707-
}
1708-
PG_CATCH();
1709-
{
17101691
PQclear(last_res);
1711-
PG_RE_THROW();
1692+
last_res = res;
17121693
}
1713-
PG_END_TRY();
1714-
1694+
exit:
17151695
if (failed)
17161696
PQclear(last_res);
17171697
else

0 commit comments

Comments
 (0)