Rename COPY option from SAVE_ERROR_TO to ON_ERROR
authorAlexander Korotkov <akorotkov@postgresql.org>
Fri, 19 Jan 2024 13:08:40 +0000 (15:08 +0200)
committerAlexander Korotkov <akorotkov@postgresql.org>
Fri, 19 Jan 2024 13:15:51 +0000 (15:15 +0200)
The option names now are "stop" (default) and "ignore".  The future options
could be "file 'filename.log'" and "table 'tablename'".

Discussion: https://postgr.es/m/20240117.164859.2242646601795501168.horikyota.ntt%40gmail.com
Author: Jian He
Reviewed-by: Atsushi Torikoshi
doc/src/sgml/ref/copy.sgml
src/backend/commands/copy.c
src/backend/commands/copyfrom.c
src/backend/commands/copyfromparse.c
src/bin/psql/tab-complete.c
src/include/commands/copy.h
src/test/regress/expected/copy2.out
src/test/regress/sql/copy2.sql
src/tools/pgindent/typedefs.list

index 85881ca0ad60558ceb9b9622b3a89d982395939a..21a5c4a0529df4d136c5a7aa76a44fecb4346c3a 100644 (file)
@@ -43,7 +43,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
     FORCE_NOT_NULL { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
     FORCE_NULL { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
-    SAVE_ERROR_TO '<replaceable class="parameter">location</replaceable>'
+    ON_ERROR '<replaceable class="parameter">error_action</replaceable>'
     ENCODING '<replaceable class="parameter">encoding_name</replaceable>'
 </synopsis>
  </refsynopsisdiv>
@@ -375,20 +375,20 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
-    <term><literal>SAVE_ERROR_TO</literal></term>
+    <term><literal>ON_ERROR</literal></term>
     <listitem>
      <para>
-      Specifies to save error information to <replaceable class="parameter">
-      location</replaceable> when there is malformed data in the input.
-      Currently, only <literal>error</literal> (default) and <literal>none</literal>
+      Specifies which <replaceable class="parameter">
+      error_action</replaceable> to perform when there is malformed data in the input.
+      Currently, only <literal>stop</literal> (default) and <literal>ignore</literal>
       values are supported.
-      If the <literal>error</literal> value is specified,
+      If the <literal>stop</literal> value is specified,
       <command>COPY</command> stops operation at the first error.
-      If the <literal>none</literal> value is specified,
+      If the <literal>ignore</literal> value is specified,
       <command>COPY</command> skips malformed data and continues copying data.
       The option is allowed only in <command>COPY FROM</command>.
-      The <literal>none</literal> value is allowed only when
-      not using <literal>binary</literal> format.
+      Only <literal>stop</literal> value is allowed when
+      using <literal>binary</literal> format.
      </para>
     </listitem>
    </varlistentry>
@@ -577,7 +577,7 @@ COPY <replaceable class="parameter">count</replaceable>
 
    <para>
     <command>COPY</command> stops operation at the first error when
-    <literal>SAVE_ERROR_TO</literal> is not specified. This
+    <literal>ON_ERROR</literal> is not specified. This
     should not lead to problems in the event of a <command>COPY
     TO</command>, but the target table will already have received
     earlier rows in a <command>COPY FROM</command>. These rows will not
index c36d7f1daafc2e3acffd22be9a3dc47fc94218b7..cc0786c6f4aecc5843648dd7b07e8933fa2063a0 100644 (file)
@@ -395,39 +395,39 @@ defGetCopyHeaderChoice(DefElem *def, bool is_from)
 }
 
 /*
- * Extract a CopySaveErrorToChoice value from a DefElem.
+ * Extract a CopyOnErrorChoice value from a DefElem.
  */
-static CopySaveErrorToChoice
-defGetCopySaveErrorToChoice(DefElem *def, ParseState *pstate, bool is_from)
+static CopyOnErrorChoice
+defGetCopyOnErrorChoice(DefElem *def, ParseState *pstate, bool is_from)
 {
        char       *sval;
 
        if (!is_from)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                errmsg("COPY SAVE_ERROR_TO cannot be used with COPY TO"),
+                                errmsg("COPY ON_ERROR cannot be used with COPY TO"),
                                 parser_errposition(pstate, def->location)));
 
        /*
         * If no parameter value given, assume the default value.
         */
        if (def->arg == NULL)
-               return COPY_SAVE_ERROR_TO_ERROR;
+               return COPY_ON_ERROR_STOP;
 
        /*
-        * Allow "error", or "none" values.
+        * Allow "stop", or "ignore" values.
         */
        sval = defGetString(def);
-       if (pg_strcasecmp(sval, "error") == 0)
-               return COPY_SAVE_ERROR_TO_ERROR;
-       if (pg_strcasecmp(sval, "none") == 0)
-               return COPY_SAVE_ERROR_TO_NONE;
+       if (pg_strcasecmp(sval, "stop") == 0)
+               return COPY_ON_ERROR_STOP;
+       if (pg_strcasecmp(sval, "ignore") == 0)
+               return COPY_ON_ERROR_IGNORE;
 
        ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                        errmsg("COPY save_error_to \"%s\" not recognized", sval),
+                        errmsg("COPY ON_ERROR \"%s\" not recognized", sval),
                         parser_errposition(pstate, def->location)));
-       return COPY_SAVE_ERROR_TO_ERROR;        /* keep compiler quiet */
+       return COPY_ON_ERROR_STOP;      /* keep compiler quiet */
 }
 
 /*
@@ -455,7 +455,7 @@ ProcessCopyOptions(ParseState *pstate,
        bool            format_specified = false;
        bool            freeze_specified = false;
        bool            header_specified = false;
-       bool            save_error_to_specified = false;
+       bool            on_error_specified = false;
        ListCell   *option;
 
        /* Support external use for option sanity checking */
@@ -608,12 +608,12 @@ ProcessCopyOptions(ParseState *pstate,
                                                                defel->defname),
                                                 parser_errposition(pstate, defel->location)));
                }
-               else if (strcmp(defel->defname, "save_error_to") == 0)
+               else if (strcmp(defel->defname, "on_error") == 0)
                {
-                       if (save_error_to_specified)
+                       if (on_error_specified)
                                errorConflictingDefElem(defel, pstate);
-                       save_error_to_specified = true;
-                       opts_out->save_error_to = defGetCopySaveErrorToChoice(defel, pstate, is_from);
+                       on_error_specified = true;
+                       opts_out->on_error = defGetCopyOnErrorChoice(defel, pstate, is_from);
                }
                else
                        ereport(ERROR,
@@ -642,10 +642,10 @@ ProcessCopyOptions(ParseState *pstate,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("cannot specify DEFAULT in BINARY mode")));
 
-       if (opts_out->binary && opts_out->save_error_to != COPY_SAVE_ERROR_TO_ERROR)
+       if (opts_out->binary && opts_out->on_error != COPY_ON_ERROR_STOP)
                ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("cannot specify SAVE_ERROR_TO in BINARY mode")));
+                                errmsg("only ON_ERROR STOP is allowed in BINARY mode")));
 
        /* Set defaults for omitted options */
        if (!opts_out->delim)
index 50e245d555cdb311cd75744be4d8eb65f727498f..173a736ad5231710e353b55ccb46e1e009e1031e 100644 (file)
@@ -657,7 +657,7 @@ CopyFrom(CopyFromState cstate)
        Assert(cstate->rel);
        Assert(list_length(cstate->range_table) == 1);
 
-       if (cstate->opts.save_error_to != COPY_SAVE_ERROR_TO_ERROR)
+       if (cstate->opts.on_error != COPY_ON_ERROR_STOP)
                Assert(cstate->escontext);
 
        /*
@@ -996,14 +996,14 @@ CopyFrom(CopyFromState cstate)
                if (!NextCopyFrom(cstate, econtext, myslot->tts_values, myslot->tts_isnull))
                        break;
 
-               if (cstate->opts.save_error_to != COPY_SAVE_ERROR_TO_ERROR &&
+               if (cstate->opts.on_error != COPY_ON_ERROR_STOP &&
                        cstate->escontext->error_occurred)
                {
                        /*
-                        * Soft error occured, skip this tuple and save error information
-                        * according to SAVE_ERROR_TO.
+                        * Soft error occured, skip this tuple and deal with error
+                        * information according to ON_ERROR.
                         */
-                       if (cstate->opts.save_error_to == COPY_SAVE_ERROR_TO_NONE)
+                       if (cstate->opts.on_error == COPY_ON_ERROR_IGNORE)
 
                                /*
                                 * Just make ErrorSaveContext ready for the next NextCopyFrom.
@@ -1307,7 +1307,7 @@ CopyFrom(CopyFromState cstate)
        /* Done, clean up */
        error_context_stack = errcallback.previous;
 
-       if (cstate->opts.save_error_to != COPY_SAVE_ERROR_TO_ERROR &&
+       if (cstate->opts.on_error != COPY_ON_ERROR_STOP &&
                cstate->num_errors > 0)
                ereport(NOTICE,
                                errmsg_plural("%llu row was skipped due to data type incompatibility",
@@ -1450,18 +1450,18 @@ BeginCopyFrom(ParseState *pstate,
                }
        }
 
-       /* Set up soft error handler for SAVE_ERROR_TO */
-       if (cstate->opts.save_error_to != COPY_SAVE_ERROR_TO_ERROR)
+       /* Set up soft error handler for ON_ERROR */
+       if (cstate->opts.on_error != COPY_ON_ERROR_STOP)
        {
                cstate->escontext = makeNode(ErrorSaveContext);
                cstate->escontext->type = T_ErrorSaveContext;
                cstate->escontext->error_occurred = false;
 
                /*
-                * Currently we only support COPY_SAVE_ERROR_TO_NONE. We'll add other
+                * Currently we only support COPY_ON_ERROR_IGNORE. We'll add other
                 * options later
                 */
-               if (cstate->opts.save_error_to == COPY_SAVE_ERROR_TO_NONE)
+               if (cstate->opts.on_error == COPY_ON_ERROR_IGNORE)
                        cstate->escontext->details_wanted = false;
        }
        else
index 7207eb269838667648bb0d6860e6ba6dc1aa7010..7cacd0b752c984c516f27c9bc92cdf8590553b59 100644 (file)
@@ -956,7 +956,11 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
 
                                values[m] = ExecEvalExpr(defexprs[m], econtext, &nulls[m]);
                        }
-                       /* If SAVE_ERROR_TO is specified, skip rows with soft errors */
+
+                       /*
+                        * If ON_ERROR is specified with IGNORE, skip rows with soft
+                        * errors
+                        */
                        else if (!InputFunctionCallSafe(&in_functions[m],
                                                                                        string,
                                                                                        typioparams[m],
index 6bfdb5f0082dfd7f949a093b46645806f13bbf69..ada711d02ff297ff274cd1b047f63ff8306212d3 100644 (file)
@@ -2899,15 +2899,15 @@ psql_completion(const char *text, int start, int end)
                COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
                                          "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
                                          "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING", "DEFAULT",
-                                         "SAVE_ERROR_TO");
+                                         "ON_ERROR");
 
        /* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
        else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "(", "FORMAT"))
                COMPLETE_WITH("binary", "csv", "text");
 
-       /* Complete COPY <sth> FROM filename WITH (SAVE_ERROR_TO */
-       else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "(", "SAVE_ERROR_TO"))
-               COMPLETE_WITH("error", "none");
+       /* Complete COPY <sth> FROM filename WITH (ON_ERROR */
+       else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "(", "ON_ERROR"))
+               COMPLETE_WITH("stop", "ignore");
 
        /* Complete COPY <sth> FROM <sth> WITH (<options>) */
        else if (Matches("COPY|\\copy", MatchAny, "FROM", MatchAny, "WITH", MatchAny))
index 8972c6180d720daf02ea0672f44c2c87a7ee73be..b3da3cb0be7996b031eb302cebdde8781aa20873 100644 (file)
@@ -34,11 +34,11 @@ typedef enum CopyHeaderChoice
  * Represents where to save input processing errors.  More values to be added
  * in the future.
  */
-typedef enum CopySaveErrorToChoice
+typedef enum CopyOnErrorChoice
 {
-       COPY_SAVE_ERROR_TO_ERROR = 0,   /* immediately throw errors */
-       COPY_SAVE_ERROR_TO_NONE,        /* ignore errors */
-} CopySaveErrorToChoice;
+       COPY_ON_ERROR_STOP = 0,         /* immediately throw errors, default */
+       COPY_ON_ERROR_IGNORE,           /* ignore errors */
+} CopyOnErrorChoice;
 
 /*
  * A struct to hold COPY options, in a parsed form. All of these are related
@@ -72,7 +72,7 @@ typedef struct CopyFormatOptions
        bool            force_null_all; /* FORCE_NULL *? */
        bool       *force_null_flags;   /* per-column CSV FN flags */
        bool            convert_selectively;    /* do selective binary conversion? */
-       CopySaveErrorToChoice save_error_to;    /* where to save error information */
+       CopyOnErrorChoice on_error; /* what to do when error happened */
        List       *convert_select; /* list of column names (can be NIL) */
 } CopyFormatOptions;
 
index 42cbcb2e92fc7054972dc996a84efde2236ca29a..25c401ce3443c1dfd6f8128df6a70d1ea9120d2c 100644 (file)
@@ -77,21 +77,21 @@ COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii');
 ERROR:  conflicting or redundant options
 LINE 1: COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii...
                                                  ^
-COPY x from stdin (save_error_to none,save_error_to none);
+COPY x from stdin (on_error ignore, on_error ignore);
 ERROR:  conflicting or redundant options
-LINE 1: COPY x from stdin (save_error_to none,save_error_to none);
-                                              ^
+LINE 1: COPY x from stdin (on_error ignore, on_error ignore);
+                                            ^
 -- incorrect options
 COPY x to stdin (format BINARY, delimiter ',');
 ERROR:  cannot specify DELIMITER in BINARY mode
 COPY x to stdin (format BINARY, null 'x');
 ERROR:  cannot specify NULL in BINARY mode
-COPY x from stdin (format BINARY, save_error_to none);
-ERROR:  cannot specify SAVE_ERROR_TO in BINARY mode
-COPY x to stdin (save_error_to none);
-ERROR:  COPY SAVE_ERROR_TO cannot be used with COPY TO
-LINE 1: COPY x to stdin (save_error_to none);
-                         ^
+COPY x from stdin (format BINARY, on_error ignore);
+ERROR:  only ON_ERROR STOP is allowed in BINARY mode
+COPY x from stdin (on_error unsupported);
+ERROR:  COPY ON_ERROR "unsupported" not recognized
+LINE 1: COPY x from stdin (on_error unsupported);
+                           ^
 COPY x to stdin (format TEXT, force_quote(a));
 ERROR:  COPY FORCE_QUOTE requires CSV mode
 COPY x from stdin (format CSV, force_quote(a));
@@ -104,9 +104,9 @@ COPY x to stdout (format TEXT, force_null(a));
 ERROR:  COPY FORCE_NULL requires CSV mode
 COPY x to stdin (format CSV, force_null(a));
 ERROR:  COPY FORCE_NULL cannot be used with COPY TO
-COPY x to stdin (format BINARY, save_error_to unsupported);
-ERROR:  COPY SAVE_ERROR_TO cannot be used with COPY TO
-LINE 1: COPY x to stdin (format BINARY, save_error_to unsupported);
+COPY x to stdin (format BINARY, on_error unsupported);
+ERROR:  COPY ON_ERROR cannot be used with COPY TO
+LINE 1: COPY x to stdin (format BINARY, on_error unsupported);
                                         ^
 -- too many columns in column list: should fail
 COPY x (a, b, c, d, e, d, c) from stdin;
@@ -724,12 +724,12 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
--- tests for SAVE_ERROR_TO option
+-- tests for on_error option
 CREATE TABLE check_ign_err (n int, m int[], k int);
-COPY check_ign_err FROM STDIN WITH (save_error_to error);
+COPY check_ign_err FROM STDIN WITH (on_error stop);
 ERROR:  invalid input syntax for type integer: "a"
 CONTEXT:  COPY check_ign_err, line 2, column n: "a"
-COPY check_ign_err FROM STDIN WITH (save_error_to none);
+COPY check_ign_err FROM STDIN WITH (on_error ignore);
 NOTICE:  4 rows were skipped due to data type incompatibility
 SELECT * FROM check_ign_err;
  n |  m  | k 
@@ -740,15 +740,15 @@ SELECT * FROM check_ign_err;
 
 -- test datatype error that can't be handled as soft: should fail
 CREATE TABLE hard_err(foo widget);
-COPY hard_err FROM STDIN WITH (save_error_to none);
+COPY hard_err FROM STDIN WITH (on_error ignore);
 ERROR:  invalid input syntax for type widget: "1"
 CONTEXT:  COPY hard_err, line 1, column foo: "1"
 -- test missing data: should fail
-COPY check_ign_err FROM STDIN WITH (save_error_to none);
+COPY check_ign_err FROM STDIN WITH (on_error ignore);
 ERROR:  missing data for column "k"
 CONTEXT:  COPY check_ign_err, line 1: "1       {1}"
 -- test extra data: should fail
-COPY check_ign_err FROM STDIN WITH (save_error_to none);
+COPY check_ign_err FROM STDIN WITH (on_error ignore);
 ERROR:  extra data after last expected column
 CONTEXT:  COPY check_ign_err, line 1: "1       {1}     3       abc"
 -- clean up
index c48d556350d2ef36d4152cb3269efffc1ead9bf9..b5e549e8563ea70e88bcd8992b0147d7252ec39e 100644 (file)
@@ -66,20 +66,20 @@ COPY x from stdin (force_not_null (a), force_not_null (b));
 COPY x from stdin (force_null (a), force_null (b));
 COPY x from stdin (convert_selectively (a), convert_selectively (b));
 COPY x from stdin (encoding 'sql_ascii', encoding 'sql_ascii');
-COPY x from stdin (save_error_to none,save_error_to none);
+COPY x from stdin (on_error ignore, on_error ignore);
 
 -- incorrect options
 COPY x to stdin (format BINARY, delimiter ',');
 COPY x to stdin (format BINARY, null 'x');
-COPY x from stdin (format BINARY, save_error_to none);
-COPY x to stdin (save_error_to none);
+COPY x from stdin (format BINARY, on_error ignore);
+COPY x from stdin (on_error unsupported);
 COPY x to stdin (format TEXT, force_quote(a));
 COPY x from stdin (format CSV, force_quote(a));
 COPY x to stdout (format TEXT, force_not_null(a));
 COPY x to stdin (format CSV, force_not_null(a));
 COPY x to stdout (format TEXT, force_null(a));
 COPY x to stdin (format CSV, force_null(a));
-COPY x to stdin (format BINARY, save_error_to unsupported);
+COPY x to stdin (format BINARY, on_error unsupported);
 
 -- too many columns in column list: should fail
 COPY x (a, b, c, d, e, d, c) from stdin;
@@ -498,9 +498,9 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
--- tests for SAVE_ERROR_TO option
+-- tests for on_error option
 CREATE TABLE check_ign_err (n int, m int[], k int);
-COPY check_ign_err FROM STDIN WITH (save_error_to error);
+COPY check_ign_err FROM STDIN WITH (on_error stop);
 1      {1}     1
 a      {2}     2
 3      {3}     3333333333
@@ -508,7 +508,7 @@ a   {2}     2
 
 5      {5}     5
 \.
-COPY check_ign_err FROM STDIN WITH (save_error_to none);
+COPY check_ign_err FROM STDIN WITH (on_error ignore);
 1      {1}     1
 a      {2}     2
 3      {3}     3333333333
@@ -520,17 +520,17 @@ SELECT * FROM check_ign_err;
 
 -- test datatype error that can't be handled as soft: should fail
 CREATE TABLE hard_err(foo widget);
-COPY hard_err FROM STDIN WITH (save_error_to none);
+COPY hard_err FROM STDIN WITH (on_error ignore);
 1
 \.
 
 -- test missing data: should fail
-COPY check_ign_err FROM STDIN WITH (save_error_to none);
+COPY check_ign_err FROM STDIN WITH (on_error ignore);
 1      {1}
 \.
 
 -- test extra data: should fail
-COPY check_ign_err FROM STDIN WITH (save_error_to none);
+COPY check_ign_err FROM STDIN WITH (on_error ignore);
 1      {1}     3       abc
 \.
 
index aa74ed695eba5d8ff5eef6638a30da79d7ca7f9f..16421f034cb6a78b6d89695534c3b19028ed8a69 100644 (file)
@@ -478,6 +478,7 @@ CopyHeaderChoice
 CopyInsertMethod
 CopyMultiInsertBuffer
 CopyMultiInsertInfo
+CopyOnErrorChoice
 CopySource
 CopyStmt
 CopyToState
@@ -4041,4 +4042,3 @@ manifest_writer
 rfile
 ws_options
 ws_file_info
-CopySaveErrorToChoice