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

JingsongLi 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 10bf6c5f fix(c): align append vector filter with core behavior (#793)
10bf6c5f is described below

commit 10bf6c5fe29d9b4bb74cdb6b6d1acdf94911261c
Author: QuakeWang <[email protected]>
AuthorDate: Fri Sep 11 14:21:13 2026 +0800

    fix(c): align append vector filter with core behavior (#793)
---
 bindings/c/src/tests.rs         | 54 ++++++++++++++++++++++++++---------------
 bindings/c/src/vector_search.rs |  5 +++-
 2 files changed, 39 insertions(+), 20 deletions(-)

diff --git a/bindings/c/src/tests.rs b/bindings/c/src/tests.rs
index 31b62de2..6cf7bdb4 100644
--- a/bindings/c/src/tests.rs
+++ b/bindings/c/src/tests.rs
@@ -3263,32 +3263,48 @@ fn vector_search_pk_filter_excludes_neighbor() {
 }
 
 #[test]
-fn vector_search_append_filter_returns_invalid_input() {
-    let path = "memory:/vsearch_append_filter_err";
+fn vector_search_append_filter_matches_rust() {
+    let path = "memory:/vsearch_append_filter_read";
     let table = build_append_vector_table(path);
+    let query = [1.0f32, 0.0];
+    let limit = 3;
+
+    let unfiltered = rust_execute_read_pairs(&table, "embedding", 
query.to_vec(), limit, None);
+    assert!(
+        unfiltered.iter().any(|(id, _)| *id == 0),
+        "fixture must include the filtered nearest neighbor in the unfiltered 
Top-K"
+    );
+
+    let rust_filter = PredicateBuilder::new(table.schema().fields())
+        .greater_or_equal("id", Datum::Int(1))
+        .unwrap();
+    let rust_pairs = rust_execute_read_pairs(
+        &table,
+        "embedding",
+        query.to_vec(),
+        limit,
+        Some(rust_filter),
+    );
+    assert_eq!(
+        rust_pairs.len(),
+        limit,
+        "filter-before-Top-K must refill the result after excluding id 0"
+    );
+    assert!(
+        rust_pairs.iter().all(|(id, _)| *id >= 1),
+        "Rust core returned a row excluded by the filter"
+    );
+
     let handle = unsafe { wrap_table(table) };
     unsafe {
         let predicate = build_predicate_ge(handle, "id", 1);
-        let builder = c_vector_builder(handle, "embedding", &[1.0f32, 0.0], 3, 
predicate);
-        let result = paimon_vector_search_builder_execute_read(builder);
-        paimon_vector_search_builder_free(builder);
+        let builder = c_vector_builder(handle, "embedding", &query, limit, 
predicate);
+        let c_pairs = c_execute_read_pairs(builder);
 
-        assert!(
-            result.reader.is_null(),
-            "errored read must not yield a reader"
-        );
-        assert!(!result.error.is_null(), "DE filter must fail loud");
         assert_eq!(
-            (*result.error).code,
-            PaimonErrorCode::InvalidInput as i32,
-            "DE filter error must map to InvalidInput"
-        );
-        let message = error_message(result.error);
-        assert!(
-            message.contains("primary-key vector path"),
-            "unexpected error message: {message}"
+            c_pairs, rust_pairs,
+            "filtered C pairs must match the Rust core reference"
         );
-        paimon_error_free(result.error);
         unwrap_table(handle);
     }
 }
diff --git a/bindings/c/src/vector_search.rs b/bindings/c/src/vector_search.rs
index 80d79efe..f63e152d 100644
--- a/bindings/c/src/vector_search.rs
+++ b/bindings/c/src/vector_search.rs
@@ -185,7 +185,10 @@ pub unsafe extern "C" fn 
paimon_vector_search_builder_with_options(
     std::ptr::null_mut()
 }
 
-/// Set an optional scalar residual filter for a vector-search builder.
+/// Set an optional scalar predicate applied before vector Top-K.
+///
+/// The Rust core resolves the predicate to an allow-list for the selected
+/// primary-key or data-evolution/global-index search path.
 ///
 /// The predicate is consumed (ownership transferred to the builder). Pass null
 /// to clear any previously set filter.

Reply via email to