Add cancel handlers so it's possible to Ctrl-C clusterdb, reindexdb
and vacuumdb. ITAGAKI Takahiro, with minor fixes from me.
This commit is contained in:
parent
bbed5ba914
commit
6e09df9d26
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* Portions Copyright (c) 2002-2007, PostgreSQL Global Development Group
|
* 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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_cancel_handler();
|
||||||
|
|
||||||
if (alldb)
|
if (alldb)
|
||||||
{
|
{
|
||||||
if (dbname)
|
if (dbname)
|
||||||
@ -159,7 +161,6 @@ cluster_one_database(const char *dbname, const char *table,
|
|||||||
PQExpBufferData sql;
|
PQExpBufferData sql;
|
||||||
|
|
||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
PGresult *result;
|
|
||||||
|
|
||||||
initPQExpBuffer(&sql);
|
initPQExpBuffer(&sql);
|
||||||
|
|
||||||
@ -169,12 +170,7 @@ cluster_one_database(const char *dbname, const char *table,
|
|||||||
appendPQExpBuffer(&sql, ";\n");
|
appendPQExpBuffer(&sql, ";\n");
|
||||||
|
|
||||||
conn = connectDatabase(dbname, host, port, username, password, progname);
|
conn = connectDatabase(dbname, host, port, username, password, progname);
|
||||||
|
if (!executeMaintenanceCommand(conn, sql.data, echo))
|
||||||
if (echo)
|
|
||||||
printf("%s", sql.data);
|
|
||||||
result = PQexec(conn, sql.data);
|
|
||||||
|
|
||||||
if (PQresultStatus(result) != PGRES_COMMAND_OK)
|
|
||||||
{
|
{
|
||||||
if (table)
|
if (table)
|
||||||
fprintf(stderr, _("%s: clustering of table \"%s\" in database \"%s\" failed: %s"),
|
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);
|
PQfinish(conn);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PQclear(result);
|
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
termPQExpBuffer(&sql);
|
termPQExpBuffer(&sql);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -15,14 +15,23 @@
|
|||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "libpq/pqsignal.h"
|
||||||
|
|
||||||
|
static void SetCancelConn(PGconn *conn);
|
||||||
|
static void ResetCancelConn(void);
|
||||||
|
|
||||||
#ifndef HAVE_INT_OPTRESET
|
#ifndef HAVE_INT_OPTRESET
|
||||||
int optreset;
|
int optreset;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static PGcancel *volatile cancelConn = NULL;
|
||||||
|
#ifdef WIN32
|
||||||
|
static CRITICAL_SECTION cancelConnLock;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the current user name.
|
* 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.
|
* 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));
|
_(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 */
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2003-2007, PostgreSQL Global Development Group
|
* 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
|
#ifndef COMMON_H
|
||||||
#define 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,
|
extern void executeCommand(PGconn *conn, const char *query,
|
||||||
const char *progname, bool echo);
|
const char *progname, bool echo);
|
||||||
|
|
||||||
|
extern bool executeMaintenanceCommand(PGconn *conn, const char *query,
|
||||||
|
bool echo);
|
||||||
|
|
||||||
extern bool yesno_prompt(const char *question);
|
extern bool yesno_prompt(const char *question);
|
||||||
|
|
||||||
|
extern void setup_cancel_handler(void);
|
||||||
|
|
||||||
#endif /* COMMON_H */
|
#endif /* COMMON_H */
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* 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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_cancel_handler();
|
||||||
|
|
||||||
if (alldb)
|
if (alldb)
|
||||||
{
|
{
|
||||||
if (dbname)
|
if (dbname)
|
||||||
@ -214,7 +216,6 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
|
|||||||
PQExpBufferData sql;
|
PQExpBufferData sql;
|
||||||
|
|
||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
PGresult *result;
|
|
||||||
|
|
||||||
initPQExpBuffer(&sql);
|
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);
|
conn = connectDatabase(dbname, host, port, username, password, progname);
|
||||||
|
|
||||||
if (echo)
|
if (!executeMaintenanceCommand(conn, sql.data, echo))
|
||||||
printf("%s", sql.data);
|
|
||||||
result = PQexec(conn, sql.data);
|
|
||||||
|
|
||||||
if (PQresultStatus(result) != PGRES_COMMAND_OK)
|
|
||||||
{
|
{
|
||||||
if (strcmp(type, "TABLE") == 0)
|
if (strcmp(type, "TABLE") == 0)
|
||||||
fprintf(stderr, _("%s: reindexing of table \"%s\" in database \"%s\" failed: %s"),
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PQclear(result);
|
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
termPQExpBuffer(&sql);
|
termPQExpBuffer(&sql);
|
||||||
|
|
||||||
@ -294,27 +290,19 @@ reindex_system_catalogs(const char *dbname, const char *host, const char *port,
|
|||||||
PQExpBufferData sql;
|
PQExpBufferData sql;
|
||||||
|
|
||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
PGresult *result;
|
|
||||||
|
|
||||||
initPQExpBuffer(&sql);
|
initPQExpBuffer(&sql);
|
||||||
|
|
||||||
appendPQExpBuffer(&sql, "REINDEX SYSTEM %s;\n", dbname);
|
appendPQExpBuffer(&sql, "REINDEX SYSTEM %s;\n", dbname);
|
||||||
|
|
||||||
conn = connectDatabase(dbname, host, port, username, password, progname);
|
conn = connectDatabase(dbname, host, port, username, password, progname);
|
||||||
|
if (!executeMaintenanceCommand(conn, sql.data, echo))
|
||||||
if (echo)
|
|
||||||
printf("%s", sql.data);
|
|
||||||
result = PQexec(conn, sql.data);
|
|
||||||
|
|
||||||
if (PQresultStatus(result) != PGRES_COMMAND_OK)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: reindexing of system catalogs failed: %s"),
|
fprintf(stderr, _("%s: reindexing of system catalogs failed: %s"),
|
||||||
progname, PQerrorMessage(conn));
|
progname, PQerrorMessage(conn));
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PQclear(result);
|
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
termPQExpBuffer(&sql);
|
termPQExpBuffer(&sql);
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_cancel_handler();
|
||||||
|
|
||||||
if (alldb)
|
if (alldb)
|
||||||
{
|
{
|
||||||
if (dbname)
|
if (dbname)
|
||||||
@ -178,7 +180,6 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
|
|||||||
PQExpBufferData sql;
|
PQExpBufferData sql;
|
||||||
|
|
||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
PGresult *result;
|
|
||||||
|
|
||||||
initPQExpBuffer(&sql);
|
initPQExpBuffer(&sql);
|
||||||
|
|
||||||
@ -194,12 +195,7 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
|
|||||||
appendPQExpBuffer(&sql, ";\n");
|
appendPQExpBuffer(&sql, ";\n");
|
||||||
|
|
||||||
conn = connectDatabase(dbname, host, port, username, password, progname);
|
conn = connectDatabase(dbname, host, port, username, password, progname);
|
||||||
|
if (!executeMaintenanceCommand(conn, sql.data, echo))
|
||||||
if (echo)
|
|
||||||
printf("%s", sql.data);
|
|
||||||
result = PQexec(conn, sql.data);
|
|
||||||
|
|
||||||
if (PQresultStatus(result) != PGRES_COMMAND_OK)
|
|
||||||
{
|
{
|
||||||
if (table)
|
if (table)
|
||||||
fprintf(stderr, _("%s: vacuuming of table \"%s\" in database \"%s\" failed: %s"),
|
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);
|
PQfinish(conn);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PQclear(result);
|
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
termPQExpBuffer(&sql);
|
termPQExpBuffer(&sql);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user