diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index a33e460bca..1f29615f83 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -2090,7 +2090,7 @@ lo_import 152801
Sets the output format to one of unaligned,
aligned, wrapped,
- html,
+ html, asciidoc,
latex (uses tabular),
latex-longtable, or
troff-ms.
@@ -2119,7 +2119,7 @@ lo_import 152801
- The html>, latex>,
+ The html>, asciidoc>, latex>,
latex-longtable, and troff-ms>
formats put out tables that are intended to
be included in documents using the respective mark-up
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index e64c033bf8..916f1c6301 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -2249,6 +2249,9 @@ _align2string(enum printFormat in)
case PRINT_HTML:
return "html";
break;
+ case PRINT_ASCIIDOC:
+ return "asciidoc";
+ break;
case PRINT_LATEX:
return "latex";
break;
@@ -2325,6 +2328,8 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
popt->topt.format = PRINT_WRAPPED;
else if (pg_strncasecmp("html", value, vallen) == 0)
popt->topt.format = PRINT_HTML;
+ else if (pg_strncasecmp("asciidoc", value, vallen) == 0)
+ popt->topt.format = PRINT_ASCIIDOC;
else if (pg_strncasecmp("latex", value, vallen) == 0)
popt->topt.format = PRINT_LATEX;
else if (pg_strncasecmp("latex-longtable", value, vallen) == 0)
@@ -2333,7 +2338,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
popt->topt.format = PRINT_TROFF_MS;
else
{
- psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, latex, troff-ms\n");
+ psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, asciidoc, latex, troff-ms\n");
return false;
}
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 2da444b6d5..f58f5e52f3 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -351,7 +351,7 @@ helpVariables(unsigned short int pager)
fprintf(output, _(" expanded (or x) toggle expanded output\n"));
fprintf(output, _(" fieldsep field separator for unaligned output (default '|')\n"));
fprintf(output, _(" fieldsep_zero set field separator in unaligned mode to zero\n"));
- fprintf(output, _(" format set output format [unaligned, aligned, wrapped, html, latex, ..]\n"));
+ fprintf(output, _(" format set output format [unaligned, aligned, wrapped, html, asciidoc, ...]\n"));
fprintf(output, _(" footer enable or disable display of the table footer [on, off]\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"));
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index 9c12dbe049..e97b5635c0 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -1878,6 +1878,227 @@ print_html_vertical(const printTableContent *cont, FILE *fout)
}
+/*************************/
+/* ASCIIDOC */
+/*************************/
+
+static void
+asciidoc_escaped_print(const char *in, FILE *fout)
+{
+ const char *p;
+ for (p = in; *p; p++)
+ {
+ switch(*p)
+ {
+ case '|':
+ fputs("\\|", fout);
+ break;
+ default:
+ fputc(*p, fout);
+ }
+ }
+}
+
+static void
+print_asciidoc_text(const printTableContent *cont, FILE *fout)
+{
+ bool opt_tuples_only = cont->opt->tuples_only;
+ unsigned short opt_border = cont->opt->border;
+ unsigned int i;
+ const char *const * ptr;
+
+ if (cancel_pressed)
+ return;
+
+ if (cont->opt->start_table)
+ {
+ /* print table in new paragraph - enforce preliminary new line */
+ fputs("\n", fout);
+
+ /* print title */
+ if (!opt_tuples_only && cont->title)
+ {
+ fputs(".", fout);
+ fputs(cont->title, fout);
+ fputs("\n", fout);
+ }
+
+ /* print table [] header definition */
+ fprintf(fout, "[%scols=\"", !opt_tuples_only ? "options=\"header\"," : "");
+ for(i = 0; i < cont->ncolumns; i++)
+ {
+ if (i != 0)
+ fputs(",", fout);
+ fprintf(fout, "%s", cont->aligns[(i) % cont->ncolumns] == 'r' ? ">l" : "headers; *ptr; ptr++)
+ {
+ if (ptr != cont->headers)
+ fputs(" ", fout);
+ fputs("^l|", fout);
+ asciidoc_escaped_print(*ptr, fout);
+ }
+ fputs("\n", fout);
+ }
+ }
+
+ /* print cells */
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
+ {
+ if (i % cont->ncolumns == 0)
+ {
+ if (cancel_pressed)
+ break;
+ }
+
+ if (i % cont->ncolumns != 0)
+ fputs(" ", fout);
+ fputs("|", fout);
+
+ /* protect against needless spaces */
+ if ((*ptr)[strspn(*ptr, " \t")] == '\0')
+ {
+ if ((i + 1) % cont->ncolumns != 0)
+ fputs(" ", fout);
+ }
+ else
+ asciidoc_escaped_print(*ptr, fout);
+
+ if ((i + 1) % cont->ncolumns == 0)
+ fputs("\n", fout);
+ }
+
+ fputs("|====\n", fout);
+
+ if (cont->opt->stop_table)
+ {
+ printTableFooter *footers = footers_with_default(cont);
+
+ /* print footers */
+ if (!opt_tuples_only && footers != NULL && !cancel_pressed)
+ {
+ printTableFooter *f;
+
+ fputs("\n....\n", fout);
+ for (f = footers; f; f = f->next)
+ {
+ fputs(f->data, fout);
+ fputs("\n", fout);
+ }
+ fputs("....\n", fout);
+ }
+ }
+}
+
+static void
+print_asciidoc_vertical(const printTableContent *cont, FILE *fout)
+{
+ bool opt_tuples_only = cont->opt->tuples_only;
+ unsigned short opt_border = cont->opt->border;
+ unsigned long record = cont->opt->prior_records + 1;
+ unsigned int i;
+ const char *const * ptr;
+
+ if (cancel_pressed)
+ return;
+
+ if (cont->opt->start_table)
+ {
+ /* print table in new paragraph - enforce preliminary new line */
+ fputs("\n", fout);
+
+ /* print title */
+ if (!opt_tuples_only && cont->title)
+ {
+ fputs(".", fout);
+ fputs(cont->title, fout);
+ fputs("\n", fout);
+ }
+
+ /* print table [] header definition */
+ fputs("[cols=\"h,l\"", fout);
+ switch (opt_border)
+ {
+ case 0:
+ fputs(",frame=\"none\",grid=\"none\"", fout);
+ break;
+ case 1:
+ fputs(",frame=\"none\"", fout);
+ break;
+ case 2:
+ fputs(",frame=\"all\",grid=\"all\"", fout);
+ break;
+ }
+ fputs("]\n", fout);
+ fputs("|====\n", fout);
+ }
+
+ /* print records */
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
+ {
+ if (i % cont->ncolumns == 0)
+ {
+ if (cancel_pressed)
+ break;
+ if (!opt_tuples_only)
+ fprintf(fout,
+ "2+^|Record %lu\n",
+ record++);
+ else
+ fputs("2+|\n", fout);
+ }
+
+ fputs("headers[i % cont->ncolumns], fout);
+
+ fprintf(fout, " %s|", cont->aligns[i % cont->ncolumns] == 'r' ? ">l" : "opt->stop_table)
+ {
+ /* print footers */
+ if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
+ {
+ printTableFooter *f;
+
+ fputs("\n....\n", fout);
+ for (f = cont->footers; f; f = f->next)
+ {
+ fputs(f->data, fout);
+ fputs("\n", fout);
+ }
+ fputs("....\n", fout);
+ }
+ }
+}
+
/*************************/
/* LaTeX */
/*************************/
@@ -2872,6 +3093,12 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
else
print_html_text(cont, fout);
break;
+ case PRINT_ASCIIDOC:
+ if (cont->opt->expanded == 1)
+ print_asciidoc_vertical(cont, fout);
+ else
+ print_asciidoc_text(cont, fout);
+ break;
case PRINT_LATEX:
if (cont->opt->expanded == 1)
print_latex_vertical(cont, fout);
diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h
index 66cdaf32ae..322db4d6ef 100644
--- a/src/bin/psql/print.h
+++ b/src/bin/psql/print.h
@@ -18,6 +18,7 @@ enum printFormat
PRINT_ALIGNED,
PRINT_WRAPPED,
PRINT_HTML,
+ PRINT_ASCIIDOC,
PRINT_LATEX,
PRINT_LATEX_LONGTABLE,
PRINT_TROFF_MS
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index e39a07caf1..dfcb66ba6d 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3790,8 +3790,8 @@ psql_completion(const char *text, int start, int end)
if (strcmp(prev_wd, "format") == 0)
{
static const char *const my_list[] =
- {"unaligned", "aligned", "wrapped", "html", "latex",
- "troff-ms", NULL};
+ {"unaligned", "aligned", "wrapped", "html", "asciidoc",
+ "latex", "latex-longtable", "troff-ms", NULL};
COMPLETE_WITH_LIST_CS(my_list);
}
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index a2a261595a..6ff9be1167 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -2126,3 +2126,209 @@ execute q;
+------------------+-------------------+
deallocate q;
+prepare q as select ' | = | lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (&' as " | -- | 012345678 9abc def!*@#&!@(*&*~~_+-=\ \", '11' as "0123456789", 11 as int from generate_series(1,10) as n;
+\pset format asciidoc
+\pset expanded off
+\pset border 0
+execute q;
+
+[options="header",cols="l",frame="none",grid="none"]
+|====
+^l| \| -- \| 012345678 9abc def!*@#&!@(*&*~~_+-=\ \ ^l|0123456789 ^l|int
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+|====
+
+....
+(10 rows)
+....
+\pset border 1
+execute q;
+
+[options="header",cols="l",frame="none"]
+|====
+^l| \| -- \| 012345678 9abc def!*@#&!@(*&*~~_+-=\ \ ^l|0123456789 ^l|int
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+|====
+
+....
+(10 rows)
+....
+\pset border 2
+execute q;
+
+[options="header",cols="l",frame="all",grid="all"]
+|====
+^l| \| -- \| 012345678 9abc def!*@#&!@(*&*~~_+-=\ \ ^l|0123456789 ^l|int
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+| \| = \| lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (& |11 |11
+|====
+
+....
+(10 rows)
+....
+\pset expanded on
+\pset border 0
+execute q;
+
+[cols="h,l",frame="none",grid="none"]
+|====
+2+^|Record 1
+l|11
+2+^|Record 2
+l|11
+2+^|Record 3
+l|11
+2+^|Record 4
+l|11
+2+^|Record 5
+l|11
+2+^|Record 6
+l|11
+2+^|Record 7
+l|11
+2+^|Record 8
+l|11
+2+^|Record 9
+l|11
+2+^|Record 10
+l|11
+|====
+\pset border 1
+execute q;
+
+[cols="h,l",frame="none"]
+|====
+2+^|Record 1
+l|11
+2+^|Record 2
+l|11
+2+^|Record 3
+l|11
+2+^|Record 4
+l|11
+2+^|Record 5
+l|11
+2+^|Record 6
+l|11
+2+^|Record 7
+l|11
+2+^|Record 8
+l|11
+2+^|Record 9
+l|11
+2+^|Record 10
+l|11
+|====
+\pset border 2
+execute q;
+
+[cols="h,l",frame="all",grid="all"]
+|====
+2+^|Record 1
+l|11
+2+^|Record 2
+l|11
+2+^|Record 3
+l|11
+2+^|Record 4
+l|11
+2+^|Record 5
+l|11
+2+^|Record 6
+l|11
+2+^|Record 7
+l|11
+2+^|Record 8
+l|11
+2+^|Record 9
+l|11
+2+^|Record 10
+l|11
+|====
+deallocate q;
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index 5ccc68f4ed..fa1df8b2d7 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -276,3 +276,28 @@ execute q;
execute q;
deallocate q;
+
+prepare q as select ' | = | lkjsafi\\/ /oeu rio)(!@&*#)*(!&@*) \ (&' as " | -- | 012345678 9abc def!*@#&!@(*&*~~_+-=\ \", '11' as "0123456789", 11 as int from generate_series(1,10) as n;
+
+\pset format asciidoc
+\pset expanded off
+\pset border 0
+execute q;
+
+\pset border 1
+execute q;
+
+\pset border 2
+execute q;
+
+\pset expanded on
+\pset border 0
+execute q;
+
+\pset border 1
+execute q;
+
+\pset border 2
+execute q;
+
+deallocate q;