mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
libpq-be-fe-helpers.h: wrap new cancel APIs
Commit 61461a300c
introduced new functions to libpq for cancelling
queries. This commit introduces a helper function that backend-side
libraries and extensions can use to invoke those. This function takes a
timeout and can itself be interrupted while it is waiting for a cancel
request to be sent and processed, instead of being blocked.
This replaces the usage of the old functions in postgres_fdw and dblink.
Finally, it also adds some test coverage for the cancel support in
postgres_fdw.
Author: Jelte Fennema-Nio <postgres@jeltef.nl>
Discussion: https://postgr.es/m/CAGECzQT_VgOWWENUqvUV9xQmbaCyXjtRRAYO8W07oqashk_N+g@mail.gmail.com
This commit is contained in:
@ -133,7 +133,7 @@ static void pgfdw_inval_callback(Datum arg, int cacheid, uint32 hashvalue);
|
||||
static void pgfdw_reject_incomplete_xact_state_change(ConnCacheEntry *entry);
|
||||
static void pgfdw_reset_xact_state(ConnCacheEntry *entry, bool toplevel);
|
||||
static bool pgfdw_cancel_query(PGconn *conn);
|
||||
static bool pgfdw_cancel_query_begin(PGconn *conn);
|
||||
static bool pgfdw_cancel_query_begin(PGconn *conn, TimestampTz endtime);
|
||||
static bool pgfdw_cancel_query_end(PGconn *conn, TimestampTz endtime,
|
||||
bool consume_input);
|
||||
static bool pgfdw_exec_cleanup_query(PGconn *conn, const char *query,
|
||||
@ -1315,36 +1315,31 @@ pgfdw_cancel_query(PGconn *conn)
|
||||
endtime = TimestampTzPlusMilliseconds(GetCurrentTimestamp(),
|
||||
CONNECTION_CLEANUP_TIMEOUT);
|
||||
|
||||
if (!pgfdw_cancel_query_begin(conn))
|
||||
if (!pgfdw_cancel_query_begin(conn, endtime))
|
||||
return false;
|
||||
return pgfdw_cancel_query_end(conn, endtime, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Submit a cancel request to the given connection, waiting only until
|
||||
* the given time.
|
||||
*
|
||||
* We sleep interruptibly until we receive confirmation that the cancel
|
||||
* request has been accepted, and if it is, return true; if the timeout
|
||||
* lapses without that, or the request fails for whatever reason, return
|
||||
* false.
|
||||
*/
|
||||
static bool
|
||||
pgfdw_cancel_query_begin(PGconn *conn)
|
||||
pgfdw_cancel_query_begin(PGconn *conn, TimestampTz endtime)
|
||||
{
|
||||
PGcancel *cancel;
|
||||
char errbuf[256];
|
||||
char *errormsg = libpqsrv_cancel(conn, endtime);
|
||||
|
||||
/*
|
||||
* Issue cancel request. Unfortunately, there's no good way to limit the
|
||||
* amount of time that we might block inside PQgetCancel().
|
||||
*/
|
||||
if ((cancel = PQgetCancel(conn)))
|
||||
{
|
||||
if (!PQcancel(cancel, errbuf, sizeof(errbuf)))
|
||||
{
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_CONNECTION_FAILURE),
|
||||
errmsg("could not send cancel request: %s",
|
||||
errbuf)));
|
||||
PQfreeCancel(cancel);
|
||||
return false;
|
||||
}
|
||||
PQfreeCancel(cancel);
|
||||
}
|
||||
if (errormsg != NULL)
|
||||
ereport(WARNING,
|
||||
errcode(ERRCODE_CONNECTION_FAILURE),
|
||||
errmsg("could not send cancel request: %s", errormsg));
|
||||
|
||||
return true;
|
||||
return errormsg == NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1685,7 +1680,11 @@ pgfdw_abort_cleanup_begin(ConnCacheEntry *entry, bool toplevel,
|
||||
*/
|
||||
if (PQtransactionStatus(entry->conn) == PQTRANS_ACTIVE)
|
||||
{
|
||||
if (!pgfdw_cancel_query_begin(entry->conn))
|
||||
TimestampTz endtime;
|
||||
|
||||
endtime = TimestampTzPlusMilliseconds(GetCurrentTimestamp(),
|
||||
CONNECTION_CLEANUP_TIMEOUT);
|
||||
if (!pgfdw_cancel_query_begin(entry->conn, endtime))
|
||||
return false; /* Unable to cancel running query */
|
||||
*cancel_requested = lappend(*cancel_requested, entry);
|
||||
}
|
||||
|
@ -2739,6 +2739,21 @@ SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c
|
||||
(10 rows)
|
||||
|
||||
ALTER VIEW v4 OWNER TO regress_view_owner;
|
||||
-- Make sure this big CROSS JOIN query is pushed down
|
||||
EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 CROSS JOIN ft2 CROSS JOIN ft4 CROSS JOIN ft5;
|
||||
QUERY PLAN
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Foreign Scan
|
||||
Output: (count(*))
|
||||
Relations: Aggregate on ((((public.ft1) INNER JOIN (public.ft2)) INNER JOIN (public.ft4)) INNER JOIN (public.ft5))
|
||||
Remote SQL: SELECT count(*) FROM ((("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (TRUE)) INNER JOIN "S 1"."T 3" r4 ON (TRUE)) INNER JOIN "S 1"."T 4" r6 ON (TRUE))
|
||||
(4 rows)
|
||||
|
||||
-- Make sure query cancellation works
|
||||
SET statement_timeout = '10ms';
|
||||
select count(*) from ft1 CROSS JOIN ft2 CROSS JOIN ft4 CROSS JOIN ft5; -- this takes very long
|
||||
ERROR: canceling statement due to statement timeout
|
||||
RESET statement_timeout;
|
||||
-- ====================================================================
|
||||
-- Check that userid to use when querying the remote table is correctly
|
||||
-- propagated into foreign rels present in subqueries under an UNION ALL
|
||||
|
@ -737,6 +737,13 @@ SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c
|
||||
SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
|
||||
ALTER VIEW v4 OWNER TO regress_view_owner;
|
||||
|
||||
-- Make sure this big CROSS JOIN query is pushed down
|
||||
EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 CROSS JOIN ft2 CROSS JOIN ft4 CROSS JOIN ft5;
|
||||
-- Make sure query cancellation works
|
||||
SET statement_timeout = '10ms';
|
||||
select count(*) from ft1 CROSS JOIN ft2 CROSS JOIN ft4 CROSS JOIN ft5; -- this takes very long
|
||||
RESET statement_timeout;
|
||||
|
||||
-- ====================================================================
|
||||
-- Check that userid to use when querying the remote table is correctly
|
||||
-- propagated into foreign rels present in subqueries under an UNION ALL
|
||||
|
Reference in New Issue
Block a user