]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix psql's pager selection for wrapped expanded output.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 5 Jul 2026 22:11:40 +0000 (18:11 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 5 Jul 2026 22:11:40 +0000 (18:11 -0400)
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

src/bin/psql/t/030_pager.pl
src/fe_utils/print.c

index d3f964639d3ae44249907f83cc87404154dd0252..7b8b32b3caf9ac23b8d362f351a6300fc298900e 100644 (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 $?";
 
index 2edd95022edb7706208a002bf8d8dd29b85d331a..acf20cb498ba6c4cc570a8cf098595031d5a16b4 100644 (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++)
        {