From 0e0776bc99553ff229e0d536ed8c78ab9db62464 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 30 Nov 2015 17:53:32 -0500 Subject: [PATCH] Rework wrap-width calculation in psql's print_aligned_vertical() function. This area was rather heavily whacked around in 6513633b9 and follow-on commits, and it was showing it, because the logic to calculate the allowable data width in wrapped expanded mode had only the vaguest relationship to the logic that was actually printing the data. It was not very close to being right about the conditions requiring overhead columns to be added. Aside from being wrong, it was pretty unreadable and under-commented. Rewrite it so it corresponds to what the printing code actually does. In passing, remove a couple of dead tests in the printing logic, too. Per a complaint from Jeff Janes, though this doesn't look much like his patch because it fixes a number of other corner-case bogosities too. One such fix that's visible in the regression test results is that although the code was attempting to enforce a minimum data width of 3 columns, it sometimes left less space than that available. --- src/bin/psql/print.c | 133 +++++--- src/test/regress/expected/psql.out | 511 +++++++++++++++++++++++------ src/test/regress/sql/psql.sql | 27 ++ 3 files changed, 514 insertions(+), 157 deletions(-) diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index ad4350e1fe..b53e81be37 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -1346,88 +1346,115 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout) #endif } + /* + * Calculate available width for data in wrapped mode + */ if (cont->opt->format == PRINT_WRAPPED) { - /* - * Separators width - */ - unsigned int width, - min_width, - swidth, - iwidth = 0; + unsigned int swidth, + rwidth = 0, + newdwidth; if (opt_border == 0) { /* - * For border = 0, one space in the middle. + * For border = 0, one space in the middle. (If we discover we + * need to wrap, the spacer column will be replaced by a wrap + * marker, and we'll make room below for another wrap marker at + * the end of the line. But for now, assume no wrap is needed.) */ swidth = 1; + + /* We might need a column for header newline markers, too */ + if (hmultiline) + swidth++; } else if (opt_border == 1) { /* - * For border = 1, one for the pipe (|) in the middle between the - * two spaces. + * For border = 1, two spaces and a vrule in the middle. (As + * above, we might need one more column for a wrap marker.) */ swidth = 3; + + /* We might need a column for left header newline markers, too */ + if (hmultiline && (format == &pg_asciiformat_old)) + swidth++; } else - - /* - * For border = 2, two more for the pipes (|) at the beginning and - * at the end of the lines. - */ - swidth = 7; - - if ((opt_border < 2) && - ((hmultiline && - (format == &pg_asciiformat_old)) || - (dmultiline && - (format != &pg_asciiformat_old)))) - iwidth++; /* for newline indicators */ - - min_width = hwidth + iwidth + swidth + 3; - - /* - * Record header width - */ - if (!opt_tuples_only) { /* - * Record number + * For border = 2, two more for the vrules at the beginning and + * end of the lines, plus spacer columns adjacent to these. (We + * won't need extra columns for wrap/newline markers, we'll just + * repurpose the spacers.) */ - unsigned int rwidth = 1 + log10(cont->nrows); + swidth = 7; + } + /* Reserve a column for data newline indicators, too, if needed */ + if (dmultiline && + opt_border < 2 && format != &pg_asciiformat_old) + swidth++; + + /* Determine width required for record header lines */ + if (!opt_tuples_only) + { + rwidth = 1 + log10(cont->nrows); if (opt_border == 0) rwidth += 9; /* "* RECORD " */ else if (opt_border == 1) rwidth += 12; /* "-[ RECORD ]" */ else rwidth += 15; /* "+-[ RECORD ]-+" */ + } + /* We might need to do the rest of the calculation twice */ + for (;;) + { + unsigned int width, + min_width; + + /* Total width required to not wrap data */ + width = hwidth + swidth + dwidth; + + /* Minimum acceptable width: room for just 3 columns of data */ + min_width = hwidth + swidth + 3; + /* ... but not less than what the record header lines need */ if (rwidth > min_width) min_width = rwidth; - } - /* Wrap to minimum width */ - width = hwidth + iwidth + swidth + dwidth; - if ((width < min_width) || (output_columns < min_width)) - width = min_width - hwidth - iwidth - swidth; - else if (output_columns > 0) + if (width < min_width || output_columns < min_width) + { + /* Set data width to match min_width */ + newdwidth = min_width - hwidth - swidth; + } + else if (output_columns > 0) + { + /* Set data width to match output_columns */ + newdwidth = output_columns - hwidth - swidth; + } + else + { + /* Use native data width */ + newdwidth = dwidth; + } /* - * Wrap to maximum width + * If we will need to wrap data and didn't already allocate a data + * newline/wrap marker column, do so and recompute. */ - width = output_columns - hwidth - iwidth - swidth; - - if ((width < dwidth) || (dheight > 1)) - { - dmultiline = true; - if ((opt_border == 0) && - (format != &pg_asciiformat_old)) - width--; /* for wrap indicators */ + if (newdwidth < dwidth && !dmultiline && + opt_border < 2 && format != &pg_asciiformat_old) + { + dmultiline = true; + swidth++; + } + else + break; } - dwidth = width; + + dwidth = newdwidth; } /* print records */ @@ -1558,12 +1585,10 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout) { if (offset) fputs(format->midvrule_wrap, fout); - else if (!dline) + else if (dline == 0) fputs(dformat->midvrule, fout); - else if (dline) - fputs(format->midvrule_nl, fout); else - fputs(format->midvrule_blank, fout); + fputs(format->midvrule_nl, fout); } /* Data */ @@ -1574,9 +1599,9 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout) swidth = dwidth; /* - * Left spacer on wrap indicator + * Left spacer or wrap indicator */ - fputs(!dcomplete && !offset ? " " : format->wrap_left, fout); + fputs(offset == 0 ? " " : format->wrap_left, fout); /* * Data text diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index d6f4f4831d..371cef3cd7 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -1185,6 +1185,338 @@ execute q; +--------------------+-----------------+ (10 rows) +\pset expanded on +\pset columns 30 +\pset border 0 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; +* Record 1 +0123456789abcdef xx +0123456789 yyyyyyyyyyyyyyyyyy +* Record 2 +0123456789abcdef xxxx +0123456789 yyyyyyyyyyyyyyyy +* Record 3 +0123456789abcdef xxxxxx +0123456789 yyyyyyyyyyyyyy +* Record 4 +0123456789abcdef xxxxxxxx +0123456789 yyyyyyyyyyyy +* Record 5 +0123456789abcdef xxxxxxxxxx +0123456789 yyyyyyyyyy +* Record 6 +0123456789abcdef xxxxxxxxxxxx +0123456789 yyyyyyyy +* Record 7 +0123456789abcdef xxxxxxxxxxxxxx +0123456789 yyyyyy +* Record 8 +0123456789abcdef xxxxxxxxxxxxxxxx +0123456789 yyyy +* Record 9 +0123456789abcdef xxxxxxxxxxxxxxxxxx +0123456789 yy +* Record 10 +0123456789abcdef xxxxxxxxxxxxxxxxxxxx +0123456789 + +\pset format wrapped +execute q; +* Record 1 +0123456789abcdef xx +0123456789 yyyyyyyyyyyy. + .yyyyyy +* Record 2 +0123456789abcdef xxxx +0123456789 yyyyyyyyyyyy. + .yyyy +* Record 3 +0123456789abcdef xxxxxx +0123456789 yyyyyyyyyyyy. + .yy +* Record 4 +0123456789abcdef xxxxxxxx +0123456789 yyyyyyyyyyyy +* Record 5 +0123456789abcdef xxxxxxxxxx +0123456789 yyyyyyyyyy +* Record 6 +0123456789abcdef xxxxxxxxxxxx +0123456789 yyyyyyyy +* Record 7 +0123456789abcdef xxxxxxxxxxxx. + .xx +0123456789 yyyyyy +* Record 8 +0123456789abcdef xxxxxxxxxxxx. + .xxxx +0123456789 yyyy +* Record 9 +0123456789abcdef xxxxxxxxxxxx. + .xxxxxx +0123456789 yy +* Record 10 +0123456789abcdef xxxxxxxxxxxx. + .xxxxxxxx +0123456789 + +\pset border 1 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; +-[ RECORD 1 ]----+--------------------- +0123456789abcdef | xx +0123456789 | yyyyyyyyyyyyyyyyyy +-[ RECORD 2 ]----+--------------------- +0123456789abcdef | xxxx +0123456789 | yyyyyyyyyyyyyyyy +-[ RECORD 3 ]----+--------------------- +0123456789abcdef | xxxxxx +0123456789 | yyyyyyyyyyyyyy +-[ RECORD 4 ]----+--------------------- +0123456789abcdef | xxxxxxxx +0123456789 | yyyyyyyyyyyy +-[ RECORD 5 ]----+--------------------- +0123456789abcdef | xxxxxxxxxx +0123456789 | yyyyyyyyyy +-[ RECORD 6 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxx +0123456789 | yyyyyyyy +-[ RECORD 7 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxx +0123456789 | yyyyyy +-[ RECORD 8 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxx +0123456789 | yyyy +-[ RECORD 9 ]----+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxxxx +0123456789 | yy +-[ RECORD 10 ]---+--------------------- +0123456789abcdef | xxxxxxxxxxxxxxxxxxxx +0123456789 | + +\pset format wrapped +execute q; +-[ RECORD 1 ]----+----------- +0123456789abcdef | xx +0123456789 | yyyyyyyyyy. + |.yyyyyyyy +-[ RECORD 2 ]----+----------- +0123456789abcdef | xxxx +0123456789 | yyyyyyyyyy. + |.yyyyyy +-[ RECORD 3 ]----+----------- +0123456789abcdef | xxxxxx +0123456789 | yyyyyyyyyy. + |.yyyy +-[ RECORD 4 ]----+----------- +0123456789abcdef | xxxxxxxx +0123456789 | yyyyyyyyyy. + |.yy +-[ RECORD 5 ]----+----------- +0123456789abcdef | xxxxxxxxxx +0123456789 | yyyyyyyyyy +-[ RECORD 6 ]----+----------- +0123456789abcdef | xxxxxxxxxx. + |.xx +0123456789 | yyyyyyyy +-[ RECORD 7 ]----+----------- +0123456789abcdef | xxxxxxxxxx. + |.xxxx +0123456789 | yyyyyy +-[ RECORD 8 ]----+----------- +0123456789abcdef | xxxxxxxxxx. + |.xxxxxx +0123456789 | yyyy +-[ RECORD 9 ]----+----------- +0123456789abcdef | xxxxxxxxxx. + |.xxxxxxxx +0123456789 | yy +-[ RECORD 10 ]---+----------- +0123456789abcdef | xxxxxxxxxx. + |.xxxxxxxxxx +0123456789 | + +\pset border 2 +\pset format unaligned +execute q; +0123456789abcdef|xx +0123456789|yyyyyyyyyyyyyyyyyy + +0123456789abcdef|xxxx +0123456789|yyyyyyyyyyyyyyyy + +0123456789abcdef|xxxxxx +0123456789|yyyyyyyyyyyyyy + +0123456789abcdef|xxxxxxxx +0123456789|yyyyyyyyyyyy + +0123456789abcdef|xxxxxxxxxx +0123456789|yyyyyyyyyy + +0123456789abcdef|xxxxxxxxxxxx +0123456789|yyyyyyyy + +0123456789abcdef|xxxxxxxxxxxxxx +0123456789|yyyyyy + +0123456789abcdef|xxxxxxxxxxxxxxxx +0123456789|yyyy + +0123456789abcdef|xxxxxxxxxxxxxxxxxx +0123456789|yy + +0123456789abcdef|xxxxxxxxxxxxxxxxxxxx +0123456789| +\pset format aligned +execute q; ++-[ RECORD 1 ]-----+----------------------+ +| 0123456789abcdef | xx | +| 0123456789 | yyyyyyyyyyyyyyyyyy | ++-[ RECORD 2 ]-----+----------------------+ +| 0123456789abcdef | xxxx | +| 0123456789 | yyyyyyyyyyyyyyyy | ++-[ RECORD 3 ]-----+----------------------+ +| 0123456789abcdef | xxxxxx | +| 0123456789 | yyyyyyyyyyyyyy | ++-[ RECORD 4 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxx | +| 0123456789 | yyyyyyyyyyyy | ++-[ RECORD 5 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxx | +| 0123456789 | yyyyyyyyyy | ++-[ RECORD 6 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxx | +| 0123456789 | yyyyyyyy | ++-[ RECORD 7 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxx | +| 0123456789 | yyyyyy | ++-[ RECORD 8 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxx | +| 0123456789 | yyyy | ++-[ RECORD 9 ]-----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxxxx | +| 0123456789 | yy | ++-[ RECORD 10 ]----+----------------------+ +| 0123456789abcdef | xxxxxxxxxxxxxxxxxxxx | +| 0123456789 | | ++------------------+----------------------+ + +\pset format wrapped +execute q; ++-[ RECORD 1 ]-----+---------+ +| 0123456789abcdef | xx | +| 0123456789 | yyyyyyy.| +| |.yyyyyyy.| +| |.yyyy | ++-[ RECORD 2 ]-----+---------+ +| 0123456789abcdef | xxxx | +| 0123456789 | yyyyyyy.| +| |.yyyyyyy.| +| |.yy | ++-[ RECORD 3 ]-----+---------+ +| 0123456789abcdef | xxxxxx | +| 0123456789 | yyyyyyy.| +| |.yyyyyyy | ++-[ RECORD 4 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.x | +| 0123456789 | yyyyyyy.| +| |.yyyyy | ++-[ RECORD 5 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxx | +| 0123456789 | yyyyyyy.| +| |.yyy | ++-[ RECORD 6 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxxxx | +| 0123456789 | yyyyyyy.| +| |.y | ++-[ RECORD 7 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxxxxxx | +| 0123456789 | yyyyyy | ++-[ RECORD 8 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxxxxxx.| +| |.xx | +| 0123456789 | yyyy | ++-[ RECORD 9 ]-----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxxxxxx.| +| |.xxxx | +| 0123456789 | yy | ++-[ RECORD 10 ]----+---------+ +| 0123456789abcdef | xxxxxxx.| +| |.xxxxxxx.| +| |.xxxxxx | +| 0123456789 | | ++------------------+---------+ + \pset expanded on \pset columns 20 \pset border 0 @@ -1254,115 +1586,88 @@ execute q; \pset format wrapped execute q; -* Record 1 +* Record 1 0123456789abcdef xx -0123456789 yy. - .yy. - .yy. - .yy. - .yy. - .yy. - .yy. - .yy. +0123456789 yyy. + .yyy. + .yyy. + .yyy. + .yyy. + .yyy +* Record 2 +0123456789abcdef xxx. + .x +0123456789 yyy. + .yyy. + .yyy. + .yyy. + .yyy. + .y +* Record 3 +0123456789abcdef xxx. + .xxx +0123456789 yyy. + .yyy. + .yyy. + .yyy. .yy -* Record 2 -0123456789abcdef xx. +* Record 4 +0123456789abcdef xxx. + .xxx. .xx -0123456789 yy. - .yy. - .yy. - .yy. - .yy. - .yy. - .yy. +0123456789 yyy. + .yyy. + .yyy. + .yyy +* Record 5 +0123456789abcdef xxx. + .xxx. + .xxx. + .x +0123456789 yyy. + .yyy. + .yyy. + .y +* Record 6 +0123456789abcdef xxx. + .xxx. + .xxx. + .xxx +0123456789 yyy. + .yyy. .yy -* Record 3 -0123456789abcdef xx. - .xx. - .xx -0123456789 yy. - .yy. - .yy. - .yy. - .yy. - .yy. - .yy -* Record 4 -0123456789abcdef xx. - .xx. - .xx. - .xx -0123456789 yy. - .yy. - .yy. - .yy. - .yy. - .yy -* Record 5 -0123456789abcdef xx. - .xx. - .xx. - .xx. - .xx -0123456789 yy. - .yy. - .yy. - .yy. - .yy -* Record 6 -0123456789abcdef xx. - .xx. - .xx. - .xx. - .xx. - .xx -0123456789 yy. - .yy. - .yy. - .yy -* Record 7 -0123456789abcdef xx. - .xx. - .xx. - .xx. - .xx. - .xx. - .xx -0123456789 yy. - .yy. - .yy -* Record 8 -0123456789abcdef xx. - .xx. - .xx. - .xx. - .xx. - .xx. - .xx. - .xx -0123456789 yy. - .yy -* Record 9 -0123456789abcdef xx. - .xx. - .xx. - .xx. - .xx. - .xx. - .xx. - .xx. +* Record 7 +0123456789abcdef xxx. + .xxx. + .xxx. + .xxx. .xx +0123456789 yyy. + .yyy +* Record 8 +0123456789abcdef xxx. + .xxx. + .xxx. + .xxx. + .xxx. + .x +0123456789 yyy. + .y +* Record 9 +0123456789abcdef xxx. + .xxx. + .xxx. + .xxx. + .xxx. + .xxx 0123456789 yy -* Record 10 -0123456789abcdef xx. - .xx. - .xx. - .xx. - .xx. - .xx. - .xx. - .xx. - .xx. +* Record 10 +0123456789abcdef xxx. + .xxx. + .xxx. + .xxx. + .xxx. + .xxx. .xx 0123456789 diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql index b93764a684..2f81380e22 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -193,6 +193,33 @@ execute q; \pset format wrapped execute q; +\pset expanded on +\pset columns 30 + +\pset border 0 +\pset format unaligned +execute q; +\pset format aligned +execute q; +\pset format wrapped +execute q; + +\pset border 1 +\pset format unaligned +execute q; +\pset format aligned +execute q; +\pset format wrapped +execute q; + +\pset border 2 +\pset format unaligned +execute q; +\pset format aligned +execute q; +\pset format wrapped +execute q; + \pset expanded on \pset columns 20