*
* This function offers quick responsiveness by checking for any interruptions.
*
- * This function emulates the PQexec()'s behavior of returning the last result
+ * 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.
PGresult *
pgfdw_get_result(PGconn *conn, const char *query)
{
- PGresult *last_res = NULL;
+ PGresult *volatile last_res = NULL;
- for (;;)
+ /* In what follows, do not leak any PGresults on an error. */
+ PG_TRY();
{
- PGresult *res;
-
- while (PQisBusy(conn))
+ for (;;)
{
- int wc;
+ PGresult *res;
- /* Sleep until there's something to do */
- wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE,
- PQsocket(conn),
- -1L, PG_WAIT_EXTENSION);
- ResetLatch(MyLatch);
+ while (PQisBusy(conn))
+ {
+ int wc;
- CHECK_FOR_INTERRUPTS();
+ /* Sleep until there's something to do */
+ wc = WaitLatchOrSocket(MyLatch,
+ WL_LATCH_SET | WL_SOCKET_READABLE,
+ PQsocket(conn),
+ -1L, PG_WAIT_EXTENSION);
+ ResetLatch(MyLatch);
- /* Data available in socket */
- if (wc & WL_SOCKET_READABLE)
- {
- if (!PQconsumeInput(conn))
- pgfdw_report_error(ERROR, NULL, conn, false, query);
+ 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 */
+ res = PQgetResult(conn);
+ if (res == NULL)
+ break; /* query is complete */
+ PQclear(last_res);
+ last_res = res;
+ }
+ }
+ PG_CATCH();
+ {
PQclear(last_res);
- last_res = res;
+ PG_RE_THROW();
}
+ PG_END_TRY();
return last_res;
}
pgfdw_report_error(WARNING, result, conn, true, query);
return ignore_errors;
}
+ PQclear(result);
return true;
}
static bool
pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
{
- PGresult *last_res = NULL;
+ volatile bool timed_out = false;
+ PGresult *volatile last_res = NULL;
- for (;;)
+ /* In what follows, do not leak any PGresults on an error. */
+ PG_TRY();
{
- PGresult *res;
-
- while (PQisBusy(conn))
+ for (;;)
{
- 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,
+ 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);
+ PQsocket(conn),
+ cur_timeout, PG_WAIT_EXTENSION);
+ ResetLatch(MyLatch);
- CHECK_FOR_INTERRUPTS();
+ CHECK_FOR_INTERRUPTS();
- /* Data available in socket */
- if (wc & WL_SOCKET_READABLE)
- {
- if (!PQconsumeInput(conn))
+ /* Data available in socket? */
+ if (wc & WL_SOCKET_READABLE)
{
- *result = NULL;
- return false;
+ 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 */
+ res = PQgetResult(conn);
+ if (res == NULL)
+ break; /* query is complete */
+ PQclear(last_res);
+ last_res = res;
+ }
+exit: ;
+ }
+ PG_CATCH();
+ {
PQclear(last_res);
- last_res = res;
+ PG_RE_THROW();
}
+ PG_END_TRY();
- *result = last_res;
- return false;
+ if (timed_out)
+ PQclear(last_res);
+ else
+ *result = last_res;
+ return timed_out;
}