PG1204 opened a new pull request, #23521:
URL: https://github.com/apache/datafusion/pull/23521
## Which issue does this PR close?
- Closes #23474.
## Rationale for this change
A bare `MAP {'k1': NULL}` literal infers a `Null` value type, producing
`Map("entries": Struct("key": Utf8, "value": Null))`. Placing it in a VALUES
list alongside concretely-typed map rows failed with:
Error during planning: Inconsistent data type across values list at row 1
column 0.
This is because `type_union_resolution_coercion` (the pairwise worker behind
`type_union_resolution`, which the VALUES builder uses to widen row types) had
recursion arms for `Dictionary`, `RunEndEncoded`, `Struct`, and `List` (via
`list_coercion`), but none for `Map`. Scalar NULL inference across a VALUES
list (`VALUES (1), (NULL)`) already worked; the same inference just never
reached into a map's value type. This gap was noted in #23406, where the tests
had to use a `CAST(NULL AS BIGINT)` workaround.
## What changes are included in this PR?
- A one-line fix in `datafusion/expr-common/src/type_coercion/binary.rs`:
wire the existing `map_coercion` helper (already used by `comparison_coercion`
and `type_union_coercion`) into `type_union_resolution_coercion`'s fallback
chain. The recursion into the map's key/value types then applies the exact same
rules as scalar VALUES coercion (`null_coercion` for NULL inference,
`binary_numeric_coercion` for numeric widening), symmetrically in either row
order.
- A unit test (`test_type_union_resolution_map`) covering Null + Int64 value
types in both orders, Int64 + Null + Float64 widening, and Map vs. Struct still
refusing to unify.
- A new "map NULL value coercion in VALUES" section in
`datafusion/sqllogictest/test_files/map.slt` covering: the issue reproducer,
the reversed row order, all-NULL values (resulting type `Map("entries":
Struct("key": Utf8, "value": Null))`, verified via `arrow_typeof`), multi-key
rows with one NULL value, NULL scattered across three rows, numeric widening to
Float64, two-level nested maps, NULL round-tripping as NULL through `SELECT`,
and `INSERT INTO ... VALUES`.
- Incompatible concrete value types still error: `(MAP {'k': 1}), (MAP {'k':
'hello'})` follows the scalar VALUES rule (coerce to the numeric type, then
fail with `Cast error: Cannot cast string 'hello' to value of Int64 type`,
which is the same behavior as `VALUES (1), ('hello')`).
- A note above the #23406 tests documenting that the `CAST(NULL AS BIGINT)`
workaround is no longer required (those tests are left unchanged).
## Are these changes tested?
Yes. New unit test in `datafusion-expr-common` and new sqllogictests in
`map.slt` as described above. The full sqllogictest suite (492 files) passes
locally with zero regressions, as do `cargo test -p datafusion-expr -p
datafusion-expr-common`, `cargo fmt`, and `cargo clippy --workspace
--all-targets -- -D warnings`.
## Are there any user-facing changes?
`VALUES` lists (and other contexts that use `type_union_resolution`, such as
`CASE`/`COALESCE`/array literals) now unify Map types whose key/value types are
coercible, including bare NULL map values. No API changes; previously failing
queries now succeed, and incompatible-type errors are preserved.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]