Fix psql's pager selection for wrapped expanded output.

psql decided whether to use the pager in expanded output without
accounting for possible wrapping of column values.  This could
allow it to not use the pager in cases where it should do so.

To fix, move the IsPagerNeeded decision in print_aligned_vertical()
down until after the wrapped data width is known.  Then, if we're in
wrapped mode, prepare a width_wrap array specifying that width (which,
in vertical mode, is the same for all columns).

This is fixing an omission in 27da1a796, so back-patch to v19
where that came in.

Author: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Erik Wienhold <ewie@ewie.name>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/A44110E7-6A03-4C67-95AD-527192A6C768@gmail.com
Backpatch-through: 19
This commit is contained in:
Tom Lane 2026-07-05 18:11:40 -04:00
parent 9f03dab457
commit 07abbc93ba
2 changed files with 40 additions and 18 deletions

View file

@ -130,6 +130,11 @@ do_command(
qr/55\r?$/m,
"execute command with footer that needs pagination");
do_command(
"\\pset expanded on\n\\pset format wrapped\nSELECT repeat('x',80) AS payload FROM generate_series(1,11);\n",
qr/34\r?$/m,
"execute SELECT query that needs pagination in expanded wrapped mode");
# send psql an explicit \q to shut it down, else pty won't close properly
$h->quit or die "psql returned $?";

View file

@ -1354,17 +1354,6 @@ print_aligned_vertical(const printTableContent *cont,
return;
}
/*
* Deal with the pager here instead of in printTable(), because we could
* get here via print_aligned_text() in expanded auto mode, and so we have
* to recalculate the pager requirement based on vertical output.
*/
if (!is_pager)
{
IsPagerNeeded(cont, NULL, true, &fout, &is_pager);
is_local_pager = is_pager;
}
/* Find the maximum dimensions for the headers */
for (i = 0; i < cont->ncolumns; i++)
{
@ -1415,13 +1404,6 @@ print_aligned_vertical(const printTableContent *cont,
dlineptr->ptr = pg_malloc(dformatsize);
hlineptr->ptr = pg_malloc(hformatsize);
if (cont->opt->start_table)
{
/* print title */
if (!opt_tuples_only && cont->title)
fprintf(fout, "%s\n", cont->title);
}
/*
* Choose target output width: \pset columns, or $COLUMNS, or ioctl
*/
@ -1569,6 +1551,41 @@ print_aligned_vertical(const printTableContent *cont,
dwidth = newdwidth;
}
/*
* Deal with the pager here instead of in printTable(), because we could
* get here via print_aligned_text() in expanded auto mode, and so we have
* to recalculate the pager requirement based on vertical output.
*/
if (!is_pager)
{
unsigned int *width_wrap = NULL;
/*
* Wrapping can add extra output lines, which count_table_lines() can
* only account for if it has wrap widths. But vertical output uses
* the same data width for every field, so that's easy: use dwidth for
* every column.
*/
if (cont->opt->format == PRINT_WRAPPED && cont->ncolumns > 0)
{
width_wrap = pg_malloc_array(unsigned int, cont->ncolumns);
for (i = 0; i < cont->ncolumns; i++)
width_wrap[i] = dwidth;
}
IsPagerNeeded(cont, width_wrap, true, &fout, &is_pager);
is_local_pager = is_pager;
free(width_wrap);
}
if (cont->opt->start_table)
{
/* print title */
if (!opt_tuples_only && cont->title)
fprintf(fout, "%s\n", cont->title);
}
/* print records */
for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{