psql-csv-backslash-dot-fix-v2.txt

text/plain

Filename: psql-csv-backslash-dot-fix-v2.txt
Type: text/plain
Part: 0
Message: Re: csv format for psql
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index 3b07280..d9c701f 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
@@ -1825,16 +1841,28 @@ print_csv_vertical(const printTableContent *cont, FILE *fout)
 		if (cancel_pressed)
 			return;
 
-		/* print name of column */
-		csv_print_field(cont->headers[i % cont->ncolumns], fout,
-						cont->opt->fieldSepCsv);
-
-		/* print field separator */
-		fputs(cont->opt->fieldSepCsv, fout);
+		/*
+		 * A \. alone on a line must be quoted to be compatible with COPY CSV,
+		 * for which \. is an end-of-data marker.
+		 */
+		if (strcmp(cont->headers[i % cont->ncolumns], "\\") == 0
+			&& strcmp(cont->opt->fieldSepCsv, ".") == 0
+			&& **ptr == '\0')
+		{
+			csv_escaped_print("\\.", fout);
+		}
+		else
+		{
+			/* print name of column */
+			csv_print_field(cont->headers[i % cont->ncolumns], fout,
+							cont->opt->fieldSepCsv);
 
-		/* print field value */
-		csv_print_field(*ptr, fout, cont->opt->fieldSepCsv);
+			/* print field separator */
+			fputs(cont->opt->fieldSepCsv, fout);
 
+			/* print field value */
+			csv_print_field(*ptr, fout, cont->opt->fieldSepCsv);
+		}
 		fputc('\n', fout);
 	}
 }