diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 65bb0a6a3f3..a95ddd60ee2 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -2842,6 +2842,39 @@ lo_import 152801
+
+ xheader_width
+
+
+ Sets the maximum width of the header for expanded output to one of
+ full (the default value),
+ column, page, or an
+ integer value.
+
+
+
+ full: the expanded header is not truncated,
+ and will be as wide as the widest output
+ line.
+
+
+
+ column: truncate the header line at the
+ width of the first column.
+
+
+
+ page: truncate the the header line at the terminal
+ width.
+
+
+
+ integer value: specify
+ the exact maximum width of the header line.
+
+
+
+
fieldsep
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index cac98804ab5..a81bd3307b4 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -2244,6 +2244,7 @@ exec_command_pset(PsqlScanState scan_state, bool active_branch)
"unicode_border_linestyle",
"unicode_column_linestyle",
"unicode_header_linestyle",
+ "xheader_width",
NULL
};
@@ -4369,6 +4370,29 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
popt->topt.expanded = !popt->topt.expanded;
}
+ /* header line width in expanded mode */
+ else if (strcmp(param, "xheader_width") == 0)
+ {
+ if (! value)
+ ;
+ else if (pg_strcasecmp(value, "full") == 0)
+ popt->topt.expanded_header_width_type = PRINT_XHEADER_FULL;
+ else if (pg_strcasecmp(value, "column") == 0)
+ popt->topt.expanded_header_width_type = PRINT_XHEADER_COLUMN;
+ else if (pg_strcasecmp(value, "page") == 0)
+ popt->topt.expanded_header_width_type = PRINT_XHEADER_PAGE;
+ else
+ {
+ popt->topt.expanded_header_width_type = PRINT_XHEADER_EXACT_WIDTH;
+ popt->topt.expanded_header_exact_width = atoi(value);
+ if (popt->topt.expanded_header_exact_width == 0)
+ {
+ pg_log_error("\\pset: allowed xheader_width values are full (default), column, page, or a number specifying the exact width.");
+ return false;
+ }
+ }
+ }
+
/* field separator for CSV format */
else if (strcmp(param, "csv_fieldsep") == 0)
{
@@ -4561,6 +4585,19 @@ printPsetInfo(const char *param, printQueryOpt *popt)
printf(_("Expanded display is off.\n"));
}
+ /* show xheader width value */
+ else if (strcmp(param, "xheader_width") == 0)
+ {
+ if (popt->topt.expanded_header_width_type == PRINT_XHEADER_FULL)
+ printf(_("Expanded header width is 'full'.\n"));
+ else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_COLUMN)
+ printf(_("Expanded header width is 'column'.\n"));
+ else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_PAGE)
+ printf(_("Expanded header width is 'page'.\n"));
+ else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_EXACT_WIDTH)
+ printf(_("Expanded header width is %d.\n"), popt->topt.expanded_header_exact_width);
+ }
+
/* show field separator for CSV format */
else if (strcmp(param, "csv_fieldsep") == 0)
{
@@ -4881,6 +4918,23 @@ pset_value_string(const char *param, printQueryOpt *popt)
return pstrdup(_unicode_linestyle2string(popt->topt.unicode_column_linestyle));
else if (strcmp(param, "unicode_header_linestyle") == 0)
return pstrdup(_unicode_linestyle2string(popt->topt.unicode_header_linestyle));
+ else if (strcmp(param, "xheader_width") == 0)
+ {
+ if (popt->topt.expanded_header_width_type == PRINT_XHEADER_FULL)
+ return(pstrdup("full"));
+ else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_COLUMN)
+ return(pstrdup("column"));
+ else if (popt->topt.expanded_header_width_type == PRINT_XHEADER_PAGE)
+ return(pstrdup("page"));
+ else
+ {
+ /* must be PRINT_XHEADER_EXACT_WIDTH */
+ char wbuff[32];
+ snprintf(wbuff, sizeof(wbuff), "%d",
+ popt->topt.expanded_header_exact_width);
+ return pstrdup(wbuff);
+ }
+ }
else
return pstrdup("ERROR");
}
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 5f06768085f..f265e043e95 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -4654,13 +4654,16 @@ psql_completion(const char *text, int start, int end)
"tableattr", "title", "tuples_only",
"unicode_border_linestyle",
"unicode_column_linestyle",
- "unicode_header_linestyle");
+ "unicode_header_linestyle",
+ "xheader_width");
else if (TailMatchesCS("\\pset", MatchAny))
{
if (TailMatchesCS("format"))
COMPLETE_WITH_CS("aligned", "asciidoc", "csv", "html", "latex",
"latex-longtable", "troff-ms", "unaligned",
"wrapped");
+ else if (TailMatchesCS("xheader_width"))
+ COMPLETE_WITH_CS("full", "column", "page");
else if (TailMatchesCS("linestyle"))
COMPLETE_WITH_CS("ascii", "old-ascii", "unicode");
else if (TailMatchesCS("pager"))
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index fe676a971b9..a48c9196978 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -1222,15 +1222,16 @@ cleanup:
static void
-print_aligned_vertical_line(const printTextFormat *format,
- const unsigned short opt_border,
+print_aligned_vertical_line(const printTableOpt *topt,
unsigned long record,
unsigned int hwidth,
unsigned int dwidth,
+ int output_columns,
printTextRule pos,
FILE *fout)
{
- const printTextLineFormat *lformat = &format->lrule[pos];
+ const printTextLineFormat *lformat = &get_line_style(topt)->lrule[pos];
+ const unsigned short opt_border = topt->border;
unsigned int i;
int reclen = 0;
@@ -1259,8 +1260,18 @@ print_aligned_vertical_line(const printTextFormat *format,
if (reclen-- <= 0)
fputs(lformat->hrule, fout);
if (reclen-- <= 0)
- fputs(lformat->midvrule, fout);
- if (reclen-- <= 0)
+ {
+ if (topt->expanded_header_width_type == PRINT_XHEADER_COLUMN)
+ {
+ fputs(lformat->rightvrule, fout);
+ }
+ else
+ {
+ fputs(lformat->midvrule, fout);
+ }
+ }
+ if (reclen-- <= 0
+ && topt->expanded_header_width_type != PRINT_XHEADER_COLUMN)
fputs(lformat->hrule, fout);
}
else
@@ -1268,12 +1279,43 @@ print_aligned_vertical_line(const printTextFormat *format,
if (reclen-- <= 0)
fputc(' ', fout);
}
- if (reclen < 0)
- reclen = 0;
- for (i = reclen; i < dwidth; i++)
- fputs(opt_border > 0 ? lformat->hrule : " ", fout);
- if (opt_border == 2)
- fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
+
+ if (topt->expanded_header_width_type != PRINT_XHEADER_COLUMN)
+ {
+ if (topt->expanded_header_width_type == PRINT_XHEADER_PAGE
+ || topt->expanded_header_width_type == PRINT_XHEADER_EXACT_WIDTH)
+ {
+ if (topt->expanded_header_width_type == PRINT_XHEADER_EXACT_WIDTH)
+ {
+ output_columns = topt->expanded_header_exact_width;
+ }
+ if (output_columns > 0)
+ {
+ if (opt_border == 0)
+ dwidth = Min(dwidth, Max(0, (int) (output_columns - hwidth)));
+ if (opt_border == 1)
+ dwidth = Min(dwidth, Max(0, (int) (output_columns - hwidth - 3)));
+ /*
+ * Handling the xheader width for border=2 doesn't make
+ * much sense because this format has an additional
+ * right border, but keep this for consistency.
+ */
+ if (opt_border == 2)
+ dwidth = Min(dwidth, Max(0, (int) (output_columns - hwidth - 7)));
+ }
+ }
+
+ if (reclen < 0)
+ reclen = 0;
+ if (dwidth < reclen)
+ dwidth = reclen;
+
+ for (i = reclen; i < dwidth; i++)
+ fputs(opt_border > 0 ? lformat->hrule : " ", fout);
+ if (opt_border == 2)
+ fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
+ }
+
fputc('\n', fout);
}
@@ -1570,11 +1612,12 @@ print_aligned_vertical(const printTableContent *cont,
lhwidth++; /* for newline indicators */
if (!opt_tuples_only)
- print_aligned_vertical_line(format, opt_border, record++,
- lhwidth, dwidth, pos, fout);
+ print_aligned_vertical_line(cont->opt, record++,
+ lhwidth, dwidth, output_columns,
+ pos, fout);
else if (i != 0 || !cont->opt->start_table || opt_border == 2)
- print_aligned_vertical_line(format, opt_border, 0, lhwidth,
- dwidth, pos, fout);
+ print_aligned_vertical_line(cont->opt, 0, lhwidth,
+ dwidth, output_columns, pos, fout);
}
/* Format the header */
@@ -1760,8 +1803,8 @@ print_aligned_vertical(const printTableContent *cont,
if (cont->opt->stop_table)
{
if (opt_border == 2 && !cancel_pressed)
- print_aligned_vertical_line(format, opt_border, 0, hwidth, dwidth,
- PRINT_RULE_BOTTOM, fout);
+ print_aligned_vertical_line(cont->opt, 0, hwidth, dwidth,
+ output_columns, PRINT_RULE_BOTTOM, fout);
/* print footers */
if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
diff --git a/src/include/fe_utils/print.h b/src/include/fe_utils/print.h
index bb2f1bf4e64..b8dbfa5f543 100644
--- a/src/include/fe_utils/print.h
+++ b/src/include/fe_utils/print.h
@@ -66,6 +66,15 @@ typedef enum printTextLineWrap
PRINT_LINE_WRAP_NEWLINE /* Newline in data */
} printTextLineWrap;
+typedef enum printXheaderWidthType
+{
+ /* Expanded header line width variants */
+ PRINT_XHEADER_FULL, /* do not truncate header line (this is the default) */
+ PRINT_XHEADER_COLUMN, /* only print header line above the first column */
+ PRINT_XHEADER_PAGE, /* header line must not be longer than terminal width */
+ PRINT_XHEADER_EXACT_WIDTH, /* explicitly specified width */
+} printXheaderWidthType;
+
typedef struct printTextFormat
{
/* A complete line style */
@@ -101,6 +110,8 @@ typedef struct printTableOpt
enum printFormat format; /* see enum above */
unsigned short int expanded; /* expanded/vertical output (if supported
* by output format); 0=no, 1=yes, 2=auto */
+ printXheaderWidthType expanded_header_width_type; /* width type for header line in expanded mode */
+ int expanded_header_exact_width; /* explicit width for header line in expanded mode */
unsigned short int border; /* Print a border around the table. 0=none,
* 1=dividing lines, 2=full */
unsigned short int pager; /* use pager for output (if to stdout and
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 60acbd1241e..a7f5700edc1 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -317,6 +317,7 @@ tuples_only off
unicode_border_linestyle single
unicode_column_linestyle single
unicode_header_linestyle single
+xheader_width full
-- test multi-line headers, wrapping, and newline indicators
-- in aligned, unaligned, and wrapped formats
prepare q as select array_to_string(array_agg(repeat('x',2*n)),E'\n') as "ab
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 34a76ceb60f..60709ddc987 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3569,6 +3569,7 @@ printTextFormat
printTextLineFormat
printTextLineWrap
printTextRule
+printXheaderWidthType
printfunc
priv_map
process_file_callback_t