diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2006-06-14 16:49:03 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2006-06-14 16:49:03 +0000 |
commit | f3164c020028de70e4cd991ccbd3d696c9060709 (patch) | |
tree | 02b6ad16c4498a1d8609e9237b769e57eb1a6aaf /src/bin/psql/print.c | |
parent | ace93353eadf1316364bcb76f52952c413779083 (diff) |
Clean up psql's control-C handling to avoid longjmp'ing out of random
places --- that risks corrupting data structures, losing sync with the
backend, etc. We now longjmp only from calls to readline, fgets, and
fread, which we assume are coded to protect themselves against interrupts
at undesirable times. This requires adding explicit tests for
cancel_pressed in long-running loops, but on the whole it's far cleaner.
Martijn van Oosterhout and Tom Lane.
Diffstat (limited to 'src/bin/psql/print.c')
-rw-r--r-- | src/bin/psql/print.c | 148 |
1 files changed, 120 insertions, 28 deletions
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index 1ad04783d0c..97f6f1e665c 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -3,11 +3,15 @@ * * 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> @@ -28,6 +32,17 @@ #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; @@ -171,6 +186,9 @@ print_unaligned_text(const char *title, const char *const * headers, const char *const * ptr; bool need_recordsep = false; + if (cancel_pressed) + return; + if (!opt_fieldsep) opt_fieldsep = ""; if (!opt_recordsep) @@ -202,6 +220,8 @@ print_unaligned_text(const char *title, const char *const * headers, { fputs(opt_recordsep, fout); need_recordsep = false; + if (cancel_pressed) + break; } if (opt_align[i % col_count] == 'r' && opt_numeric_locale) { @@ -222,7 +242,7 @@ print_unaligned_text(const char *title, const char *const * headers, /* print footers */ - if (!opt_tuples_only && footers) + if (!opt_tuples_only && footers && !cancel_pressed) for (ptr = footers; *ptr; ptr++) { if (need_recordsep) @@ -252,6 +272,9 @@ print_unaligned_vertical(const char *title, const char *const * headers, unsigned int i; const char *const * ptr; + if (cancel_pressed) + return; + if (!opt_fieldsep) opt_fieldsep = ""; if (!opt_recordsep) @@ -273,6 +296,8 @@ print_unaligned_vertical(const char *title, const char *const * headers, 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); @@ -289,7 +314,7 @@ print_unaligned_vertical(const char *title, const char *const * headers, } /* 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++) @@ -369,6 +394,9 @@ print_aligned_text(const char *title, const char *const * headers, int *complete; /* Array remembering which columns have completed output */ + if (cancel_pressed) + return; + /* count columns */ for (ptr = headers; *ptr; ptr++) col_count++; @@ -543,7 +571,6 @@ print_aligned_text(const char *title, const char *const * headers, fputc('\n', fout); } - _print_horizontal_line(col_count, widths, opt_border, fout); } @@ -553,7 +580,10 @@ print_aligned_text(const char *title, const char *const * headers, 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]); @@ -630,11 +660,11 @@ print_aligned_text(const char *title, const char *const * headers, } } - 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); @@ -681,6 +711,9 @@ print_aligned_vertical(const char *title, const char *const * headers, char *divider; unsigned int cell_count = 0; struct lineptr *hlineptr, *dlineptr; + + if (cancel_pressed) + return; if (cells[0] == NULL) { @@ -764,6 +797,8 @@ print_aligned_vertical(const char *title, const char *const * headers, if (i % col_count == 0) { + if (cancel_pressed) + break; if (!opt_tuples_only) { char *record_str = pg_local_malloc(32); @@ -860,12 +895,12 @@ print_aligned_vertical(const char *title, const char *const * headers, } } - 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); @@ -943,6 +978,9 @@ print_html_text(const char *title, const char *const * headers, 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); @@ -976,7 +1014,11 @@ print_html_text(const char *title, const char *const * headers, 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? */ @@ -1002,7 +1044,7 @@ print_html_text(const char *title, const char *const * headers, /* print footers */ - if (!opt_tuples_only && footers && *footers) + if (!opt_tuples_only && footers && *footers && !cancel_pressed) { fputs("<p>", fout); for (ptr = footers; *ptr; ptr++) @@ -1029,6 +1071,9 @@ print_html_vertical(const char *title, const char *const * headers, 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); @@ -1051,6 +1096,8 @@ print_html_vertical(const char *title, const char *const * headers, { 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 @@ -1081,7 +1128,7 @@ print_html_vertical(const char *title, const char *const * headers, 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++) @@ -1151,6 +1198,8 @@ print_latex_text(const char *title, const char *const * headers, unsigned int i; const char *const * ptr; + if (cancel_pressed) + return; /* print title */ if (!opt_tuples_only && title) @@ -1216,7 +1265,11 @@ print_latex_text(const char *title, const char *const * headers, latex_escaped_print(*ptr, fout); if ((i + 1) % col_count == 0) + { fputs(" \\\\\n", fout); + if (cancel_pressed) + break; + } else fputs(" & ", fout); } @@ -1229,7 +1282,7 @@ print_latex_text(const char *title, const char *const * headers, /* print footers */ - if (footers && !opt_tuples_only) + if (footers && !opt_tuples_only && !cancel_pressed) for (ptr = footers; *ptr; ptr++) { latex_escaped_print(*ptr, fout); @@ -1255,6 +1308,9 @@ print_latex_vertical(const char *title, const char *const * headers, (void) opt_align; /* currently unused parameter */ + if (cancel_pressed) + return; + /* print title */ if (!opt_tuples_only && title) { @@ -1285,6 +1341,8 @@ print_latex_vertical(const char *title, const char *const * headers, /* new record */ if (i % col_count == 0) { + if (cancel_pressed) + break; if (!opt_tuples_only) { if (opt_border == 2) @@ -1313,7 +1371,7 @@ print_latex_vertical(const char *title, const char *const * headers, /* print footers */ - if (footers && !opt_tuples_only) + if (footers && !opt_tuples_only && !cancel_pressed) for (ptr = footers; *ptr; ptr++) { if (opt_numeric_locale) @@ -1367,6 +1425,8 @@ print_troff_ms_text(const char *title, const char *const * headers, unsigned int i; const char *const * ptr; + if (cancel_pressed) + return; /* print title */ if (!opt_tuples_only && title) @@ -1425,7 +1485,11 @@ print_troff_ms_text(const char *title, const char *const * headers, troff_ms_escaped_print(*ptr, fout); if ((i + 1) % col_count == 0) + { fputc('\n', fout); + if (cancel_pressed) + break; + } else fputc('\t', fout); } @@ -1435,7 +1499,7 @@ print_troff_ms_text(const char *title, const char *const * headers, /* 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); @@ -1462,6 +1526,9 @@ print_troff_ms_vertical(const char *title, const char *const * headers, (void) opt_align; /* currently unused parameter */ + if (cancel_pressed) + return; + /* print title */ if (!opt_tuples_only && title) { @@ -1491,6 +1558,8 @@ print_troff_ms_vertical(const char *title, const char *const * headers, /* new record */ if (i % col_count == 0) { + if (cancel_pressed) + break; if (!opt_tuples_only) { if (current_format != 1) @@ -1542,7 +1611,7 @@ print_troff_ms_vertical(const char *title, const char *const * headers, /* 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); @@ -1618,6 +1687,9 @@ printTable(const char *title, FILE *output; bool use_expanded; + if (cancel_pressed) + return; + if (opt->format == PRINT_NOTHING) return; @@ -1731,6 +1803,17 @@ printTable(const char *title, /* 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); @@ -1751,6 +1834,9 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f char *align; int i; + if (cancel_pressed) + return; + /* extract headers */ nfields = PQnfields(result); @@ -1798,18 +1884,24 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f { 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 */ |