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