1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-17 06:41:09 +03:00

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.
This commit is contained in:
Tom Lane
2006-06-14 16:49:03 +00:00
parent ace93353ea
commit f3164c0200
12 changed files with 352 additions and 161 deletions

View File

@ -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 */