From 07abbc93ba5ba41b60927221db92bc73f75fd1ba Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 5 Jul 2026 18:11:40 -0400 Subject: [PATCH] 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 Reviewed-by: Erik Wienhold Reviewed-by: Tom Lane Discussion: https://postgr.es/m/A44110E7-6A03-4C67-95AD-527192A6C768@gmail.com Backpatch-through: 19 --- src/bin/psql/t/030_pager.pl | 5 ++++ src/fe_utils/print.c | 53 ++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/bin/psql/t/030_pager.pl b/src/bin/psql/t/030_pager.pl index d3f964639d3..7b8b32b3caf 100644 --- a/src/bin/psql/t/030_pager.pl +++ b/src/bin/psql/t/030_pager.pl @@ -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 $?"; diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c index 2edd95022ed..acf20cb498b 100644 --- a/src/fe_utils/print.c +++ b/src/fe_utils/print.c @@ -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++) {