Add cancel handlers so it's possible to Ctrl-C clusterdb, reindexdb
authorMagnus Hagander <magnus@hagander.net>
Mon, 9 Apr 2007 18:21:22 +0000 (18:21 +0000)
committerMagnus Hagander <magnus@hagander.net>
Mon, 9 Apr 2007 18:21:22 +0000 (18:21 +0000)
and vacuumdb.
ITAGAKI Takahiro, with minor fixes from me.

src/bin/scripts/clusterdb.c
src/bin/scripts/common.c
src/bin/scripts/common.h
src/bin/scripts/reindexdb.c
src/bin/scripts/vacuumdb.c

index 193eaf781ace74ab08a14d691c12806faec3d622..c077e26f43d7107b01fc25361a054c1afe482bab 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Portions Copyright (c) 2002-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/scripts/clusterdb.c,v 1.16 2007/02/13 18:06:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/scripts/clusterdb.c,v 1.17 2007/04/09 18:21:22 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -111,6 +111,8 @@ main(int argc, char *argv[])
                        exit(1);
        }
 
+       setup_cancel_handler();
+
        if (alldb)
        {
                if (dbname)
@@ -159,7 +161,6 @@ cluster_one_database(const char *dbname, const char *table,
        PQExpBufferData sql;
 
        PGconn     *conn;
-       PGresult   *result;
 
        initPQExpBuffer(&sql);
 
@@ -169,12 +170,7 @@ cluster_one_database(const char *dbname, const char *table,
        appendPQExpBuffer(&sql, ";\n");
 
        conn = connectDatabase(dbname, host, port, username, password, progname);
-
-       if (echo)
-               printf("%s", sql.data);
-       result = PQexec(conn, sql.data);
-
-       if (PQresultStatus(result) != PGRES_COMMAND_OK)
+       if (!executeMaintenanceCommand(conn, sql.data, echo))
        {
                if (table)
                        fprintf(stderr, _("%s: clustering of table \"%s\" in database \"%s\" failed: %s"),
@@ -185,8 +181,6 @@ cluster_one_database(const char *dbname, const char *table,
                PQfinish(conn);
                exit(1);
        }
-
-       PQclear(result);
        PQfinish(conn);
        termPQExpBuffer(&sql);
 
index b12cba2e8b28548f32c0f8ef722c2e331556c957..dfe9a52be43103203d73480d112f3e5ba954e817 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.25 2007/01/05 22:19:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.26 2007/04/09 18:21:22 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres_fe.h"
 
 #include <pwd.h>
+#include <signal.h>
 #include <unistd.h>
 
 #include "common.h"
+#include "libpq/pqsignal.h"
+
+static void SetCancelConn(PGconn *conn);
+static void ResetCancelConn(void);
 
 #ifndef HAVE_INT_OPTRESET
 int                    optreset;
 #endif
 
+static PGcancel *volatile cancelConn = NULL;
+#ifdef WIN32
+static CRITICAL_SECTION cancelConnLock;
+#endif
 
 /*
  * Returns the current user name.
@@ -194,6 +203,33 @@ executeCommand(PGconn *conn, const char *query,
 }
 
 
+/*
+ * As above for a SQL maintenance command (returns command success).
+ * Command is executed with a cancel handler set, so Ctrl-C can
+ * interrupt it.
+ */
+bool
+executeMaintenanceCommand(PGconn *conn, const char *query, bool echo)
+{
+       PGresult   *res;
+       bool            r;
+
+       if (echo)
+               printf("%s\n", query);
+
+       SetCancelConn(conn);
+       res = PQexec(conn, query);
+       ResetCancelConn();
+
+       r = (res && PQresultStatus(res) == PGRES_COMMAND_OK);
+
+       if (res)
+               PQclear(res);
+
+       return r;
+}
+
+
 /*
  * Check yes/no answer in a localized way.     1=yes, 0=no, -1=neither.
  */
@@ -237,3 +273,135 @@ yesno_prompt(const char *question)
                           _(PG_YESLETTER), _(PG_NOLETTER));
        }
 }
+
+
+/*
+ * SetCancelConn
+ *
+ * Set cancelConn to point to the current database connection.
+ */
+static 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.
+ */
+static 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 cancelling the current command,
+ * if it's being executed through executeMaintenanceCommand(),
+ * and thus has a cancelConn 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)))
+                       fprintf(stderr, _("Cancel request sent\n"));
+               else
+                       fprintf(stderr, _("Could not send cancel request: %s\n"), errbuf);
+       }
+
+       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"));
+                       else
+                               fprintf(stderr, _("Could not send cancel request: %s"), errbuf);
+               }
+               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 */
+
index c2ecf1a663617ae871534591fd983c087149bec8..9f5922304762f969381cb878895adc6f60f8b709 100644 (file)
@@ -4,7 +4,7 @@
  *
  *     Copyright (c) 2003-2007, PostgreSQL Global Development Group
  *
- *     $PostgreSQL: pgsql/src/bin/scripts/common.h,v 1.16 2007/01/05 22:19:50 momjian Exp $
+ *     $PostgreSQL: pgsql/src/bin/scripts/common.h,v 1.17 2007/04/09 18:21:22 mha Exp $
  */
 #ifndef COMMON_H
 #define COMMON_H
@@ -35,6 +35,11 @@ extern PGresult *executeQuery(PGconn *conn, const char *query,
 extern void executeCommand(PGconn *conn, const char *query,
                           const char *progname, bool echo);
 
+extern bool executeMaintenanceCommand(PGconn *conn, const char *query,
+                                                          bool echo);
+
 extern bool yesno_prompt(const char *question);
 
+extern void setup_cancel_handler(void);
+
 #endif   /* COMMON_H */
index 057fbd876eaa9f3fa2979107c2f54b541599fc64..34dd72ff4b4f92dff72693c7a997c26e410beb2e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/scripts/reindexdb.c,v 1.9 2007/02/13 18:06:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/scripts/reindexdb.c,v 1.10 2007/04/09 18:21:22 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -126,6 +126,8 @@ main(int argc, char *argv[])
                        exit(1);
        }
 
+       setup_cancel_handler();
+
        if (alldb)
        {
                if (dbname)
@@ -214,7 +216,6 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
        PQExpBufferData sql;
 
        PGconn     *conn;
-       PGresult   *result;
 
        initPQExpBuffer(&sql);
 
@@ -229,11 +230,7 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
 
        conn = connectDatabase(dbname, host, port, username, password, progname);
 
-       if (echo)
-               printf("%s", sql.data);
-       result = PQexec(conn, sql.data);
-
-       if (PQresultStatus(result) != PGRES_COMMAND_OK)
+       if (!executeMaintenanceCommand(conn, sql.data, echo))
        {
                if (strcmp(type, "TABLE") == 0)
                        fprintf(stderr, _("%s: reindexing of table \"%s\" in database \"%s\" failed: %s"),
@@ -248,7 +245,6 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
                exit(1);
        }
 
-       PQclear(result);
        PQfinish(conn);
        termPQExpBuffer(&sql);
 
@@ -294,27 +290,19 @@ reindex_system_catalogs(const char *dbname, const char *host, const char *port,
        PQExpBufferData sql;
 
        PGconn     *conn;
-       PGresult   *result;
 
        initPQExpBuffer(&sql);
 
        appendPQExpBuffer(&sql, "REINDEX SYSTEM %s;\n", dbname);
 
        conn = connectDatabase(dbname, host, port, username, password, progname);
-
-       if (echo)
-               printf("%s", sql.data);
-       result = PQexec(conn, sql.data);
-
-       if (PQresultStatus(result) != PGRES_COMMAND_OK)
+       if (!executeMaintenanceCommand(conn, sql.data, echo))
        {
                fprintf(stderr, _("%s: reindexing of system catalogs failed: %s"),
                                progname, PQerrorMessage(conn));
                PQfinish(conn);
                exit(1);
        }
-
-       PQclear(result);
        PQfinish(conn);
        termPQExpBuffer(&sql);
 
index aaa897b747729c586178487e427f5df85a7aa0cb..b767133361e96e457309014f898155aef83d1a1c 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/scripts/vacuumdb.c,v 1.16 2007/02/13 17:39:39 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/scripts/vacuumdb.c,v 1.17 2007/04/09 18:21:22 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -128,6 +128,8 @@ main(int argc, char *argv[])
                        exit(1);
        }
 
+       setup_cancel_handler();
+
        if (alldb)
        {
                if (dbname)
@@ -178,7 +180,6 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
        PQExpBufferData sql;
 
        PGconn     *conn;
-       PGresult   *result;
 
        initPQExpBuffer(&sql);
 
@@ -194,12 +195,7 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
        appendPQExpBuffer(&sql, ";\n");
 
        conn = connectDatabase(dbname, host, port, username, password, progname);
-
-       if (echo)
-               printf("%s", sql.data);
-       result = PQexec(conn, sql.data);
-
-       if (PQresultStatus(result) != PGRES_COMMAND_OK)
+       if (!executeMaintenanceCommand(conn, sql.data, echo))
        {
                if (table)
                        fprintf(stderr, _("%s: vacuuming of table \"%s\" in database \"%s\" failed: %s"),
@@ -210,8 +206,6 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
                PQfinish(conn);
                exit(1);
        }
-
-       PQclear(result);
        PQfinish(conn);
        termPQExpBuffer(&sql);