Skip to content

Commit 6e09df9

Browse files
committed
Add cancel handlers so it's possible to Ctrl-C clusterdb, reindexdb
and vacuumdb. ITAGAKI Takahiro, with minor fixes from me.
1 parent bbed5ba commit 6e09df9

File tree

5 files changed

+188
-39
lines changed

5 files changed

+188
-39
lines changed

src/bin/scripts/clusterdb.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* Portions Copyright (c) 2002-2007, PostgreSQL Global Development Group
66
*
7-
* $PostgreSQL: pgsql/src/bin/scripts/clusterdb.c,v 1.16 2007/02/13 18:06:18 momjian Exp $
7+
* $PostgreSQL: pgsql/src/bin/scripts/clusterdb.c,v 1.17 2007/04/09 18:21:22 mha Exp $
88
*
99
*-------------------------------------------------------------------------
1010
*/
@@ -111,6 +111,8 @@ main(int argc, char *argv[])
111111
exit(1);
112112
}
113113

114+
setup_cancel_handler();
115+
114116
if (alldb)
115117
{
116118
if (dbname)
@@ -159,7 +161,6 @@ cluster_one_database(const char *dbname, const char *table,
159161
PQExpBufferData sql;
160162

161163
PGconn *conn;
162-
PGresult *result;
163164

164165
initPQExpBuffer(&sql);
165166

@@ -169,12 +170,7 @@ cluster_one_database(const char *dbname, const char *table,
169170
appendPQExpBuffer(&sql, ";\n");
170171

171172
conn = connectDatabase(dbname, host, port, username, password, progname);
172-
173-
if (echo)
174-
printf("%s", sql.data);
175-
result = PQexec(conn, sql.data);
176-
177-
if (PQresultStatus(result) != PGRES_COMMAND_OK)
173+
if (!executeMaintenanceCommand(conn, sql.data, echo))
178174
{
179175
if (table)
180176
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,
185181
PQfinish(conn);
186182
exit(1);
187183
}
188-
189-
PQclear(result);
190184
PQfinish(conn);
191185
termPQExpBuffer(&sql);
192186

src/bin/scripts/common.c

Lines changed: 169 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,31 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.25 2007/01/05 22:19:50 momjian Exp $
10+
* $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.26 2007/04/09 18:21:22 mha Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
1414

1515
#include "postgres_fe.h"
1616

1717
#include <pwd.h>
18+
#include <signal.h>
1819
#include <unistd.h>
1920

2021
#include "common.h"
22+
#include "libpq/pqsignal.h"
23+
24+
static void SetCancelConn(PGconn *conn);
25+
static void ResetCancelConn(void);
2126

2227
#ifndef HAVE_INT_OPTRESET
2328
int optreset;
2429
#endif
2530

31+
static PGcancel *volatile cancelConn = NULL;
32+
#ifdef WIN32
33+
static CRITICAL_SECTION cancelConnLock;
34+
#endif
2635

2736
/*
2837
* Returns the current user name.
@@ -194,6 +203,33 @@ executeCommand(PGconn *conn, const char *query,
194203
}
195204

196205

206+
/*
207+
* As above for a SQL maintenance command (returns command success).
208+
* Command is executed with a cancel handler set, so Ctrl-C can
209+
* interrupt it.
210+
*/
211+
bool
212+
executeMaintenanceCommand(PGconn *conn, const char *query, bool echo)
213+
{
214+
PGresult *res;
215+
bool r;
216+
217+
if (echo)
218+
printf("%s\n", query);
219+
220+
SetCancelConn(conn);
221+
res = PQexec(conn, query);
222+
ResetCancelConn();
223+
224+
r = (res && PQresultStatus(res) == PGRES_COMMAND_OK);
225+
226+
if (res)
227+
PQclear(res);
228+
229+
return r;
230+
}
231+
232+
197233
/*
198234
* Check yes/no answer in a localized way. 1=yes, 0=no, -1=neither.
199235
*/
@@ -237,3 +273,135 @@ yesno_prompt(const char *question)
237273
_(PG_YESLETTER), _(PG_NOLETTER));
238274
}
239275
}
276+
277+
278+
/*
279+
* SetCancelConn
280+
*
281+
* Set cancelConn to point to the current database connection.
282+
*/
283+
static void
284+
SetCancelConn(PGconn *conn)
285+
{
286+
PGcancel *oldCancelConn;
287+
288+
#ifdef WIN32
289+
EnterCriticalSection(&cancelConnLock);
290+
#endif
291+
292+
/* Free the old one if we have one */
293+
oldCancelConn = cancelConn;
294+
295+
/* be sure handle_sigint doesn't use pointer while freeing */
296+
cancelConn = NULL;
297+
298+
if (oldCancelConn != NULL)
299+
PQfreeCancel(oldCancelConn);
300+
301+
cancelConn = PQgetCancel(conn);
302+
303+
#ifdef WIN32
304+
LeaveCriticalSection(&cancelConnLock);
305+
#endif
306+
}
307+
308+
/*
309+
* ResetCancelConn
310+
*
311+
* Free the current cancel connection, if any, and set to NULL.
312+
*/
313+
static void
314+
ResetCancelConn(void)
315+
{
316+
PGcancel *oldCancelConn;
317+
318+
#ifdef WIN32
319+
EnterCriticalSection(&cancelConnLock);
320+
#endif
321+
322+
oldCancelConn = cancelConn;
323+
324+
/* be sure handle_sigint doesn't use pointer while freeing */
325+
cancelConn = NULL;
326+
327+
if (oldCancelConn != NULL)
328+
PQfreeCancel(oldCancelConn);
329+
330+
#ifdef WIN32
331+
LeaveCriticalSection(&cancelConnLock);
332+
#endif
333+
}
334+
335+
#ifndef WIN32
336+
/*
337+
* Handle interrupt signals by cancelling the current command,
338+
* if it's being executed through executeMaintenanceCommand(),
339+
* and thus has a cancelConn set.
340+
*/
341+
static void
342+
handle_sigint(SIGNAL_ARGS)
343+
{
344+
int save_errno = errno;
345+
char errbuf[256];
346+
347+
/* Send QueryCancel if we are processing a database query */
348+
if (cancelConn != NULL)
349+
{
350+
if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
351+
fprintf(stderr, _("Cancel request sent\n"));
352+
else
353+
fprintf(stderr, _("Could not send cancel request: %s\n"), errbuf);
354+
}
355+
356+
errno = save_errno; /* just in case the write changed it */
357+
}
358+
359+
void
360+
setup_cancel_handler(void)
361+
{
362+
pqsignal(SIGINT, handle_sigint);
363+
}
364+
365+
#else /* WIN32 */
366+
367+
/*
368+
* Console control handler for Win32. Note that the control handler will
369+
* execute on a *different thread* than the main one, so we need to do
370+
* proper locking around those structures.
371+
*/
372+
static BOOL WINAPI
373+
consoleHandler(DWORD dwCtrlType)
374+
{
375+
char errbuf[256];
376+
377+
if (dwCtrlType == CTRL_C_EVENT ||
378+
dwCtrlType == CTRL_BREAK_EVENT)
379+
{
380+
/* Send QueryCancel if we are processing a database query */
381+
EnterCriticalSection(&cancelConnLock);
382+
if (cancelConn != NULL)
383+
{
384+
if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
385+
fprintf(stderr, _("Cancel request sent\n"));
386+
else
387+
fprintf(stderr, _("Could not send cancel request: %s"), errbuf);
388+
}
389+
LeaveCriticalSection(&cancelConnLock);
390+
391+
return TRUE;
392+
}
393+
else
394+
/* Return FALSE for any signals not being handled */
395+
return FALSE;
396+
}
397+
398+
void
399+
setup_cancel_handler(void)
400+
{
401+
InitializeCriticalSection(&cancelConnLock);
402+
403+
SetConsoleCtrlHandler(consoleHandler, TRUE);
404+
}
405+
406+
#endif /* WIN32 */
407+

src/bin/scripts/common.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* Copyright (c) 2003-2007, PostgreSQL Global Development Group
66
*
7-
* $PostgreSQL: pgsql/src/bin/scripts/common.h,v 1.16 2007/01/05 22:19:50 momjian Exp $
7+
* $PostgreSQL: pgsql/src/bin/scripts/common.h,v 1.17 2007/04/09 18:21:22 mha Exp $
88
*/
99
#ifndef COMMON_H
1010
#define COMMON_H
@@ -35,6 +35,11 @@ extern PGresult *executeQuery(PGconn *conn, const char *query,
3535
extern void executeCommand(PGconn *conn, const char *query,
3636
const char *progname, bool echo);
3737

38+
extern bool executeMaintenanceCommand(PGconn *conn, const char *query,
39+
bool echo);
40+
3841
extern bool yesno_prompt(const char *question);
3942

43+
extern void setup_cancel_handler(void);
44+
4045
#endif /* COMMON_H */

src/bin/scripts/reindexdb.c

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
66
*
7-
* $PostgreSQL: pgsql/src/bin/scripts/reindexdb.c,v 1.9 2007/02/13 18:06:18 momjian Exp $
7+
* $PostgreSQL: pgsql/src/bin/scripts/reindexdb.c,v 1.10 2007/04/09 18:21:22 mha Exp $
88
*
99
*-------------------------------------------------------------------------
1010
*/
@@ -126,6 +126,8 @@ main(int argc, char *argv[])
126126
exit(1);
127127
}
128128

129+
setup_cancel_handler();
130+
129131
if (alldb)
130132
{
131133
if (dbname)
@@ -214,7 +216,6 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
214216
PQExpBufferData sql;
215217

216218
PGconn *conn;
217-
PGresult *result;
218219

219220
initPQExpBuffer(&sql);
220221

@@ -229,11 +230,7 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
229230

230231
conn = connectDatabase(dbname, host, port, username, password, progname);
231232

232-
if (echo)
233-
printf("%s", sql.data);
234-
result = PQexec(conn, sql.data);
235-
236-
if (PQresultStatus(result) != PGRES_COMMAND_OK)
233+
if (!executeMaintenanceCommand(conn, sql.data, echo))
237234
{
238235
if (strcmp(type, "TABLE") == 0)
239236
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,
248245
exit(1);
249246
}
250247

251-
PQclear(result);
252248
PQfinish(conn);
253249
termPQExpBuffer(&sql);
254250

@@ -294,27 +290,19 @@ reindex_system_catalogs(const char *dbname, const char *host, const char *port,
294290
PQExpBufferData sql;
295291

296292
PGconn *conn;
297-
PGresult *result;
298293

299294
initPQExpBuffer(&sql);
300295

301296
appendPQExpBuffer(&sql, "REINDEX SYSTEM %s;\n", dbname);
302297

303298
conn = connectDatabase(dbname, host, port, username, password, progname);
304-
305-
if (echo)
306-
printf("%s", sql.data);
307-
result = PQexec(conn, sql.data);
308-
309-
if (PQresultStatus(result) != PGRES_COMMAND_OK)
299+
if (!executeMaintenanceCommand(conn, sql.data, echo))
310300
{
311301
fprintf(stderr, _("%s: reindexing of system catalogs failed: %s"),
312302
progname, PQerrorMessage(conn));
313303
PQfinish(conn);
314304
exit(1);
315305
}
316-
317-
PQclear(result);
318306
PQfinish(conn);
319307
termPQExpBuffer(&sql);
320308

src/bin/scripts/vacuumdb.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
66
* Portions Copyright (c) 1994, Regents of the University of California
77
*
8-
* $PostgreSQL: pgsql/src/bin/scripts/vacuumdb.c,v 1.16 2007/02/13 17:39:39 momjian Exp $
8+
* $PostgreSQL: pgsql/src/bin/scripts/vacuumdb.c,v 1.17 2007/04/09 18:21:22 mha Exp $
99
*
1010
*-------------------------------------------------------------------------
1111
*/
@@ -128,6 +128,8 @@ main(int argc, char *argv[])
128128
exit(1);
129129
}
130130

131+
setup_cancel_handler();
132+
131133
if (alldb)
132134
{
133135
if (dbname)
@@ -178,7 +180,6 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
178180
PQExpBufferData sql;
179181

180182
PGconn *conn;
181-
PGresult *result;
182183

183184
initPQExpBuffer(&sql);
184185

@@ -194,12 +195,7 @@ vacuum_one_database(const char *dbname, bool full, bool verbose, bool analyze,
194195
appendPQExpBuffer(&sql, ";\n");
195196

196197
conn = connectDatabase(dbname, host, port, username, password, progname);
197-
198-
if (echo)
199-
printf("%s", sql.data);
200-
result = PQexec(conn, sql.data);
201-
202-
if (PQresultStatus(result) != PGRES_COMMAND_OK)
198+
if (!executeMaintenanceCommand(conn, sql.data, echo))
203199
{
204200
if (table)
205201
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,
210206
PQfinish(conn);
211207
exit(1);
212208
}
213-
214-
PQclear(result);
215209
PQfinish(conn);
216210
termPQExpBuffer(&sql);
217211

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy