From 99fa3b6d623105c5eea6fe14b2dc7287663fe8fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lapeyre?= Date: Fri, 17 Jul 2020 01:50:06 +0200 Subject: [PATCH v3 1/2] Add header support to "COPY TO" text format MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.27.0" This is a multi-part message in MIME format. --------------2.27.0 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit CSV format supports the HEADER option to output a header in the output, it is convenient when other programs need to consume the output. This patch adds the same option to the default text format. Discussion: https://www.postgresql.org/message-id/flat/CAF1-J-0PtCWMeLtswwGV2M70U26n4g33gpe1rcKQqe6wVQDrFA@mail.gmail.com --- contrib/file_fdw/input/file_fdw.source | 1 - contrib/file_fdw/output/file_fdw.source | 4 +--- doc/src/sgml/ref/copy.sgml | 3 ++- src/backend/commands/copy.c | 11 +++++++---- src/test/regress/input/copy.source | 12 ++++++++++++ src/test/regress/output/copy.source | 8 ++++++++ 6 files changed, 30 insertions(+), 9 deletions(-) --------------2.27.0 Content-Type: text/x-patch; name="v3-0001-Add-header-support-to-COPY-TO-text-format.patch" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="v3-0001-Add-header-support-to-COPY-TO-text-format.patch" diff --git a/contrib/file_fdw/input/file_fdw.source b/contrib/file_fdw/input/file_fdw.source index 45b728eeb3..83edb71077 100644 --- a/contrib/file_fdw/input/file_fdw.source +++ b/contrib/file_fdw/input/file_fdw.source @@ -37,7 +37,6 @@ CREATE USER MAPPING FOR regress_no_priv_user SERVER file_server; -- validator tests CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'xml'); -- ERROR -CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'text', header 'true'); -- ERROR CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'text', quote ':'); -- ERROR CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'text', escape ':'); -- ERROR CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'binary', header 'true'); -- ERROR diff --git a/contrib/file_fdw/output/file_fdw.source b/contrib/file_fdw/output/file_fdw.source index 52b4d5f1df..547b81fd16 100644 --- a/contrib/file_fdw/output/file_fdw.source +++ b/contrib/file_fdw/output/file_fdw.source @@ -33,14 +33,12 @@ CREATE USER MAPPING FOR regress_no_priv_user SERVER file_server; -- validator tests CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'xml'); -- ERROR ERROR: COPY format "xml" not recognized -CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'text', header 'true'); -- ERROR -ERROR: COPY HEADER available only in CSV mode CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'text', quote ':'); -- ERROR ERROR: COPY quote available only in CSV mode CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'text', escape ':'); -- ERROR ERROR: COPY escape available only in CSV mode CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'binary', header 'true'); -- ERROR -ERROR: COPY HEADER available only in CSV mode +ERROR: COPY HEADER available only in CSV and text mode CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'binary', quote ':'); -- ERROR ERROR: COPY quote available only in CSV mode CREATE FOREIGN TABLE tbl () SERVER file_server OPTIONS (format 'binary', escape ':'); -- ERROR diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml index 18189abc6c..c628a69c57 100644 --- a/doc/src/sgml/ref/copy.sgml +++ b/doc/src/sgml/ref/copy.sgml @@ -269,7 +269,8 @@ COPY { table_name [ ( CSV format. + This option is allowed only when using CSV or + text format. diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 44da71c4cb..a21508a974 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -136,7 +136,7 @@ typedef struct CopyStateData bool binary; /* binary format? */ bool freeze; /* freeze rows on loading? */ bool csv_mode; /* Comma Separated Value format? */ - bool header_line; /* CSV header line? */ + bool header_line; /* CSV or text header line? */ char *null_print; /* NULL marker string (server encoding!) */ int null_print_len; /* length of same */ char *null_print_client; /* same converted to file encoding */ @@ -1363,10 +1363,10 @@ ProcessCopyOptions(ParseState *pstate, errmsg("COPY delimiter cannot be \"%s\"", cstate->delim))); /* Check header */ - if (!cstate->csv_mode && cstate->header_line) + if (cstate->binary && cstate->header_line) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("COPY HEADER available only in CSV mode"))); + errmsg("COPY HEADER available only in CSV and text mode"))); /* Check quote */ if (!cstate->csv_mode && cstate->quote != NULL) @@ -2099,8 +2099,11 @@ CopyTo(CopyState cstate) colname = NameStr(TupleDescAttr(tupDesc, attnum - 1)->attname); - CopyAttributeOutCSV(cstate, colname, false, + if (cstate->csv_mode) + CopyAttributeOutCSV(cstate, colname, false, list_length(cstate->attnumlist) == 1); + else + CopyAttributeOutText(cstate, colname); } CopySendEndOfRow(cstate); diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source index a1d529ad36..2368649111 100644 --- a/src/test/regress/input/copy.source +++ b/src/test/regress/input/copy.source @@ -134,6 +134,18 @@ this is just a line full of junk that would error out if parsed copy copytest3 to stdout csv header; +create temp table copytest4 ( + c1 int, + "col with tabulation: " text); + +copy copytest4 from stdin (header); +this is just a line full of junk that would error out if parsed +1 a +2 b +\. + +copy copytest4 to stdout (header); + -- test copy from with a partitioned table create table parted_copytest ( a int, diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source index 938d3551da..c1f7f99747 100644 --- a/src/test/regress/output/copy.source +++ b/src/test/regress/output/copy.source @@ -95,6 +95,14 @@ copy copytest3 to stdout csv header; c1,"col with , comma","col with "" quote" 1,a,1 2,b,2 +create temp table copytest4 ( + c1 int, + "col with tabulation: " text); +copy copytest4 from stdin (header); +copy copytest4 to stdout (header); +c1 col with tabulation: \t +1 a +2 b -- test copy from with a partitioned table create table parted_copytest ( a int, --------------2.27.0--