Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9955eb8

Browse files
jianhe-funCommitfest Bot
authored and
Commitfest Bot
committed
Introduce json format for COPY TO
json format is only allowed in COPY TO operation. also cannot be used with {header, default, null, delimiter} options and many other options. fully tested on src/test/regress/sql/copy.sql. CopyFormat enum part was coied from Joel Jacobson <joel@compiler.org> refactored by Jian He to fix some miscellaneous issue. refactored by Junwang Zhao to adapt the newly introduced CopyToRoutine struct(2e4127b). Author: Joe Conway <mail@joeconway.com> Reviewed-by: "Andrey M. Borodin" <x4mmm@yandex-team.ru>, Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>, Reviewed-by: Daniel Verite <daniel@manitou-mail.org>, Reviewed-by: Andrew Dunstan <andrew@dunslane.net>, Reviewed-by: Davin Shearer <davin@apache.org>, Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>, Reviewed-by: Alvaro Herrera <alvherre@alvh.no-ip.org> discussion: https://postgr.es/m/CALvfUkBxTYy5uWPFVwpk_7ii2zgT07t3d-yR_cy4sfrrLU%3Dkcg%40mail.gmail.com discussion: https://postgr.es/m/6a04628d-0d53-41d9-9e35-5a8dc302c34c@joeconway.com
1 parent c3eda50 commit 9955eb8

File tree

13 files changed

+286
-52
lines changed

13 files changed

+286
-52
lines changed

doc/src/sgml/ref/copy.sgml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,15 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
219219
Selects the data format to be read or written:
220220
<literal>text</literal>,
221221
<literal>csv</literal> (Comma Separated Values),
222+
<literal>json</literal> (JavaScript Object Notation),
222223
or <literal>binary</literal>.
223224
The default is <literal>text</literal>.
224225
See <xref linkend="sql-copy-file-formats"/> below for details.
225226
</para>
227+
<para>
228+
The <literal>json</literal> option is allowed only in
229+
<command>COPY TO</command>.
230+
</para>
226231
</listitem>
227232
</varlistentry>
228233

@@ -257,7 +262,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
257262
(line) of the file. The default is a tab character in text format,
258263
a comma in <literal>CSV</literal> format.
259264
This must be a single one-byte character.
260-
This option is not allowed when using <literal>binary</literal> format.
265+
This option is not allowed when using <literal>binary</literal> or <literal>json</literal> format.
261266
</para>
262267
</listitem>
263268
</varlistentry>
@@ -271,7 +276,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
271276
string in <literal>CSV</literal> format. You might prefer an
272277
empty string even in text format for cases where you don't want to
273278
distinguish nulls from empty strings.
274-
This option is not allowed when using <literal>binary</literal> format.
279+
This option is not allowed when using <literal>binary</literal> or <literal>json</literal> format.
275280
</para>
276281

277282
<note>
@@ -294,7 +299,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
294299
is found in the input file, the default value of the corresponding column
295300
will be used.
296301
This option is allowed only in <command>COPY FROM</command>, and only when
297-
not using <literal>binary</literal> format.
302+
not using <literal>binary</literal> or <literal>json</literal> format.
298303
</para>
299304
</listitem>
300305
</varlistentry>
@@ -310,7 +315,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
310315
If this option is set to <literal>MATCH</literal>, the number and names
311316
of the columns in the header line must match the actual column names of
312317
the table, in order; otherwise an error is raised.
313-
This option is not allowed when using <literal>binary</literal> format.
318+
This option is not allowed when using <literal>binary</literal> or <literal>json</literal> format.
314319
The <literal>MATCH</literal> option is only valid for <command>COPY
315320
FROM</command> commands.
316321
</para>

src/backend/commands/copy.c

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -525,11 +525,13 @@ ProcessCopyOptions(ParseState *pstate,
525525
errorConflictingDefElem(defel, pstate);
526526
format_specified = true;
527527
if (strcmp(fmt, "text") == 0)
528-
/* default format */ ;
528+
opts_out->format = COPY_FORMAT_TEXT;
529529
else if (strcmp(fmt, "csv") == 0)
530-
opts_out->csv_mode = true;
530+
opts_out->format = COPY_FORMAT_CSV;
531531
else if (strcmp(fmt, "binary") == 0)
532-
opts_out->binary = true;
532+
opts_out->format = COPY_FORMAT_BINARY;
533+
else if (strcmp(fmt, "json") == 0)
534+
opts_out->format = COPY_FORMAT_JSON;
533535
else
534536
ereport(ERROR,
535537
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -689,31 +691,47 @@ ProcessCopyOptions(ParseState *pstate,
689691
* Check for incompatible options (must do these three before inserting
690692
* defaults)
691693
*/
692-
if (opts_out->binary && opts_out->delim)
694+
if (opts_out->format == COPY_FORMAT_BINARY && opts_out->delim)
693695
ereport(ERROR,
694696
(errcode(ERRCODE_SYNTAX_ERROR),
695697
/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
696698
errmsg("cannot specify %s in BINARY mode", "DELIMITER")));
697699

698-
if (opts_out->binary && opts_out->null_print)
700+
if (opts_out->format == COPY_FORMAT_JSON && opts_out->delim)
701+
ereport(ERROR,
702+
errcode(ERRCODE_SYNTAX_ERROR),
703+
/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
704+
errmsg("cannot specify %s in JSON mode", "DELIMITER"));
705+
706+
if (opts_out->format == COPY_FORMAT_BINARY && opts_out->null_print)
699707
ereport(ERROR,
700708
(errcode(ERRCODE_SYNTAX_ERROR),
701709
errmsg("cannot specify %s in BINARY mode", "NULL")));
702710

703-
if (opts_out->binary && opts_out->default_print)
711+
if (opts_out->format == COPY_FORMAT_JSON && opts_out->null_print)
712+
ereport(ERROR,
713+
errcode(ERRCODE_SYNTAX_ERROR),
714+
errmsg("cannot specify %s in JSON mode", "NULL"));
715+
716+
if (opts_out->format == COPY_FORMAT_BINARY && opts_out->default_print)
704717
ereport(ERROR,
705718
(errcode(ERRCODE_SYNTAX_ERROR),
706719
errmsg("cannot specify %s in BINARY mode", "DEFAULT")));
707720

721+
if (opts_out->format == COPY_FORMAT_JSON && opts_out->default_print)
722+
ereport(ERROR,
723+
errcode(ERRCODE_SYNTAX_ERROR),
724+
errmsg("cannot specify %s in JSON mode", "DEFAULT"));
725+
708726
/* Set defaults for omitted options */
709727
if (!opts_out->delim)
710-
opts_out->delim = opts_out->csv_mode ? "," : "\t";
728+
opts_out->delim = opts_out->format == COPY_FORMAT_CSV ? "," : "\t";
711729

712730
if (!opts_out->null_print)
713-
opts_out->null_print = opts_out->csv_mode ? "" : "\\N";
731+
opts_out->null_print = opts_out->format == COPY_FORMAT_CSV ? "" : "\\N";
714732
opts_out->null_print_len = strlen(opts_out->null_print);
715733

716-
if (opts_out->csv_mode)
734+
if (opts_out->format == COPY_FORMAT_CSV)
717735
{
718736
if (!opts_out->quote)
719737
opts_out->quote = "\"";
@@ -761,51 +779,56 @@ ProcessCopyOptions(ParseState *pstate,
761779
* future-proofing. Likewise we disallow all digits though only octal
762780
* digits are actually dangerous.
763781
*/
764-
if (!opts_out->csv_mode &&
782+
if (opts_out->format != COPY_FORMAT_CSV &&
765783
strchr("\\.abcdefghijklmnopqrstuvwxyz0123456789",
766784
opts_out->delim[0]) != NULL)
767785
ereport(ERROR,
768786
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
769787
errmsg("COPY delimiter cannot be \"%s\"", opts_out->delim)));
770788

771789
/* Check header */
772-
if (opts_out->binary && opts_out->header_line)
790+
if (opts_out->format == COPY_FORMAT_BINARY && opts_out->header_line)
773791
ereport(ERROR,
774792
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
775793
/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
776794
errmsg("cannot specify %s in BINARY mode", "HEADER")));
777795

796+
if (opts_out->format == COPY_FORMAT_JSON && opts_out->header_line)
797+
ereport(ERROR,
798+
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
799+
errmsg("cannot specify %s in JSON mode", "HEADER"));
800+
778801
/* Check quote */
779-
if (!opts_out->csv_mode && opts_out->quote != NULL)
802+
if (opts_out->format != COPY_FORMAT_CSV && opts_out->quote != NULL)
780803
ereport(ERROR,
781804
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
782805
/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
783806
errmsg("COPY %s requires CSV mode", "QUOTE")));
784807

785-
if (opts_out->csv_mode && strlen(opts_out->quote) != 1)
808+
if (opts_out->format == COPY_FORMAT_CSV && strlen(opts_out->quote) != 1)
786809
ereport(ERROR,
787810
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
788811
errmsg("COPY quote must be a single one-byte character")));
789812

790-
if (opts_out->csv_mode && opts_out->delim[0] == opts_out->quote[0])
813+
if (opts_out->format == COPY_FORMAT_CSV && opts_out->delim[0] == opts_out->quote[0])
791814
ereport(ERROR,
792815
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
793816
errmsg("COPY delimiter and quote must be different")));
794817

795818
/* Check escape */
796-
if (!opts_out->csv_mode && opts_out->escape != NULL)
819+
if (opts_out->format != COPY_FORMAT_CSV && opts_out->escape != NULL)
797820
ereport(ERROR,
798821
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
799822
/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
800823
errmsg("COPY %s requires CSV mode", "ESCAPE")));
801824

802-
if (opts_out->csv_mode && strlen(opts_out->escape) != 1)
825+
if (opts_out->format == COPY_FORMAT_CSV && strlen(opts_out->escape) != 1)
803826
ereport(ERROR,
804827
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
805828
errmsg("COPY escape must be a single one-byte character")));
806829

807830
/* Check force_quote */
808-
if (!opts_out->csv_mode && (opts_out->force_quote || opts_out->force_quote_all))
831+
if (opts_out->format != COPY_FORMAT_CSV && (opts_out->force_quote || opts_out->force_quote_all))
809832
ereport(ERROR,
810833
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
811834
/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -819,8 +842,8 @@ ProcessCopyOptions(ParseState *pstate,
819842
"COPY FROM")));
820843

821844
/* Check force_notnull */
822-
if (!opts_out->csv_mode && (opts_out->force_notnull != NIL ||
823-
opts_out->force_notnull_all))
845+
if (opts_out->format != COPY_FORMAT_CSV && (opts_out->force_notnull != NIL ||
846+
opts_out->force_notnull_all))
824847
ereport(ERROR,
825848
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
826849
/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -835,8 +858,8 @@ ProcessCopyOptions(ParseState *pstate,
835858
"COPY TO")));
836859

837860
/* Check force_null */
838-
if (!opts_out->csv_mode && (opts_out->force_null != NIL ||
839-
opts_out->force_null_all))
861+
if (opts_out->format != COPY_FORMAT_CSV && (opts_out->force_null != NIL ||
862+
opts_out->force_null_all))
840863
ereport(ERROR,
841864
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
842865
/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -860,7 +883,7 @@ ProcessCopyOptions(ParseState *pstate,
860883
"NULL")));
861884

862885
/* Don't allow the CSV quote char to appear in the null string. */
863-
if (opts_out->csv_mode &&
886+
if (opts_out->format == COPY_FORMAT_CSV &&
864887
strchr(opts_out->null_print, opts_out->quote[0]) != NULL)
865888
ereport(ERROR,
866889
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -877,6 +900,12 @@ ProcessCopyOptions(ParseState *pstate,
877900
errmsg("COPY %s cannot be used with %s", "FREEZE",
878901
"COPY TO")));
879902

903+
/* Check json format */
904+
if (opts_out->format == COPY_FORMAT_JSON && is_from)
905+
ereport(ERROR,
906+
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
907+
errmsg("COPY json mode cannot be used with %s", "COPY FROM"));
908+
880909
if (opts_out->default_print)
881910
{
882911
if (!is_from)
@@ -896,7 +925,7 @@ ProcessCopyOptions(ParseState *pstate,
896925
"DEFAULT")));
897926

898927
/* Don't allow the CSV quote char to appear in the default string. */
899-
if (opts_out->csv_mode &&
928+
if (opts_out->format == COPY_FORMAT_CSV &&
900929
strchr(opts_out->default_print, opts_out->quote[0]) != NULL)
901930
ereport(ERROR,
902931
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -913,7 +942,7 @@ ProcessCopyOptions(ParseState *pstate,
913942
errmsg("NULL specification and DEFAULT specification cannot be the same")));
914943
}
915944
/* Check on_error */
916-
if (opts_out->binary && opts_out->on_error != COPY_ON_ERROR_STOP)
945+
if (opts_out->format == COPY_FORMAT_BINARY && opts_out->on_error != COPY_ON_ERROR_STOP)
917946
ereport(ERROR,
918947
(errcode(ERRCODE_SYNTAX_ERROR),
919948
errmsg("only ON_ERROR STOP is allowed in BINARY mode")));

src/backend/commands/copyfrom.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ static const CopyFromRoutine CopyFromRoutineBinary = {
155155
static const CopyFromRoutine *
156156
CopyFromGetRoutine(const CopyFormatOptions *opts)
157157
{
158-
if (opts->csv_mode)
158+
if (opts->format == COPY_FORMAT_CSV)
159159
return &CopyFromRoutineCSV;
160-
else if (opts->binary)
160+
else if (opts->format == COPY_FORMAT_BINARY)
161161
return &CopyFromRoutineBinary;
162162

163163
/* default is text */
@@ -261,7 +261,7 @@ CopyFromErrorCallback(void *arg)
261261
cstate->cur_relname);
262262
return;
263263
}
264-
if (cstate->opts.binary)
264+
if (cstate->opts.format == COPY_FORMAT_BINARY)
265265
{
266266
/* can't usefully display the data */
267267
if (cstate->cur_attname)

src/backend/commands/copyfromparse.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ ReceiveCopyBegin(CopyFromState cstate)
171171
{
172172
StringInfoData buf;
173173
int natts = list_length(cstate->attnumlist);
174-
int16 format = (cstate->opts.binary ? 1 : 0);
174+
int16 format = (cstate->opts.format == COPY_FORMAT_BINARY ? 1 : 0);
175175
int i;
176176

177177
pq_beginmessage(&buf, PqMsg_CopyInResponse);
@@ -747,7 +747,7 @@ bool
747747
NextCopyFromRawFields(CopyFromState cstate, char ***fields, int *nfields)
748748
{
749749
return NextCopyFromRawFieldsInternal(cstate, fields, nfields,
750-
cstate->opts.csv_mode);
750+
cstate->opts.format == COPY_FORMAT_CSV);
751751
}
752752

753753
/*
@@ -774,7 +774,7 @@ NextCopyFromRawFieldsInternal(CopyFromState cstate, char ***fields, int *nfields
774774
bool done;
775775

776776
/* only available for text or csv input */
777-
Assert(!cstate->opts.binary);
777+
Assert(!(cstate->opts.format == COPY_FORMAT_BINARY));
778778

779779
/* on input check that the header line is correct if needed */
780780
if (cstate->cur_lineno == 0 && cstate->opts.header_line)

0 commit comments

Comments
 (0)