This is an automated email from the ASF dual-hosted git repository.

jerry-024 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new 8c4c7943 datafusion: cast lateral vector search rows to provider 
schema (#781)
8c4c7943 is described below

commit 8c4c79434d823ab12967fe72764db0c746b53265
Author: shyjsarah <[email protected]>
AuthorDate: Wed Sep 2 14:47:13 2026 +0800

    datafusion: cast lateral vector search rows to provider schema (#781)
---
 .../datafusion/src/lateral_vector_search.rs        | 22 ++++++++++--
 .../integrations/datafusion/tests/read_tables.rs   | 42 ++++++++++++++++++++--
 2 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/crates/integrations/datafusion/src/lateral_vector_search.rs 
b/crates/integrations/datafusion/src/lateral_vector_search.rs
index 8e88c538..2500d8b5 100644
--- a/crates/integrations/datafusion/src/lateral_vector_search.rs
+++ b/crates/integrations/datafusion/src/lateral_vector_search.rs
@@ -31,6 +31,7 @@ use datafusion::arrow::array::{
     new_empty_array, Array, ArrayRef, FixedSizeListArray, Float32Array, 
Int64Array, ListArray,
     RecordBatch, UInt32Array,
 };
+use datafusion::arrow::compute::cast;
 use datafusion::arrow::datatypes::SchemaRef as ArrowSchemaRef;
 use datafusion::catalog::default_table_source::source_as_provider;
 use datafusion::common::stats::Precision;
@@ -1066,9 +1067,24 @@ async fn read_target_rows(
         row_id_to_index.insert(row_id, row as u32);
     }
 
-    let target_columns = (0..target_schema.fields().len())
-        .map(|index| Arc::clone(batch.column(index)))
-        .collect::<Vec<_>>();
+    // Paimon reads use storage Arrow types (for example `Utf8`), while the
+    // DataFusion provider schema may expose view types such as `Utf8View`.
+    let target_columns = target_schema
+        .fields()
+        .iter()
+        .map(|field| -> DFResult<ArrayRef> {
+            let index = batch
+                .schema()
+                .index_of(field.name())
+                .map_err(DataFusionError::from)?;
+            let column = batch.column(index);
+            if column.data_type() == field.data_type() {
+                Ok(Arc::clone(column))
+            } else {
+                cast(column.as_ref(), 
field.data_type()).map_err(DataFusionError::from)
+            }
+        })
+        .collect::<DFResult<Vec<_>>>()?;
     let target_batch = RecordBatch::try_new(target_schema.clone(), 
target_columns)
         .map_err(DataFusionError::from)?;
     Ok((target_batch, row_id_to_index))
diff --git a/crates/integrations/datafusion/tests/read_tables.rs 
b/crates/integrations/datafusion/tests/read_tables.rs
index 2226b18c..e2d9189b 100644
--- a/crates/integrations/datafusion/tests/read_tables.rs
+++ b/crates/integrations/datafusion/tests/read_tables.rs
@@ -2082,9 +2082,8 @@ mod vector_search_tests {
         assert_eq!(extract_ids_in_order(&limited), vec![2, 5]);
     }
 
-    /// Regression: a result containing a string column must not fail on the 
provider's
-    /// `Utf8View` schema vs the Paimon read's `Utf8` — the gather casts to 
the output
-    /// schema (the plain scan path did this via `to_datafusion_batch`).
+    /// Regression: direct and lateral vector search results containing a 
string column
+    /// must align the Paimon read's `Utf8` arrays with the provider's 
`Utf8View` schema.
     #[tokio::test]
     async fn test_vector_search_casts_string_column() {
         let (ctx, catalog, _tmp) = create_empty_vector_search_context().await;
@@ -2189,6 +2188,43 @@ mod vector_search_tests {
         let mut ids = extract_ids_in_order(&batches);
         ids.sort();
         assert_eq!(ids, vec![1, 2]);
+
+        let query_batch = build_vector_batch(vec![10], vec![vec![0.0, 1.0]]);
+        let query_table = MemTable::try_new(query_batch.schema(), 
vec![vec![query_batch]])
+            .expect("Failed to create query vector table");
+        ctx.register_temp_table("paimon.default.string_queries", 
Arc::new(query_table))
+            .expect("Failed to register query vector table");
+
+        let lateral_batches = ctx
+            .sql(
+                "SELECT r.id, r.name \
+                 FROM paimon.default.string_queries q \
+                 CROSS JOIN LATERAL vector_search( \
+                     'paimon.default.vindex_string_e2e', \
+                     'embedding', \
+                     q.embedding, \
+                     2 \
+                 ) AS r",
+            )
+            .await
+            .expect("lateral vector search SQL should parse")
+            .collect()
+            .await
+            .expect("lateral vector search with a string column should 
execute");
+        let mut lateral_ids = extract_ids_in_order(&lateral_batches);
+        lateral_ids.sort();
+        assert_eq!(lateral_ids, vec![1, 2]);
+        let mut lateral_names = lateral_batches
+            .iter()
+            .flat_map(|batch| {
+                let names = batch.column_by_name("name").expect("Expected name 
column");
+                (0..batch.num_rows())
+                    .map(|row| string_value(names.as_ref(), row).to_string())
+                    .collect::<Vec<_>>()
+            })
+            .collect::<Vec<_>>();
+        lateral_names.sort();
+        assert_eq!(lateral_names, vec!["one", "two"]);
     }
 
     #[tokio::test]

Reply via email to