1- use crate :: roc_sql;
21use roc_io_error:: IOErr ;
32use roc_std:: { RocBox , RocList , RocResult , RocStr } ;
43use std:: cell:: RefCell ;
@@ -324,83 +323,6 @@ pub extern "C" fn roc_fx_dir_list(
324323 roc_file:: dir_list ( roc_path)
325324}
326325
327- #[ no_mangle]
328- pub extern "C" fn roc_fx_sqlite_execute (
329- db_path : & roc_std:: RocStr ,
330- query : & roc_std:: RocStr ,
331- bindings : & RocList < roc_sql:: SQLiteBindings > ,
332- ) -> RocResult < RocList < RocList < roc_sql:: SQLiteValue > > , roc_sql:: SQLiteError > {
333- // Get the connection
334- let connection = {
335- match roc_sql:: get_connection ( db_path. as_str ( ) ) {
336- Ok ( c) => c,
337- Err ( err) => {
338- return RocResult :: err ( roc_sql:: SQLiteError {
339- code : err. code . unwrap_or_default ( ) as i64 ,
340- message : RocStr :: from ( err. message . unwrap_or_default ( ) . as_str ( ) ) ,
341- } ) ;
342- }
343- }
344- } ;
345-
346- // Prepare the query
347- let mut statement = {
348- match connection. prepare ( query. as_str ( ) ) {
349- Ok ( c) => c,
350- Err ( err) => {
351- return RocResult :: err ( roc_sql:: SQLiteError {
352- code : err. code . unwrap_or_default ( ) as i64 ,
353- message : RocStr :: from ( err. message . unwrap_or_default ( ) . as_str ( ) ) ,
354- } ) ;
355- }
356- }
357- } ;
358-
359- // Add bindings for the query
360- for binding in bindings {
361- match statement. bind ( binding) {
362- Ok ( ( ) ) => { }
363- Err ( err) => {
364- return RocResult :: err ( roc_sql:: SQLiteError {
365- code : err. code . unwrap_or_default ( ) as i64 ,
366- message : RocStr :: from ( err. message . unwrap_or_default ( ) . as_str ( ) ) ,
367- } ) ;
368- }
369- }
370- }
371-
372- let mut cursor = statement. iter ( ) ;
373- let column_count = cursor. column_count ( ) ;
374-
375- // Save space for 1000 rows without allocating
376- let mut roc_values: RocList < RocList < roc_sql:: SQLiteValue > > = RocList :: with_capacity ( 1000 ) ;
377-
378- while let Ok ( Some ( row_values) ) = cursor. try_next ( ) {
379- let mut row = RocList :: with_capacity ( column_count) ;
380-
381- // For each column in the row
382- for value in row_values {
383- row. push ( roc_sql_from_sqlite_value ( value) ) ;
384- }
385-
386- roc_values. push ( row) ;
387- }
388-
389- RocResult :: ok ( roc_values)
390- }
391-
392- fn roc_sql_from_sqlite_value ( value : sqlite:: Value ) -> roc_sql:: SQLiteValue {
393- match value {
394- sqlite:: Value :: Binary ( bytes) => {
395- roc_sql:: SQLiteValue :: bytes ( RocList :: from_slice ( & bytes[ ..] ) )
396- }
397- sqlite:: Value :: Float ( f64) => roc_sql:: SQLiteValue :: real ( f64) ,
398- sqlite:: Value :: Integer ( i64) => roc_sql:: SQLiteValue :: integer ( i64) ,
399- sqlite:: Value :: String ( str) => roc_sql:: SQLiteValue :: string ( RocStr :: from ( str. as_str ( ) ) ) ,
400- sqlite:: Value :: Null => roc_sql:: SQLiteValue :: null ( ) ,
401- }
402- }
403-
404326#[ no_mangle]
405327pub extern "C" fn roc_fx_temp_dir ( ) -> RocList < u8 > {
406328 roc_env:: temp_dir ( )
@@ -418,6 +340,12 @@ impl Model {
418340 let rc_ptr = data_ptr. offset ( -1 ) ;
419341 let max_refcount = 0 ;
420342 * rc_ptr = max_refcount;
343+
344+ // Ensure all sqlite stmts that escapes init has an zero (constant) refcount.
345+ // This ensures it is safe to share between threads and is never freed.
346+ let heap = roc_sqlite:: heap ( ) ;
347+ heap. promote_all_to_constant ( ) ;
348+
421349 Self {
422350 model : std:: mem:: transmute :: < * mut usize , roc_std:: RocBox < ( ) > > ( data_ptr) ,
423351 }
@@ -523,3 +451,44 @@ pub extern "C" fn roc_fx_getLocales() -> RocList<RocStr> {
523451pub extern "C" fn roc_fx_currentArchOS ( ) -> roc_env:: ReturnArchOS {
524452 roc_env:: current_arch_os ( )
525453}
454+
455+ #[ no_mangle]
456+ pub extern "C" fn roc_fx_sqlite_bind (
457+ stmt : RocBox < ( ) > ,
458+ bindings : & RocList < roc_sqlite:: SqliteBindings > ,
459+ ) -> RocResult < ( ) , roc_sqlite:: SqliteError > {
460+ roc_sqlite:: bind ( stmt, bindings)
461+ }
462+
463+ #[ no_mangle]
464+ pub extern "C" fn roc_fx_sqlite_prepare (
465+ db_path : & roc_std:: RocStr ,
466+ query : & roc_std:: RocStr ,
467+ ) -> roc_std:: RocResult < RocBox < ( ) > , roc_sqlite:: SqliteError > {
468+ roc_sqlite:: prepare ( db_path, query)
469+ }
470+
471+ #[ no_mangle]
472+ pub extern "C" fn roc_fx_sqlite_columns ( stmt : RocBox < ( ) > ) -> RocList < RocStr > {
473+ roc_sqlite:: columns ( stmt)
474+ }
475+
476+ #[ no_mangle]
477+ pub extern "C" fn roc_fx_sqlite_column_value (
478+ stmt : RocBox < ( ) > ,
479+ i : u64 ,
480+ ) -> RocResult < roc_sqlite:: SqliteValue , roc_sqlite:: SqliteError > {
481+ roc_sqlite:: column_value ( stmt, i)
482+ }
483+
484+ #[ no_mangle]
485+ pub extern "C" fn roc_fx_sqlite_step (
486+ stmt : RocBox < ( ) > ,
487+ ) -> RocResult < roc_sqlite:: SqliteState , roc_sqlite:: SqliteError > {
488+ roc_sqlite:: step ( stmt)
489+ }
490+
491+ #[ no_mangle]
492+ pub extern "C" fn roc_fx_sqlite_reset ( stmt : RocBox < ( ) > ) -> RocResult < ( ) , roc_sqlite:: SqliteError > {
493+ roc_sqlite:: reset ( stmt)
494+ }
0 commit comments