aboutsummaryrefslogtreecommitdiff
path: root/src/bin/psql/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/psql/common.c')
-rw-r--r--src/bin/psql/common.c187
1 files changed, 26 insertions, 161 deletions
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index 53a1ea2bdb9..9c0d53689ec 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -23,6 +23,7 @@
#include "common/logging.h"
#include "copy.h"
#include "crosstabview.h"
+#include "fe_utils/cancel.h"
#include "fe_utils/mbprint.h"
#include "fe_utils/string_utils.h"
#include "portability/instr_time.h"
@@ -228,58 +229,28 @@ NoticeProcessor(void *arg, const char *message)
* Code to support query cancellation
*
* Before we start a query, we enable the SIGINT signal catcher to send a
- * cancel request to the backend. Note that sending the cancel directly from
- * the signal handler is safe because PQcancel() is written to make it
- * so. We use write() to report to stderr because it's better to use simple
- * facilities in a signal handler.
- *
- * On win32, the signal canceling happens on a separate thread, because
- * that's how SetConsoleCtrlHandler works. The PQcancel function is safe
- * for this (unlike PQrequestCancel). However, a CRITICAL_SECTION is required
- * to protect the PGcancel structure against being changed while the signal
- * thread is using it.
+ * cancel request to the backend.
*
* 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
- * fgets are coded to handle possible interruption. (XXX currently this does
- * not work on win32, so control-C is less useful there)
+ * fgets are coded to handle possible interruption.
+ *
+ * On Windows, currently this does not work, so control-C is less useful
+ * there, and the callback is just a no-op.
*/
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_cancel_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 +259,24 @@ 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 */
+#else
-static BOOL WINAPI
-consoleHandler(DWORD dwCtrlType)
+static void
+psql_cancel_callback(void)
{
- 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;
+ /* nothing to do here */
}
+#endif /* !WIN32 */
+
void
-setup_cancel_handler(void)
+psql_setup_cancel_handler(void)
{
- InitializeCriticalSection(&cancelConnLock);
-
- SetConsoleCtrlHandler(consoleHandler, TRUE);
+ setup_cancel_handler(psql_cancel_callback);
}
-#endif /* WIN32 */
/* ConnectionUp
@@ -428,62 +349,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 +572,7 @@ PSQLexec(const char *query)
return NULL;
}
- SetCancelConn();
+ SetCancelConn(pset.db);
res = PQexec(pset.db, query);
@@ -746,7 +611,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt)
return 0;
}
- SetCancelConn();
+ SetCancelConn(pset.db);
if (pset.timing)
INSTR_TIME_SET_CURRENT(before);
@@ -773,7 +638,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 +838,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 +956,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 +1207,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 +1225,7 @@ SendQuery(const char *query)
fflush(pset.logfile);
}
- SetCancelConn();
+ SetCancelConn(pset.db);
transaction_status = PQtransactionStatus(pset.db);
@@ -1886,7 +1751,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;
}