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