Skip to content

fix: preserve nested collection expression semantics - #5545

Closed
sunchao wants to merge 20 commits into
apache:mainfrom
sunchao:fix/issue-5544-collections-20260829
Closed

fix: preserve nested collection expression semantics#5545
sunchao wants to merge 20 commits into
apache:mainfrom
sunchao:fix/issue-5544-collections-20260829

Conversation

@sunchao

@sunchao sunchao commented Aug 29, 2026

Copy link
Copy Markdown
Member

Which issue does this PR close?

Closes #5544.

This is a draft follow-up to #5452 and leaves that PR unchanged, following the agreement to address the remaining cases separately. It depends on #5452: the current main-based diff temporarily includes that PR's unmerged changes. The intended follow-up is these three fix commits. They need to be rebased onto main after #5452 merges and validated again before this draft is marked ready.

Rationale for this change

The remaining cases in #5544 can return incorrect stateful lookup or collation results, evaluate a throwing key for a null collection, or fail because a constructed array's nested type differs from its declared result type. They require coverage beyond the existing SQL fixtures, which disable constant folding and normally run without ANSI mode.

What changes are included in this PR?

  • Evaluate native map/array lookup inputs once, from left to right, and evaluate keys or indices only for non-null collections. This removes the Scala ANSI guard that duplicated stateful operands and covers bracket lookup and try_element_at as well as ordinary element_at.
  • Send collated array_contains comparisons through Spark codegen, including nested arrays/structs and mixed collated-string/floating-point values. allowIncompatible=true does not bypass the collation safeguard.
  • Keep the common nullable child type needed during array construction, then restore the declared nested element type before downstream slice or conditional expressions consume it. Retain ArrayInsert's separate result-type normalization.

The fixes are separate commits (f6057825c, 6ce68f786, and 732e7acfc). The branch also merges main at 98cd8c967, preserving its unconditional aggregate-nullability normalization when resolving the planner conflict.

How are these changes tested?

Added native and Spark regression coverage for null/empty/scalar collections, selected stateful evaluation across batches, throwing keys, folded map literals, nested collations, and all-true/all-false/mixed conditional batches. Stateful Spark fixtures use one small ordered Parquet input so both rows exercise the same batch.

Local validation on the combined branch, using Spark 4.1.3, JDK 17, and the rebuilt native development library:

  • 23 native tests: 12 lookup tests, 3 aggregate-nullability tests, and 8 remote-shuffle schema tests.
  • 214 tests across the complete Array/Map expression suites and both TPC-DS plan-stability suites.
  • All 14 original reproductions and controls, including the seven previously failing variants.
  • All 12 changed SQL fixture runs, 5 nested-cast matrix tests, and 2 cache complex-type round trips.
  • Rust formatting, workspace Clippy with warnings denied, Maven Spotless, suite registration, and whitespace checks pass.

Native code was built before the root-reactor JVM tests; the tests used current compiled sources without serializer overlays. This is 270 focused local checks, not a full-project, release-profile, cross-Spark-version, or live Celeborn cluster run. Hosted CI is checked separately.

comphead and others added 20 commits August 24, 2026 10:22
Evaluate the collection once and evaluate the key only for non-null rows.
This covers element_at, bracket lookup, and try_element_at in both ANSI
modes without duplicating stateful operands through a CASE expression.

Keep the existing map lookup and type coercion, preserve scalar
broadcasting, and mask null-map rows. Add native and Spark regressions for
throwing keys, stateful operands, null inputs, and batch shape.
Dispatch collated array_contains operands through Spark codegen, including
nested arrays and structs. Check collations before floating-point opt-in
so allowIncompatible cannot select a kernel that loses string collation.

Cover folded integer-key maps with collated values, case-sensitive
controls, nulls, nested values, and both compatibility settings. Update
collated-key membership coverage to expect the safe codegen path.
Keep deeply nullable children while constructing an array, then restore
its declared nested element type. This prevents metadata widening from
breaking downstream slice and conditional expressions.

Cover folded and dynamic map arrays and conditional branches on all-true,
all-false, and mixed batches. Retain ArrayInsert's separate result-type
normalization and refresh its comments.
Include a NULL array element so Spark 3.4, 3.5, and 4.0 retain the nullable
result of element_at for a NULL array in ANSI mode. The stateful index still
distinguishes lazy evaluation: eager evaluation selects the NULL second
element rather than 7.
@sunchao sunchao closed this Aug 29, 2026
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.

Fix remaining reported issues for arrays of map

2 participants