]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix COPY FROM ON_ERROR SET_NULL with selective column list
authorFujii Masao <fujii@postgresql.org>
Tue, 19 May 2026 01:11:41 +0000 (10:11 +0900)
committerFujii Masao <fujii@postgresql.org>
Tue, 19 May 2026 01:11:41 +0000 (10:11 +0900)
When using COPY FROM ... ON_ERROR SET_NULL with a selective column list, the
domain_with_constraint array was incorrectly allocated based on the length of
the target column list. While the array was populated sequentially,
CopyFromTextLikeOneRow attempted to access it using the physical attribute
index (attnum - 1). This mismatch caused out-of-bounds reads when targeting
high-numbered columns, allowing NULL values to bypass NOT NULL domain checks
and be silently inserted.

Fix by allocating the array to match the total number of physical attributes
(num_phys_attrs) and indexing via attnum - 1, bringing it into alignment with
other per-column arrays in BeginCopyFrom.

Author: SATYANARAYANA NARLAPURAM <satyanarlapuram@gmail.com>
Reviewed-by: Jian He <jian.universality@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAHg+QDdej0c0gWJi2FnbirzhgzyZNPiTwC1P5B_-dSNCzq-91A@mail.gmail.com

src/backend/commands/copyfrom.c
src/test/regress/expected/copy2.out
src/test/regress/sql/copy2.sql

index 64ac3063c61a9a8af00c285981999fbf0344939f..0087585b2c4e118f7d84d8492afb1e849e88b0ae 100644 (file)
@@ -1636,8 +1636,6 @@ BeginCopyFrom(ParseState *pstate,
 
        if (cstate->opts.on_error == COPY_ON_ERROR_SET_NULL)
        {
-               int                     attr_count = list_length(cstate->attnumlist);
-
                /*
                 * When data type conversion fails and ON_ERROR is SET_NULL, we need
                 * ensure that the input column allow null values.  ExecConstraints()
@@ -1646,15 +1644,13 @@ BeginCopyFrom(ParseState *pstate,
                 * check must be performed during the initial string-to-datum
                 * conversion (see CopyFromTextLikeOneRow()).
                 */
-               cstate->domain_with_constraint = palloc0_array(bool, attr_count);
+               cstate->domain_with_constraint = palloc0_array(bool, num_phys_attrs);
 
                foreach_int(attno, cstate->attnumlist)
                {
-                       int                     i = foreach_current_index(attno);
-
                        Form_pg_attribute att = TupleDescAttr(tupDesc, attno - 1);
 
-                       cstate->domain_with_constraint[i] = DomainHasConstraints(att->atttypid, NULL);
+                       cstate->domain_with_constraint[attno - 1] = DomainHasConstraints(att->atttypid, NULL);
                }
        }
 
index 7600e5239d29c0d4b53c5ec7c261be0afa46a4fc..919eabd5f78f8bc8b21b75d4c5dcdd74dbf8242b 100644 (file)
@@ -805,6 +805,10 @@ COPY t_on_error_null FROM STDIN WITH (on_error set_null); -- fail
 ERROR:  domain d_int_not_null does not allow null values
 DETAIL:  ON_ERROR SET_NULL cannot be applied because column "a" (domain d_int_not_null) does not accept null values.
 CONTEXT:  COPY t_on_error_null, line 1, column a: null input
+COPY t_on_error_null(c, a) FROM STDIN WITH (on_error set_null); -- fail
+ERROR:  domain d_int_not_null does not allow null values
+DETAIL:  ON_ERROR SET_NULL cannot be applied because column "a" (domain d_int_not_null) does not accept null values.
+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:  domain d_int_not_null does not allow null values
 DETAIL:  ON_ERROR SET_NULL cannot be applied because column "a" (domain d_int_not_null) does not accept null values.
index e0810109473b4b5df1e077999001fc3b2f04f32a..f853499021d68bbb59b9be046456660eba75b42b 100644 (file)
@@ -555,6 +555,10 @@ COPY t_on_error_null FROM STDIN WITH (on_error set_null); -- fail
 \N     11      13
 \.
 
+COPY t_on_error_null(c, a) FROM STDIN WITH (on_error set_null); -- fail
+11     \N
+\.
+
 COPY t_on_error_null FROM STDIN WITH (on_error set_null); -- fail
 ss     11      14
 \.