2323#include "common/logging.h"
2424#include "copy.h"
2525#include "crosstabview.h"
26+ #include "fe_utils/cancel.h"
2627#include "fe_utils/mbprint.h"
2728#include "fe_utils/string_utils.h"
2829#include "portability/instr_time.h"
@@ -228,58 +229,28 @@ NoticeProcessor(void *arg, const char *message)
228229 * Code to support query cancellation
229230 *
230231 * Before we start a query, we enable the SIGINT signal catcher to send a
231- * cancel request to the backend. Note that sending the cancel directly from
232- * the signal handler is safe because PQcancel() is written to make it
233- * so. We use write() to report to stderr because it's better to use simple
234- * facilities in a signal handler.
235- *
236- * On win32, the signal canceling happens on a separate thread, because
237- * that's how SetConsoleCtrlHandler works. The PQcancel function is safe
238- * for this (unlike PQrequestCancel). However, a CRITICAL_SECTION is required
239- * to protect the PGcancel structure against being changed while the signal
240- * thread is using it.
232+ * cancel request to the backend.
241233 *
242234 * SIGINT is supposed to abort all long-running psql operations, not only
243235 * database queries. In most places, this is accomplished by checking
244- * cancel_pressed during long-running loops. However, that won't work when
236+ * CancelRequested during long-running loops. However, that won't work when
245237 * blocked on user input (in readline() or fgets()). In those places, we
246238 * set sigint_interrupt_enabled true while blocked, instructing the signal
247239 * catcher to longjmp through sigint_interrupt_jmp. We assume readline and
248- * fgets are coded to handle possible interruption. (XXX currently this does
249- * not work on win32, so control-C is less useful there)
240+ * fgets are coded to handle possible interruption.
241+ *
242+ * On Windows, currently this does not work, so control-C is less useful
243+ * there, and the callback is just a no-op.
250244 */
251245volatile bool sigint_interrupt_enabled = false;
252246
253247sigjmp_buf sigint_interrupt_jmp ;
254248
255- static PGcancel * volatile cancelConn = NULL ;
256-
257- #ifdef WIN32
258- static CRITICAL_SECTION cancelConnLock ;
259- #endif
260-
261- /*
262- * Write a simple string to stderr --- must be safe in a signal handler.
263- * We ignore the write() result since there's not much we could do about it.
264- * Certain compilers make that harder than it ought to be.
265- */
266- #define write_stderr (str ) \
267- do { \
268- const char *str_ = (str); \
269- int rc_; \
270- rc_ = write(fileno(stderr), str_, strlen(str_)); \
271- (void) rc_; \
272- } while (0)
273-
274-
275249#ifndef WIN32
276250
277251static void
278- handle_sigint ( SIGNAL_ARGS )
252+ psql_cancel_callback ( void )
279253{
280- int save_errno = errno ;
281- char errbuf [256 ];
282-
283254 /* if we are waiting for input, longjmp out of it */
284255 if (sigint_interrupt_enabled )
285256 {
@@ -288,74 +259,24 @@ handle_sigint(SIGNAL_ARGS)
288259 }
289260
290261 /* else, set cancel flag to stop any long-running loops */
291- cancel_pressed = true;
292-
293- /* and send QueryCancel if we are processing a database query */
294- if (cancelConn != NULL )
295- {
296- if (PQcancel (cancelConn , errbuf , sizeof (errbuf )))
297- write_stderr ("Cancel request sent\n" );
298- else
299- {
300- write_stderr ("Could not send cancel request: " );
301- write_stderr (errbuf );
302- }
303- }
304-
305- errno = save_errno ; /* just in case the write changed it */
262+ CancelRequested = true;
306263}
307264
308- void
309- setup_cancel_handler (void )
310- {
311- pqsignal (SIGINT , handle_sigint );
312- }
313- #else /* WIN32 */
265+ #else
314266
315- static BOOL WINAPI
316- consoleHandler ( DWORD dwCtrlType )
267+ static void
268+ psql_cancel_callback ( void )
317269{
318- char errbuf [256 ];
319-
320- if (dwCtrlType == CTRL_C_EVENT ||
321- dwCtrlType == CTRL_BREAK_EVENT )
322- {
323- /*
324- * Can't longjmp here, because we are in wrong thread :-(
325- */
326-
327- /* set cancel flag to stop any long-running loops */
328- cancel_pressed = true;
329-
330- /* and send QueryCancel if we are processing a database query */
331- EnterCriticalSection (& cancelConnLock );
332- if (cancelConn != NULL )
333- {
334- if (PQcancel (cancelConn , errbuf , sizeof (errbuf )))
335- write_stderr ("Cancel request sent\n" );
336- else
337- {
338- write_stderr ("Could not send cancel request: " );
339- write_stderr (errbuf );
340- }
341- }
342- LeaveCriticalSection (& cancelConnLock );
343-
344- return TRUE;
345- }
346- else
347- /* Return FALSE for any signals not being handled */
348- return FALSE;
270+ /* nothing to do here */
349271}
350272
273+ #endif /* !WIN32 */
274+
351275void
352- setup_cancel_handler (void )
276+ psql_setup_cancel_handler (void )
353277{
354- InitializeCriticalSection (& cancelConnLock );
355-
356- SetConsoleCtrlHandler (consoleHandler , TRUE);
278+ setup_cancel_handler (psql_cancel_callback );
357279}
358- #endif /* WIN32 */
359280
360281
361282/* ConnectionUp
@@ -428,62 +349,6 @@ CheckConnection(void)
428349
429350
430351
431- /*
432- * SetCancelConn
433- *
434- * Set cancelConn to point to the current database connection.
435- */
436- void
437- SetCancelConn (void )
438- {
439- PGcancel * oldCancelConn ;
440-
441- #ifdef WIN32
442- EnterCriticalSection (& cancelConnLock );
443- #endif
444-
445- /* Free the old one if we have one */
446- oldCancelConn = cancelConn ;
447- /* be sure handle_sigint doesn't use pointer while freeing */
448- cancelConn = NULL ;
449-
450- if (oldCancelConn != NULL )
451- PQfreeCancel (oldCancelConn );
452-
453- cancelConn = PQgetCancel (pset .db );
454-
455- #ifdef WIN32
456- LeaveCriticalSection (& cancelConnLock );
457- #endif
458- }
459-
460-
461- /*
462- * ResetCancelConn
463- *
464- * Free the current cancel connection, if any, and set to NULL.
465- */
466- void
467- ResetCancelConn (void )
468- {
469- PGcancel * oldCancelConn ;
470-
471- #ifdef WIN32
472- EnterCriticalSection (& cancelConnLock );
473- #endif
474-
475- oldCancelConn = cancelConn ;
476- /* be sure handle_sigint doesn't use pointer while freeing */
477- cancelConn = NULL ;
478-
479- if (oldCancelConn != NULL )
480- PQfreeCancel (oldCancelConn );
481-
482- #ifdef WIN32
483- LeaveCriticalSection (& cancelConnLock );
484- #endif
485- }
486-
487352
488353/*
489354 * AcceptResult
@@ -707,7 +572,7 @@ PSQLexec(const char *query)
707572 return NULL ;
708573 }
709574
710- SetCancelConn ();
575+ SetCancelConn (pset . db );
711576
712577 res = PQexec (pset .db , query );
713578
@@ -746,7 +611,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt)
746611 return 0 ;
747612 }
748613
749- SetCancelConn ();
614+ SetCancelConn (pset . db );
750615
751616 if (pset .timing )
752617 INSTR_TIME_SET_CURRENT (before );
@@ -773,7 +638,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt)
773638 * consumed. The user's intention, though, is to cancel the entire watch
774639 * process, so detect a sent cancellation request and exit in this case.
775640 */
776- if (cancel_pressed )
641+ if (CancelRequested )
777642 {
778643 PQclear (res );
779644 return 0 ;
@@ -973,8 +838,8 @@ ExecQueryTuples(const PGresult *result)
973838 {
974839 const char * query = PQgetvalue (result , r , c );
975840
976- /* Abandon execution if cancel_pressed */
977- if (cancel_pressed )
841+ /* Abandon execution if CancelRequested */
842+ if (CancelRequested )
978843 goto loop_exit ;
979844
980845 /*
@@ -1091,7 +956,7 @@ ProcessResult(PGresult **results)
1091956 FILE * copystream ;
1092957 PGresult * copy_result ;
1093958
1094- SetCancelConn ();
959+ SetCancelConn (pset . db );
1095960 if (result_status == PGRES_COPY_OUT )
1096961 {
1097962 bool need_close = false;
@@ -1342,7 +1207,7 @@ SendQuery(const char *query)
13421207 if (fgets (buf , sizeof (buf ), stdin ) != NULL )
13431208 if (buf [0 ] == 'x' )
13441209 goto sendquery_cleanup ;
1345- if (cancel_pressed )
1210+ if (CancelRequested )
13461211 goto sendquery_cleanup ;
13471212 }
13481213 else if (pset .echo == PSQL_ECHO_QUERIES )
@@ -1360,7 +1225,7 @@ SendQuery(const char *query)
13601225 fflush (pset .logfile );
13611226 }
13621227
1363- SetCancelConn ();
1228+ SetCancelConn (pset . db );
13641229
13651230 transaction_status = PQtransactionStatus (pset .db );
13661231
@@ -1886,7 +1751,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
18861751 * writing things to the stream, we presume $PAGER has disappeared and
18871752 * stop bothering to pull down more data.
18881753 */
1889- if (ntuples < fetch_count || cancel_pressed || flush_error ||
1754+ if (ntuples < fetch_count || CancelRequested || flush_error ||
18901755 ferror (fout ))
18911756 break ;
18921757 }
0 commit comments