Fix psql pager selection for wrapped expanded output

Started by Chao Li2 months ago8 messageshackers
Jump to latest
#1Chao Li
li.evan.chao@gmail.com

Hi,

While testing “[27da1a796] Improve psql's ability to select pager mode accurately”, I found that the pager doesn’t work for expanded wrapped mode. However, I realized that this is not a new problem introduced by 27da1a796, it didn’t work before 27da1a796 either. Instead, with 27da1a796, we are almost there to make it work.

27da1a796 introduces a new helper count_table_lines(), that takes a per-column-width array. For expanded mode (vertical mode), all columns use the same data width. So we can simply build such a width_wrap array, and move IsPagerNeeded() to after dwidth is computed. Then the pager works in expanded wrapped mode.

I tested with this procedure (making the terminal small with ~30 rows):
```
\pset pager on
\pset columns 25
\pset expanded on
\pset format wrapped
select g AS id, 'name_' || g AS name, repeat('x', g * 5) AS payload from generate_series(1, 10) AS g;
```
See the attached patch for details. I’m not going to add this to the v19 open items, as it’s not a v19-new bug.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

Attachments:

v1-0001-Fix-psql-pager-selection-for-wrapped-expanded-out.patchapplication/octet-stream; name=v1-0001-Fix-psql-pager-selection-for-wrapped-expanded-out.patch; x-unix-mode=0644Download+42-19
#2Chao Li
li.evan.chao@gmail.com
In reply to: Chao Li (#1)
Re: Fix psql pager selection for wrapped expanded output

On Jun 12, 2026, at 18:01, Chao Li <li.evan.chao@gmail.com> wrote:

Hi,

While testing “[27da1a796] Improve psql's ability to select pager mode accurately”, I found that the pager doesn’t work for expanded wrapped mode. However, I realized that this is not a new problem introduced by 27da1a796, it didn’t work before 27da1a796 either. Instead, with 27da1a796, we are almost there to make it work.

27da1a796 introduces a new helper count_table_lines(), that takes a per-column-width array. For expanded mode (vertical mode), all columns use the same data width. So we can simply build such a width_wrap array, and move IsPagerNeeded() to after dwidth is computed. Then the pager works in expanded wrapped mode.

I tested with this procedure (making the terminal small with ~30 rows):
```
\pset pager on
\pset columns 25
\pset expanded on
\pset format wrapped
select g AS id, 'name_' || g AS name, repeat('x', g * 5) AS payload from generate_series(1, 10) AS g;
```
See the attached patch for details. I’m not going to add this to the v19 open items, as it’s not a v19-new bug.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

<v1-0001-Fix-psql-pager-selection-for-wrapped-expanded-out.patch>

This is simpler repro:
```
\pset pager on
\pset format wrapped
\pset expanded on
\pset columns 5
SELECT repeat('x',100) AS payload;
```

My terminal size:
```
evantest=# \! stty size
27 170
```

BTW, I also ran into another issue that confused me. After changing print.c, running make from the source root didn’t rebuild psql. I had to run "make clean" and rebuild everything. Is that known or intentional?

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

#3Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Chao Li (#2)
Re: Fix psql pager selection for wrapped expanded output

On 2026-Jun-12, Chao Li wrote:

BTW, I also ran into another issue that confused me. After changing
print.c, running make from the source root didn’t rebuild psql. I had
to run "make clean" and rebuild everything. Is that known or
intentional?

Do you use "configure --enable-depend"? If not, then I think you're
pretty much expected to do "make clean" or similar before every single
file change. I think this as a very developer unfriendly environment,
so I always use configure --enable-depend. (Well, except when on Meson
of course, which is what I normally use for most recent branches.)

--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
Thou shalt check the array bounds of all strings (indeed, all arrays), for
surely where thou typest "foo" someone someday shall type
"supercalifragilisticexpialidocious" (5th Commandment for C programmers)

#4Chao Li
li.evan.chao@gmail.com
In reply to: Alvaro Herrera (#3)
Re: Fix psql pager selection for wrapped expanded output

On Jun 12, 2026, at 22:44, Álvaro Herrera <alvherre@kurilemu.de> wrote:

On 2026-Jun-12, Chao Li wrote:

BTW, I also ran into another issue that confused me. After changing
print.c, running make from the source root didn’t rebuild psql. I had
to run "make clean" and rebuild everything. Is that known or
intentional?

Do you use "configure --enable-depend"? If not, then I think you're
pretty much expected to do "make clean" or similar before every single
file change. I think this as a very developer unfriendly environment,
so I always use configure --enable-depend. (Well, except when on Meson
of course, which is what I normally use for most recent branches.)

--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
Thou shalt check the array bounds of all strings (indeed, all arrays), for
surely where thou typest "foo" someone someday shall type
"supercalifragilisticexpialidocious" (5th Commandment for C programmers)

I’m using --enable-depend. I have this configure command in my notes, and I always copy it when I need to reconfigure:
```
./configure --enable-debug --enable-cassert --enable-tap-tests --enable-depend --with-python --enable-injection-points
```

I just looked into the problem. After changing print.c, only libpgfeutils.a is rebuilt. psql runs submake-libpgfeutils, but it does not have libpgfeutils.a as a normal prerequisite, so it is not relinked when the archive changes.

I made a simple change like this:
```
diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile
index be0032652cd..d12bcfcc660 100644
--- a/src/bin/psql/Makefile
+++ b/src/bin/psql/Makefile
@@ -23,6 +23,7 @@ REFDOCDIR= $(top_srcdir)/doc/src/sgml/ref

override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS)
LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
+libpgfeutils = $(top_builddir)/src/fe_utils/libpgfeutils.a

OBJS = \
$(WIN32RES) \
@@ -46,9 +47,11 @@ OBJS = \

all: psql

-psql: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
+psql: $(OBJS) $(libpgfeutils) | submake-libpq submake-libpgport
        $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+$(libpgfeutils): | submake-libpgfeutils
+
 help.o: sql_help.h

# See notes in src/backend/parser/Makefile about the following two rules
```

It simply adds libpgfeutils.a as a normal prerequisite of psql, while still using submake-libpgfeutils to build it. Then psql is automatically relinked when print.c changes and the archive is rebuilt.

I didn’t check if meson has the same issue. If this is considered worth a patch, I can start a new thread.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

#5Erik Wienhold
ewie@ewie.name
In reply to: Chao Li (#1)
Re: Fix psql pager selection for wrapped expanded output

On 2026-06-12 12:01 +0200, Chao Li wrote:

While testing “[27da1a796] Improve psql's ability to select pager mode
accurately”, I found that the pager doesn’t work for expanded wrapped
mode. However, I realized that this is not a new problem introduced by
27da1a796, it didn’t work before 27da1a796 either. Instead, with
27da1a796, we are almost there to make it work.

27da1a796 introduces a new helper count_table_lines(), that takes a
per-column-width array. For expanded mode (vertical mode), all columns
use the same data width. So we can simply build such a width_wrap
array, and move IsPagerNeeded() to after dwidth is computed. Then the
pager works in expanded wrapped mode.

I tested with this procedure (making the terminal small with ~30 rows):
```
\pset pager on
\pset columns 25
\pset expanded on
\pset format wrapped
select g AS id, 'name_' || g AS name, repeat('x', g * 5) AS payload from generate_series(1, 10) AS g;
```
See the attached patch for details. I’m not going to add this to the
v19 open items, as it’s not a v19-new bug.

The changes to print.c look good to me and it works in manual testing.

+# With the 80-column pty, the payload wraps to two lines per row.
+# Expanded output also prints one record header per row, plus a trailing
+# blank line, so this produces 11 * 3 + 1 = 34 lines.
+do_command(
+   "\\pset expanded on\n\\pset format wrapped\n\\pset columns 80\nSELECT repeat('x',138) AS payload FROM generate_series(1,11);\n",

We can do without \pset columns 80 here since the PTY is already set to
80 columns by the test setup on line 82. I'd also change the query to
return repeat('x', 80) which is sufficiently long for the wrapping to
occur. It's then also clear that this length is related to the PTY
width while 138 lacks any meaning IMO.

--
Erik Wienhold

#6Chao Li
li.evan.chao@gmail.com
In reply to: Erik Wienhold (#5)
Re: Fix psql pager selection for wrapped expanded output

On Jul 1, 2026, at 04:34, Erik Wienhold <ewie@ewie.name> wrote:

On 2026-06-12 12:01 +0200, Chao Li wrote:

While testing “[27da1a796] Improve psql's ability to select pager mode
accurately”, I found that the pager doesn’t work for expanded wrapped
mode. However, I realized that this is not a new problem introduced by
27da1a796, it didn’t work before 27da1a796 either. Instead, with
27da1a796, we are almost there to make it work.

27da1a796 introduces a new helper count_table_lines(), that takes a
per-column-width array. For expanded mode (vertical mode), all columns
use the same data width. So we can simply build such a width_wrap
array, and move IsPagerNeeded() to after dwidth is computed. Then the
pager works in expanded wrapped mode.

I tested with this procedure (making the terminal small with ~30 rows):
```
\pset pager on
\pset columns 25
\pset expanded on
\pset format wrapped
select g AS id, 'name_' || g AS name, repeat('x', g * 5) AS payload from generate_series(1, 10) AS g;
```
See the attached patch for details. I’m not going to add this to the
v19 open items, as it’s not a v19-new bug.

The changes to print.c look good to me and it works in manual testing.

Thanks for your review and test.

+# With the 80-column pty, the payload wraps to two lines per row.
+# Expanded output also prints one record header per row, plus a trailing
+# blank line, so this produces 11 * 3 + 1 = 34 lines.
+do_command(
+   "\\pset expanded on\n\\pset format wrapped\n\\pset columns 80\nSELECT repeat('x',138) AS payload FROM generate_series(1,11);\n",

We can do without \pset columns 80 here since the PTY is already set to
80 columns by the test setup on line 82. I'd also change the query to
return repeat('x', 80) which is sufficiently long for the wrapping to
occur. It's then also clear that this length is related to the PTY
width while 138 lacks any meaning IMO.

Agreed and addressed in v2.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

Attachments:

v2-0001-Fix-psql-pager-selection-for-wrapped-expanded-out.patchapplication/octet-stream; name=v2-0001-Fix-psql-pager-selection-for-wrapped-expanded-out.patch; x-unix-mode=0644Download+42-19
#7Erik Wienhold
ewie@ewie.name
In reply to: Chao Li (#6)
Re: Fix psql pager selection for wrapped expanded output

On 2026-07-01 09:14 +0200, Chao Li wrote:

On Jul 1, 2026, at 04:34, Erik Wienhold <ewie@ewie.name> wrote:

On 2026-06-12 12:01 +0200, Chao Li wrote:

While testing “[27da1a796] Improve psql's ability to select pager mode
accurately”, I found that the pager doesn’t work for expanded wrapped
mode. However, I realized that this is not a new problem introduced by
27da1a796, it didn’t work before 27da1a796 either. Instead, with
27da1a796, we are almost there to make it work.

27da1a796 introduces a new helper count_table_lines(), that takes a
per-column-width array. For expanded mode (vertical mode), all columns
use the same data width. So we can simply build such a width_wrap
array, and move IsPagerNeeded() to after dwidth is computed. Then the
pager works in expanded wrapped mode.

I tested with this procedure (making the terminal small with ~30 rows):
```
\pset pager on
\pset columns 25
\pset expanded on
\pset format wrapped
select g AS id, 'name_' || g AS name, repeat('x', g * 5) AS payload from generate_series(1, 10) AS g;
```
See the attached patch for details. I’m not going to add this to the
v19 open items, as it’s not a v19-new bug.

The changes to print.c look good to me and it works in manual testing.

Thanks for your review and test.

+# With the 80-column pty, the payload wraps to two lines per row.
+# Expanded output also prints one record header per row, plus a trailing
+# blank line, so this produces 11 * 3 + 1 = 34 lines.
+do_command(
+   "\\pset expanded on\n\\pset format wrapped\n\\pset columns 80\nSELECT repeat('x',138) AS payload FROM generate_series(1,11);\n",

We can do without \pset columns 80 here since the PTY is already set to
80 columns by the test setup on line 82. I'd also change the query to
return repeat('x', 80) which is sufficiently long for the wrapping to
occur. It's then also clear that this length is related to the PTY
width while 138 lacks any meaning IMO.

Agreed and addressed in v2.

Thanks! LGTM.

--
Erik Wienhold

#8Tom Lane
tgl@sss.pgh.pa.us
In reply to: Erik Wienhold (#7)
Re: Fix psql pager selection for wrapped expanded output

Erik Wienhold <ewie@ewie.name> writes:

On 2026-07-01 09:14 +0200, Chao Li wrote:

Agreed and addressed in v2.

Thanks! LGTM.

LGTM too, pushed with some minor comment-fiddling. I am of the
opinion that this is a bug in 27da1a796, which intended to cover
such cases and evidently missed. So I backpatched to 19 too.

regards, tom lane