diff -ru a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml --- a/doc/src/sgml/ref/psql-ref.sgml 2017-02-06 22:45:25.000000000 +0100 +++ b/doc/src/sgml/ref/psql-ref.sgml 2017-03-06 01:35:46.000000000 +0100 @@ -2326,7 +2326,8 @@ aligned, wrapped, html, asciidoc, latex (uses tabular), - latex-longtable, or + latex-longtable, + rst, markdown, or troff-ms. Unique abbreviations are allowed. (That would mean one letter is enough.) @@ -2354,7 +2355,8 @@ The html, asciidoc, latex, - latex-longtable, and troff-ms + latex-longtable, troff-ms, + and markdown and rst formats put out tables that are intended to be included in documents using the respective mark-up language. They are not complete documents! This might not be diff -ru a/src/bin/psql/command.c b/src/bin/psql/command.c --- a/src/bin/psql/command.c 2017-02-06 22:45:25.000000000 +0100 +++ b/src/bin/psql/command.c 2017-03-06 03:27:07.000000000 +0100 @@ -2494,6 +2494,12 @@ case PRINT_TROFF_MS: return "troff-ms"; break; + case PRINT_MARKDOWN: + return "markdown"; + break; + case PRINT_RST: + return "rst"; + break; } return "unknown"; } @@ -2565,9 +2571,13 @@ popt->topt.format = PRINT_LATEX_LONGTABLE; else if (pg_strncasecmp("troff-ms", value, vallen) == 0) popt->topt.format = PRINT_TROFF_MS; + else if (pg_strncasecmp("markdown", value, vallen) == 0) /*markdown*/ + popt->topt.format = PRINT_MARKDOWN; + else if (pg_strncasecmp("rst", value, vallen) == 0) /*rst*/ + popt->topt.format = PRINT_RST; else { - psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, asciidoc, latex, latex-longtable, troff-ms\n"); + psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, asciidoc, latex, latex-longtable, troff-ms, markdown, rst\n"); return false; } diff -ru a/src/bin/psql/help.c b/src/bin/psql/help.c --- a/src/bin/psql/help.c 2017-02-06 22:45:25.000000000 +0100 +++ b/src/bin/psql/help.c 2017-03-06 01:46:41.000000000 +0100 @@ -373,7 +373,7 @@ fprintf(output, _(" fieldsep field separator for unaligned output (default \"%s\")\n"), DEFAULT_FIELD_SEP); fprintf(output, _(" fieldsep_zero set field separator for unaligned output to zero byte\n")); fprintf(output, _(" footer enable or disable display of the table footer [on, off]\n")); - fprintf(output, _(" format set output format [unaligned, aligned, wrapped, html, asciidoc, ...]\n")); + fprintf(output, _(" format set output format [unaligned, aligned, wrapped, html, asciidoc, rst, markdown ...]\n")); fprintf(output, _(" linestyle set the border line drawing style [ascii, old-ascii, unicode]\n")); fprintf(output, _(" null set the string to be printed in place of a null value\n")); fprintf(output, _(" numericlocale enable or disable display of a locale-specific character to separate\n" diff -ru a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c --- a/src/bin/psql/tab-complete.c 2017-02-06 22:45:25.000000000 +0100 +++ b/src/bin/psql/tab-complete.c 2017-03-06 00:57:11.000000000 +0100 @@ -3070,7 +3070,7 @@ { static const char *const my_list[] = {"unaligned", "aligned", "wrapped", "html", "asciidoc", - "latex", "latex-longtable", "troff-ms", NULL}; + "latex", "latex-longtable", "troff-ms", "markdown", "rst", NULL}; COMPLETE_WITH_LIST_CS(my_list); } diff -ru a/src/fe_utils/print.c b/src/fe_utils/print.c --- a/src/fe_utils/print.c 2017-02-06 22:45:25.000000000 +0100 +++ b/src/fe_utils/print.c 2017-03-18 22:15:18.000000000 +0100 @@ -57,6 +57,48 @@ static printTableFooter default_footer_cell = {default_footer, NULL}; /* Line style control structures */ +const printTextFormat pg_markdown = +{ + "markdown", + { + {"", "", "", ""}, + {"-", "|", "|", "|"}, + {"", "", "", ""}, + {"", "|", "|", "|"} + }, + "|", + "|", + "|", + " ", + "+", + " ", + " ", + ".", + ".", + true +}; + +const printTextFormat pg_rst = +{ + "rst", + { + {"-", "+", "+", "+"}, + {"=", "+", "+", "+"}, + {"-", "+", "+", "+"}, + {" ", "|", "|", "|"} + }, + "|", + "|", + "|", + " ", + "+", + " ", + " ", + ".", + ".", + true +}; + const printTextFormat pg_asciiformat = { "ascii", @@ -206,6 +248,7 @@ static void print_aligned_vertical(const printTableContent *cont, FILE *fout, bool is_pager); +static void skip_leading_spaces_print(const char *in, FILE *fout); /* Count number of digits in integral part of number */ static int @@ -575,6 +618,40 @@ fputc('\n', fout); } +/* + * skip leading spaces + */ +static void +skip_leading_spaces_print(const char *in, FILE *fout) +{ + const char *p; + bool leading_space = true; + unsigned int spac; /**leading spaces*/ + spac = 0; + + for (p = in; *p; p++) + { + if (*p != ' ' && *p != '\n') + { + leading_space = false; + fputc(*p, fout); + } + else if (*p == '\n') + { + fputc(*p, fout); + leading_space = true; + } + else if (leading_space) + spac++; /*fputs(".", fout);*/ + else + fputc(*p, fout); + + } + if (spac != 0) + fprintf(fout, "%*s", spac, " "); + +} + /* * Print pretty boxes around cells. @@ -623,6 +700,12 @@ if (opt_border > 2) opt_border = 2; + if (format == &pg_markdown) + opt_border = 2; + + if (format == &pg_rst) + opt_border = 2; + if (cont->ncolumns > 0) { col_count = cont->ncolumns; @@ -1053,9 +1136,13 @@ else /* Left aligned cell */ { /* spaces second */ - fputnbytes(fout, - (char *) (this_line->ptr + bytes_output[j]), - bytes_to_output); + if (format != &pg_rst) + fputnbytes(fout, + (char *) (this_line->ptr + bytes_output[j]), + bytes_to_output); + + else + skip_leading_spaces_print((char *) (this_line->ptr + bytes_output[j]), fout); } bytes_output[j] += bytes_to_output; @@ -1124,13 +1211,20 @@ fputc('\n', fout); } while (more_lines); + + /* add line after every record */ + if (opt_border == 2 && format == &pg_rst) + _print_horizontal_line(col_count, width_wrap, opt_border, + PRINT_RULE_BOTTOM, format, fout); } if (cont->opt->stop_table) { printTableFooter *footers = footers_with_default(cont); - if (opt_border == 2 && !cancel_pressed) + /* dont add line after last row, because line is added after every row + **/ + if ((opt_border == 2 && format != &pg_rst) && !cancel_pressed) _print_horizontal_line(col_count, width_wrap, opt_border, PRINT_RULE_BOTTOM, format, fout); @@ -1138,6 +1232,12 @@ if (footers && !opt_tuples_only && !cancel_pressed) { printTableFooter *f; + /*add newline after table because rst needs empty line after table + */ + if (format == &pg_rst || format == &pg_markdown) + { + fprintf(fout, "\n"); + } for (f = footers; f; f = f->next) fprintf(fout, "%s\n", f->data); @@ -1193,6 +1293,8 @@ { if (opt_border == 0) reclen = fprintf(fout, "* Record %lu", record); + else if (format == &pg_rst) + reclen = fprintf(fout, "**RECORD %lu**", record); else reclen = fprintf(fout, "[ RECORD %lu ]", record); } @@ -1258,6 +1360,10 @@ if (opt_border > 2) opt_border = 2; + if (cont->opt->format == PRINT_RST) /*rst works only with border 2*/ + opt_border = 2; + + if (cont->cells[0] == NULL && cont->opt->start_table && cont->opt->stop_table) { @@ -1307,6 +1413,9 @@ hformatsize = fs; } + if (format == &pg_rst) + hwidth = hwidth + 4; /*this broke print RECORD without pipe */ + /* find longest data cell */ for (i = 0, ptr = cont->cells; *ptr; ptr++, i++) { @@ -1504,7 +1613,7 @@ if (cancel_pressed) break; - if (i == 0) + if (i == 0 || cont->opt->format == PRINT_RST) pos = PRINT_RULE_TOP; else pos = PRINT_RULE_MIDDLE; @@ -1519,9 +1628,19 @@ (format == &pg_asciiformat_old)) lhwidth++; /* for newline indicators */ - if (!opt_tuples_only) + if (!opt_tuples_only && cont->opt->format != PRINT_RST) print_aligned_vertical_line(format, opt_border, record++, lhwidth, dwidth, pos, fout); + else if (!opt_tuples_only && format == &pg_rst) + { + if (i ==0) + print_aligned_vertical_line(format, opt_border, 0, lhwidth, + dwidth, pos, fout); + print_aligned_vertical_line(format, opt_border, record++, + 0, lhwidth + dwidth, PRINT_RULE_DATA, fout); /* because need of only one column*/ + print_aligned_vertical_line(format, opt_border, 0, lhwidth, + dwidth, 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); @@ -1565,9 +1684,18 @@ /* * Header text */ - strlen_max_width(hlineptr[hline].ptr, &target_width, - encoding); - fprintf(fout, "%-s", hlineptr[hline].ptr); + + if (format != &pg_rst) + strlen_max_width(hlineptr[hline].ptr, &target_width, + encoding); + else + strlen_max_width(hlineptr[hline].ptr, &target_width - 4, + encoding); + + if (format != &pg_rst) + fprintf(fout, "%-s", hlineptr[hline].ptr); + else + fprintf(fout, "**%-s**", hlineptr[hline].ptr); /*header bold*/ /* * Spacer @@ -1641,8 +1769,12 @@ */ bytes_to_output = strlen_max_width(dlineptr[dline].ptr + offset, &target_width, encoding); - fputnbytes(fout, (char *) (dlineptr[dline].ptr + offset), - bytes_to_output); + + if (format != &pg_rst) + fputnbytes(fout, (char *) (dlineptr[dline].ptr + offset), + bytes_to_output); + else + skip_leading_spaces_print((char *) (dlineptr[dline].ptr + offset), fout); chars_to_output -= target_width; offset += bytes_to_output; @@ -1704,12 +1836,18 @@ else fprintf(fout, "%*s %s\n", dwidth, "", dformat->rightvrule); } - } + /*if (opt_border == 2 && format == &pg_rst) + print_aligned_vertical_line(format, opt_border, 0, hwidth, dwidth, + PRINT_RULE_BOTTOM, fout); */ + } + if (opt_border == 2 && format == &pg_rst) + print_aligned_vertical_line(format, opt_border, 0, hwidth, dwidth, + PRINT_RULE_BOTTOM, fout); } if (cont->opt->stop_table) { - if (opt_border == 2 && !cancel_pressed) + if (opt_border == 2 && !cancel_pressed && format != &pg_rst) print_aligned_vertical_line(format, opt_border, 0, hwidth, dwidth, PRINT_RULE_BOTTOM, fout); @@ -3263,6 +3401,18 @@ else print_troff_ms_text(cont, fout); break; + + case PRINT_RST: + if (cont->opt->expanded == 1) + print_aligned_vertical(cont, fout, false); + else + print_aligned_text(cont, fout, false); + break; + + case PRINT_MARKDOWN: + print_aligned_text(cont, fout, false); + break; + default: fprintf(stderr, _("invalid output format (internal error): %d"), cont->opt->format); @@ -3417,8 +3567,12 @@ * printTableOpt struct can be initialized to zeroes to get default * behavior. */ - if (opt->line_style != NULL) - return opt->line_style; + if (opt->format == PRINT_RST) + return &pg_rst; + else if (opt->format == PRINT_MARKDOWN) + return &pg_markdown; + else if (opt->line_style != NULL) + return opt->line_style; else return &pg_asciiformat; } diff -ru a/src/include/fe_utils/print.h b/src/include/fe_utils/print.h --- a/src/include/fe_utils/print.h 2017-02-06 22:45:25.000000000 +0100 +++ b/src/include/fe_utils/print.h 2017-03-05 18:28:04.000000000 +0100 @@ -33,7 +33,9 @@ PRINT_ASCIIDOC, PRINT_LATEX, PRINT_LATEX_LONGTABLE, - PRINT_TROFF_MS + PRINT_TROFF_MS, + PRINT_MARKDOWN, + PRINT_RST /* add your favourite output format here ... */ }; @@ -176,6 +178,8 @@ extern volatile bool cancel_pressed; extern const printTextFormat pg_asciiformat; +extern const printTextFormat pg_markdown; /*linestyle markdown*/ +extern const printTextFormat pg_rst; /*linestyle rst*/ extern const printTextFormat pg_asciiformat_old; extern printTextFormat pg_utf8format; /* ideally would be const, but... */ diff -ru a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out --- a/src/test/regress/expected/psql.out 2017-02-06 22:45:25.000000000 +0100 +++ b/src/test/regress/expected/psql.out 2017-03-18 22:24:40.000000000 +0100 @@ -2714,3 +2714,102 @@ CONTEXT: PL/pgSQL function inline_code_block line 3 at RAISE ERROR: bar CONTEXT: PL/pgSQL function inline_code_block line 4 at RAISE +prepare q AS VALUES(E'Elephant, kangaroo,\nsquirrel, gorilla', 121, +(279./278.)::text, 0.1111, repeat('Hello ', 10)) + , (E'goat, rhinoceros,\nmonkey, ape', 11121, (1279./1278.)::text, 5.1111, + repeat('xxxxxx ', 10)) + , (E'donkey, cow, horse, tit,\neagle, whale,\naligator, + pelican,\ngrasshoper\npig\n\tbat', 14351, (12345./245.)::text, 345.11, + repeat('yyyyyy ', 10)); +\pset format rst +execute q; ++--------------------------+---------+---------------------+---------+------------------------------------------------------------------------+ +| column1 | column2 | column3 | column4 | column5 | ++==========================+=========+=====================+=========+========================================================================+ +| Elephant, kangaroo, | 121 | 1.0035971223021583 | 0.1111 | Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello | +| squirrel, gorilla | | | | | ++--------------------------+---------+---------------------+---------+------------------------------------------------------------------------+ +| goat, rhinoceros, | 11121 | 1.0007824726134585 | 5.1111 | xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx | +| monkey, ape | | | | | ++--------------------------+---------+---------------------+---------+------------------------------------------------------------------------+ +| donkey, cow, horse, tit, | 14351 | 50.3877551020408163 | 345.11 | yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy | +| eagle, whale, | | | | | +| aligator, | | | | | +| pelican, | | | | | +| grasshoper | | | | | +| pig | | | | | +| bat | | | | | ++--------------------------+---------+---------------------+---------+------------------------------------------------------------------------+ + +(3 rows) + +\pset format markdown +execute q; + +| column1 | column2 | column3 | column4 | column5 | +|--------------------------|---------|---------------------|---------|------------------------------------------------------------------------| +| Elephant, kangaroo, | 121 | 1.0035971223021583 | 0.1111 | Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello | +| squirrel, gorilla | | | | | +| goat, rhinoceros, | 11121 | 1.0007824726134585 | 5.1111 | xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx | +| monkey, ape | | | | | +| donkey, cow, horse, tit, | 14351 | 50.3877551020408163 | 345.11 | yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy | +| eagle, whale, | | | | | +| aligator, | | | | | +| pelican, | | | | | +| grasshoper | | | | | +| pig | | | | | +| bat | | | | | + + +(3 rows) + +\pset format rst +\x +execute q; ++-------------+------------------------------------------------------------------------+ +| **RECORD 1** | ++-------------+------------------------------------------------------------------------+ +| **column1** | Elephant, kangaroo, | +| | squirrel, gorilla | ++-------------+------------------------------------------------------------------------+ +| **column2** | 121 | ++-------------+------------------------------------------------------------------------+ +| **column3** | 1.0035971223021583 | ++-------------+------------------------------------------------------------------------+ +| **column4** | 0.1111 | ++-------------+------------------------------------------------------------------------+ +| **column5** | Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello | ++-------------+------------------------------------------------------------------------+ +| **RECORD 2** | ++-------------+------------------------------------------------------------------------+ +| **column1** | goat, rhinoceros, | +| | monkey, ape | ++-------------+------------------------------------------------------------------------+ +| **column2** | 11121 | ++-------------+------------------------------------------------------------------------+ +| **column3** | 1.0007824726134585 | ++-------------+------------------------------------------------------------------------+ +| **column4** | 5.1111 | ++-------------+------------------------------------------------------------------------+ +| **column5** | xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx | ++-------------+------------------------------------------------------------------------+ +| **RECORD 3** | ++-------------+------------------------------------------------------------------------+ +| **column1** | donkey, cow, horse, tit, | +| | eagle, whale, | +| | aligator, | +| | pelican, | +| | grasshoper | +| | pig | +| | bat | ++-------------+------------------------------------------------------------------------+ +| **column2** | 14351 | ++-------------+------------------------------------------------------------------------+ +| **column3** | 50.3877551020408163 | ++-------------+------------------------------------------------------------------------+ +| **column4** | 345.11 | ++-------------+------------------------------------------------------------------------+ +| **column5** | yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy yyyyyy | ++-------------+------------------------------------------------------------------------+ + +deallocate q; diff -ru a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql --- a/src/test/regress/sql/psql.sql 2017-02-06 22:45:25.000000000 +0100 +++ b/src/test/regress/sql/psql.sql 2017-03-18 22:21:54.000000000 +0100 @@ -379,3 +379,20 @@ raise notice 'foo'; raise exception 'bar'; end $$; + +prepare q AS VALUES(E'Elephant, kangaroo,\nsquirrel, gorilla', 121, +(279./278.)::text, 0.1111, repeat('Hello ', 10)) + , (E'goat, rhinoceros,\nmonkey, ape', 11121, (1279./1278.)::text, 5.1111, + repeat('xxxxxx ', 10)) + , (E'donkey, cow, horse, tit,\neagle, whale,\naligator, + pelican,\ngrasshoper\npig\n\tbat', 14351, (12345./245.)::text, 345.11, + repeat('yyyyyy ', 10)); + +\pset format rst +execute q; +\pset format markdown +execute q; +\pset format rst +\x +execute q; +deallocate q;