Skip to content

[core] Extend Arrow input support for row-level updates - #1149

Merged
JingsongLi merged 3 commits into
apache:mainfrom
JingsongLi:codex/native-nested-update-inputs
Oct 17, 2026
Merged

JingsongLi merged 3 commits into
apache:mainfrom
JingsongLi:codex/native-nested-update-inputs

Conversation

@JingsongLi

@JingsongLi JingsongLi commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Complete external Arrow input paths already accepted by PyPaimon's public row-level update APIs. Native currently rejects MAP entries and Union inputs, loses half-float text digits, rounds wide decimals differently, and can fail on exact decimal rescaling across large scale differences.

This adapts input to existing declared Paimon types. It adds no logical table type, MAP-to-ARRAY schema evolution, or storage format. Java decimal rules remain authoritative; Arrow encodings follow the existing Python API contracts.

Brief change log

  • Accept MAP inputs for two-field ARRAY/ROW elements, including renamed fields, nesting, dictionaries, slices, NULLs and empty containers. Share recursive MAP entry conversion.
  • Preserve fixed-size binary UTF-8 strings and all significant Float16 text digits; reject invalid UTF-8.
  • Share Java DECIMAL-to-FLOAT/DOUBLE conversion with schema reads. Normalize Decimal32/64/128/256 inputs for valid Java precision/scale, retaining compact long/divisor versus wide BigDecimal rounding.
  • Share exact DECIMAL rescaling with match keys. Check scale differences before Arrow's i8 arithmetic and power table; parse full coefficients when needed. Allow zero/NULL without accepting fractional loss or overflow.
  • Support dense/sparse Union payloads in the existing whole-column row-ID constructor fallback, including matched upserts. Convert only active values; preserve arbitrary IDs, repeated/reordered dense offsets, slices and active child NULLs.
  • Restore dictionary NULL indices, NULL parents and missing ROW fields after target conversion, without assigning a Union's unrelated active value to a missing index.
  • Preserve root-only MAP pair construction through encoding wrappers. Keep safe predicate/MERGE assignments and unmatched append validation strict.
  • Correct sparse Union offsets at the Python C Data boundary before Arrow Rust materializes arrays, including nested STRUCT/FixedSizeList offsets and unaligned foreign buffers. This private bridge handles layout; conversion semantics stay in core.

Review follow-up

  • Fix Decimal256 source precision 39..76 and coefficients wider than i128 when assigning FLOAT/DOUBLE. Use complete decimal coefficients while retaining Java compact/wide rules for valid logical DECIMAL inputs.
  • Normalize ordinary nested STRUCT siblings and active Union children along with sparse Union slices; avoid applying nested offsets twice.
  • Defer NULL/non-nullable-child validation until parent and child coordinates are both normalized, including masked STRUCT and FixedSizeList values.
  • Add 264 public-API regression cases. All three findings were reproduced before the fix; subsequent independent review found no remaining actionable issues. Java 8 BigDecimal results were checked directly.

Tests

Old Native failures were reproduced through public APIs for MAP-to-ARRAY, fixed-binary text, half-float text, wide decimal floating conversion and Union input. Corresponding Python reference cases pass.

  • Core update input tests: 50 passed; schema cast regressions: 26 passed; match-key tests: 5 passed.
  • Core MERGE tests: 17 passed; upsert tests: 10 passed.
  • Python binding C Data offset tests: 4 passed, including nested parent offsets.
  • Rust 1.98.0 Clippy with -D warnings passed for core and Python bindings; formatting and diff checks passed.
  • All 795 added scalar/encoded Python reference cases passed before Native verification. Targeted Native sparse Union slice and unaligned-buffer checks also passed.
  • New and existing nested update, selected-value upsert, match-key, Blob, MERGE and row-shape regressions: 2669 passed, 2 skipped, with Native plan/read/write/commit enabled. Counters: 3243 plans, 4036 reads, 1451 writes, 147 commits.

Companion Python PR: apache/paimon#10632. Its Native CI stays on Rust main and depends on this change.

API and documentation

No new public API, dependency, configuration or storage format. Python production code remains unchanged. Internal comments explain constructor scope, NULL selection order and C Data offset handling.

@JingsongLi JingsongLi changed the title [core] Accept Arrow MAP inputs for ARRAY ROW updates [core] Extend Arrow input support for row-level updates Oct 17, 2026

@leaves12138 leaves12138 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM

@JingsongLi
JingsongLi merged commit adc8717 into apache:main Oct 17, 2026
16 checks passed
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.

2 participants