Then you need to add #include libpq-fe.h in cancel.h. Our policy is
that headers compile standalone (c.h / postgres_fe.h / postgres.h
excluded).
Ok. I do not make a habit of adding headers in postgres, so I did not
notice there was an alphabetical logic to that.
Attached patch v4 does it.
--
Fabien.
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 03bcd22996..904d6f0e00 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -59,6 +59,7 @@
#include "common/int.h"
#include "common/logging.h"
+#include "fe_utils/cancel.h"
#include "fe_utils/conditional.h"
#include "getopt_long.h"
#include "libpq-fe.h"
@@ -3887,6 +3888,9 @@ initGenerateData(PGconn *con)
exit(1);
}
+ if (CancelRequested)
+ break;
+
/*
* If we want to stick with the original logging, print a message each
* 100k inserted rows.
@@ -4057,6 +4061,9 @@ runInitSteps(const char *initialize_steps)
if ((con = doConnect()) == NULL)
exit(1);
+ setup_cancel_handler(NULL);
+ SetCancelConn(con);
+
for (step = initialize_steps; *step != '\0'; step++)
{
instr_time start;
@@ -4120,6 +4127,7 @@ runInitSteps(const char *initialize_steps)
}
fprintf(stderr, "done in %.2f s (%s).\n", run_time, stats.data);
+ ResetCancelConn();
PQfinish(con);
termPQExpBuffer(&stats);
}
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index b981ae81ff..f1d9e0298a 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -29,6 +29,7 @@
#include "libpq-fe.h"
#include "pqexpbuffer.h"
#include "common/logging.h"
+#include "fe_utils/cancel.h"
#include "fe_utils/print.h"
#include "fe_utils/string_utils.h"
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 90f6380170..0a66b71372 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -24,6 +24,7 @@
#include "copy.h"
#include "crosstabview.h"
#include "fe_utils/mbprint.h"
+#include "fe_utils/cancel.h"
#include "fe_utils/string_utils.h"
#include "portability/instr_time.h"
#include "settings.h"
@@ -223,6 +224,7 @@ NoticeProcessor(void *arg, const char *message)
}
+#ifndef WIN32
/*
* Code to support query cancellation
@@ -241,7 +243,7 @@ NoticeProcessor(void *arg, const char *message)
*
* SIGINT is supposed to abort all long-running psql operations, not only
* database queries. In most places, this is accomplished by checking
- * cancel_pressed during long-running loops. However, that won't work when
+ * CancelRequested during long-running loops. However, that won't work when
* blocked on user input (in readline() or fgets()). In those places, we
* set sigint_interrupt_enabled true while blocked, instructing the signal
* catcher to longjmp through sigint_interrupt_jmp. We assume readline and
@@ -252,34 +254,9 @@ volatile bool sigint_interrupt_enabled = false;
sigjmp_buf sigint_interrupt_jmp;
-static PGcancel *volatile cancelConn = NULL;
-
-#ifdef WIN32
-static CRITICAL_SECTION cancelConnLock;
-#endif
-
-/*
- * Write a simple string to stderr --- must be safe in a signal handler.
- * We ignore the write() result since there's not much we could do about it.
- * Certain compilers make that harder than it ought to be.
- */
-#define write_stderr(str) \
- do { \
- const char *str_ = (str); \
- int rc_; \
- rc_ = write(fileno(stderr), str_, strlen(str_)); \
- (void) rc_; \
- } while (0)
-
-
-#ifndef WIN32
-
static void
-handle_sigint(SIGNAL_ARGS)
+psql_sigint_callback(void)
{
- int save_errno = errno;
- char errbuf[256];
-
/* if we are waiting for input, longjmp out of it */
if (sigint_interrupt_enabled)
{
@@ -288,74 +265,20 @@ handle_sigint(SIGNAL_ARGS)
}
/* else, set cancel flag to stop any long-running loops */
- cancel_pressed = true;
-
- /* and send QueryCancel if we are processing a database query */
- if (cancelConn != NULL)
- {
- if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
- write_stderr("Cancel request sent\n");
- else
- {
- write_stderr("Could not send cancel request: ");
- write_stderr(errbuf);
- }
- }
-
- errno = save_errno; /* just in case the write changed it */
+ CancelRequested = true;
}
-void
-setup_cancel_handler(void)
-{
- pqsignal(SIGINT, handle_sigint);
-}
-#else /* WIN32 */
-
-static BOOL WINAPI
-consoleHandler(DWORD dwCtrlType)
-{
- char errbuf[256];
-
- if (dwCtrlType == CTRL_C_EVENT ||
- dwCtrlType == CTRL_BREAK_EVENT)
- {
- /*
- * Can't longjmp here, because we are in wrong thread :-(
- */
-
- /* set cancel flag to stop any long-running loops */
- cancel_pressed = true;
-
- /* and send QueryCancel if we are processing a database query */
- EnterCriticalSection(&cancelConnLock);
- if (cancelConn != NULL)
- {
- if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
- write_stderr("Cancel request sent\n");
- else
- {
- write_stderr("Could not send cancel request: ");
- write_stderr(errbuf);
- }
- }
- LeaveCriticalSection(&cancelConnLock);
-
- return TRUE;
- }
- else
- /* Return FALSE for any signals not being handled */
- return FALSE;
-}
+#endif /* !WIN32 */
void
-setup_cancel_handler(void)
+psql_setup_cancel_handler(void)
{
- InitializeCriticalSection(&cancelConnLock);
-
- SetConsoleCtrlHandler(consoleHandler, TRUE);
+#ifndef WIN32
+ setup_cancel_handler(psql_sigint_callback);
+#else
+ setup_cancel_handler(NULL);
+#endif /* WIN32 */
}
-#endif /* WIN32 */
/* ConnectionUp
@@ -369,7 +292,6 @@ ConnectionUp(void)
}
-
/* CheckConnection
*
* Verify that we still have a good connection to the backend, and if not,
@@ -428,62 +350,6 @@ CheckConnection(void)
-/*
- * SetCancelConn
- *
- * Set cancelConn to point to the current database connection.
- */
-void
-SetCancelConn(void)
-{
- PGcancel *oldCancelConn;
-
-#ifdef WIN32
- EnterCriticalSection(&cancelConnLock);
-#endif
-
- /* Free the old one if we have one */
- oldCancelConn = cancelConn;
- /* be sure handle_sigint doesn't use pointer while freeing */
- cancelConn = NULL;
-
- if (oldCancelConn != NULL)
- PQfreeCancel(oldCancelConn);
-
- cancelConn = PQgetCancel(pset.db);
-
-#ifdef WIN32
- LeaveCriticalSection(&cancelConnLock);
-#endif
-}
-
-
-/*
- * ResetCancelConn
- *
- * Free the current cancel connection, if any, and set to NULL.
- */
-void
-ResetCancelConn(void)
-{
- PGcancel *oldCancelConn;
-
-#ifdef WIN32
- EnterCriticalSection(&cancelConnLock);
-#endif
-
- oldCancelConn = cancelConn;
- /* be sure handle_sigint doesn't use pointer while freeing */
- cancelConn = NULL;
-
- if (oldCancelConn != NULL)
- PQfreeCancel(oldCancelConn);
-
-#ifdef WIN32
- LeaveCriticalSection(&cancelConnLock);
-#endif
-}
-
/*
* AcceptResult
@@ -707,7 +573,7 @@ PSQLexec(const char *query)
return NULL;
}
- SetCancelConn();
+ SetCancelConn(pset.db);
res = PQexec(pset.db, query);
@@ -746,7 +612,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt)
return 0;
}
- SetCancelConn();
+ SetCancelConn(pset.db);
if (pset.timing)
INSTR_TIME_SET_CURRENT(before);
@@ -773,7 +639,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt)
* consumed. The user's intention, though, is to cancel the entire watch
* process, so detect a sent cancellation request and exit in this case.
*/
- if (cancel_pressed)
+ if (CancelRequested)
{
PQclear(res);
return 0;
@@ -973,8 +839,8 @@ ExecQueryTuples(const PGresult *result)
{
const char *query = PQgetvalue(result, r, c);
- /* Abandon execution if cancel_pressed */
- if (cancel_pressed)
+ /* Abandon execution if CancelRequested */
+ if (CancelRequested)
goto loop_exit;
/*
@@ -1091,7 +957,7 @@ ProcessResult(PGresult **results)
FILE *copystream;
PGresult *copy_result;
- SetCancelConn();
+ SetCancelConn(pset.db);
if (result_status == PGRES_COPY_OUT)
{
bool need_close = false;
@@ -1342,7 +1208,7 @@ SendQuery(const char *query)
if (fgets(buf, sizeof(buf), stdin) != NULL)
if (buf[0] == 'x')
goto sendquery_cleanup;
- if (cancel_pressed)
+ if (CancelRequested)
goto sendquery_cleanup;
}
else if (pset.echo == PSQL_ECHO_QUERIES)
@@ -1360,7 +1226,7 @@ SendQuery(const char *query)
fflush(pset.logfile);
}
- SetCancelConn();
+ SetCancelConn(pset.db);
transaction_status = PQtransactionStatus(pset.db);
@@ -1886,7 +1752,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
* writing things to the stream, we presume $PAGER has disappeared and
* stop bothering to pull down more data.
*/
- if (ntuples < fetch_count || cancel_pressed || flush_error ||
+ if (ntuples < fetch_count || CancelRequested || flush_error ||
ferror(fout))
break;
}
diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h
index 282a520116..0b87ec5836 100644
--- a/src/bin/psql/common.h
+++ b/src/bin/psql/common.h
@@ -26,10 +26,7 @@ extern volatile bool sigint_interrupt_enabled;
extern sigjmp_buf sigint_interrupt_jmp;
-extern void setup_cancel_handler(void);
-
-extern void SetCancelConn(void);
-extern void ResetCancelConn(void);
+extern void psql_setup_cancel_handler(void);
extern PGresult *PSQLexec(const char *query);
extern int PSQLexecWatch(const char *query, const printQueryOpt *opt);
diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c
index 042403e0f7..b2ddb3512e 100644
--- a/src/bin/psql/large_obj.c
+++ b/src/bin/psql/large_obj.c
@@ -11,6 +11,7 @@
#include "common/logging.h"
#include "large_obj.h"
#include "settings.h"
+#include "fe_utils/cancel.h"
static void print_lo_result(const char *fmt,...) pg_attribute_printf(1, 2);
@@ -146,7 +147,7 @@ do_lo_export(const char *loid_arg, const char *filename_arg)
if (!start_lo_xact("\\lo_export", &own_transaction))
return false;
- SetCancelConn();
+ SetCancelConn(NULL);
status = lo_export(pset.db, atooid(loid_arg), filename_arg);
ResetCancelConn();
@@ -182,7 +183,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
if (!start_lo_xact("\\lo_import", &own_transaction))
return false;
- SetCancelConn();
+ SetCancelConn(NULL);
loid = lo_import(pset.db, filename_arg);
ResetCancelConn();
@@ -244,7 +245,7 @@ do_lo_unlink(const char *loid_arg)
if (!start_lo_xact("\\lo_unlink", &own_transaction))
return false;
- SetCancelConn();
+ SetCancelConn(NULL);
status = lo_unlink(pset.db, loid);
ResetCancelConn();
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 0d941ef5ba..43cf139a31 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -301,7 +301,7 @@ main(int argc, char *argv[])
exit(EXIT_BADCONN);
}
- setup_cancel_handler();
+ psql_setup_cancel_handler();
PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c
index d380127356..3aee5f2834 100644
--- a/src/bin/scripts/clusterdb.c
+++ b/src/bin/scripts/clusterdb.c
@@ -133,7 +133,7 @@ main(int argc, char *argv[])
exit(1);
}
- setup_cancel_handler();
+ setup_cancel_handler(NULL);
if (alldb)
{
diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c
index 1b38a1da49..d2a7547441 100644
--- a/src/bin/scripts/common.c
+++ b/src/bin/scripts/common.c
@@ -24,14 +24,6 @@
#define ERRCODE_UNDEFINED_TABLE "42P01"
-
-static PGcancel *volatile cancelConn = NULL;
-bool CancelRequested = false;
-
-#ifdef WIN32
-static CRITICAL_SECTION cancelConnLock;
-#endif
-
/*
* Provide strictly harmonized handling of --help and --version
* options.
@@ -465,142 +457,3 @@ yesno_prompt(const char *question)
_(PG_YESLETTER), _(PG_NOLETTER));
}
}
-
-/*
- * SetCancelConn
- *
- * Set cancelConn to point to the current database connection.
- */
-void
-SetCancelConn(PGconn *conn)
-{
- PGcancel *oldCancelConn;
-
-#ifdef WIN32
- EnterCriticalSection(&cancelConnLock);
-#endif
-
- /* Free the old one if we have one */
- oldCancelConn = cancelConn;
-
- /* be sure handle_sigint doesn't use pointer while freeing */
- cancelConn = NULL;
-
- if (oldCancelConn != NULL)
- PQfreeCancel(oldCancelConn);
-
- cancelConn = PQgetCancel(conn);
-
-#ifdef WIN32
- LeaveCriticalSection(&cancelConnLock);
-#endif
-}
-
-/*
- * ResetCancelConn
- *
- * Free the current cancel connection, if any, and set to NULL.
- */
-void
-ResetCancelConn(void)
-{
- PGcancel *oldCancelConn;
-
-#ifdef WIN32
- EnterCriticalSection(&cancelConnLock);
-#endif
-
- oldCancelConn = cancelConn;
-
- /* be sure handle_sigint doesn't use pointer while freeing */
- cancelConn = NULL;
-
- if (oldCancelConn != NULL)
- PQfreeCancel(oldCancelConn);
-
-#ifdef WIN32
- LeaveCriticalSection(&cancelConnLock);
-#endif
-}
-
-#ifndef WIN32
-/*
- * Handle interrupt signals by canceling the current command, if a cancelConn
- * is set.
- */
-static void
-handle_sigint(SIGNAL_ARGS)
-{
- int save_errno = errno;
- char errbuf[256];
-
- /* Send QueryCancel if we are processing a database query */
- if (cancelConn != NULL)
- {
- if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
- {
- CancelRequested = true;
- fprintf(stderr, _("Cancel request sent\n"));
- }
- else
- fprintf(stderr, _("Could not send cancel request: %s"), errbuf);
- }
- else
- CancelRequested = true;
-
- errno = save_errno; /* just in case the write changed it */
-}
-
-void
-setup_cancel_handler(void)
-{
- pqsignal(SIGINT, handle_sigint);
-}
-#else /* WIN32 */
-
-/*
- * Console control handler for Win32. Note that the control handler will
- * execute on a *different thread* than the main one, so we need to do
- * proper locking around those structures.
- */
-static BOOL WINAPI
-consoleHandler(DWORD dwCtrlType)
-{
- char errbuf[256];
-
- if (dwCtrlType == CTRL_C_EVENT ||
- dwCtrlType == CTRL_BREAK_EVENT)
- {
- /* Send QueryCancel if we are processing a database query */
- EnterCriticalSection(&cancelConnLock);
- if (cancelConn != NULL)
- {
- if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
- {
- fprintf(stderr, _("Cancel request sent\n"));
- CancelRequested = true;
- }
- else
- fprintf(stderr, _("Could not send cancel request: %s"), errbuf);
- }
- else
- CancelRequested = true;
-
- LeaveCriticalSection(&cancelConnLock);
-
- return TRUE;
- }
- else
- /* Return FALSE for any signals not being handled */
- return FALSE;
-}
-
-void
-setup_cancel_handler(void)
-{
- InitializeCriticalSection(&cancelConnLock);
-
- SetConsoleCtrlHandler(consoleHandler, TRUE);
-}
-
-#endif /* WIN32 */
diff --git a/src/bin/scripts/common.h b/src/bin/scripts/common.h
index f36b26a576..12748258a6 100644
--- a/src/bin/scripts/common.h
+++ b/src/bin/scripts/common.h
@@ -13,6 +13,7 @@
#include "libpq-fe.h"
#include "getopt_long.h" /* pgrminclude ignore */
#include "pqexpbuffer.h" /* pgrminclude ignore */
+#include "fe_utils/cancel.h"
enum trivalue
{
@@ -60,10 +61,4 @@ extern void appendQualifiedRelation(PQExpBuffer buf, const char *name,
extern bool yesno_prompt(const char *question);
-extern void setup_cancel_handler(void);
-
-extern void SetCancelConn(PGconn *conn);
-extern void ResetCancelConn(void);
-
-
#endif /* COMMON_H */
diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c
index f00aec15de..bedd95cf9d 100644
--- a/src/bin/scripts/reindexdb.c
+++ b/src/bin/scripts/reindexdb.c
@@ -187,7 +187,7 @@ main(int argc, char *argv[])
exit(1);
}
- setup_cancel_handler();
+ setup_cancel_handler(NULL);
if (alldb)
{
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
index 2c7219239f..83a94dc632 100644
--- a/src/bin/scripts/vacuumdb.c
+++ b/src/bin/scripts/vacuumdb.c
@@ -257,7 +257,7 @@ main(int argc, char *argv[])
/* allow 'and_analyze' with 'analyze_only' */
}
- setup_cancel_handler();
+ setup_cancel_handler(NULL);
/* Avoid opening extra connections. */
if (tbl_count && (concurrentCons > tbl_count))
diff --git a/src/fe_utils/Makefile b/src/fe_utils/Makefile
index f2e516a2aa..43a5bf5d49 100644
--- a/src/fe_utils/Makefile
+++ b/src/fe_utils/Makefile
@@ -20,7 +20,7 @@ include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -DFRONTEND -I$(libpq_srcdir) $(CPPFLAGS)
OBJS = conditional.o mbprint.o print.o psqlscan.o recovery_gen.o \
- simple_list.o string_utils.o
+ simple_list.o string_utils.o cancel.o
all: libpgfeutils.a
diff --git a/src/fe_utils/cancel.c b/src/fe_utils/cancel.c
new file mode 100644
index 0000000000..f8a8299fcb
--- /dev/null
+++ b/src/fe_utils/cancel.c
@@ -0,0 +1,194 @@
+/*
+ * interrupt a connection
+ *
+ * Copyright (c) 2000-2019, PostgreSQL Global Development Group
+ *
+ * src/fe-utils/cancel.c
+ */
+
+#include "postgres_fe.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "libpq-fe.h"
+#include "fe_utils/connect.h"
+#include "fe_utils/string_utils.h"
+#include "fe_utils/cancel.h"
+
+/*
+ * Write a simple string to stderr --- must be safe in a signal handler.
+ * We ignore the write() result since there's not much we could do about it.
+ * Certain compilers make that harder than it ought to be.
+ */
+#define write_stderr(str) \
+ do { \
+ const char *str_ = (str); \
+ int rc_; \
+ rc_ = write(fileno(stderr), str_, strlen(str_)); \
+ (void) rc_; \
+ } while (0)
+
+static PGcancel *volatile cancelConn = NULL;
+bool CancelRequested = false;
+
+#ifdef WIN32
+static CRITICAL_SECTION cancelConnLock;
+#endif
+
+/*
+ * SetCancelConn
+ *
+ * Set cancelConn to point to the current database connection.
+ */
+void
+SetCancelConn(PGconn *conn)
+{
+ PGcancel *oldCancelConn;
+
+#ifdef WIN32
+ EnterCriticalSection(&cancelConnLock);
+#endif
+
+ /* Free the old one if we have one */
+ oldCancelConn = cancelConn;
+ /* be sure handle_sigint doesn't use pointer while freeing */
+ cancelConn = NULL;
+
+ if (oldCancelConn != NULL)
+ PQfreeCancel(oldCancelConn);
+
+ cancelConn = PQgetCancel(conn);
+
+#ifdef WIN32
+ LeaveCriticalSection(&cancelConnLock);
+#endif
+}
+
+
+/*
+ * ResetCancelConn
+ *
+ * Free the current cancel connection, if any, and set to NULL.
+ */
+void
+ResetCancelConn(void)
+{
+ PGcancel *oldCancelConn;
+
+#ifdef WIN32
+ EnterCriticalSection(&cancelConnLock);
+#endif
+
+ oldCancelConn = cancelConn;
+ /* be sure handle_sigint doesn't use pointer while freeing */
+ cancelConn = NULL;
+
+ if (oldCancelConn != NULL)
+ PQfreeCancel(oldCancelConn);
+
+#ifdef WIN32
+ LeaveCriticalSection(&cancelConnLock);
+#endif
+}
+
+#ifndef WIN32
+/*
+ * Additional callback to handle interrupts
+ */
+static void (*sigint_callback)(void) = NULL;
+
+/*
+ * Handle interrupt signals by canceling the current command, if a cancelConn
+ * is set.
+ */
+static void
+handle_sigint(SIGNAL_ARGS)
+{
+ int save_errno = errno;
+ char errbuf[256];
+
+ if (sigint_callback != NULL)
+ sigint_callback();
+
+ /* Send QueryCancel if we are processing a database query */
+ if (cancelConn != NULL)
+ {
+ if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
+ {
+ CancelRequested = true;
+ write_stderr(_("Cancel request sent\n"));
+ }
+ else
+ {
+ write_stderr(_("Could not send cancel request: "));
+ write_stderr(errbuf);
+ }
+ }
+ else
+ CancelRequested = true;
+
+ errno = save_errno; /* just in case the write changed it */
+}
+
+void
+setup_cancel_handler(void (*callback)(void))
+{
+ sigint_callback = callback;
+ pqsignal(SIGINT, handle_sigint);
+ /* what about SIGTERM? SIGQUIT? */
+}
+
+#else /* WIN32 */
+
+/*
+ * Console control handler for Win32. Note that the control handler will
+ * execute on a *different thread* than the main one, so we need to do
+ * proper locking around those structures.
+ */
+static BOOL WINAPI
+consoleHandler(DWORD dwCtrlType)
+{
+ char errbuf[256];
+
+ if (dwCtrlType == CTRL_C_EVENT ||
+ dwCtrlType == CTRL_BREAK_EVENT)
+ {
+ /* Send QueryCancel if we are processing a database query */
+ EnterCriticalSection(&cancelConnLock);
+ if (cancelConn != NULL)
+ {
+ if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
+ {
+ write_stderr(_("Cancel request sent\n"));
+ CancelRequested = true;
+ }
+ else
+ {
+ write_stderr(_("Could not send cancel request: %s"));
+ write_stderr(errbuf);
+ }
+ }
+ else
+ CancelRequested = true;
+
+ LeaveCriticalSection(&cancelConnLock);
+
+ return TRUE;
+ }
+ else
+ /* Return FALSE for any signals not being handled */
+ return FALSE;
+}
+
+void
+setup_cancel_handler(void *ignored)
+{
+ Assert(ignored == NULL);
+
+ InitializeCriticalSection(&cancelConnLock);
+
+ SetConsoleCtrlHandler(consoleHandler, TRUE);
+}
+
+#endif /* WIN32 */
diff --git a/src/include/fe_utils/cancel.h b/src/include/fe_utils/cancel.h
new file mode 100644
index 0000000000..10eac155a6
--- /dev/null
+++ b/src/include/fe_utils/cancel.h
@@ -0,0 +1,32 @@
+/*-------------------------------------------------------------------------
+ *
+ * Query Cancelation
+ *
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/fe_utils/cancel.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef CANCEL_H
+#define CANCEL_H
+
+#include "libpq-fe.h"
+
+extern void SetCancelConn(PGconn *conn);
+extern void ResetCancelConn(void);
+extern bool CancelRequested;
+
+#ifndef WIN32
+extern void setup_cancel_handler(void (*callback)(void));
+#else
+/*
+ * Ensure that the signature is the same under windows, at the price of
+ * an ignored function parameter.
+ */
+extern void setup_cancel_handler(void *ignored);
+#endif /* WIN32 */
+
+#endif /* CANCEL_H */
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 7a103e6140..e6e04a7ea6 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -143,7 +143,7 @@ sub mkvcbuild
our @pgfeutilsfiles = qw(
conditional.c mbprint.c print.c psqlscan.l psqlscan.c
- simple_list.c string_utils.c recovery_gen.c);
+ simple_list.c string_utils.c recovery_gen.c cancel.c);
$libpgport = $solution->AddProject('libpgport', 'lib', 'misc');
$libpgport->AddDefine('FRONTEND');