@@ -22,7 +22,7 @@ use crate::{
2222 BaseValues , ContainerValues , ExternalFunctionId , WrappedTable ,
2323 common:: Value ,
2424 free_join:: { CounterId , Counters , ExternalFunctions , TableId , TableInfo , Variable } ,
25- pool:: { Clear , Pooled , with_pool_set} ,
25+ pool:: { Clear , Pool , Pooled , with_pool_set} ,
2626 table_spec:: { ColumnId , MutationBuffer } ,
2727} ;
2828
@@ -55,6 +55,12 @@ impl From<Value> for QueryEntry {
5555 }
5656}
5757
58+ #[ derive( Debug , Clone ) ]
59+ pub ( crate ) enum ArgBindings {
60+ Owned ( Vec < QueryEntry > ) ,
61+ BorrowedWindow { start : Variable , len : usize } ,
62+ }
63+
5864/// A value that can be written to a table in an action.
5965#[ derive( Debug , Clone , Copy ) ]
6066pub enum WriteVal {
@@ -279,6 +285,75 @@ impl Bindings {
279285 }
280286}
281287
288+ fn invoke_batch_from_args (
289+ this : & dyn crate :: free_join:: ExternalFunction ,
290+ state : & mut ExecutionState ,
291+ mask : & mut Mask ,
292+ bindings : & mut Bindings ,
293+ args : & ArgBindings ,
294+ out_var : Variable ,
295+ ) {
296+ match args {
297+ ArgBindings :: Owned ( args) => invoke_batch ( this, state, mask, bindings, args, out_var) ,
298+ ArgBindings :: BorrowedWindow { start, len } => {
299+ let pool: Pool < Vec < Value > > = with_pool_set ( |ps| ps. get_pool ( ) . clone ( ) ) ;
300+ let mut out = pool. get ( ) ;
301+ out. reserve ( mask. len ( ) ) ;
302+ let start_index = start. index ( ) ;
303+ let arity = * len;
304+ let iter = mask. iter_dynamic (
305+ with_pool_set ( crate :: pool:: PoolSet :: get_pool) ,
306+ ( 0 ..arity)
307+ . map ( |i| ValueSource :: Slice ( & bindings[ Variable :: from_usize ( start_index + i) ] ) ) ,
308+ ) ;
309+ iter. fill_vec ( & mut out, Value :: stale, |_, args| {
310+ this. invoke ( state, args. as_slice ( ) )
311+ } ) ;
312+ bindings. insert ( out_var, & out) ;
313+ }
314+ }
315+ }
316+
317+ fn invoke_batch_assign_from_args (
318+ this : & dyn crate :: free_join:: ExternalFunction ,
319+ state : & mut ExecutionState ,
320+ mask : & mut Mask ,
321+ bindings : & mut Bindings ,
322+ args : & ArgBindings ,
323+ out_var : Variable ,
324+ ) {
325+ match args {
326+ ArgBindings :: Owned ( args) => invoke_batch_assign ( this, state, mask, bindings, args, out_var) ,
327+ ArgBindings :: BorrowedWindow { start, len } => {
328+ let mut out = bindings. take ( out_var) . expect ( "out_var must be bound" ) ;
329+ let start_index = start. index ( ) ;
330+ let arity = * len;
331+ let iter = mask. iter_dynamic (
332+ with_pool_set ( crate :: pool:: PoolSet :: get_pool) ,
333+ ( 0 ..arity)
334+ . map ( |i| ValueSource :: Slice ( & bindings[ Variable :: from_usize ( start_index + i) ] ) ) ,
335+ ) ;
336+ iter. assign_vec_and_retain ( & mut out. vals , |_, args| this. invoke ( state, & args) ) ;
337+ bindings. replace ( out) ;
338+ }
339+ }
340+ }
341+
342+ fn single_external_borrowed_window (
343+ instrs : & [ Instr ] ,
344+ ) -> Option < ( ExternalFunctionId , Variable , usize , Variable ) > {
345+ match instrs {
346+ [
347+ Instr :: External {
348+ func,
349+ args : ArgBindings :: BorrowedWindow { start, len } ,
350+ dst,
351+ } ,
352+ ] => Some ( ( * func, * start, * len, * dst) ) ,
353+ _ => None ,
354+ }
355+ }
356+
282357/// A binding that has been extracted from a [`Bindings`] struct via the [`Bindings::take`] method.
283358///
284359/// This allows for a variable's contents to be read while the [`Bindings`] struct has been
@@ -603,6 +678,33 @@ impl ExecutionState<'_> {
603678 bindings. matches = 1 ;
604679 }
605680
681+ if let Some ( ( func, start, len, dst) ) = single_external_borrowed_window ( instrs) {
682+ let matches = bindings. matches ;
683+ let mut out: Pooled < Vec < Value > > = with_pool_set ( |ps| ps. get ( ) ) ;
684+ out. resize ( matches, Value :: stale ( ) ) ;
685+ let mut transposed: Pooled < Vec < Value > > = with_pool_set ( |ps| ps. get ( ) ) ;
686+ transposed. resize ( matches * len, Value :: stale ( ) ) ;
687+ let start_index = start. index ( ) ;
688+ let mut succeeded = 0usize ;
689+ for row in 0 ..matches {
690+ for col in 0 ..len {
691+ transposed[ row * len + col] =
692+ bindings[ Variable :: from_usize ( start_index + col) ] [ row] ;
693+ }
694+ if self . should_stop ( ) {
695+ break ;
696+ }
697+ if let Some ( value) =
698+ self . call_external_func ( func, & transposed[ row * len..( row + 1 ) * len] )
699+ {
700+ out[ row] = value;
701+ succeeded += 1 ;
702+ }
703+ }
704+ bindings. insert ( dst, & out) ;
705+ return succeeded;
706+ }
707+
606708 // Vectorized execution for larger batch sizes
607709 let mut mask = with_pool_set ( |ps| Mask :: new ( 0 ..bindings. matches , ps) ) ;
608710 for instr in instrs {
@@ -758,7 +860,7 @@ impl ExecutionState<'_> {
758860 }
759861
760862 // Call the given external function on all entries where the lookup failed.
761- invoke_batch_assign (
863+ invoke_batch_assign_from_args (
762864 self . db . external_funcs [ * func] . as_ref ( ) ,
763865 self ,
764866 & mut to_call_func,
@@ -817,7 +919,7 @@ impl ExecutionState<'_> {
817919 } ) ;
818920 }
819921 Instr :: External { func, args, dst } => {
820- invoke_batch (
922+ invoke_batch_from_args (
821923 self . db . external_funcs [ * func] . as_ref ( ) ,
822924 self ,
823925 mask,
@@ -834,7 +936,7 @@ impl ExecutionState<'_> {
834936 dst,
835937 } => {
836938 let mut f1_result = mask. clone ( ) ;
837- invoke_batch (
939+ invoke_batch_from_args (
838940 self . db . external_funcs [ * f1] . as_ref ( ) ,
839941 self ,
840942 & mut f1_result,
@@ -848,7 +950,7 @@ impl ExecutionState<'_> {
848950 return ;
849951 }
850952 // Call the given external function on all entries where the first call failed.
851- invoke_batch_assign (
953+ invoke_batch_assign_from_args (
852954 self . db . external_funcs [ * f2] . as_ref ( ) ,
853955 self ,
854956 & mut to_call_f2,
@@ -921,7 +1023,7 @@ pub(crate) enum Instr {
9211023 table : TableId ,
9221024 table_key : Vec < QueryEntry > ,
9231025 func : ExternalFunctionId ,
924- func_args : Vec < QueryEntry > ,
1026+ func_args : ArgBindings ,
9251027 dst_col : ColumnId ,
9261028 dst_var : Variable ,
9271029 } ,
@@ -950,7 +1052,7 @@ pub(crate) enum Instr {
9501052 /// Bind the result of the external function to a variable.
9511053 External {
9521054 func : ExternalFunctionId ,
953- args : Vec < QueryEntry > ,
1055+ args : ArgBindings ,
9541056 dst : Variable ,
9551057 } ,
9561058
@@ -959,9 +1061,9 @@ pub(crate) enum Instr {
9591061 /// single failure of `External`).
9601062 ExternalWithFallback {
9611063 f1 : ExternalFunctionId ,
962- args1 : Vec < QueryEntry > ,
1064+ args1 : ArgBindings ,
9631065 f2 : ExternalFunctionId ,
964- args2 : Vec < QueryEntry > ,
1066+ args2 : ArgBindings ,
9651067 dst : Variable ,
9661068 } ,
9671069
0 commit comments