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