Repository navigation
[fix](iceberg) Validate required NULLs before file creation - #69327
Conversation
### What problem does this PR solve? Issue Number: N/A Problem Summary: Iceberg required fields could be written as SQL NULL for both ORC and Parquet. Doris could then publish a snapshot containing data that the Iceberg schema declares non-null, and a failed write could leave an unreferenced physical file behind. Add a common BE Iceberg Block validator used by both formats. It recursively checks required STRUCT fields, required LIST elements, required MAP values, and always-required MAP keys while honoring a NULL optional parent as a mask. Validation runs before the first partition writer or file is created and before every subsequent Block write. On the BE failure path, destroy the format writer/output stream before deleting the physical object, defer cleanup until any asynchronous close finishes, and never emit commit data for a failed file. On the FE path, rollback now removes files already reported by completed BE fragments, clears commit data, and continues to rely on the transaction lifecycle to avoid publishing a snapshot. Tests: - BE release build and targeted validator/TableWriter/partition cleanup tests. - FE IcebergTransaction rollback unit tests. - Checkstyle, connector import gate, clang-format, and BE build hygiene. - Manual ORC/Parquet E2E for required NULL, MAP key NULL, optional parent NULL, snapshot/file/row atomicity, and INSERT SELECT. - Regression tests updated for ORC/Parquet, nested required fields, optional parent mask, maps, and distributed INSERT SELECT. ### Release note Iceberg writes now reject required NULL values before creating a data file, including nested STRUCT/LIST/MAP values and MAP keys. Failed writes are rolled back without publishing a snapshot and clean up their physical files. ### Check List (For Author) - Test: Unit Test / Manual test / Regression test updated - Behavior changed: Yes, invalid Iceberg data is rejected before file creation - Does this need documentation: No
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
### What problem does this PR solve? Issue Number: N/A Problem Summary: Remove unused validator state, fold one-use location formatting, share LIST/MAP offset validation, and rename the local validation location helper without changing validation behavior. ### Release note None ### Check List (For Author) - Test: Unit Test / Manual test - Behavior changed: No - Does this need documentation: No
|
run buildall |
|
/review |
There was a problem hiding this comment.
Static review of PR #69327 at d7c653c: no substantiated new findings. Reviewed all 13 changed paths and their relevant upstream/downstream control flow. The supplied existing-thread bundle and refreshed PR comments contain no existing findings to carry forward. No additional user focus was supplied.
Converged after 1 round: both complete-coverage reviewers and the separate risk reviewer returned NO_NEW_VALUABLE_FINDINGS on the unchanged empty finding set. Main-agent verification dismissed all initial risks with evidence; no unresolved static candidate or assigned coverage gap remains.
| Required checkpoint | Conclusion |
|---|---|
| Goal and evidence | The shared BE check rejects required root/nested NULLs and MAP keys before writer creation for each block, while optional NULL parents mask their children. Added validator/table-writer tests exercise these branches; FE rollback test covers deletion of reported outputs. These tests were inspected, not executed. |
| Scope, clarity and reuse | Focused shared validator and reuse of existing writer callbacks, authenticated FileIO and report ownership; no unrelated source changes. |
| Concurrency and locks | Validator state is local to the async writer. Existing sorter locking remains in place. FE manager serializes terminal lifecycle and fragment delivery; rollback snapshots the list under its monitor and performs deletion outside that list monitor. No new thread or lock-order inversion identified. |
| Lifecycle and static initialization | Failed-output cleanup destroys the format stream before FileWriter and before deletion; S3 destruction waits outstanding upload work. Cleanup is scheduled once and repeated failed close retains its terminal error. No new cross-TU static initializer or ownership cycle. |
| Configuration | No configuration item added or changed. |
| Compatibility | No changed persisted format, existing public SPI contract or required mixed-version payload. Existing schema JSON and file/report protocols are reused. |
| Thrift and protobuf IDs | No gensrc/thrift or gensrc/proto changes. |
| Parallel paths | Reviewed ORC/Parquet, static/hybrid/dynamic/unpartitioned dispatch, sorted/spilled writes, MERGE insert filtering and sibling cleanup, REWRITE source/output separation, and DELETE/deletion-vector output ownership. |
| Conditional checks and errors | Optional-parent masking and destruction ordering are explained locally. Required-null failures carry field path and row/collection ordinal and propagate to the outer writer; cleanup failures are logged. Existing column-construction invariants exclude nested constants. |
| Test coverage | Root/STRUCT/LIST/MAP failures, optional parent success, pre-creation rejection, terminal-close idempotence, FE reported-file deletion and both format regressions are covered by inspected tests. Deeper mixed nesting and real asynchronous fault injection would strengthen runtime evidence. |
| Test results | No expected-output files changed. Builds, tests and runtime validation were not run under the review contract; author-reported passes were not independently reproduced. |
| Observability | Required-field errors identify path/location; cleanup logs identify paths and FE transaction IDs. No additional metrics need identified for these failure paths. |
| Transactions and persistence | No EditLog or persistent metadata field added. Manager removes a transaction before any SDK commit attempt, so subsequent error/backstop rollback cannot delete committed or uncertain-commit outputs. Rewrite cancellation is ordered with commit. |
| Write atomicity and crash limits | Invalid writes preserve their original error and enter existing BE cleanup; FE rollback deletes reported new outputs rather than rewrite sources/referenced data files. Late fragments are rejected by the manager. Physical deletion remains best effort; FE/BE crashes and ambiguous report outcomes may still require orphan maintenance. |
| FE/BE variable propagation | No new cross-process field or variable. |
| Performance and memory | Required primitive roots use the nullable scan; nested traversal follows constrained branches. Temporary path state is schema-depth bounded; rollback copying/deduplication scales with reported output count and deletes each distinct path once. No demonstrated material regression; no benchmark performed. |
| Other concerns and user focus | All initial risk questions and reviewer investigations were resolved with evidence, with no extra user-specific concern or verified bug remaining. |
Validation limits: this is a static review. The regressions check snapshots, metadata file counts and rows; they do not enumerate physical storage objects, and the nested-negative case may be rejected by FE before reaching BE. New cleanup unit tests use a fake transformer rather than a real asynchronous object-store writer. Runtime upload timing, physical orphan absence and restart/failover behavior were not verified. These are validation limits, not unresolved code findings.
Review converged after 1 round(s).
FE UT Coverage ReportIncrement line coverage `` 🎉 |
BE UT Coverage ReportIncrement line coverage Increment coverage report
|
TPC-H: Total hot run time: 28390 ms |
TPC-DS: Total hot run time: 151103 ms |
ClickBench: Total hot run time: 24.43 s |
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
FE Regression Coverage ReportIncrement line coverage |
|
run external |
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
FE Regression Coverage ReportIncrement line coverage |
### What problem does this PR solve? Issue Number: None Related PR: apache#69032, apache#69327 Problem Summary: Merge official upstream/master at 67f31fa. Its unified failed-file cleanup overlaps with the spatial writer open-error cleanup. Keep upstream rollback callbacks and repeated-close behavior while retaining blocking close and writer destruction before callback or final deletion. Preserve both sets of tests and cover asynchronous close failure before outer cleanup. ### Release note None ### Check List (For Author) - Test: Unit Test - VIcebergPartitionWriterTest.*, VIcebergTableWriterTest.*, IcebergWriteValidatorTest.* (25 cases, clang21/ASAN); clang-format 16, build hygiene and clang-tidy (no warnings). - Behavior changed: No; preserve spatial failed-write cleanup while integrating upstream lifecycle handling. - Does this need documentation: No; merge resolution only.
|
PR approved by anyone and no changes requested. |
|
PR approved by at least one committer and no changes requested. |
### What problem does this PR solve? Related PR: apache#69327 The Iceberg validator now rejects required NULLs before format-specific writers run. Two regression suites still expect generic file-writer errors. Update all six assertions, preserving the offending field and NULL reason, including the full arr.element and m.value paths. Keep metadata, write, post-ALTER nullability, and Spark comparison coverage unchanged. ### Release note None ### Check List (For Author) - Test: Regression test - Same CI binary package: both original suites fail locally. - Both corrected suites pass: 2 passed, 0 failed, 0 skipped. - Full diff self-review and git diff --check passed. - Behavior changed: No product behavior change. - Does this need documentation: No.
…9416) ### What problem does this PR solve? This PR corrects three external-regression test issues: - `test_iceberg_modify_binary_column`: the initial golden treats the required `digest` field as nullable. Regenerate that expectation as non-nullable; retain the nullable expectation after `ALTER ... NULL`. - `test_iceberg_show_nullable` and `test_iceberg_modify_binary_column`: their six negative-write assertions still expect generic file-writer errors. After #69327, Iceberg validates required NULLs before creating writers/files and reports `Iceberg required field '<path>' contains NULL`. Update the expected diagnostics for `id`, `value`, `digest`, `arr.element`, and `m.value`. The first two errors stop their respective suites; the remaining four assertions have the same stale expectation. The writes correctly fail, so this fixes test expectations without changing product behavior or weakening the required-field checks. - `test_paimon_hms_catalog`: use the recognized `fs.gcs.support` property instead of `fs.gs.support` for explicit GCS-provider selection, retaining both credential-property variants. The Iceberg coverage still checks metadata nullability, rejected NULL writes, successful writes after constraints are relaxed, nested fields, and Spark read-back. Both TVF suites retain their original fixture handling. Related PRs: #68640, #69285, #69327. ### Validation Current failure fix, using the same CI binary package (FE `436941a8bb`, BE `0a77e2dd98`; package master revision `e779124b5f60`): - Ran both original suites locally with `run-regression-test.sh`: 2 failed, reproducing the exact stale exception assertions for `digest` and `id`. - Updated all six assertions and reran both complete suites in normal comparison mode: **2 passed, 0 failed, 0 fatal, 0 skipped**. All six expected NULL rejections, post-ALTER writes, metadata/snapshot checks, and Spark read-back passed. No golden output was regenerated for this assertion-only update. - One intermediate run encountered `SQLITE_BUSY` while the local REST fixture cleaned up an existing table. Restarted that fixture, then reran both complete suites successfully; the environment failure is not counted as a passing validation. - Reviewed the full diff and passed `git diff --check`. Only regression scripts change in this update; no FE/BE source changes. Earlier validation: - Reproduced the initial Iceberg `digest` nullability mismatch with runtime `6ca5ef36d8`. Generated the golden with `run-regression-test.sh -forceGenOut`, then passed the complete binary-column suite in normal comparison mode, including Spark read-back. - Loaded the actual GCS directory plugin and checked both `gs.*` and `s3.*` credential variants: the old flag fails `gs` filesystem resolution; the corrected flag selects GCS and resolves `S3AFileSystem`. This checks plugin binding and filesystem resolution; the full remote Paimon HMS/GCS suite was not run locally. - Regression framework build and its 50 tests passed. ### Release note None ### Check List (For Author) - Test: - [x] Regression test - [x] Manual test - Behavior changed: - [x] No product behavior change. - Does this need documentation? - [x] No.
…ash (#69487) ### What problem does this PR solve? Issue Number: None Related PR: #69223, #69174, #69327, #69183 Problem Summary: BE UT of every PR based on master fails since 2026-10-22. Two test-only breakages were merged by PRs whose own CI ran on an older master. 1. doris_be_test does not compile (TeamCity: "BE BUILD FAIL"): be/test/exprs/function/function_string_test.cpp:2971: error: no matching conversion for functional-style cast from 'std::string' to 'Field' be/test/exprs/function/function_string_test.cpp:2982: error: no member named 'FRAGMENT_LOCAL' in 'doris::FunctionContext' function_translate_mixed_const_map_test, added by #69223, builds a Field directly from std::string and uses FunctionContext::FRAGMENT_LOCAL. Field must be created with Field::create_field<TYPE_STRING>() now, and #69174 made FunctionStateScope an enum class. Use both current spellings, as the rest of be/test does. 2. Once it compiles, doris_be_test aborts (TeamCity: "CORE DUMPED") in DefaultAndConfiguredLimits/ExternalTableWriterPartitionLimitTest. IcebergRejectsNextPartitionBeforeOpeningAFile/0: shared_ptr_base.h:1344: [_Tp = doris::iceberg::Schema]: Assertion '__p != nullptr' failed. #69327 made VIcebergTableWriter validate every block against the schema pinned by open(): `iceberg::validate_write_block(*_schema, ...)`. The test added by #69183 skips open() and calls write_prepared_block() directly, so _schema is null. open() always sets _schema in production, so the writer stays unchanged. The test now pins a one-field schema that matches its block (optional INT "p", the source field of its identity partition), as viceberg_table_writer_test.cpp does. Co-authored-by: csun5285 <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]>
…rom master ### What problem does this PR solve? Issue Number: None Related PR: apache#69327, apache#69183, apache#69487 Problem Summary: The first commit of this PR takes the async-writer dependencies out of VIcebergTableWriter, so its constructor takes only the sink and the output expressions. Master has since added three tests that still pass two null dependencies: RejectsRequiredNullBeforeWriterCreation and RejectsNestedRequiredNullBeforeWriterCreation in viceberg_table_writer_test.cpp (apache#69327), and IcebergRejectsNextPartitionBeforeOpeningAFile in external_table_writer_partition_limit_test.cpp (apache#69183, which apache#69487 made pin the writer schema). On that master doris_be_test does not compile. Construct the writer in these tests with the two arguments; nothing else in them changes. ### Release note None ### Check List (For Author) - Test: Unit Test - doris_be_test builds on master bf278a5 with this PR; 63 tests in VIcebergTableWriterTest, VIcebergTableWriterLifecycleTest, ExternalTableWriterPartitionLimitTest, IcebergTableSinkOperatorTest, SpillIcebergTableSinkOperatorTest, VIcebergPartitionWriterTest, IcebergWriteValidatorTest, FullSorterTest and SorterReserveMemoryTest pass (ASAN) - Behavior changed: No - Does this need documentation: No Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…rom master ### What problem does this PR solve? Issue Number: None Related PR: apache#69327, apache#69183, apache#69487, apache#69358 Problem Summary: The first commit of this PR takes the async-writer dependencies out of VIcebergTableWriter, so its constructor takes only the sink and the output expressions. Master has since added four tests that still pass two null dependencies: RejectsRequiredNullBeforeWriterCreation and RejectsNestedRequiredNullBeforeWriterCreation (apache#69327) and VoidPartitionFieldNeedsNoSourceColumn (apache#69358) in viceberg_table_writer_test.cpp, and IcebergRejectsNextPartitionBeforeOpeningAFile in external_table_writer_partition_limit_test.cpp (apache#69183, which apache#69487 made pin the writer schema). On that master doris_be_test does not compile. Construct the writer in these tests with the two arguments; nothing else in them changes. ### Release note None ### Check List (For Author) - Test: Unit Test - doris_be_test builds on master 2e7f79e with this PR; 64 tests in VIcebergTableWriterTest, VIcebergTableWriterLifecycleTest, ExternalTableWriterPartitionLimitTest, IcebergTableSinkOperatorTest, SpillIcebergTableSinkOperatorTest, VIcebergPartitionWriterTest, IcebergWriteValidatorTest, FullSorterTest and SorterReserveMemoryTest pass (ASAN) - Behavior changed: No - Does this need documentation: No Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Issue Number: N/A Related PR: apache#69327 Problem Summary: Iceberg ORC and Parquet writes could accept NULL required values, including nested STRUCT/LIST/MAP fields and MAP keys. Failed writes could also leave physical files produced by writers or completed BE fragments behind. Validate every prepared block before creating or dispatching partition writers, while preserving optional-parent NULL masking. Destroy failed writer streams before deferring file deletion to the existing outer cleanup lifecycle. Adapt FE cleanup to branch-4.2's legacy IcebergTransaction and retained catalog lease. Clean failed-commit files before releasing the lease, and retain files when Iceberg reports an unknown commit state. Carry over the necessary sorted writer close error propagation that the original PR's baseline already has. Split container validation into focused helpers for the target lint thresholds. Iceberg ORC/Parquet writes reject required NULL values and clean up failed files without publishing a snapshot. - Test: Modified Java files pass Checkstyle; repository clang-format 16 and whitespace checks pass; regression framework compilation and 47 framework unit tests pass. FE build and focused unit-test attempts were interrupted by confirmed host OOM kills. BE ASAN product/UT configuration succeeds, but full compilation and BE unit execution remain incomplete. Both focused regression suites were attempted and failed connecting to the isolated FE. Validator clang-tidy diagnostics were fixed; the check remains blocked by an existing unmatched NOLINTEND in core/types.h. - Behavior changed: Yes, invalid required NULL writes are rejected and failed external files are cleaned up. - Does this need documentation: No
### What problem does this PR solve? Issue Number: N/A Related PR: apache#69327, apache#69842 Problem Summary: A REST catalog can publish an Iceberg snapshot before a lost or malformed response raises an exception. Preserve reported files after SDK commit entry unless a CleanableFailure proves deletion safe, including on a later rollback. Convert sorted EOS allocation exceptions to Status before unconditional partition finalization so outer cleanup can remove the failed file. Add published-snapshot and persisted-file tests, cover missing container validation branches, and update nullable regression error expectations. ### Release note Prevent deletion of potentially committed Iceberg files after an indeterminate commit response, and remove failed sorted-write files after EOS allocation errors. ### Check List (For Author) - Test: Unit Test - IcebergTransactionTest, 39 passed; local FE changed executable line coverage 34/38 (89.47%). Related BE production sources compiled under ASAN; the focused BE unit-test build is still running. Java Checkstyle and BE clang-format/check-format passed. External regression requires new-head CI. - Behavior changed: Yes - preserve files when commit publication is uncertain and finalize failed sorted output before outer file cleanup. - Does this need documentation: No
### What problem does this PR solve? Issue Number: N/A Related PR: apache#69327, apache#69842 Problem Summary: MAP constant materialization reconstructs the column and checks that its final offset matches both child lengths. The out-of-range offset fixture invalidated that final offset and aborted before reaching the Iceberg validator. Keep the final offset consistent and use an invalid intermediate offset so the validator can reject the first-row range. ### Release note None ### Check List (For Author) - Test: Unit Test - run-be-ut.sh focused Iceberg validator, partition writer and table writer suites: 37 ASAN tests passed, zero failures/errors/disabled tests. clang-format, check-format and git diff --check passed. Changed-file clang-tidy has no diagnostics; full analysis retains the existing unmatched NOLINTEND in core/types.h:578. - Behavior changed: No - test fixture only. - Does this need documentation: No
Issue Number: N/A Related PR: apache#69327 Problem Summary: Iceberg ORC and Parquet writes could accept NULL required values, including nested STRUCT/LIST/MAP fields and MAP keys. Failed writes could also leave physical files produced by writers or completed BE fragments behind. Validate every prepared block before creating or dispatching partition writers, while preserving optional-parent NULL masking. Destroy failed writer streams before deferring file deletion to the existing outer cleanup lifecycle. Adapt FE cleanup to branch-4.2's legacy IcebergTransaction and retained catalog lease. Clean failed-commit files before releasing the lease, and retain files when Iceberg reports an unknown commit state. Carry over the necessary sorted writer close error propagation that the original PR's baseline already has. Split container validation into focused helpers for the target lint thresholds. Iceberg ORC/Parquet writes reject required NULL values and clean up failed files without publishing a snapshot. - Test: Modified Java files pass Checkstyle; repository clang-format 16 and whitespace checks pass; regression framework compilation and 47 framework unit tests pass. FE build and focused unit-test attempts were interrupted by confirmed host OOM kills. BE ASAN product/UT configuration succeeds, but full compilation and BE unit execution remain incomplete. Both focused regression suites were attempted and failed connecting to the isolated FE. Validator clang-tidy diagnostics were fixed; the check remains blocked by an existing unmatched NOLINTEND in core/types.h. - Behavior changed: Yes, invalid required NULL writes are rejected and failed external files are cleaned up. - Does this need documentation: No
### What problem does this PR solve? Issue Number: N/A Related PR: apache#69327, apache#69842 Problem Summary: A REST catalog can publish an Iceberg snapshot before a lost or malformed response raises an exception. Preserve reported files after SDK commit entry unless a CleanableFailure proves deletion safe, including on a later rollback. Convert sorted EOS allocation exceptions to Status before unconditional partition finalization so outer cleanup can remove the failed file. Add published-snapshot and persisted-file tests, cover missing container validation branches, and update nullable regression error expectations. ### Release note Prevent deletion of potentially committed Iceberg files after an indeterminate commit response, and remove failed sorted-write files after EOS allocation errors. ### Check List (For Author) - Test: Unit Test - IcebergTransactionTest, 39 passed; local FE changed executable line coverage 34/38 (89.47%). Related BE production sources compiled under ASAN; the focused BE unit-test build is still running. Java Checkstyle and BE clang-format/check-format passed. External regression requires new-head CI. - Behavior changed: Yes - preserve files when commit publication is uncertain and finalize failed sorted output before outer file cleanup. - Does this need documentation: No
### What problem does this PR solve? Issue Number: N/A Related PR: apache#69327, apache#69842 Problem Summary: MAP constant materialization reconstructs the column and checks that its final offset matches both child lengths. The out-of-range offset fixture invalidated that final offset and aborted before reaching the Iceberg validator. Keep the final offset consistent and use an invalid intermediate offset so the validator can reject the first-row range. ### Release note None ### Check List (For Author) - Test: Unit Test - run-be-ut.sh focused Iceberg validator, partition writer and table writer suites: 37 ASAN tests passed, zero failures/errors/disabled tests. clang-format, check-format and git diff --check passed. Changed-file clang-tidy has no diagnostics; full analysis retains the existing unmatched NOLINTEND in core/types.h:578. - Behavior changed: No - test fixture only. - Does this need documentation: No
### What problem does this PR solve? Issue Number: N/A Related PR: apache#69327, apache#69842 Problem Summary: Keep sorted Iceberg writer finalization consistent with the master baseline used by this backport. Close the underlying partition writer explicitly before choosing the returned status, and retain the unit test that checks propagation of file-close failures. ### Release note None ### Check List (For Author) - Test: BE clang-format 16, check-format, and git diff --check passed. FE and BE builds are in progress; final-head CI will validate the rebased branch. - Behavior changed: Yes - use the master sorted-writer finalization flow. - Does this need documentation: No
### What problem does this PR solve? Issue Number: N/A Related PR: apache#69327, apache#69842 Problem Summary: EOS sorting, spill, merge, and write operations can throw a Doris allocation exception before the partition writer is finalized. Convert these exceptions to a failure Status before closing the partition writer and cleaning spill streams, so outer cleanup can remove the failed physical file. Include the allocation-failure unit test that checks file removal. ### Release note Fix orphan files after Iceberg sorted-write allocation failures during finalization. ### Check List (For Author) - Test: clang-format 16, repository check-format, and git diff --check passed. Local compilation, unit tests, and regression tests were not rerun as requested. - Behavior changed: Yes - finalize failed sorted output after caught Doris allocation exceptions and preserve the failure status for outer cleanup. - Does this need documentation: No
What problem does this PR solve?
Issue Number: N/A
Related PR: N/A
Problem Summary:
Iceberg required fields could be written as NULL for ORC and Parquet, and failed writes could leave data files behind. This PR adds a shared BE Block validator for required nested fields and MAP keys, runs validation before writers/files are created, and cleans up failed files without publishing a snapshot. FE rollback now also removes files already reported by completed BE fragments.
Release note
Fix Iceberg ORC/Parquet writes to reject required NULL values and clean up failed files without publishing a snapshot.
Check List (For Author)
Test
Behavior changed:
Does this need documentation?
Check List (For Reviewer who merge this PR)