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

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 84688d6d81 test(arrow-select): additional tests for inline-view filter 
fast path (tests for #9755) (#10054)
84688d6d81 is described below

commit 84688d6d81a9adac624c8470cc3359308c9c6c57
Author: Andrew Lamb <[email protected]>
AuthorDate: Tue Jun 23 14:13:26 2026 -0400

    test(arrow-select): additional tests for inline-view filter fast path 
(tests for #9755) (#10054)
    
    # Which issue does this PR close?
    
    - Follow-up / test coverage for #9755
    
    # Rationale for this change
    
    While reviewing #9755 I found, via `cargo llvm-cov`, there are some
    uncovered code paths (for very sparse filters as well as for outputting
    intermediate blocks)
    
    
    # What changes are included in this PR?
    
    * Add tests with  5% selectivity filters
    * Add test case whose buffered rows cross `target_batch_size` forcing a
    flush
    
    # Are there any user-facing changes?
    
    No. This is test only
---
 arrow-select/src/coalesce.rs | 131 +++++++++++++++++++++++++++++++++++++++----
 1 file changed, 119 insertions(+), 12 deletions(-)

diff --git a/arrow-select/src/coalesce.rs b/arrow-select/src/coalesce.rs
index 0d5199941f..0f1086be82 100644
--- a/arrow-select/src/coalesce.rs
+++ b/arrow-select/src/coalesce.rs
@@ -1458,28 +1458,101 @@ mod tests {
     }
 
     #[test]
-    fn test_mixed_boolean_inline_string_view_filtered() {
-        let bool_values = BooleanArray::from_iter((0..1000).map(|v| Some(v % 3 
== 0)));
+    fn test_inline_binary_view_sparse() {
+        // All-inline binary views (<=12 bytes) + 5% selectivity
+        let values: Vec<Option<&[u8]>> = vec![Some(b"foo"), None, 
Some(b"barbaz")];
+        let binary_view =
+            
BinaryViewArray::from_iter(std::iter::repeat(values.iter()).flatten().take(1000));
+        let batch =
+            RecordBatch::try_from_iter(vec![("c0", Arc::new(binary_view) as 
ArrayRef)]).unwrap();
+        let filter = very_sparse_filter(1000);
+
+        Test::new("inline_binary_view_sparse")
+            .with_batch(batch.clone())
+            .with_filter(filter.clone())
+            .with_batch(batch)
+            .with_filter(filter)
+            .with_batch_size(1024)
+            .with_expected_output_sizes(vec![100])
+            .run();
+    }
+
+    #[test]
+    fn test_inline_string_view_sparse() {
+        let values: Vec<Option<&str>> = vec![Some("foo"), None, 
Some("barbaz")];
+        let string_view =
+            
StringViewArray::from_iter(std::iter::repeat(values.iter()).flatten().take(1000));
+        let batch =
+            RecordBatch::try_from_iter(vec![("c0", Arc::new(string_view) as 
ArrayRef)]).unwrap();
+        let filter = very_sparse_filter(1000);
+
+        Test::new("inline_string_view_sparse")
+            .with_batch(batch.clone())
+            .with_filter(filter.clone())
+            .with_batch(batch)
+            .with_filter(filter)
+            .with_batch_size(1024)
+            .with_expected_output_sizes(vec![100])
+            .run();
+    }
+
+    #[test]
+    fn test_inline_mixed_sparse() {
+        // Mixing primitives with inline views exercises materialized `Indices`
+        // selection for both the primitive and the byte-view.
+        let int_values =
+            Int32Array::from_iter((0..1000).map(|v| if v % 5 == 0 { None } 
else { Some(v) }));
+        let float_values = 
arrow_array::Float64Array::from_iter((0..1000).map(|v| Some(v as f64)));
         let string_values: Vec<Option<&str>> = vec![Some("foo"), None, 
Some("barbaz")];
         let string_view = StringViewArray::from_iter(
             std::iter::repeat(string_values.iter()).flatten().take(1000),
         );
+        let binary_values: Vec<Option<&[u8]>> = vec![Some(b"x"), None, 
Some(b"abcdef")];
+        let binary_view = BinaryViewArray::from_iter(
+            std::iter::repeat(binary_values.iter()).flatten().take(1000),
+        );
 
         let batch = RecordBatch::try_from_iter(vec![
-            ("b", Arc::new(bool_values) as ArrayRef),
+            ("i", Arc::new(int_values) as ArrayRef),
+            ("f", Arc::new(float_values) as ArrayRef),
             ("s", Arc::new(string_view) as ArrayRef),
+            ("b", Arc::new(binary_view) as ArrayRef),
         ])
         .unwrap();
+        let filter = very_sparse_filter(1000);
 
-        let filter = sparse_filter(1000);
-
-        Test::new("coalesce_mixed_boolean_inline_string_view_filtered")
+        Test::new("inline_mixed_sparse")
             .with_batch(batch.clone())
             .with_filter(filter.clone())
             .with_batch(batch)
             .with_filter(filter)
-            .with_batch_size(300)
-            .with_expected_output_sizes(vec![250])
+            .with_batch_size(1024)
+            .with_expected_output_sizes(vec![100])
+            .run();
+    }
+
+    #[test]
+    fn test_inline_crosses_target_batch_size() {
+        // Each 1000-row batch selects 50 rows; target_batch_size 100
+        // exercises intermediate batch flushing batch (not just the final
+        // flush).
+        let values: Vec<Option<&[u8]>> = vec![Some(b"foo"), None, 
Some(b"barbaz")];
+        let make_batch = || {
+            let binary_view =
+                
BinaryViewArray::from_iter(std::iter::repeat(values.iter()).flatten().take(1000));
+            RecordBatch::try_from_iter(vec![("c0", Arc::new(binary_view) as 
ArrayRef)]).unwrap()
+        };
+        let filter = very_sparse_filter(1000);
+
+        Test::new("inline_crosses_target_batch_size")
+            .with_batch(make_batch())
+            .with_filter(filter.clone())
+            .with_batch(make_batch())
+            .with_filter(filter.clone())
+            .with_batch(make_batch())
+            .with_filter(filter)
+            .with_batch_size(100)
+            .with_expected_output_sizes(vec![100, 50])
             .run();
     }
 
@@ -1501,6 +1574,32 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_mixed_boolean_inline_string_view_filtered() {
+        let bool_values = BooleanArray::from_iter((0..1000).map(|v| Some(v % 3 
== 0)));
+        let string_values: Vec<Option<&str>> = vec![Some("foo"), None, 
Some("barbaz")];
+        let string_view = StringViewArray::from_iter(
+            std::iter::repeat(string_values.iter()).flatten().take(1000),
+        );
+
+        let batch = RecordBatch::try_from_iter(vec![
+            ("b", Arc::new(bool_values) as ArrayRef),
+            ("s", Arc::new(string_view) as ArrayRef),
+        ])
+        .unwrap();
+
+        let filter = sparse_filter(1000);
+
+        Test::new("coalesce_mixed_boolean_inline_string_view_filtered")
+            .with_batch(batch.clone())
+            .with_filter(filter.clone())
+            .with_batch(batch)
+            .with_filter(filter)
+            .with_batch_size(300)
+            .with_expected_output_sizes(vec![250])
+            .run();
+    }
+
     #[test]
     fn test_filter_fast_path_schema_capability() {
         let supported = Arc::new(Schema::new(vec![
@@ -2012,10 +2111,6 @@ mod tests {
         }
     }
 
-    fn sparse_filter(len: usize) -> BooleanArray {
-        BooleanArray::from_iter((0..len).map(|idx| Some(idx % 8 == 0)))
-    }
-
     /// Returns the named column as a StringViewArray
     fn col_as_string_view<'b>(name: &str, batch: &'b RecordBatch) -> &'b 
StringViewArray {
         batch
@@ -2025,6 +2120,18 @@ mod tests {
             .expect("column is not a string view")
     }
 
+    /// Filter that selects 12.5% of the rows (`idx % 8 == 0`)
+    fn sparse_filter(len: usize) -> BooleanArray {
+        BooleanArray::from_iter((0..len).map(|idx| Some(idx % 8 == 0)))
+    }
+
+    /// Filter that selects 5% of the rows (`idx % 20 == 0`)
+    ///
+    /// Different code paths are taken for very sparse filters
+    fn very_sparse_filter(len: usize) -> BooleanArray {
+        BooleanArray::from_iter((0..len).map(|idx| Some(idx % 20 == 0)))
+    }
+
     /// Normalize the `RecordBatch` so that the memory layout is consistent
     /// (e.g. StringArray is compacted).
     fn normalize_batch(batch: RecordBatch) -> RecordBatch {

Reply via email to