*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.118 2006/05/26 19:51:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.119 2006/06/14 16:49:02 tgl Exp $
*/
#include "postgres_fe.h"
#include "common.h"
#ifndef WIN32
#include <sys/time.h>
#include <unistd.h> /* for write() */
-#include <setjmp.h>
#else
#include <io.h> /* for _write() */
#include <win32.h>
((T)->millitm - (U)->millitm))
#endif
-extern bool prompt_state;
-
static bool command_no_begin(const char *query);
/*
* Code to support query cancellation
*
- * Before we start a query, we enable a SIGINT signal catcher that sends a
+ * 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 print to stderr because it's better to use simple
+ * so. We use write() to report to stderr because it's better to use simple
* facilities in a signal handler.
*
* On win32, the signal cancelling 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 other
+ * to protect the PGcancel structure against being changed while the signal
* thread is using it.
+ *
+ * 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
+ * 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)
*/
-static PGcancel *cancelConn = NULL;
+volatile bool sigint_interrupt_enabled = false;
+
+sigjmp_buf sigint_interrupt_jmp;
+
+static PGcancel * volatile cancelConn = NULL;
#ifdef WIN32
static CRITICAL_SECTION cancelConnLock;
#endif
-volatile bool cancel_pressed = false;
-
#define write_stderr(str) write(fileno(stderr), str, strlen(str))
#ifndef WIN32
-void
+static void
handle_sigint(SIGNAL_ARGS)
{
int save_errno = errno;
char errbuf[256];
- /* Don't muck around if prompting for a password. */
- if (prompt_state)
- return;
-
- if (cancelConn == NULL)
- siglongjmp(main_loop_jmp, 1);
+ /* if we are waiting for input, longjmp out of it */
+ if (sigint_interrupt_enabled)
+ {
+ sigint_interrupt_enabled = false;
+ siglongjmp(sigint_interrupt_jmp, 1);
+ }
+ /* else, set cancel flag to stop any long-running loops */
cancel_pressed = true;
- if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
- write_stderr("Cancel request sent\n");
- else
+ /* and send QueryCancel if we are processing a database query */
+ if (cancelConn != NULL)
{
- write_stderr("Could not send cancel request: ");
- write_stderr(errbuf);
+ 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 */
}
+
+void
+setup_cancel_handler(void)
+{
+ pqsignal(SIGINT, handle_sigint);
+}
+
#else /* WIN32 */
static BOOL WINAPI
if (dwCtrlType == CTRL_C_EVENT ||
dwCtrlType == CTRL_BREAK_EVENT)
{
- if (prompt_state)
- return TRUE;
+ /*
+ * Can't longjmp here, because we are in wrong thread :-(
+ */
+
+ /* set cancel flag to stop any long-running loops */
+ cancel_pressed = true;
- /* Perform query cancel */
+ /* and send QueryCancel if we are processing a database query */
EnterCriticalSection(&cancelConnLock);
if (cancelConn != NULL)
{
- cancel_pressed = true;
-
if (PQcancel(cancelConn, errbuf, sizeof(errbuf)))
write_stderr("Cancel request sent\n");
else
return FALSE;
}
-void
-setup_win32_locks(void)
-{
- InitializeCriticalSection(&cancelConnLock);
-}
-
void
setup_cancel_handler(void)
{
- static bool done = false;
+ InitializeCriticalSection(&cancelConnLock);
- /* only need one handler per process */
- if (!done)
- {
- SetConsoleCtrlHandler(consoleHandler, TRUE);
- done = true;
- }
+ SetConsoleCtrlHandler(consoleHandler, TRUE);
}
+
#endif /* WIN32 */
*
* Set cancelConn to point to the current database connection.
*/
-static void
+void
SetCancelConn(void)
{
+ PGcancel *oldCancelConn;
+
#ifdef WIN32
EnterCriticalSection(&cancelConnLock);
#endif
/* Free the old one if we have one */
- if (cancelConn != NULL)
- PQfreeCancel(cancelConn);
+ oldCancelConn = cancelConn;
+ /* be sure handle_sigint doesn't use pointer while freeing */
+ cancelConn = NULL;
+
+ if (oldCancelConn != NULL)
+ PQfreeCancel(oldCancelConn);
cancelConn = PQgetCancel(pset.db);
void
ResetCancelConn(void)
{
+ PGcancel *oldCancelConn;
+
#ifdef WIN32
EnterCriticalSection(&cancelConnLock);
#endif
- if (cancelConn)
- PQfreeCancel(cancelConn);
-
+ oldCancelConn = cancelConn;
+ /* be sure handle_sigint doesn't use pointer while freeing */
cancelConn = NULL;
+ if (oldCancelConn != NULL)
+ PQfreeCancel(oldCancelConn);
+
#ifdef WIN32
LeaveCriticalSection(&cancelConnLock);
#endif
case PGRES_TUPLES_OK:
case PGRES_EMPTY_QUERY:
case PGRES_COPY_IN:
- /* Fine, do nothing */
- break;
-
case PGRES_COPY_OUT:
- /*
- * Keep cancel connection active during copy out state.
- * The matching ResetCancelConn() is in handleCopyOut.
- */
- SetCancelConn();
+ /* Fine, do nothing */
break;
default:
break;
case PGRES_COPY_OUT:
+ SetCancelConn();
success = handleCopyOut(pset.db, pset.queryFout);
+ ResetCancelConn();
break;
case PGRES_COPY_IN:
+ SetCancelConn();
success = handleCopyIn(pset.db, pset.cur_cmd_source,
PQbinaryTuples(results));
+ ResetCancelConn();
break;
default:
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/common.h,v 1.49 2006/06/01 00:15:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/common.h,v 1.50 2006/06/14 16:49:02 tgl Exp $
*/
#ifndef COMMON_H
#define COMMON_H
#include "postgres_fe.h"
-#include <signal.h>
-#include "pqsignal.h"
+#include <setjmp.h>
#include "libpq-fe.h"
#ifdef USE_ASSERT_CHECKING
extern void NoticeProcessor(void *arg, const char *message);
-extern volatile bool cancel_pressed;
+extern volatile bool sigint_interrupt_enabled;
-extern void ResetCancelConn(void);
+extern sigjmp_buf sigint_interrupt_jmp;
+
+extern volatile bool cancel_pressed;
+/* Note: cancel_pressed is defined in print.c, see that file for reasons */
-#ifndef WIN32
-extern void handle_sigint(SIGNAL_ARGS);
-#else
-extern void setup_win32_locks(void);
extern void setup_cancel_handler(void);
-#endif
+
+extern void SetCancelConn(void);
+extern void ResetCancelConn(void);
extern PGresult *PSQLexec(const char *query, bool start_xact);
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.65 2006/06/07 22:24:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.66 2006/06/14 16:49:02 tgl Exp $
*/
#include "postgres_fe.h"
#include "copy.h"
switch (PQresultStatus(result))
{
case PGRES_COPY_OUT:
+ SetCancelConn();
success = handleCopyOut(pset.db, copystream);
+ ResetCancelConn();
break;
case PGRES_COPY_IN:
+ SetCancelConn();
success = handleCopyIn(pset.db, copystream,
PQbinaryTuples(result));
+ ResetCancelConn();
break;
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
OK = false;
}
PQclear(res);
-
- /* Disable cancel connection (see AcceptResult in common.c) */
- ResetCancelConn();
return OK;
}
bool
handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary)
{
- bool OK = true;
+ bool OK;
const char *prompt;
char buf[COPYBUFSIZ];
PGresult *res;
+ /*
+ * Establish longjmp destination for exiting from wait-for-input.
+ * (This is only effective while sigint_interrupt_enabled is TRUE.)
+ */
+ if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
+ {
+ /* got here with longjmp */
+
+ /* Terminate data transfer */
+ PQputCopyEnd(conn, _("aborted by user cancel"));
+
+ /* Check command status and return to normal libpq state */
+ res = PQgetResult(conn);
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ psql_error("%s", PQerrorMessage(conn));
+ PQclear(res);
+
+ return false;
+ }
+
/* Prompt if interactive input */
if (isatty(fileno(copystream)))
{
else
prompt = NULL;
+ OK = true;
+
if (isbinary)
{
- int buflen;
-
/* interactive input probably silly, but give one prompt anyway */
if (prompt)
{
fflush(stdout);
}
- while ((buflen = fread(buf, 1, COPYBUFSIZ, copystream)) > 0)
+ for (;;)
{
+ int buflen;
+
+ /* enable longjmp while waiting for input */
+ sigint_interrupt_enabled = true;
+
+ buflen = fread(buf, 1, COPYBUFSIZ, copystream);
+
+ sigint_interrupt_enabled = false;
+
+ if (buflen <= 0)
+ break;
+
if (PQputCopyData(conn, buf, buflen) <= 0)
{
OK = false;
while (!linedone)
{ /* for each bufferload in line ... */
int linelen;
+ char *fgresult;
+
+ /* enable longjmp while waiting for input */
+ sigint_interrupt_enabled = true;
+
+ fgresult = fgets(buf, COPYBUFSIZ, copystream);
+
+ sigint_interrupt_enabled = false;
- if (!fgets(buf, COPYBUFSIZ, copystream))
+ if (!fgresult)
{
copydone = true;
break;
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.139 2006/06/01 00:15:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.140 2006/06/14 16:49:02 tgl Exp $
*/
#include "postgres_fe.h"
#include "describe.h"
PQclear(res);
return false;
}
+ if (cancel_pressed)
+ {
+ PQclear(res);
+ return false;
+ }
}
PQclear(res);
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.54 2006/06/11 23:06:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/input.c,v 1.55 2006/06/14 16:49:02 tgl Exp $
*/
#include "postgres_fe.h"
* gets_interactive()
*
* Gets a line of interactive input, using readline if desired.
- * The result is malloc'ed.
+ * The result is a malloc'd string.
+ *
+ * Caller *must* have set up sigint_interrupt_jmp before calling.
*/
char *
gets_interactive(const char *prompt)
#ifdef USE_READLINE
if (useReadline)
{
+ char *result;
+
+ /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
+ sigint_interrupt_enabled = true;
+
/* On some platforms, readline is declared as readline(char *) */
- return readline((char *) prompt);
+ result = readline((char *) prompt);
+
+ /* Disable SIGINT again */
+ sigint_interrupt_enabled = false;
+
+ return result;
}
#endif
* gets_fromFile
*
* Gets a line of noninteractive input from a file (which could be stdin).
+ * The result is a malloc'd string.
+ *
+ * Caller *must* have set up sigint_interrupt_jmp before calling.
+ *
+ * Note: we re-use a static PQExpBuffer for each call. This is to avoid
+ * leaking memory if interrupted by SIGINT.
*/
char *
gets_fromFile(FILE *source)
{
- PQExpBufferData buffer;
+ static PQExpBuffer buffer = NULL;
+
char line[1024];
- initPQExpBuffer(&buffer);
+ if (buffer == NULL) /* first time through? */
+ buffer = createPQExpBuffer();
+ else
+ resetPQExpBuffer(buffer);
- while (fgets(line, sizeof(line), source) != NULL)
+ for (;;)
{
- appendPQExpBufferStr(&buffer, line);
- if (buffer.data[buffer.len - 1] == '\n')
+ char *result;
+
+ /* Enable SIGINT to longjmp to sigint_interrupt_jmp */
+ sigint_interrupt_enabled = true;
+
+ /* Get some data */
+ result = fgets(line, sizeof(line), source);
+
+ /* Disable SIGINT again */
+ sigint_interrupt_enabled = false;
+
+ /* EOF? */
+ if (result == NULL)
+ break;
+
+ appendPQExpBufferStr(buffer, line);
+
+ /* EOL? */
+ if (buffer->data[buffer->len - 1] == '\n')
{
- buffer.data[buffer.len - 1] = '\0';
- return buffer.data;
+ buffer->data[buffer->len - 1] = '\0';
+ return pg_strdup(buffer->data);
}
}
- if (buffer.len > 0)
- return buffer.data; /* EOF after reading some bufferload(s) */
+ if (buffer->len > 0) /* EOF after reading some bufferload(s) */
+ return pg_strdup(buffer->data);
/* EOF, so return null */
- termPQExpBuffer(&buffer);
return NULL;
}
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/large_obj.c,v 1.43 2006/05/28 21:13:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/large_obj.c,v 1.44 2006/06/14 16:49:02 tgl Exp $
*/
#include "postgres_fe.h"
#include "large_obj.h"
if (!start_lo_xact("\\lo_export", &own_transaction))
return false;
+ SetCancelConn();
status = lo_export(pset.db, atooid(loid_arg), filename_arg);
+ ResetCancelConn();
+
+ /* of course this status is documented nowhere :( */
if (status != 1)
- { /* of course this status is documented nowhere
- * :( */
+ {
fputs(PQerrorMessage(pset.db), stderr);
return fail_lo_xact("\\lo_export", own_transaction);
}
if (!start_lo_xact("\\lo_import", &own_transaction))
return false;
+ SetCancelConn();
loid = lo_import(pset.db, filename_arg);
+ ResetCancelConn();
+
if (loid == InvalidOid)
{
fputs(PQerrorMessage(pset.db), stderr);
if (!start_lo_xact("\\lo_unlink", &own_transaction))
return false;
+ SetCancelConn();
status = lo_unlink(pset.db, loid);
+ ResetCancelConn();
+
if (status == -1)
{
fputs(PQerrorMessage(pset.db), stderr);
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.79 2006/06/11 23:06:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/mainloop.c,v 1.80 2006/06/14 16:49:02 tgl Exp $
*/
#include "postgres_fe.h"
#include "mainloop.h"
#include "psqlscan.h"
#include "settings.h"
-#ifndef WIN32
-#include <setjmp.h>
-sigjmp_buf main_loop_jmp;
-#endif
-
/*
* Main processing loop for reading lines of input
while (successResult == EXIT_SUCCESS)
{
/*
- * Welcome code for Control-C
+ * Clean up after a previous Control-C
*/
if (cancel_pressed)
{
if (!pset.cur_cmd_interactive)
{
/*
- * You get here if you stopped a script with Ctrl-C and a
- * query cancel was issued. In that case we don't do the
- * longjmp, so the query routine can finish nicely.
+ * You get here if you stopped a script with Ctrl-C.
*/
successResult = EXIT_USER;
break;
cancel_pressed = false;
}
-#ifndef WIN32
- if (sigsetjmp(main_loop_jmp, 1) != 0)
+ /*
+ * Establish longjmp destination for exiting from wait-for-input.
+ * We must re-do this each time through the loop for safety, since
+ * the jmpbuf might get changed during command execution.
+ */
+ if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
{
/* got here with longjmp */
/* reset parsing state */
- resetPQExpBuffer(query_buf);
psql_scan_finish(scan_state);
psql_scan_reset(scan_state);
+ resetPQExpBuffer(query_buf);
+ resetPQExpBuffer(history_buf);
count_eof = 0;
slashCmdStatus = PSQL_CMD_UNKNOWN;
prompt_status = PROMPT_READY;
+ cancel_pressed = false;
if (pset.cur_cmd_interactive)
putc('\n', stdout);
}
}
- /*
- * establish the control-C handler only after main_loop_jmp is ready
- */
- pqsignal(SIGINT, handle_sigint); /* control-C => cancel */
-#else /* WIN32 */
- setup_cancel_handler();
-#endif
-
fflush(stdout);
/*
}
/*
- * Reset SIGINT handler because main_loop_jmp will be invalid as soon as
- * we exit this routine. If there is an outer MainLoop instance, it will
- * re-enable ^C catching as soon as it gets back to the top of its loop
- * and resets main_loop_jmp to point to itself.
+ * Let's just make real sure the SIGINT handler won't try to use
+ * sigint_interrupt_jmp after we exit this routine. If there is an outer
+ * MainLoop instance, it will reset sigint_interrupt_jmp to point to
+ * itself at the top of its loop, before any further interactive input
+ * happens.
*/
-#ifndef WIN32
- pqsignal(SIGINT, SIG_DFL);
-#endif
+ sigint_interrupt_enabled = false;
destroyPQExpBuffer(query_buf);
destroyPQExpBuffer(previous_buf);
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/mainloop.h,v 1.18 2006/03/05 15:58:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/mainloop.h,v 1.19 2006/06/14 16:49:02 tgl Exp $
*/
#ifndef MAINLOOP_H
#define MAINLOOP_H
#include "postgres_fe.h"
#include <stdio.h>
-#ifndef WIN32
-#include <setjmp.h>
-
-extern sigjmp_buf main_loop_jmp;
-#endif
int MainLoop(FILE *source);
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.86 2006/06/07 22:24:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.87 2006/06/14 16:49:02 tgl Exp $
+ *
+ * Note: we include postgres.h not postgres_fe.h so that we can include
+ * catalog/pg_type.h, and thereby have access to INT4OID and similar macros.
*/
-#include "postgres_fe.h"
+#include "postgres.h"
#include "common.h"
#include "print.h"
+#include "catalog/pg_type.h"
#include <math.h>
#include <signal.h>
#include "mbprint.h"
+/*
+ * We define the cancel_pressed flag in this file, rather than common.c where
+ * it naturally belongs, because this file is also used by non-psql programs
+ * (see the bin/scripts/ directory). In those programs cancel_pressed will
+ * never become set and will have no effect.
+ *
+ * Note: print.c's general strategy for when to check cancel_pressed is to do
+ * so at completion of each row of output.
+ */
+volatile bool cancel_pressed = false;
+
static char *decimal_point;
static char *grouping;
static char *thousands_sep;
const char *const * ptr;
bool need_recordsep = false;
+ if (cancel_pressed)
+ return;
+
if (!opt_fieldsep)
opt_fieldsep = "";
if (!opt_recordsep)
{
fputs(opt_recordsep, fout);
need_recordsep = false;
+ if (cancel_pressed)
+ break;
}
if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
{
/* print footers */
- if (!opt_tuples_only && footers)
+ if (!opt_tuples_only && footers && !cancel_pressed)
for (ptr = footers; *ptr; ptr++)
{
if (need_recordsep)
unsigned int i;
const char *const * ptr;
+ if (cancel_pressed)
+ return;
+
if (!opt_fieldsep)
opt_fieldsep = "";
if (!opt_recordsep)
fputs(opt_recordsep, fout);
if (i % col_count == 0)
fputs(opt_recordsep, fout); /* another one */
+ if (cancel_pressed)
+ break;
}
fputs(headers[i % col_count], fout);
}
/* print footers */
- if (!opt_tuples_only && footers && *footers)
+ if (!opt_tuples_only && footers && *footers && !cancel_pressed)
{
fputs(opt_recordsep, fout);
for (ptr = footers; *ptr; ptr++)
int *complete; /* Array remembering which columns have completed output */
+ if (cancel_pressed)
+ return;
+
/* count columns */
for (ptr = headers; *ptr; ptr++)
col_count++;
fputc('\n', fout);
}
-
_print_horizontal_line(col_count, widths, opt_border, fout);
}
int j;
int cols_todo = col_count;
int line_count; /* Number of lines output so far in row */
-
+
+ if (cancel_pressed)
+ break;
+
for (j = 0; j < col_count; j++)
pg_wcsformat((unsigned char*)ptr[j], strlen(ptr[j]), encoding, col_lineptrs[j], heights[j]);
}
}
- if (opt_border == 2)
+ if (opt_border == 2 && !cancel_pressed)
_print_horizontal_line(col_count, widths, opt_border, fout);
/* print footers */
- if (footers && !opt_tuples_only)
+ if (footers && !opt_tuples_only && !cancel_pressed)
for (ptr = footers; *ptr; ptr++)
fprintf(fout, "%s\n", *ptr);
char *divider;
unsigned int cell_count = 0;
struct lineptr *hlineptr, *dlineptr;
+
+ if (cancel_pressed)
+ return;
if (cells[0] == NULL)
{
if (i % col_count == 0)
{
+ if (cancel_pressed)
+ break;
if (!opt_tuples_only)
{
char *record_str = pg_local_malloc(32);
}
}
- if (opt_border == 2)
+ if (opt_border == 2 && !cancel_pressed)
fprintf(fout, "%s\n", divider);
/* print footers */
- if (!opt_tuples_only && footers && *footers)
+ if (!opt_tuples_only && footers && *footers && !cancel_pressed)
{
if (opt_border < 2)
fputc('\n', fout);
unsigned int i;
const char *const * ptr;
+ if (cancel_pressed)
+ return;
+
fprintf(fout, "<table border=\"%d\"", opt_border);
if (opt_table_attr)
fprintf(fout, " %s", opt_table_attr);
for (i = 0, ptr = cells; *ptr; i++, ptr++)
{
if (i % col_count == 0)
+ {
+ if (cancel_pressed)
+ break;
fputs(" <tr valign=\"top\">\n", fout);
+ }
fprintf(fout, " <td align=\"%s\">", opt_align[(i) % col_count] == 'r' ? "right" : "left");
/* is string only whitespace? */
/* print footers */
- if (!opt_tuples_only && footers && *footers)
+ if (!opt_tuples_only && footers && *footers && !cancel_pressed)
{
fputs("<p>", fout);
for (ptr = footers; *ptr; ptr++)
unsigned int record = 1;
const char *const * ptr;
+ if (cancel_pressed)
+ return;
+
fprintf(fout, "<table border=\"%d\"", opt_border);
if (opt_table_attr)
fprintf(fout, " %s", opt_table_attr);
{
if (i % col_count == 0)
{
+ if (cancel_pressed)
+ break;
if (!opt_tuples_only)
fprintf(fout, "\n <tr><td colspan=\"2\" align=\"center\">Record %d</td></tr>\n", record++);
else
fputs("</table>\n", fout);
/* print footers */
- if (!opt_tuples_only && footers && *footers)
+ if (!opt_tuples_only && footers && *footers && !cancel_pressed)
{
fputs("<p>", fout);
for (ptr = footers; *ptr; ptr++)
unsigned int i;
const char *const * ptr;
+ if (cancel_pressed)
+ return;
/* print title */
if (!opt_tuples_only && title)
latex_escaped_print(*ptr, fout);
if ((i + 1) % col_count == 0)
+ {
fputs(" \\\\\n", fout);
+ if (cancel_pressed)
+ break;
+ }
else
fputs(" & ", fout);
}
/* print footers */
- if (footers && !opt_tuples_only)
+ if (footers && !opt_tuples_only && !cancel_pressed)
for (ptr = footers; *ptr; ptr++)
{
latex_escaped_print(*ptr, fout);
(void) opt_align; /* currently unused parameter */
+ if (cancel_pressed)
+ return;
+
/* print title */
if (!opt_tuples_only && title)
{
/* new record */
if (i % col_count == 0)
{
+ if (cancel_pressed)
+ break;
if (!opt_tuples_only)
{
if (opt_border == 2)
/* print footers */
- if (footers && !opt_tuples_only)
+ if (footers && !opt_tuples_only && !cancel_pressed)
for (ptr = footers; *ptr; ptr++)
{
if (opt_numeric_locale)
unsigned int i;
const char *const * ptr;
+ if (cancel_pressed)
+ return;
/* print title */
if (!opt_tuples_only && title)
troff_ms_escaped_print(*ptr, fout);
if ((i + 1) % col_count == 0)
+ {
fputc('\n', fout);
+ if (cancel_pressed)
+ break;
+ }
else
fputc('\t', fout);
}
/* print footers */
- if (footers && !opt_tuples_only)
+ if (footers && !opt_tuples_only && !cancel_pressed)
for (ptr = footers; *ptr; ptr++)
{
troff_ms_escaped_print(*ptr, fout);
(void) opt_align; /* currently unused parameter */
+ if (cancel_pressed)
+ return;
+
/* print title */
if (!opt_tuples_only && title)
{
/* new record */
if (i % col_count == 0)
{
+ if (cancel_pressed)
+ break;
if (!opt_tuples_only)
{
if (current_format != 1)
/* print footers */
- if (footers && !opt_tuples_only)
+ if (footers && !opt_tuples_only && !cancel_pressed)
for (ptr = footers; *ptr; ptr++)
{
troff_ms_escaped_print(*ptr, fout);
FILE *output;
bool use_expanded;
+ if (cancel_pressed)
+ return;
+
if (opt->format == PRINT_NOTHING)
return;
/* Only close if we used the pager */
if (fout == stdout && output != stdout)
{
+ /*
+ * If printing was canceled midstream, warn about it.
+ *
+ * Some pagers like less use Ctrl-C as part of their command
+ * set. Even so, we abort our processing and warn the user
+ * what we did. If the pager quit as a result of the
+ * SIGINT, this message won't go anywhere ...
+ */
+ if (cancel_pressed)
+ fprintf(output, _("Interrupted\n"));
+
pclose(output);
#ifndef WIN32
pqsignal(SIGPIPE, SIG_DFL);
char *align;
int i;
+ if (cancel_pressed)
+ return;
+
/* extract headers */
nfields = PQnfields(result);
{
Oid ftype = PQftype(result, i);
- if (ftype == 20 || /* int8 */
- ftype == 21 || /* int2 */
- ftype == 23 || /* int4 */
- (ftype >= 26 && ftype <= 30) || /* ?id */
- ftype == 700 || /* float4 */
- ftype == 701 || /* float8 */
- ftype == 790 || /* money */
- ftype == 1700 /* numeric */
- )
- align[i] = 'r';
- else
- align[i] = 'l';
+ switch (ftype)
+ {
+ case INT2OID:
+ case INT4OID:
+ case INT8OID:
+ case FLOAT4OID:
+ case FLOAT8OID:
+ case NUMERICOID:
+ case OIDOID:
+ case XIDOID:
+ case CIDOID:
+ case CASHOID:
+ align[i] = 'r';
+ break;
+ default:
+ align[i] = 'l';
+ break;
+ }
}
/* call table printer */
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.132 2006/04/27 02:58:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.133 2006/06/14 16:49:02 tgl Exp $
*/
#include "postgres_fe.h"
#ifdef WIN32
setvbuf(stderr, NULL, _IONBF, 0);
- setup_win32_locks();
#endif
setDecimalLocale();
pset.cur_cmd_source = stdin;
if (options.action_string) /* -f - was used */
pset.inputfile = "<stdin>";
+ /* establish control-C handling for interactive operation */
+ setup_cancel_handler();
+
successResult = MainLoop(stdin);
}
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/variables.c,v 1.23 2006/03/05 15:58:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/variables.c,v 1.24 2006/06/14 16:49:03 tgl Exp $
*/
#include "postgres_fe.h"
#include "common.h"
struct _variable *ptr;
for (ptr = space->next; ptr; ptr = ptr->next)
+ {
printf("%s = '%s'\n", ptr->name, ptr->value);
+ if (cancel_pressed)
+ break;
+ }
}
bool
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/port/sprompt.c,v 1.16 2006/03/05 15:59:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/port/sprompt.c,v 1.17 2006/06/14 16:49:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <termios.h>
#endif
-bool prompt_state = false;
extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
char *
if (!destination)
return NULL;
- prompt_state = true; /* disable SIGINT */
-
/*
* Do not try to collapse these into one "w+" mode file. Doesn't work on
* some platforms (eg, HPUX 10.20).
fclose(termout);
}
- prompt_state = false; /* SIGINT okay again */
-
return destination;
}