fix: validate parquet statistics config - #24642
Conversation
7192caa to
99c04f2
Compare
kosiew
left a comment
There was a problem hiding this comment.
Thanks for working on this. Moving the Parquet statistics setting to a validated enum is a nice improvement and makes invalid configuration fail much earlier.
I found two issues that I think need to be addressed before merging. The new config test currently fails to compile without the parquet feature, and a failed SET after RESET can unexpectedly mutate the configuration to Some(Page).
I also left one non-blocking suggestion to add coverage for the proto-models decoding path.
| ); | ||
| } | ||
|
|
||
| #[test] |
There was a problem hiding this comment.
Could you gate this test with #[cfg(feature = \"parquet\")], or make the assert_contains! import unconditional? Right now the test itself is always compiled, but the macro import is only available with the parquet feature. As a result, the default-feature test build fails with cannot find macro assert_contains in this scope.
There was a problem hiding this comment.
Fixed, thanks. I gated the parquet validation test on the parquet feature, so the default-feature build no longer hits the parquet-only assertion macro.
| /// These values are not case sensitive. If NULL, uses | ||
| /// default parquet writer setting | ||
| pub statistics_enabled: Option<String>, transform = str::to_lowercase, default = Some("page".into()) | ||
| pub statistics_enabled: Option<DFParquetStatistics>, default = Some(DFParquetStatistics::Page) |
There was a problem hiding this comment.
There is a subtle state mutation here when this option is None. The blanket Option<F>::set inserts DFParquetStatistics::default() before trying to parse the new value. This means that after RESET datafusion.execution.parquet.statistics_enabled, running SET ... = 'invalid' correctly returns an error, but also changes the setting from None to Some(Page).
Could we use the parse-then-assign pattern used by Option<MaxRowGroupBytes> so a failed SET leaves the existing configuration unchanged? It would also be good to add a regression assertion covering RESET followed by an invalid SET.
There was a problem hiding this comment.
Fixed, thanks. The option now parses before assigning, so an invalid SET leaves an unset value untouched. RESET restores the configured default, Page, so the regression test explicitly starts from an unset value before trying the invalid update.
| dictionary_page_size_limit: proto.dictionary_page_size_limit as usize, | ||
| statistics_enabled: proto.statistics_enabled_opt.as_ref().map( | ||
| |opt| match opt { | ||
| statistics_enabled: proto |
There was a problem hiding this comment.
Non-blocking suggestion: could we add a direct negative test for this decoder, similar to the invalid-value test added in proto-common? Since this is a separate deserialization boundary, having a test here would make sure malformed wire values continue to be rejected if the implementations evolve independently.
There was a problem hiding this comment.
Added a negative decoder test for an invalid parquet statistics value as well.
|
Thank you for opening this pull request! Reviewer note: cargo-semver-checks reported the current version number is not SemVer-compatible with the changes in this pull request (compared against the base branch). Details |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #24642 +/- ##
========================================
Coverage 81.63% 81.63%
========================================
Files 1123 1123
Lines 409537 409674 +137
Branches 409537 409674 +137
========================================
+ Hits 334308 334424 +116
- Misses 55594 55610 +16
- Partials 19635 19640 +5 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@zhangxinyao88 |
99c04f2 to
c4b56d3
Compare
c4b56d3 to
ec51f9b
Compare
Yes - And thank you for reviewing my PR |
kosiew
left a comment
There was a problem hiding this comment.
Thanks for addressing the previous review comments. The feature-gated config test, failed SET mutation, and proto-models malformed decoder coverage all look addressed.
I found one remaining issue around RESET handling. Once that is fixed and covered by a regression test, I think this will be in good shape.
| Ok(()) | ||
| } | ||
|
|
||
| fn reset(&mut self, _key: &str) -> Result<()> { |
There was a problem hiding this comment.
Could we reject nonempty keys here instead of ignoring _key? Right now, something like RESET datafusion.execution.parquet.statistics_enabled.typo is accepted and clears the entire statistics_enabled setting. The surrounding config namespace delegates the remaining suffix to this method, so a typo can silently mutate the configuration.
Please reject nonempty keys, consistent with the scalar ConfigField implementations, and add a regression test covering a nested RESET with an invalid suffix.
There was a problem hiding this comment.
Fixed. A nested RESET now returns an error and leaves the current statistics setting unchanged. I added a regression test for the invalid suffix.
kosiew
left a comment
There was a problem hiding this comment.
Thanks for the follow-up. The previous issues around feature gating, preserving the unset state after an invalid SET, proto-models validation, and nested RESET handling look addressed.
There is one remaining issue with nested config keys. The SET path still accepts a nonempty suffix, so I think this needs one more small fix before merging.
| } | ||
| } | ||
|
|
||
| fn set(&mut self, _key: &str, value: &str) -> Result<()> { |
There was a problem hiding this comment.
Thanks for fixing the nested RESET case. I think we need the same validation here for SET as well.
set currently ignores _key, so something like SET datafusion.execution.parquet.statistics_enabled.typo = 'none' is still accepted and updates statistics_enabled. A typo in a nested field should return an error rather than silently changing the scalar option.
Could you reject nonempty keys here, and in the scalar DFParquetStatistics implementation for consistency? It would also be good to add a regression assertion showing that a nested SET fails and leaves the existing value unchanged.
There was a problem hiding this comment.
Fixed in cdc9deb. Nested SET now returns an error without changing the current value, with coverage for both option and scalar paths.
|
@zhangxinyao88 |
Which issue does this PR close?
Rationale for this change
datafusion.execution.parquet.statistics_enabledaccepts arbitrary strings. Invalid values silently fall back to the Parquet writer default instead of failing when set.What changes are included in this PR?
This adds a typed config enum for
none,chunk, andpage. It validates values at config and protobuf boundaries and passes the validated value to the Parquet writer.Are these changes tested?
Yes. Unit, protobuf round-trip, and SQL logic tests were added. The full lint and extended workspace test suites pass.
Are there any user-facing changes?
Invalid values now fail at
SETtime. Valid values remain case-insensitive and are displayed in lowercase.This changes
ParquetOptions.statistics_enabledfromOption<String>toOption<DFParquetStatistics>, so the PR may need theapi changelabel.