Repository navigation
Fix #2385: Preserve multidimensional array dimensions in CopyFrom - #2679
Merged
Merged
Conversation
When using CopyFrom with string array values, the text-to-binary encoding path via tryScanStringCopyValueThenEncode() was scanning into 'any' which flattened array dimensions. Now it detects array types and uses pgtype.Array[any] to preserve dimensions. Also adds regression test TestConnCopyFromPreservesMultidimensionalArrayString. Signed-off-by: arminazimi <arminazimi@users.noreply.github.com>
arminazimi
force-pushed
the
fix-2385-array-dimensions
branch
from
October 13, 2026 11:19
e066f6e to
b09583d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CopyFromwas flattening multidimensional arrays sent as PostgreSQL text-formatliterals (e.g.
"{{1,2},{3,4}}"). The issue is reproducible: inserting the sameliteral with
Execpreservesarray_ndims = 2, while inserting it withCopyFromgives
array_ndims = 1.Root cause: when
CopyFromneeds to binary-encode a value it cannot encode directly,it falls back into
tryScanStringCopyValueThenEncode, which rescans the text literalinto
*any.pgtype.ArrayCodec.DecodeValuethen flattens the array literal into asingle one-dimensional
[]any, so the COPY protocol binary payload carriesndim = 1even for multidimensional inputs.This PR makes that fallback path preserve the original array dimensions by scanning
the text literal into
pgtype.Array[any](anArraySetter) when the target columnis an array type, then re-encoding that value in binary.
CopyFromnow produces thesame stored shape that
Execdoes.Fixes #2385
Changes
pgx/values.go:tryScanStringCopyValueThenEncodenow usespgtype.Map.TypeForOIDand typechecks the returned
*pgtype.Type.Codecagainst*pgtype.ArrayCodecbeforefalling back to the
anyscan path. Dimension-preserving scan only applies to arraytarget columns; the
anyfallback still handles non-array types.pgx/values_internal_test.go: new DB-free internal testTestEncodeCopyValuePreservesArrayDimensionsverifyingencodeCopyValueproduces a2-D binary array header from a
"{{1,2},{3,4}}"string and a 1-D header from"{a,b,c}", with NULL-element handling and non-array-type passthrough.pgx/copy_from_test.go: new integration testTestConnCopyFromPreservesMultidimensionalArrayStringthat inserts the same 2-Dtext[][]literal via bothExecandCopyFromand assertspgtype.Array[any].Dims,array_ndims(),array_dims(),array_length(b, 1), and NULL handling all match.Test plan
TestConnCopyFromPreservesMultidimensionalArrayStringonPostgreSQL 16: inserts the same 2-D
text[][]literal via bothExecandCopyFrom, then asserts dimensions,array_ndims(),array_dims(),array_length(b, 1), NULL elements, and NULL rows all match.TestEncodeCopyValuePreservesArrayDimensions:asserts
encodeCopyValueproduces a 2-D binary array header from a"{{1,2},{3,4}}"string and a 1-D header from"{a,b,c}", with NULL-elementhandling and non-array-type passthrough.
TestConnCopyFromAutomaticStringConversionre-run and still passes:CopyFromstill auto-converts"42"toint8 42rows.TestConnCopyFromAutomaticStringConversionArrayre-run and stillpasses:
[][]string/[]stringCopyFrom rows still round-trip through numericarrays correctly.
go test ./... -racere-run against the changed package; no new races.gofmt -dclean.