@@ -4,13 +4,14 @@ use crate::auth::{AuthAction, AuthContext, Authorization};
44use crate :: connection:: AuthHook ;
55use crate :: local:: rows:: BatchedRows ;
66use crate :: params:: Params ;
7+ use crate :: udf:: { ScalarFunctionCallback , ScalarFunctionDef } ;
78use crate :: { connection:: BatchRows , errors} ;
9+ use crate :: { TransactionBehavior , Value } ;
10+ use std:: ffi:: CString ;
811use std:: time:: Duration ;
912
1013use super :: { Database , Error , Result , Rows , RowsFuture , Statement , Transaction } ;
1114
12- use crate :: TransactionBehavior ;
13-
1415use libsql_sys:: ffi;
1516use parking_lot:: RwLock ;
1617use std:: { ffi:: c_int, fmt, path:: Path , sync:: Arc } ;
@@ -494,6 +495,28 @@ impl Connection {
494495 Ok ( ( ) )
495496 }
496497
498+ pub ( crate ) fn create_scalar_function ( & self , def : ScalarFunctionDef ) -> Result < ( ) > {
499+ let userdata = Box :: into_raw ( Box :: new ( Arc :: into_raw ( def. callback ) ) ) ;
500+ let userdata_c = userdata as * mut :: std:: os:: raw:: c_void ;
501+
502+ let name = CString :: new ( def. name ) . unwrap ( ) ;
503+ unsafe {
504+ ffi:: sqlite3_create_function_v2 (
505+ self . raw ,
506+ name. as_ptr ( ) ,
507+ def. num_args ,
508+ ffi:: SQLITE_UTF8 ,
509+ userdata_c,
510+ Some ( scalar_function_callback) ,
511+ None ,
512+ None ,
513+ Some ( drop_scalar_function_callback) ,
514+ ) ;
515+ }
516+
517+ Ok ( ( ) )
518+ }
519+
497520 pub ( crate ) fn wal_checkpoint ( & self , truncate : bool ) -> Result < ( ) > {
498521 let mut pn_log = 0i32 ;
499522 let mut pn_ckpt = 0i32 ;
@@ -666,6 +689,56 @@ impl Connection {
666689 }
667690}
668691
692+ unsafe extern "C" fn scalar_function_callback (
693+ context : * mut ffi:: sqlite3_context ,
694+ argc : i32 ,
695+ args : * mut * mut ffi:: sqlite3_value ,
696+ ) {
697+ let callback = Box :: from_raw ( ffi:: sqlite3_user_data ( context) as * mut ScalarFunctionCallback ) ;
698+
699+ let values = ( 0 ..argc)
700+ . map ( |i| {
701+ let arg_ptr = * args. add ( i as usize ) ;
702+ Value :: from ( libsql_sys:: Value { raw_value : arg_ptr } )
703+ } )
704+ . collect :: < Vec < _ > > ( ) ;
705+
706+ let result = ( callback) ( values) ;
707+ std:: mem:: forget ( callback) ;
708+
709+ match result {
710+ Ok ( value) => match value {
711+ Value :: Null => ffi:: sqlite3_result_null ( context) ,
712+ Value :: Integer ( i) => ffi:: sqlite3_result_int64 ( context, i) ,
713+ Value :: Real ( d) => ffi:: sqlite3_result_double ( context, d) ,
714+ Value :: Text ( t) => {
715+ ffi:: sqlite3_result_text (
716+ context,
717+ t. as_ptr ( ) as * const i8 ,
718+ t. len ( ) as i32 ,
719+ ffi:: SQLITE_TRANSIENT ( ) ,
720+ ) ;
721+ }
722+ Value :: Blob ( b) => {
723+ ffi:: sqlite3_result_blob (
724+ context,
725+ b. as_ptr ( ) as * const :: std:: os:: raw:: c_void ,
726+ b. len ( ) as i32 ,
727+ ffi:: SQLITE_TRANSIENT ( ) ,
728+ ) ;
729+ }
730+ } ,
731+ Err ( e) => {
732+ let e_msg = e. to_string ( ) ;
733+ ffi:: sqlite3_result_error ( context, e_msg. as_ptr ( ) as * const i8 , e_msg. len ( ) as i32 ) ;
734+ }
735+ }
736+ }
737+
738+ unsafe extern "C" fn drop_scalar_function_callback ( userdata : * mut :: std:: os:: raw:: c_void ) {
739+ drop ( Box :: from_raw ( userdata as * mut ScalarFunctionCallback ) ) ;
740+ }
741+
669742unsafe extern "C" fn authorizer_callback (
670743 user_data : * mut :: std:: os:: raw:: c_void ,
671744 code : :: std:: os:: raw:: c_int ,
0 commit comments