Skip to content

fix: reject NULL partition keys during partitioned writes - #24951

Merged
kosiew merged 2 commits into
apache:mainfrom
bvolpato:bvolpato/reject-null-partition-writes
Sep 14, 2026
Merged

kosiew merged 2 commits into
apache:mainfrom
bvolpato:bvolpato/reject-null-partition-writes

Conversation

@bvolpato

@bvolpato bvolpato commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Related to #18083. Full support for NULL partition values remains covered by that issue.

Rationale for this change

Partitioned writes read partition values without checking their validity. A NULL integer partition key can be written under p=0, so reading the output turns NULL into zero and silently changes the data.

For example:

CREATE TABLE src(p INT, v INT) AS VALUES (NULL, 1), (0, 2);
COPY src TO '/tmp/null_partition/' STORED AS PARQUET PARTITIONED BY (p);

Both rows can end up in the zero partition. This PR rejects the write with NULL values are not supported for partition column 'p'.

What changes are included in this PR?

  • Check logical nulls before extracting partition keys, including NULL dictionary values referenced by valid dictionary indices.
  • Continue accepting nullable columns when the selected rows contain no NULL values.
  • Add focused unit tests and a copy.slt regression covering rejection and a filtered successful write.

What is the testing strategy for this PR?

  • The rejection regressions fail without the production fix and pass with it.
  • Focused partition-key tests: 5 passed with RUST_BACKTRACE=1.
  • cargo clippy --all-targets --all-features -- -D warnings passed.
  • The extended workspace Rust suites passed after excluding four host memory-measurement runners that also fail on current main in this environment.
  • The SQL logic harness passed all 513 files, including encrypted Parquet coverage.
  • cargo fmt --all -- --check and git diff --check passed.

Are there any user-facing changes?

Partitioned writes containing NULL partition keys now return an execution error. Callers can filter or replace these values before writing. Validation happens per batch, so files written by earlier batches can remain after an error.

@github-actions github-actions Bot added sqllogictest SQL Logic Tests (.slt) datasource Changes to the datasource crate labels Sep 5, 2026
@bvolpato
bvolpato force-pushed the bvolpato/reject-null-partition-writes branch from ddf6bdb to 2527ec7 Compare September 10, 2026 04:54
@bvolpato
bvolpato marked this pull request as ready for review September 10, 2026 04:56
@codecov-commenter

codecov-commenter commented Sep 10, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.95%. Comparing base (4c031a2) to head (b81280e).
⚠️ Report is 50 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #24951      +/-   ##
==========================================
+ Coverage   81.83%   81.95%   +0.11%     
==========================================
  Files        1130     1133       +3     
  Lines      418634   423855    +5221     
  Branches   418634   423855    +5221     
==========================================
+ Hits       342577   347354    +4777     
- Misses      55850    55907      +57     
- Partials    20207    20594     +387     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@kosiew kosiew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bvolpato,

Thanks for working on this. The NULL validation looks good overall, and the added coverage for primitive, string, sliced, dictionary, and COPY cases gives me confidence in the change.

I just have one non-blocking suggestion around the dictionary test coverage.

@kosiew kosiew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bvolpato, thanks for the follow-up!

The new fixture in b81280ef99 addresses the earlier feedback nicely. It now specifically covers a dictionary array with a NULL key and non-NULL dictionary values, while dictionary_with_null_value() continues to cover the separate case where a valid key resolves to a NULL dictionary value.

The added test makes the distinction between these cases clear, and I don't see any new issues with the follow-up change.

Looks good to me!

@kosiew

kosiew commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

🚀
@bvolpato
Thank you for your contribution.

@kosiew
kosiew added this pull request to the merge queue Sep 14, 2026
Merged via the queue into apache:main with commit 99a6af8 Sep 14, 2026
42 checks passed
Omega359 pushed a commit to Omega359/arrow-datafusion that referenced this pull request Oct 11, 2026
## Which issue does this PR close?

Related to apache#18083. Full support for NULL partition values remains
covered by that issue.

## Rationale for this change

Partitioned writes read partition values without checking their
validity. A NULL integer partition key can be written under `p=0`, so
reading the output turns NULL into zero and silently changes the data.

For example:

```sql
CREATE TABLE src(p INT, v INT) AS VALUES (NULL, 1), (0, 2);
COPY src TO '/tmp/null_partition/' STORED AS PARQUET PARTITIONED BY (p);
```

Both rows can end up in the zero partition. This PR rejects the write
with `NULL values are not supported for partition column 'p'`.

## What changes are included in this PR?

- Check logical nulls before extracting partition keys, including NULL
dictionary values referenced by valid dictionary indices.
- Continue accepting nullable columns when the selected rows contain no
NULL values.
- Add focused unit tests and a `copy.slt` regression covering rejection
and a filtered successful write.

## What is the testing strategy for this PR?

- The rejection regressions fail without the production fix and pass
with it.
- Focused partition-key tests: 5 passed with `RUST_BACKTRACE=1`.
- `cargo clippy --all-targets --all-features -- -D warnings` passed.
- The extended workspace Rust suites passed after excluding four host
memory-measurement runners that also fail on current main in this
environment.
- The SQL logic harness passed all 513 files, including encrypted
Parquet coverage.
- `cargo fmt --all -- --check` and `git diff --check` passed.

## Are there any user-facing changes?

Partitioned writes containing NULL partition keys now return an
execution error. Callers can filter or replace these values before
writing. Validation happens per batch, so files written by earlier
batches can remain after an error.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

datasource Changes to the datasource crate sqllogictest SQL Logic Tests (.slt) v56.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants