aboutsummaryrefslogtreecommitdiff
path: root/src/bin/psql/print.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2015-12-02 18:20:33 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2015-12-02 18:20:41 -0500
commitd8ff060ecd5fc2dd20021743518d376a11a0bfd8 (patch)
tree09f40f890ff8fe63c7c6f95aa37ad539f57c7271 /src/bin/psql/print.c
parent1caef31d9e550408d0cbc5788a422dcb69736df5 (diff)
downloadpostgresql-d8ff060ecd5fc2dd20021743518d376a11a0bfd8.tar.gz
postgresql-d8ff060ecd5fc2dd20021743518d376a11a0bfd8.zip
Fix behavior of printTable() and friends with externally-invoked pager.
The formatting modes that depend on knowledge of the terminal window width did not work right when printing a query result that's been fetched in sections (as a result of FETCH_SIZE). ExecQueryUsingCursor() would force use of the pager as soon as there's more than one result section, and then print.c would see an output file pointer that's not stdout and incorrectly conclude that the terminal window width isn't relevant. This has been broken all along for non-expanded "wrapped" output format, and as of 9.5 the issue affects expanded mode as well. The problem also caused "\pset expanded auto" mode to invariably *not* switch to expanded output in a segmented result, which seems to me to be exactly backwards. To fix, we need to pass down an "is_pager" flag to inform the print.c subroutines that some calling level has already replaced stdout with a pager pipe, so they should (a) not do that again and (b) nonetheless honor the window size. (Notably, this makes the first is_pager test in print_aligned_text() not be dead code anymore.) This patch is a bit invasive because there are so many existing calls of printQuery()/printTable(), but fortunately all but a couple can just pass "false" for the added parameter. Back-patch to 9.5 but no further. Given the lack of field complaints, it's not clear that we should change the behavior in stable branches. Also, the API change for printQuery()/printTable() might possibly break third-party code, again something we don't like to do in stable branches. However, it's not quite too late to do this in 9.5, and with the larger scope of the problem there, it seems worth doing.
Diffstat (limited to 'src/bin/psql/print.c')
-rw-r--r--src/bin/psql/print.c83
1 files changed, 56 insertions, 27 deletions
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index 97f9c2f1690..190f2bc5d85 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -191,10 +191,11 @@ const unicodeStyleFormat unicode_style = {
/* Local functions */
static int strlen_max_width(unsigned char *str, int *target_width, int encoding);
-static void IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded,
+static void IsPagerNeeded(const printTableContent *cont, int extra_lines, bool expanded,
FILE **fout, bool *is_pager);
-static void print_aligned_vertical(const printTableContent *cont, FILE *fout);
+static void print_aligned_vertical(const printTableContent *cont,
+ FILE *fout, bool is_pager);
/* Count number of digits in integral part of number */
@@ -570,7 +571,7 @@ _print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths,
* Print pretty boxes around cells.
*/
static void
-print_aligned_text(const printTableContent *cont, FILE *fout)
+print_aligned_text(const printTableContent *cont, FILE *fout, bool is_pager)
{
bool opt_tuples_only = cont->opt->tuples_only;
int encoding = cont->opt->encoding;
@@ -605,7 +606,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
int *bytes_output; /* Bytes output for column value */
printTextLineWrap *wrap; /* Wrap status for each column */
int output_columns = 0; /* Width of interactive console */
- bool is_pager = false;
+ bool is_local_pager = false;
if (cancel_pressed)
return;
@@ -813,7 +814,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
if (cont->opt->expanded == 2 && output_columns > 0 &&
(output_columns < total_header_width || output_columns < width_total))
{
- print_aligned_vertical(cont, fout);
+ print_aligned_vertical(cont, fout, is_pager);
goto cleanup;
}
@@ -822,11 +823,11 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
(output_columns < total_header_width || output_columns < width_total))
{
fout = PageOutput(INT_MAX, cont->opt); /* force pager */
- is_pager = true;
+ is_pager = is_local_pager = true;
}
/* Check if newlines or our wrapping now need the pager */
- if (!is_pager)
+ if (!is_pager && fout == stdout)
{
/* scan all cells, find maximum width, compute cell_count */
for (i = 0, ptr = cont->cells; *ptr; ptr++, cell_count++)
@@ -862,6 +863,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
}
}
IsPagerNeeded(cont, extra_output_lines, false, &fout, &is_pager);
+ is_local_pager = is_pager;
}
/* time to output */
@@ -1153,7 +1155,7 @@ cleanup:
free(bytes_output);
free(wrap);
- if (is_pager)
+ if (is_local_pager)
ClosePager(fout);
}
@@ -1215,7 +1217,8 @@ print_aligned_vertical_line(const printTextFormat *format,
}
static void
-print_aligned_vertical(const printTableContent *cont, FILE *fout)
+print_aligned_vertical(const printTableContent *cont,
+ FILE *fout, bool is_pager)
{
bool opt_tuples_only = cont->opt->tuples_only;
unsigned short opt_border = cont->opt->border;
@@ -1233,7 +1236,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
dformatsize = 0;
struct lineptr *hlineptr,
*dlineptr;
- bool is_pager = false,
+ bool is_local_pager = false,
hmultiline = false,
dmultiline = false;
int output_columns = 0; /* Width of interactive console */
@@ -1267,7 +1270,11 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
* get here via print_aligned_text() in expanded auto mode, and so we have
* to recalculate the pager requirement based on vertical output.
*/
- IsPagerNeeded(cont, 0, true, &fout, &is_pager);
+ if (!is_pager)
+ {
+ IsPagerNeeded(cont, 0, true, &fout, &is_pager);
+ is_local_pager = is_pager;
+ }
/* Find the maximum dimensions for the headers */
for (i = 0; i < cont->ncolumns; i++)
@@ -1714,7 +1721,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
free(hlineptr);
free(dlineptr);
- if (is_pager)
+ if (is_local_pager)
ClosePager(fout);
}
@@ -3075,8 +3082,8 @@ printTableCleanup(printTableContent *const content)
* Setup pager if required
*/
static void
-IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expanded, FILE **fout,
- bool *is_pager)
+IsPagerNeeded(const printTableContent *cont, int extra_lines, bool expanded,
+ FILE **fout, bool *is_pager)
{
if (*fout == stdout)
{
@@ -3107,12 +3114,18 @@ IsPagerNeeded(const printTableContent *cont, const int extra_lines, bool expande
}
/*
- * Use this to print just any table in the supported formats.
+ * Use this to print any table in the supported formats.
+ *
+ * cont: table data and formatting options
+ * fout: where to print to
+ * is_pager: true if caller has already redirected fout to be a pager pipe
+ * flog: if not null, also print the table there (for --log-file option)
*/
void
-printTable(const printTableContent *cont, FILE *fout, FILE *flog)
+printTable(const printTableContent *cont,
+ FILE *fout, bool is_pager, FILE *flog)
{
- bool is_pager = false;
+ bool is_local_pager = false;
if (cancel_pressed)
return;
@@ -3120,15 +3133,19 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
if (cont->opt->format == PRINT_NOTHING)
return;
- /* print_aligned_*() handles the pager themselves */
- if (cont->opt->format != PRINT_ALIGNED &&
+ /* print_aligned_*() handle the pager themselves */
+ if (!is_pager &&
+ cont->opt->format != PRINT_ALIGNED &&
cont->opt->format != PRINT_WRAPPED)
+ {
IsPagerNeeded(cont, 0, (cont->opt->expanded == 1), &fout, &is_pager);
+ is_local_pager = is_pager;
+ }
/* print the stuff */
if (flog)
- print_aligned_text(cont, flog);
+ print_aligned_text(cont, flog, false);
switch (cont->opt->format)
{
@@ -3140,10 +3157,17 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
break;
case PRINT_ALIGNED:
case PRINT_WRAPPED:
- if (cont->opt->expanded == 1)
- print_aligned_vertical(cont, fout);
+
+ /*
+ * In expanded-auto mode, force vertical if a pager is passed in;
+ * else we may make different decisions for different hunks of the
+ * query result.
+ */
+ if (cont->opt->expanded == 1 ||
+ (cont->opt->expanded == 2 && is_pager))
+ print_aligned_vertical(cont, fout, is_pager);
else
- print_aligned_text(cont, fout);
+ print_aligned_text(cont, fout, is_pager);
break;
case PRINT_HTML:
if (cont->opt->expanded == 1)
@@ -3181,17 +3205,22 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
exit(EXIT_FAILURE);
}
- if (is_pager)
+ if (is_local_pager)
ClosePager(fout);
}
/*
* Use this to print query results
*
- * It calls printTable with all the things set straight.
+ * result: result of a successful query
+ * opt: formatting options
+ * fout: where to print to
+ * is_pager: true if caller has already redirected fout to be a pager pipe
+ * flog: if not null, also print the data there (for --log-file option)
*/
void
-printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *flog)
+printQuery(const PGresult *result, const printQueryOpt *opt,
+ FILE *fout, bool is_pager, FILE *flog)
{
printTableContent cont;
int i,
@@ -3271,7 +3300,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
printTableAddFooter(&cont, *footer);
}
- printTable(&cont, fout, flog);
+ printTable(&cont, fout, is_pager, flog);
printTableCleanup(&cont);
}