Skip to content

Commit

Permalink
Add HEADER support to COPY text format
Browse files Browse the repository at this point in the history
The COPY CSV format supports the HEADER option to output a header
line.  This patch adds the same option to the default text format.  On
input, the HEADER option causes the first line to be skipped, same as
with CSV.

Author: Rémi Lapeyre <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/CAF1-J-0PtCWMeLtswwGV2M70U26n4g33gpe1rcKQqe6wVQDrFA@mail.gmail.com
  • Loading branch information
petere committed Jan 28, 2022
1 parent 5553cbd commit 43f33dc
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 9 deletions.
4 changes: 1 addition & 3 deletions contrib/file_fdw/expected/file_fdw.out
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,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: cannot specify HEADER in BINARY 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
Expand Down
1 change: 0 additions & 1 deletion contrib/file_fdw/sql/file_fdw.sql
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,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
Expand Down
2 changes: 1 addition & 1 deletion doc/src/sgml/ref/copy.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
Specifies that the file contains a header line with the names of each
column in the file. On output, the first line contains the column
names from the table, and on input, the first line is ignored.
This option is allowed only when using <literal>CSV</literal> format.
This option is not allowed when using <literal>binary</literal> format.
</para>
</listitem>
</varlistentry>
Expand Down
4 changes: 2 additions & 2 deletions src/backend/commands/copy.c
Original file line number Diff line number Diff line change
Expand Up @@ -555,10 +555,10 @@ ProcessCopyOptions(ParseState *pstate,
errmsg("COPY delimiter cannot be \"%s\"", opts_out->delim)));

/* Check header */
if (!opts_out->csv_mode && opts_out->header_line)
if (opts_out->binary && opts_out->header_line)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("COPY HEADER available only in CSV mode")));
errmsg("cannot specify HEADER in BINARY mode")));

/* Check quote */
if (!opts_out->csv_mode && opts_out->quote != NULL)
Expand Down
5 changes: 4 additions & 1 deletion src/backend/commands/copyto.c
Original file line number Diff line number Diff line change
Expand Up @@ -863,8 +863,11 @@ DoCopyTo(CopyToState cstate)

colname = NameStr(TupleDescAttr(tupDesc, attnum - 1)->attname);

CopyAttributeOutCSV(cstate, colname, false,
if (cstate->opts.csv_mode)
CopyAttributeOutCSV(cstate, colname, false,
list_length(cstate->attnumlist) == 1);
else
CopyAttributeOutText(cstate, colname);
}

CopySendEndOfRow(cstate);
Expand Down
2 changes: 1 addition & 1 deletion src/include/commands/copy.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ typedef struct CopyFormatOptions
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; /* 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 */
Expand Down
8 changes: 8 additions & 0 deletions src/test/regress/expected/copy.out
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,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,
"colname with tab: " text);
copy copytest4 from stdin (header);
copy copytest4 to stdout (header);
c1 colname with tab: \t
1 a
2 b
-- test copy from with a partitioned table
create table parted_copytest (
a int,
Expand Down
12 changes: 12 additions & 0 deletions src/test/regress/sql/copy.sql
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,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,
"colname with tab: " 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,
Expand Down

0 comments on commit 43f33dc

Please sign in to comment.