This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/asf-site by this push:
new 15bf3a358d Publish built docs triggered by
8c478e945274086edf13ea3cab89670b6368938f
15bf3a358d is described below
commit 15bf3a358d4fa5d07b5a01cdf29a4ed7e3083289
Author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Feb 3 02:23:55 2026 +0000
Publish built docs triggered by 8c478e945274086edf13ea3cab89670b6368938f
---
_sources/library-user-guide/upgrading.md.txt | 91 ++++++++++++++++++++++++++++
library-user-guide/upgrading.html | 71 ++++++++++++++++++++++
searchindex.js | 2 +-
3 files changed, 163 insertions(+), 1 deletion(-)
diff --git a/_sources/library-user-guide/upgrading.md.txt
b/_sources/library-user-guide/upgrading.md.txt
index f5c4fc0921..182f2f0ef9 100644
--- a/_sources/library-user-guide/upgrading.md.txt
+++ b/_sources/library-user-guide/upgrading.md.txt
@@ -156,6 +156,97 @@ let context = SimplifyContext::default()
See [`SimplifyContext`
documentation](https://docs.rs/datafusion-expr/latest/datafusion_expr/simplify/struct.SimplifyContext.html)
for more details.
+### Struct Casting Now Requires Field Name Overlap
+
+DataFusion's struct casting mechanism previously allowed casting between
structs with differing field names if the field counts matched. This
"positional fallback" behavior could silently misalign fields and cause data
corruption.
+
+**Breaking Change:**
+
+Starting with DataFusion 53.0.0, struct casts now require **at least one
overlapping field name** between the source and target structs. Casts without
field name overlap are rejected at plan time with a clear error message.
+
+**Who is affected:**
+
+- Applications that cast between structs with no overlapping field names
+- Queries that rely on positional struct field mapping (e.g., casting
`struct(x, y)` to `struct(a, b)` based solely on position)
+- Code that constructs or transforms struct columns programmatically
+
+**Migration guide:**
+
+If you encounter an error like:
+
+```text
+Cannot cast struct with 2 fields to 2 fields because there is no field name
overlap
+```
+
+You must explicitly rename or map fields to ensure at least one field name
matches. Here are common patterns:
+
+**Example 1: Source and target field names already match (Name-based casting)**
+
+**Success case (field names align):**
+
+```sql
+-- source_col has schema: STRUCT<x INT, y INT>
+-- Casting to the same field names succeeds (no-op or type validation only)
+SELECT CAST(source_col AS STRUCT<x INT, y INT>) FROM table1;
+```
+
+**Example 2: Source and target field names differ (Migration scenario)**
+
+**What fails now (no field name overlap):**
+
+```sql
+-- source_col has schema: STRUCT<a INT, b INT>
+-- This FAILS because there is no field name overlap:
+-- ❌ SELECT CAST(source_col AS STRUCT<x INT, y INT>) FROM table1;
+-- Error: Cannot cast struct with 2 fields to 2 fields because there is no
field name overlap
+```
+
+**Migration options (must align names):**
+
+**Option A: Use struct constructor for explicit field mapping**
+
+```sql
+-- source_col has schema: STRUCT<a INT, b INT>
+-- Use STRUCT_CONSTRUCT with explicit field names
+SELECT STRUCT_CONSTRUCT(
+ 'x', source_col.a,
+ 'y', source_col.b
+) AS renamed_struct FROM table1;
+```
+
+**Option B: Rename in the cast target to match source names**
+
+```sql
+-- source_col has schema: STRUCT<a INT, b INT>
+-- Cast to target with matching field names
+SELECT CAST(source_col AS STRUCT<a INT, b INT>) FROM table1;
+```
+
+**Example 3: Using struct constructors in Rust API**
+
+If you need to map fields programmatically, build the target struct explicitly:
+
+```rust,ignore
+// Build the target struct with explicit field names
+let target_struct_type = DataType::Struct(vec![
+ FieldRef::new("x", DataType::Int32),
+ FieldRef::new("y", DataType::Utf8),
+]);
+
+// Use struct constructors rather than casting for field mapping
+// This makes the field mapping explicit and unambiguous
+// Use struct builders or row constructors that preserve your mapping logic
+```
+
+**Why this change:**
+
+1. **Safety:** Field names are now the primary contract for struct
compatibility
+2. **Explicitness:** Prevents silent data misalignment caused by positional
assumptions
+3. **Consistency:** Matches DuckDB's behavior and aligns with other SQL
engines that enforce name-based matching
+4. **Debuggability:** Errors now appear at plan time rather than as silent
data corruption
+
+See [Issue #19841](https://github.com/apache/datafusion/issues/19841) and [PR
#19955](https://github.com/apache/datafusion/pull/19955) for more details.
+
### `FilterExec` builder methods deprecated
The following methods on `FilterExec` have been deprecated in favor of using
`FilterExecBuilder`:
diff --git a/library-user-guide/upgrading.html
b/library-user-guide/upgrading.html
index 13dc0af168..e79e507df1 100644
--- a/library-user-guide/upgrading.html
+++ b/library-user-guide/upgrading.html
@@ -519,6 +519,76 @@ literals must initialize this field.</p>
</div>
<p>See <a class="reference external"
href="https://docs.rs/datafusion-expr/latest/datafusion_expr/simplify/struct.SimplifyContext.html"><code
class="docutils literal notranslate"><span
class="pre">SimplifyContext</span></code> documentation</a> for more
details.</p>
</section>
+<section id="struct-casting-now-requires-field-name-overlap">
+<h3>Struct Casting Now Requires Field Name Overlap<a class="headerlink"
href="#struct-casting-now-requires-field-name-overlap" title="Link to this
heading">#</a></h3>
+<p>DataFusion’s struct casting mechanism previously allowed casting between
structs with differing field names if the field counts matched. This
“positional fallback” behavior could silently misalign fields and cause data
corruption.</p>
+<p><strong>Breaking Change:</strong></p>
+<p>Starting with DataFusion 53.0.0, struct casts now require <strong>at least
one overlapping field name</strong> between the source and target structs.
Casts without field name overlap are rejected at plan time with a clear error
message.</p>
+<p><strong>Who is affected:</strong></p>
+<ul class="simple">
+<li><p>Applications that cast between structs with no overlapping field
names</p></li>
+<li><p>Queries that rely on positional struct field mapping (e.g., casting
<code class="docutils literal notranslate"><span class="pre">struct(x,</span>
<span class="pre">y)</span></code> to <code class="docutils literal
notranslate"><span class="pre">struct(a,</span> <span
class="pre">b)</span></code> based solely on position)</p></li>
+<li><p>Code that constructs or transforms struct columns
programmatically</p></li>
+</ul>
+<p><strong>Migration guide:</strong></p>
+<p>If you encounter an error like:</p>
+<div class="highlight-text notranslate"><div
class="highlight"><pre><span></span>Cannot cast struct with 2 fields to 2
fields because there is no field name overlap
+</pre></div>
+</div>
+<p>You must explicitly rename or map fields to ensure at least one field name
matches. Here are common patterns:</p>
+<p><strong>Example 1: Source and target field names already match (Name-based
casting)</strong></p>
+<p><strong>Success case (field names align):</strong></p>
+<div class="highlight-sql notranslate"><div
class="highlight"><pre><span></span><span class="c1">-- source_col has schema:
STRUCT<x INT, y INT></span>
+<span class="c1">-- Casting to the same field names succeeds (no-op or type
validation only)</span>
+<span class="k">SELECT</span><span class="w"> </span><span
class="k">CAST</span><span class="p">(</span><span
class="n">source_col</span><span class="w"> </span><span
class="k">AS</span><span class="w"> </span><span class="n">STRUCT</span><span
class="o"><</span><span class="n">x</span><span class="w"> </span><span
class="nb">INT</span><span class="p">,</span><span class="w"> </span><span
class="n">y</span><span class="w"> </span><span class="nb">INT</span><span
class="o">></span>< [...]
+</pre></div>
+</div>
+<p><strong>Example 2: Source and target field names differ (Migration
scenario)</strong></p>
+<p><strong>What fails now (no field name overlap):</strong></p>
+<div class="highlight-sql notranslate"><div
class="highlight"><pre><span></span><span class="c1">-- source_col has schema:
STRUCT<a INT, b INT></span>
+<span class="c1">-- This FAILS because there is no field name overlap:</span>
+<span class="c1">-- ❌ SELECT CAST(source_col AS STRUCT<x INT, y INT>)
FROM table1;</span>
+<span class="c1">-- Error: Cannot cast struct with 2 fields to 2 fields
because there is no field name overlap</span>
+</pre></div>
+</div>
+<p><strong>Migration options (must align names):</strong></p>
+<p><strong>Option A: Use struct constructor for explicit field
mapping</strong></p>
+<div class="highlight-sql notranslate"><div
class="highlight"><pre><span></span><span class="c1">-- source_col has schema:
STRUCT<a INT, b INT></span>
+<span class="c1">-- Use STRUCT_CONSTRUCT with explicit field names</span>
+<span class="k">SELECT</span><span class="w"> </span><span
class="n">STRUCT_CONSTRUCT</span><span class="p">(</span>
+<span class="w"> </span><span class="s1">'x'</span><span
class="p">,</span><span class="w"> </span><span
class="n">source_col</span><span class="p">.</span><span
class="n">a</span><span class="p">,</span>
+<span class="w"> </span><span class="s1">'y'</span><span
class="p">,</span><span class="w"> </span><span
class="n">source_col</span><span class="p">.</span><span class="n">b</span>
+<span class="p">)</span><span class="w"> </span><span class="k">AS</span><span
class="w"> </span><span class="n">renamed_struct</span><span class="w">
</span><span class="k">FROM</span><span class="w"> </span><span
class="n">table1</span><span class="p">;</span>
+</pre></div>
+</div>
+<p><strong>Option B: Rename in the cast target to match source
names</strong></p>
+<div class="highlight-sql notranslate"><div
class="highlight"><pre><span></span><span class="c1">-- source_col has schema:
STRUCT<a INT, b INT></span>
+<span class="c1">-- Cast to target with matching field names</span>
+<span class="k">SELECT</span><span class="w"> </span><span
class="k">CAST</span><span class="p">(</span><span
class="n">source_col</span><span class="w"> </span><span
class="k">AS</span><span class="w"> </span><span class="n">STRUCT</span><span
class="o"><</span><span class="n">a</span><span class="w"> </span><span
class="nb">INT</span><span class="p">,</span><span class="w"> </span><span
class="n">b</span><span class="w"> </span><span class="nb">INT</span><span
class="o">></span>< [...]
+</pre></div>
+</div>
+<p><strong>Example 3: Using struct constructors in Rust API</strong></p>
+<p>If you need to map fields programmatically, build the target struct
explicitly:</p>
+<div class="highlight-rust notranslate"><div
class="highlight"><pre><span></span><span class="c1">// Build the target struct
with explicit field names</span>
+<span class="kd">let</span><span class="w"> </span><span
class="n">target_struct_type</span><span class="w"> </span><span
class="o">=</span><span class="w"> </span><span class="n">DataType</span><span
class="p">::</span><span class="n">Struct</span><span class="p">(</span><span
class="fm">vec!</span><span class="p">[</span>
+<span class="w"> </span><span class="n">FieldRef</span><span
class="p">::</span><span class="n">new</span><span class="p">(</span><span
class="s">"x"</span><span class="p">,</span><span class="w">
</span><span class="n">DataType</span><span class="p">::</span><span
class="n">Int32</span><span class="p">),</span>
+<span class="w"> </span><span class="n">FieldRef</span><span
class="p">::</span><span class="n">new</span><span class="p">(</span><span
class="s">"y"</span><span class="p">,</span><span class="w">
</span><span class="n">DataType</span><span class="p">::</span><span
class="n">Utf8</span><span class="p">),</span>
+<span class="p">]);</span>
+
+<span class="c1">// Use struct constructors rather than casting for field
mapping</span>
+<span class="c1">// This makes the field mapping explicit and
unambiguous</span>
+<span class="c1">// Use struct builders or row constructors that preserve your
mapping logic</span>
+</pre></div>
+</div>
+<p><strong>Why this change:</strong></p>
+<ol class="arabic simple">
+<li><p><strong>Safety:</strong> Field names are now the primary contract for
struct compatibility</p></li>
+<li><p><strong>Explicitness:</strong> Prevents silent data misalignment caused
by positional assumptions</p></li>
+<li><p><strong>Consistency:</strong> Matches DuckDB’s behavior and aligns with
other SQL engines that enforce name-based matching</p></li>
+<li><p><strong>Debuggability:</strong> Errors now appear at plan time rather
than as silent data corruption</p></li>
+</ol>
+<p>See <a class="reference external"
href="https://github.com/apache/datafusion/issues/19841">Issue #19841</a> and
<a class="reference external"
href="https://github.com/apache/datafusion/pull/19955">PR #19955</a> for more
details.</p>
+</section>
<section id="filterexec-builder-methods-deprecated">
<h3><code class="docutils literal notranslate"><span
class="pre">FilterExec</span></code> builder methods deprecated<a
class="headerlink" href="#filterexec-builder-methods-deprecated" title="Link to
this heading">#</a></h3>
<p>The following methods on <code class="docutils literal notranslate"><span
class="pre">FilterExec</span></code> have been deprecated in favor of using
<code class="docutils literal notranslate"><span
class="pre">FilterExecBuilder</span></code>:</p>
@@ -2339,6 +2409,7 @@ take care of constructing the <code class="docutils
literal notranslate"><span c
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link"
href="#datafusion-53-0-0">DataFusion <code class="docutils literal
notranslate"><span class="pre">53.0.0</span></code></a><ul class="nav
section-nav flex-column">
<li class="toc-h3 nav-item toc-entry"><a class="reference internal nav-link"
href="#filesinkconfig-adds-file-output-mode"><code class="docutils literal
notranslate"><span class="pre">FileSinkConfig</span></code> adds <code
class="docutils literal notranslate"><span
class="pre">file_output_mode</span></code></a></li>
<li class="toc-h3 nav-item toc-entry"><a class="reference internal nav-link"
href="#simplifyinfo-trait-removed-simplifycontext-now-uses-builder-style-api"><code
class="docutils literal notranslate"><span
class="pre">SimplifyInfo</span></code> trait removed, <code class="docutils
literal notranslate"><span class="pre">SimplifyContext</span></code> now uses
builder-style API</a></li>
+<li class="toc-h3 nav-item toc-entry"><a class="reference internal nav-link"
href="#struct-casting-now-requires-field-name-overlap">Struct Casting Now
Requires Field Name Overlap</a></li>
<li class="toc-h3 nav-item toc-entry"><a class="reference internal nav-link"
href="#filterexec-builder-methods-deprecated"><code class="docutils literal
notranslate"><span class="pre">FilterExec</span></code> builder methods
deprecated</a></li>
<li class="toc-h3 nav-item toc-entry"><a class="reference internal nav-link"
href="#protobuf-conversion-trait-added">Protobuf conversion trait added</a></li>
<li class="toc-h3 nav-item toc-entry"><a class="reference internal nav-link"
href="#generate-series-and-range-table-functions-changed"><code class="docutils
literal notranslate"><span class="pre">generate_series</span></code> and <code
class="docutils literal notranslate"><span class="pre">range</span></code>
table functions changed</a></li>
diff --git a/searchindex.js b/searchindex.js
index cea0434dcb..dc74a6873b 100644
--- a/searchindex.js
+++ b/searchindex.js
@@ -1 +1 @@
-Search.setIndex({"alltitles":{"!=":[[62,"op-neq"]],"!~":[[62,"op-re-not-match"]],"!~*":[[62,"op-re-not-match-i"]],"!~~":[[62,"id19"]],"!~~*":[[62,"id20"]],"#":[[62,"op-bit-xor"]],"%":[[62,"op-modulo"]],"&":[[62,"op-bit-and"]],"(relation,
name) tuples in logical fields and logical columns are
unique":[[14,"relation-name-tuples-in-logical-fields-and-logical-columns-are-unique"]],"*":[[62,"op-multiply"]],"+":[[62,"op-plus"]],"-":[[62,"op-minus"]],"/":[[62,"op-divide"]],"1.
Array Literal Con [...]
\ No newline at end of file
+Search.setIndex({"alltitles":{"!=":[[62,"op-neq"]],"!~":[[62,"op-re-not-match"]],"!~*":[[62,"op-re-not-match-i"]],"!~~":[[62,"id19"]],"!~~*":[[62,"id20"]],"#":[[62,"op-bit-xor"]],"%":[[62,"op-modulo"]],"&":[[62,"op-bit-and"]],"(relation,
name) tuples in logical fields and logical columns are
unique":[[14,"relation-name-tuples-in-logical-fields-and-logical-columns-are-unique"]],"*":[[62,"op-multiply"]],"+":[[62,"op-plus"]],"-":[[62,"op-minus"]],"/":[[62,"op-divide"]],"1.
Array Literal Con [...]
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]