Tom Lane wrote:
> OK, reasonable arguments were made why not to allow multi-character
> separators. Should we then match the server and insist on a single-byte
> separator? It's a bit inconsistent if psql can be made to emit "csv"
> files that COPY can't read, especially when it's otherwise a subset
> of what COPY allows.
I seem to be the only one advocating to accept an Unicode
character here, and I won't insist on it.
There's still a minor annoyance to solve if we want to claim full
compatibility with COPY CSV: backslash followed by dot must be
quoted to avoid being interpreted as an end of data indicator.
A proposed fix is attached. print_csv_vertical() is left unchanged
because it's not possible currently to end up with \. alone
on a line with the expanded display: we'd need to allow
first for an empty field separator, I believe.
Best regards,
--
Daniel Vérité
PostgreSQL-powered mailer: http://www.manitou-mail.org
Twitter: @DanielVerite
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index 3b07280..d31b6af 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -1793,7 +1793,16 @@ print_csv_text(const printTableContent *cont, FILE *fout)
if (cont->opt->start_table && !cont->opt->tuples_only)
{
/* print headers */
- for (ptr = cont->headers; *ptr; ptr++)
+
+ /*
+ * A \. alone on a line must be quoted to be compatible with
COPY CSV,
+ * for which \. is an end-of-data marker.
+ */
+ if (cont->ncolumns == 1 && strcmp(*cont->headers, "\\.") == 0)
+ {
+ csv_escaped_print(*cont->headers, fout);
+ }
+ else for (ptr = cont->headers; *ptr; ptr++)
{
if (ptr != cont->headers)
fputs(cont->opt->fieldSepCsv, fout);
@@ -1805,7 +1814,14 @@ print_csv_text(const printTableContent *cont, FILE *fout)
/* print cells */
for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
{
- csv_print_field(*ptr, fout, cont->opt->fieldSepCsv);
+ /*
+ * A \. alone on a line must be quoted to be compatible with
COPY CSV,
+ * for which \. is an end-of-data marker.
+ */
+ if (cont->ncolumns == 1 && strcmp(*ptr, "\\.") == 0)
+ csv_escaped_print(*ptr, fout);
+ else
+ csv_print_field(*ptr, fout, cont->opt->fieldSepCsv);
if ((i + 1) % cont->ncolumns)
fputs(cont->opt->fieldSepCsv, fout);
else