Skip to content

pg_lake_copy: reject multidimensional arrays in COPY TO before CSV serialization#428

Open
sfc-gh-rbachala wants to merge 1 commit into
Snowflake-Labs:mainfrom
sfc-gh-rbachala:fix/407-copy-to-multidim-guardrail
Open

pg_lake_copy: reject multidimensional arrays in COPY TO before CSV serialization#428
sfc-gh-rbachala wants to merge 1 commit into
Snowflake-Labs:mainfrom
sfc-gh-rbachala:fix/407-copy-to-multidim-guardrail

Conversation

@sfc-gh-rbachala

Copy link
Copy Markdown
Collaborator

Summary

  • Fixes the missing multidimensional-array guardrail in COPY <table> TO '<lake-file>' (Parquet, JSON, CSV-to-URL).
  • The Iceberg table write path already handles multidim arrays via IcebergErrorOrClampMultiDimArrayDatum in iceberg_datum_validation.c. Plain COPY TO had no equivalent — multidim values flowed into the intermediate temp CSV and reached DuckDB, which either returned a cryptic Conversion Error or crashed the shared pgduck_server process (issue DuckDB : CSV string-to-LIST cast can segfault (standalone repro) #408), disconnecting all concurrent sessions.
  • Fix is in CopyOneRowTo (csv_writer.c): after the existing numeric NaN/Inf checks, detect array-typed columns and raise ERRCODE_FEATURE_NOT_SUPPORTED when ARR_NDIM > 1, before the value is ever serialised to the CSV. The check is skipped for DATA_FORMAT_ICEBERG where the upstream guardrail already applies.
  • Also corrects a misleading comment in ConvertCSVFileTo (write_data.c) that implied clamping had occurred for all callers; it is only true for the Iceberg FDW INSERT path.

Root Cause

ProcessPgLakeCopyTo (copy.c:901) calls CreateCSVDestReceiverExecuteQueryToDestReceiver with no pre-write validation. CopyOneRowTo serializes each attribute directly. A column declared int[] can hold ARRAY[[1,2],[3,4]] at runtime (PostgreSQL cannot distinguish int[] from int[][] at the type level), which serialises to "[[1,2],[3,4]]" in the CSV. DuckDB cannot cast that string back to INTEGER[] in StringValueScanner::Flush.

Scope

The check is added once in CopyOneRowTo and covers all callers of CreateCSVDestReceiver that handle user array data. Other callers (position-delete dest, multi-file Iceberg dest) already have upstream validation or carry no user array data.

Tests

  • test_copy_to_multidim_array_errors: table with a multidim int[] value → COPY TO parquet → verifies "multidimensional arrays are not supported in COPY TO" error is raised before any engine interaction
  • test_copy_to_1d_array_succeeds: 1-D text[] column → COPY TO parquet → verifies values round-trip correctly (regression guard)

Notes

pgindent is not available locally; the C change adds one #include, one comment block, and one if block. CI should confirm formatting. This also mitigates issue #408 — multidim values are now blocked at the PG level before reaching DuckDB.

Fixes #407.
Mitigates #408.

…rialization

COPY <table> TO '<lake-file>' serializes rows to an intermediate temp CSV
and hands it to DuckDB for conversion to Parquet/JSON.  The intermediate
CSV path had no guard against multidimensional array values: a column
declared int[] can hold ARRAY[[1,2],[3,4]] at runtime, which serializes
to [[1,2],[3,4]] in the CSV.  DuckDB cannot cast that string back to a
flat LIST(T) and either returns a cryptic Conversion Error or -- for
certain element types (uuid, bigint, numeric) -- crashes the shared
pgduck_server process, disconnecting all concurrent sessions (issue Snowflake-Labs#408).

The Iceberg table write path already handles this via
IcebergErrorOrClampMultiDimArrayDatum in iceberg_datum_validation.c;
plain COPY TO had no equivalent guard.

Fix: in CopyOneRowTo (csv_writer.c), after the existing numeric NaN/Inf
checks, detect array-typed columns and raise ERRCODE_FEATURE_NOT_SUPPORTED
when ARR_NDIM > 1, before the value is serialized to the CSV.  The check
is skipped for the Iceberg format (DATA_FORMAT_ICEBERG) where the upstream
guardrail already applies.

Also corrects a misleading comment in ConvertCSVFileTo (write_data.c) that
described the ICEBERG_OOR_NONE sentinel as if clamping had already occurred
for all callers; it is only true for the Iceberg FDW INSERT path.

Tests:
- test_copy_to_multidim_array_errors: verifies a clear pg_lake error is
  raised for a table with a multidim int[] value, with no engine involved
- test_copy_to_1d_array_succeeds: regression guard confirming 1-D arrays
  still round-trip correctly after the check is added

Fixes Snowflake-Labs#407.
Mitigates Snowflake-Labs#408 (multidim values are now blocked before reaching DuckDB).

Signed-off-by: Richie Bachala <richie.bachala@snowflake.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

COPY to a data lake file does not apply the multidimensional-array guardrail that Iceberg writes have

1 participant