@@ -644,6 +644,10 @@ impl<'a> BatchVectorSearchBuilder<'a> {
644644 }
645645
646646 pub async fn execute ( & self ) -> crate :: Result < Vec < SearchResult > > {
647+ // Fail closed before validation and empty-table fast paths: batch search
648+ // returns data-derived results outside `TableScan`/`TableRead`.
649+ CoreOptions :: new ( self . table . schema ( ) . options ( ) ) . ensure_read_authorized ( ) ?;
650+
647651 let vector_column =
648652 self . vector_column
649653 . as_deref ( )
@@ -2364,6 +2368,55 @@ mod tests {
23642368 ) ;
23652369 }
23662370
2371+ #[ tokio:: test]
2372+ async fn test_batch_vector_search_auth_check_precedes_validation ( ) {
2373+ let table = crate :: table:: query_auth_table ( ) ;
2374+ let err = table
2375+ . new_batch_vector_search_builder ( )
2376+ . execute ( )
2377+ . await
2378+ . unwrap_err ( ) ;
2379+
2380+ assert ! (
2381+ matches!( err, crate :: Error :: Unsupported { ref message } if message. contains( "query-auth.enabled" ) ) ,
2382+ "batch vector search must check query auth before validating parameters"
2383+ ) ;
2384+ }
2385+
2386+ #[ tokio:: test]
2387+ async fn test_batch_vector_search_empty_table_fails_closed_when_query_auth_enabled ( ) {
2388+ let table = crate :: table:: query_auth_table ( ) ;
2389+ let err = table
2390+ . new_batch_vector_search_builder ( )
2391+ . with_vector_column ( "id" )
2392+ . with_query_vectors ( vec ! [ vec![ 1.0 ] ] )
2393+ . with_limit ( 1 )
2394+ . execute ( )
2395+ . await
2396+ . unwrap_err ( ) ;
2397+
2398+ assert ! (
2399+ matches!( err, crate :: Error :: Unsupported { ref message } if message. contains( "query-auth.enabled" ) ) ,
2400+ "batch vector search must fail closed before the empty-table fast path"
2401+ ) ;
2402+ }
2403+
2404+ #[ tokio:: test]
2405+ async fn test_batch_vector_search_empty_table_unchanged_without_query_auth ( ) {
2406+ let table = vector_test_table ( ) ;
2407+ let results = table
2408+ . new_batch_vector_search_builder ( )
2409+ . with_vector_column ( "embedding" )
2410+ . with_query_vectors ( vec ! [ vec![ 1.0 ] ] )
2411+ . with_limit ( 1 )
2412+ . execute ( )
2413+ . await
2414+ . unwrap ( ) ;
2415+
2416+ assert_eq ! ( results. len( ) , 1 ) ;
2417+ assert ! ( results[ 0 ] . is_empty( ) ) ;
2418+ }
2419+
23672420 #[ tokio:: test]
23682421 async fn test_batch_evaluate_no_matching_field_returns_empty_per_query ( ) {
23692422 let file_io = crate :: io:: FileIOBuilder :: new ( "memory" ) . build ( ) . unwrap ( ) ;
0 commit comments