On Fri Feb 6, 2026 at 9:58 AM -03, Matheus Alcantara wrote:
> Thanks, overall the patch looks good to me. I'm attaching a diff with
> just some small tweaks on documentation and error messages. Please see
> and check if it's make sense.
>
I miss to include the diff file, sorry about that.
--
Matheus Alcantara
EDB: https://www.enterprisedb.com
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index dcf6e6a2f48..2aeb38a6e5f 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -6265,10 +6265,13 @@ FROM pg_stat_get_backend_idset() AS backendid;
<structfield>tuples_skipped</structfield> <type>bigint</type>
</para>
<para>
- Number of tuples skipped because they contain malformed data.
- This counter only advances when
- <literal>ignore</literal> is specified to the
<literal>ON_ERROR</literal>
- option.
+ Number of tuples that contained malformed data. When
+ <literal>ON_ERROR</literal> is set to <literal>ignore</literal>,
+ this counts rows that were skipped. When set to
+ <literal>set_null</literal>, this counts rows where at least one
+ column was set to null due to a conversion error.
+ This counter only advances when <literal>ON_ERROR</literal>
+ is set to <literal>ignore</literal> or <literal>set_null</literal>.
</para></entry>
</row>
</tbody>
diff --git a/src/backend/commands/copyfromparse.c
b/src/backend/commands/copyfromparse.c
index 96ba23e961c..0a75800b8ab 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -1052,6 +1052,11 @@ CopyFromTextLikeOneRow(CopyFromState cstate, ExprContext
*econtext,
cstate->num_errors++;
else if (cstate->opts.on_error ==
COPY_ON_ERROR_SET_NULL)
{
+ /*
+ * Reset error state so the subsequent
InputFunctionCallSafe
+ * call (for domain constraint check) can
properly report
+ * whether it succeeded or failed.
+ */
cstate->escontext->error_occurred = false;
Assert(cstate->domain_with_constraint != NULL);
@@ -1075,13 +1080,17 @@ CopyFromTextLikeOneRow(CopyFromState cstate,
ExprContext *econtext,
else if (string == NULL)
ereport(ERROR,
errcode(ERRCODE_NOT_NULL_VIOLATION),
- errmsg("domain %s does
not allow null values", format_type_be(typioparams[m])),
+ errmsg("null value in
column \"%s\" violates not-null constraint of domain %s",
+
cstate->cur_attname, format_type_be(typioparams[m])),
errdatatype(typioparams[m]));
else
ereport(ERROR,
-
errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input
value for domain %s: \"%s\"",
-
format_type_be(typioparams[m]), string));
+
errcode(ERRCODE_NOT_NULL_VIOLATION),
+ errmsg("cannot set null
value for column \"%s\" with domain %s",
+
cstate->cur_attname, format_type_be(typioparams[m])),
+ errdetail("Column
\"%s\" does not accept null values, so ON_ERROR SET_NULL cannot be applied.",
+
cstate->cur_attname),
+
errdatatype(typioparams[m]));
/*
* We count only the number of rows (not
fields) where
diff --git a/src/test/regress/expected/copy2.out
b/src/test/regress/expected/copy2.out
index 72034796aca..d9cc7bf5f48 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -799,13 +799,15 @@ CREATE DOMAIN d_int_positive_maybe_null AS integer
CHECK(value > 0);
CREATE TABLE t_on_error_null (a d_int_not_null, b d_int_positive_maybe_null, c
integer);
\pset null NULL
COPY t_on_error_null FROM STDIN WITH (on_error set_null); --fail
-ERROR: domain d_int_not_null does not allow null values
+ERROR: null value in column "a" violates not-null constraint of domain
d_int_not_null
CONTEXT: COPY t_on_error_null, line 1, column a: null input
COPY t_on_error_null FROM STDIN WITH (on_error set_null); --fail
-ERROR: invalid input value for domain d_int_not_null: "ss"
+ERROR: cannot set null value for column "a" with domain d_int_not_null
+DETAIL: Column "a" does not accept null values, so ON_ERROR SET_NULL cannot
be applied.
CONTEXT: COPY t_on_error_null, line 1, column a: "ss"
COPY t_on_error_null FROM STDIN WITH (on_error set_null); --fail
-ERROR: invalid input value for domain d_int_not_null: "-1"
+ERROR: cannot set null value for column "a" with domain d_int_not_null
+DETAIL: Column "a" does not accept null values, so ON_ERROR SET_NULL cannot
be applied.
CONTEXT: COPY t_on_error_null, line 1, column a: "-1"
--fail, less data.
COPY t_on_error_null FROM STDIN WITH (delimiter ',', on_error set_null);