On Mon, Nov 09, 2009 at 05:40:54PM -0500, Bruce Momjian wrote: > Tom Lane wrote: > > Greg Stark <gsst...@mit.edu> writes: > > > While i agree this looks nicer I wonder what it does to things like > > > excel/gnumeric/ooffice auto-recognizing table layouts and importing > > > files. I'm not sure our old format was so great for this so maybe this > > > is actually an improvement I'm asking for. > > > > Yeah. We can do what we like with the UTF8 format but I'm considerably > > more worried about the aspect of making random changes to the > > plain-ASCII output. On the other hand, we changed that just a release > > or so ago (to put in the multiline output in the first place) and > > I didn't hear complaints about it that time. > > Sorry for the delayed reply: > > The line continuation characters were chosen in 8.4 for clarity --- if > you have found something clearer for 8.5, let's make the improvement. I > think clarity is more important in this area than consistency with the > previous psql output format.
The attached patch is proposed for the upcoming commitfest, and hopefully takes into account the comments made in this thread. To summarise the changes: - it makes the handling of newlines and wrapped lines consistent between column header and data lines. - it includes additional logic such that both the "old" and "new" styles are representable using the format structures, so we can retain backward compatibility if so desired (it's easy to remove if not). - an "ascii-old" linestyle is added which is identical to the old style for those who need guaranteed reproducibility of output, but this is not the default. - The Unicode format uses "↵" in the right-hand margin to indicate newlines. Wrapped lines use "…" in the right-hand margin before, and left-hand margin after, a break (so you can visually follow the wrap). - The ASCII format is the same but uses "+" and "." in place of carriage return and ellipsis symbols. - All the above is documented in the SGML documentation, including the old style, which I always found confusing. For comparison, I've included a transcript of all three linestyles with a test script (also attached). Any changes to the symbols used and/or their placement are trivially made by just altering the format in print.c. Regards, Roger -- .''`. Roger Leigh : :' : Debian GNU/Linux http://people.debian.org/~rleigh/ `. `' Printing on GNU/Linux? http://gutenprint.sourceforge.net/ `- GPG Public Key: 0x25BFB848 Please GPG sign your mail.
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 7f03802..4600303 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1765,18 +1765,40 @@ lo_import 152801 <listitem> <para> Sets the border line drawing style to one - of <literal>ascii</literal> or <literal>unicode</literal>. - Unique abbreviations are allowed. (That would mean one - letter is enough.) + of <literal>ascii</literal>, <literal>ascii-old</literal> + or <literal>unicode</literal>. Unique abbreviations are + allowed. (That would mean one letter is enough.) </para> <para> - <quote>ASCII</quote> uses plain <acronym>ASCII</acronym> characters. + <quote>ASCII</quote> uses plain <acronym>ASCII</acronym> + characters. Newlines in data are shown using + a <literal>+</literal> symbol in the right-hand margin. + Wrapped data uses a <literal>.</literal> symbol in the + right-hand margin of a wrapped line, and in the left-hand + margin of the following continuation line. </para> <para> + <quote>ASCII-old</quote> uses plain <acronym>ASCII</acronym> + characters, using the formatting style used + for <productname>PostgreSQL</productname> 8.4 and earlier. + Newlines in data are shown using a <literal>:</literal> + symbol in place of the left-hand column separator, while + wrapped data uses a <literal>;</literal> symbol. Newlines + in column headings are indicated by a <literal>+</literal> + symbol in the left-hand margin of additional lines. + </para> + + <para> <quote>Unicode</quote> uses Unicode box-drawing characters. - </para> + Newlines in data are shown using a carriage return symbol + (<literal>↵</literal>) in the right-hand margin. + Wrapped data uses an ellipsis symbol + (<literal>…</literal>) in the right-hand margin of a + wrapped line, and in the left-hand margin of the following + continuation line. + </para> <para> When the selected output format is one that draws lines or boxes diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 190a8d3..544a677 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -1795,11 +1795,13 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet) ; else if (pg_strncasecmp("ascii", value, vallen) == 0) popt->topt.line_style = &pg_asciiformat; + else if (pg_strncasecmp("ascii-old", value, vallen) == 0) + popt->topt.line_style = &pg_asciiformat_old; else if (pg_strncasecmp("unicode", value, vallen) == 0) popt->topt.line_style = &pg_utf8format; else { - psql_error("\\pset: allowed line styles are ascii, unicode\n"); + psql_error("\\pset: allowed line styles are ascii, ascii-old, unicode\n"); return false; } diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index 026e043..e8db912 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -45,9 +45,9 @@ static char *grouping; static char *thousands_sep; /* Line style control structures */ -const printTextFormat pg_asciiformat = +const printTextFormat pg_asciiformat_old = { - "ascii", + "ascii-old", { { "-", "+", "+", "+" }, { "-", "+", "+", "+" }, @@ -56,7 +56,36 @@ const printTextFormat pg_asciiformat = }, ":", ";", - " " + " ", + "+", + " ", + " ", + " ", + " ", + " ", + false +}; + +/* Line style control structures */ +const printTextFormat pg_asciiformat = +{ + "ascii", + { + { "-", "+", "+", "+" }, + { "-", "+", "+", "+" }, + { "-", "+", "+", "+" }, + { "", "|", "|", "|" } + }, + "|", + "|", + "|", + " ", + "+", + " ", + "+", + ".", + ".", + false }; const printTextFormat pg_utf8format = @@ -72,12 +101,23 @@ const printTextFormat pg_utf8format = /* N/A, │, │, │ */ { "", "\342\224\202", "\342\224\202", "\342\224\202" } }, - /* ╎ */ - "\342\225\216", - /* ┊ */ - "\342\224\212", - /* ╷ */ - "\342\225\267" + /* │ */ + "\342\224\202", + /* │ */ + "\342\224\202", + /* │ */ + "\342\224\202", + " ", + /* ↵ */ + "\342\206\265", + " ", + /* ↵ */ + "\342\206\265", + /* … */ + "\342\200\246", + /* … */ + "\342\200\246", + true }; @@ -479,6 +519,8 @@ print_aligned_text(const printTableContent *cont, FILE *fout) int output_columns = 0; /* Width of interactive console */ bool is_pager = false; + printTextLineWrap *wrap; + if (cancel_pressed) return; @@ -499,6 +541,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout) format_buf = pg_local_calloc(col_count, sizeof(*format_buf)); header_done = pg_local_calloc(col_count, sizeof(*header_done)); bytes_output = pg_local_calloc(col_count, sizeof(*bytes_output)); + wrap = pg_local_calloc(col_count, sizeof(*wrap)); } else { @@ -513,6 +556,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout) format_buf = NULL; header_done = NULL; bytes_output = NULL; + wrap = NULL; } /* scan all column headers, find maximum width and max max_nl_lines */ @@ -575,7 +619,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout) /* adjust the total display width based on border style */ if (opt_border == 0) - width_total = col_count - 1; + width_total = col_count; else if (opt_border == 1) width_total = col_count * 3 - 1; else @@ -770,16 +814,16 @@ print_aligned_text(const printTableContent *cont, FILE *fout) while (more_col_wrapping) { if (opt_border == 2) - fprintf(fout, "%s%c", dformat->leftvrule, - curr_nl_line ? '+' : ' '); - else if (opt_border == 1) - fputc(curr_nl_line ? '+' : ' ', fout); + fputs(dformat->leftvrule, fout); for (i = 0; i < cont->ncolumns; i++) { struct lineptr *this_line = col_lineptrs[i] + curr_nl_line; unsigned int nbspace; + if (opt_border != 0 || (format->cont_right_border == false && i > 0)) + fputs(curr_nl_line ? format->header_cont_left : " ", fout); + if (!header_done[i]) { nbspace = width_wrap[i] - this_line->width; @@ -796,21 +840,17 @@ print_aligned_text(const printTableContent *cont, FILE *fout) } else fprintf(fout, "%*s", width_wrap[i], ""); - if (i < col_count - 1) - { - if (opt_border == 0) - fputc(curr_nl_line ? '+' : ' ', fout); - else - fprintf(fout, " %s%c", dformat->midvrule, - curr_nl_line ? '+' : ' '); - } + + if (opt_border != 0 || format->cont_right_border == true) + fputs(!header_done[i] ? format->header_cont_right : " ", fout); + + if (opt_border != 0 && i < col_count - 1) + fputs(dformat->midvrule, fout); } curr_nl_line++; if (opt_border == 2) - fprintf(fout, " %s", dformat->rightvrule); - else if (opt_border == 1) - fputc(' ', fout); + fputs(dformat->rightvrule, fout); fputc('\n', fout); } @@ -861,19 +901,28 @@ print_aligned_text(const printTableContent *cont, FILE *fout) /* left border */ if (opt_border == 2) - fprintf(fout, "%s ", dformat->leftvrule); - else if (opt_border == 1) - fputc(' ', fout); + fputs(dformat->leftvrule, fout); /* for each column */ for (j = 0; j < col_count; j++) { /* We have a valid array element, so index it */ struct lineptr *this_line = &col_lineptrs[j][curr_nl_line[j]]; - int bytes_to_output; - int chars_to_output = width_wrap[j]; + int bytes_to_output; + int chars_to_output = width_wrap[j]; bool finalspaces = (opt_border == 2 || j < col_count - 1); + /* Print left-hand wrap or newline mark */ + if (opt_border != 0) + { + if (wrap[j] == PRINT_LINE_WRAP_WRAP) + fputs(format->wrap_left, fout); + else if (wrap[j] == PRINT_LINE_WRAP_CONT) + fputs(format->cont_left, fout); + else + fputc(' ', fout); + } + if (!this_line->ptr) { /* Past newline lines so just pad for other columns */ @@ -908,7 +957,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout) /* spaces second */ fprintf(fout, "%.*s", bytes_to_output, this_line->ptr + bytes_output[j]); - if (finalspaces) + if (finalspaces || col_lineptrs[j][curr_nl_line[j]].ptr != NULL) fprintf(fout, "%*s", width_wrap[j] - chars_to_output, ""); } @@ -927,29 +976,40 @@ print_aligned_text(const printTableContent *cont, FILE *fout) } } - /* print a divider, if not the last column */ - if (j < col_count - 1) + /* Determine if next line for this column is wrapped or a newline */ + wrap[j] = PRINT_LINE_WRAP_NONE; + if (col_lineptrs[j][curr_nl_line[j]].ptr != NULL) { - if (opt_border == 0) - fputc(' ', fout); - /* Next value is beyond past newlines? */ + if (bytes_output[j] != 0) + wrap[j] = PRINT_LINE_WRAP_WRAP; + else if (curr_nl_line[j] != 0) + wrap[j] = PRINT_LINE_WRAP_CONT; + } + + /* Print right-hand wrap or newline mark */ + if (wrap[j] == PRINT_LINE_WRAP_WRAP) + fputs(format->wrap_right, fout); + else if (wrap[j] == PRINT_LINE_WRAP_CONT) + fputs(format->cont_right, fout); + else if (!(opt_border == 0 && j == col_count - 1)) + fputc(' ', fout); + + if (opt_border != 0 && j < col_count - 1) + { + if (wrap[j+1] == PRINT_LINE_WRAP_WRAP) + fputs(format->midvrule_wrap, fout); + else if (wrap[j+1] == PRINT_LINE_WRAP_CONT) + fputs(format->midvrule_cont, fout); else if (col_lineptrs[j + 1][curr_nl_line[j + 1]].ptr == NULL) - fprintf(fout, " %s ", format->midvrule_blank); - /* In wrapping of value? */ - else if (bytes_output[j + 1] != 0) - fprintf(fout, " %s ", format->midvrule_wrap); - /* After first newline value */ - else if (curr_nl_line[j + 1] != 0) - fprintf(fout, " %s ", format->midvrule_cont); - /* Ordinary line */ + fputs(format->midvrule_blank, fout); else - fprintf(fout, " %s ", dformat->midvrule); + fputs(dformat->midvrule, fout); } } /* end-of-row border */ if (opt_border == 2) - fprintf(fout, " %s", dformat->rightvrule); + fputs(dformat->rightvrule, fout); fputc('\n', fout); } while (more_lines); @@ -1196,9 +1256,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout) fprintf(fout, "%*s", hwidth, ""); if (opt_border > 0) - fprintf(fout, " %s ", - (line_count == 0) ? - format->midvrule_cont : dformat->midvrule); + fprintf(fout, " %s ", dformat->midvrule); else fputc(' ', fout); diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h index 056aaa6..4aafd61 100644 --- a/src/bin/psql/print.h +++ b/src/bin/psql/print.h @@ -41,14 +41,30 @@ typedef enum printTextRule PRINT_RULE_DATA /* data line (hrule is unused here) */ } printTextRule; +typedef enum printTextLineWrap +{ + /* Types of line continuation and wrapping */ + PRINT_LINE_WRAP_NONE = 0, /* No wrapping */ + PRINT_LINE_WRAP_WRAP = 1, /* Line is wrapped */ + PRINT_LINE_WRAP_CONT = 2, /* Continuation after newline */ + PRINT_LINE_WRAP_BLANK = 3 /* Blank line after end of data */ +} printTextLineWrap; + typedef struct printTextFormat { /* A complete line style */ - const char *name; /* for display purposes */ + const char *name; /* for display purposes */ printTextLineFormat lrule[4]; /* indexed by enum printTextRule */ const char *midvrule_cont; /* vertical line for continue after newline */ const char *midvrule_wrap; /* vertical line for wrapped data */ const char *midvrule_blank; /* vertical line for blank data */ + const char *header_cont_left; /* continue after newline */ + const char *header_cont_right; /* continue after newline */ + const char *cont_left; /* continue after newline */ + const char *cont_right; /* continue after newline */ + const char *wrap_left; /* wrapped data */ + const char *wrap_right; /* wrapped data */ + bool cont_right_border; /* use right-hand border for continuation marks when border=0 */ } printTextFormat; typedef struct printTableOpt @@ -124,6 +140,7 @@ typedef struct printQueryOpt } printQueryOpt; +extern const printTextFormat pg_asciiformat_old; extern const printTextFormat pg_asciiformat; extern const printTextFormat pg_utf8format;
rleigh=# \pset linestyle ascii-old Line style is ascii-old. rleigh=# \i test.sql Pager usage is off. Border style is 0. Lorem num ipsum + dolor + ----------- --- sit amet, 5 consectetur adipisicing elit (1 row) Border style is 1. Lorem | num + ipsum |+ + dolor |+ -------------+----- sit amet, | 5 consectetur adipisicing elit (1 row) Border style is 2. +-------------+-----+ | Lorem | num | |+ ipsum |+ | |+ dolor |+ | +-------------+-----+ | sit amet, | 5 | | consectetur | | adipisicing | | elit | +-------------+-----+ (1 row) Output format is wrapped. Border style is 0. num Lorem ipsum dolor --- ----------------------------------------------------------------------------------- 5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor inc ididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exe rcitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit (1 row) Border style is 1. num | Lorem ipsum dolor -----+---------------------------------------------------------------------------------- 5 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor ; incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr ; ud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. : Duis : aute : irure : dolor : in : reprehenderit (1 row) Border style is 2. +-----+--------------------------------------------------------------------------------+ | num | Lorem ipsum dolor | +-----+--------------------------------------------------------------------------------+ | 5 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempo | | ; r incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis n | | ; ostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. | | : Duis | | : aute | | : irure | | : dolor | | : in | | : reprehenderit | +-----+--------------------------------------------------------------------------------+ (1 row) rleigh=# \pset linestyle ascii Line style is ascii. rleigh=# \i test.sql Pager usage is off. Border style is 0. Lorem num ipsum dolor ----------- --- sit amet, + 5 consectetur+ adipisicing+ elit (1 row) Border style is 1. Lorem +| num ipsum +| dolor | -------------+----- sit amet, +| 5 consectetur+| adipisicing+| elit | (1 row) Border style is 2. +-------------+-----+ | Lorem +| num | | ipsum +| | | dolor | | +-------------+-----+ | sit amet, +| 5 | | consectetur+| | | adipisicing+| | | elit | | +-------------+-----+ (1 row) Output format is wrapped. Border style is 0. num Lorem ipsum dolor --- ----------------------------------------------------------------------------------- 5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor inc. ididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exe. rcitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + Duis + aute + irure + dolor + in + reprehenderit (1 row) Border style is 1. num | Lorem ipsum dolor -----+---------------------------------------------------------------------------------- 5 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor . |.incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr. |.ud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + | Duis + | aute + | irure + | dolor + | in + | reprehenderit (1 row) Border style is 2. +-----+--------------------------------------------------------------------------------+ | num | Lorem ipsum dolor | +-----+--------------------------------------------------------------------------------+ | 5 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempo.| | |.r incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis n.| | |.ostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +| | | Duis +| | | aute +| | | irure +| | | dolor +| | | in +| | | reprehenderit | +-----+--------------------------------------------------------------------------------+ (1 row) rleigh=# \pset linestyle unicode Line style is unicode. rleigh=# \i test.sql Pager usage is off. Border style is 0. Lorem ↵num ipsum ↵ dolor ─────────── ─── sit amet, ↵ 5 consectetur↵ adipisicing↵ elit (1 row) Border style is 1. Lorem ↵│ num ipsum ↵│ dolor │ ─────────────┼───── sit amet, ↵│ 5 consectetur↵│ adipisicing↵│ elit │ (1 row) Border style is 2. ┌─────────────┬─────┐ │ Lorem ↵│ num │ │ ipsum ↵│ │ │ dolor │ │ ├─────────────┼─────┤ │ sit amet, ↵│ 5 │ │ consectetur↵│ │ │ adipisicing↵│ │ │ elit │ │ └─────────────┴─────┘ (1 row) Output format is wrapped. Border style is 0. num Lorem ipsum dolor ─── ─────────────────────────────────────────────────────────────────────────────────── 5 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor inc… ididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exe… rcitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ↵ Duis ↵ aute ↵ irure ↵ dolor ↵ in ↵ reprehenderit (1 row) Border style is 1. num │ Lorem ipsum dolor ─────┼────────────────────────────────────────────────────────────────────────────────── 5 │ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor … │…incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr… │…ud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ↵ │ Duis ↵ │ aute ↵ │ irure ↵ │ dolor ↵ │ in ↵ │ reprehenderit (1 row) Border style is 2. ┌─────┬────────────────────────────────────────────────────────────────────────────────┐ │ num │ Lorem ipsum dolor │ ├─────┼────────────────────────────────────────────────────────────────────────────────┤ │ 5 │ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempo…│ │ │…r incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis n…│ │ │…ostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ↵│ │ │ Duis ↵│ │ │ aute ↵│ │ │ irure ↵│ │ │ dolor ↵│ │ │ in ↵│ │ │ reprehenderit │ └─────┴────────────────────────────────────────────────────────────────────────────────┘ (1 row) rleigh=# \pset linestyle invalid \pset: allowed line styles are ascii, ascii-old, unicode
signature.asc
Description: Digital signature