@@ -3,8 +3,15 @@ use indexmap::IndexMap;
33use std:: cell:: RefCell ;
44use std:: collections:: HashMap ;
55use std:: rc:: Rc ;
6+ use std:: sync:: atomic:: { AtomicI64 , Ordering } ;
67use techscript_runtime:: { error:: RuntimeError , error:: RuntimeErrorKind , value:: RuntimeValue } ;
78
9+ thread_local ! {
10+ static CONNECTIONS : RefCell <HashMap <i64 , rusqlite:: Connection >> = RefCell :: new( HashMap :: new( ) ) ;
11+ }
12+
13+ static NEXT_ID : AtomicI64 = AtomicI64 :: new ( 1 ) ;
14+
815impl StdlibRegistry {
916 pub fn register_sqlite ( & mut self ) {
1017 let mut exports: HashMap < String , Rc < dyn techscript_runtime:: function:: Callable > > =
@@ -24,8 +31,9 @@ impl StdlibRegistry {
2431 None ,
2532 )
2633 } ) ?;
27- let ptr = Box :: into_raw ( Box :: new ( conn) ) as i64 ;
28- Ok ( RuntimeValue :: Int ( ptr) )
34+ let id = NEXT_ID . fetch_add ( 1 , Ordering :: SeqCst ) ;
35+ CONNECTIONS . with ( |m| m. borrow_mut ( ) . insert ( id, conn) ) ;
36+ Ok ( RuntimeValue :: Int ( id) )
2937 } ,
3038 } ) ,
3139 ) ;
@@ -36,21 +44,35 @@ impl StdlibRegistry {
3644 name : "execute" . to_string ( ) ,
3745 arity : 2 ,
3846 callback : |_ctx, args| {
39- let ptr = args[ 0 ] . try_into_int ( ) . map_err ( |_| {
47+ let id = args[ 0 ] . try_into_int ( ) . map_err ( |_| {
4048 RuntimeError :: new (
4149 RuntimeErrorKind :: InvalidOperation ( "expected int handle" . to_string ( ) ) ,
4250 None ,
4351 None ,
4452 )
4553 } ) ?;
4654 let sql = args[ 1 ] . to_string ( ) ;
47- let conn = unsafe { & mut * ( ptr as * mut rusqlite:: Connection ) } ;
48- conn. execute ( & sql, [ ] ) . map_err ( |e| {
49- RuntimeError :: new (
50- RuntimeErrorKind :: InvalidOperation ( e. to_string ( ) ) ,
51- None ,
52- None ,
53- )
55+
56+ CONNECTIONS . with ( |m| {
57+ let mut map = m. borrow_mut ( ) ;
58+ if let Some ( conn) = map. get_mut ( & id) {
59+ conn. execute ( & sql, [ ] ) . map_err ( |e| {
60+ RuntimeError :: new (
61+ RuntimeErrorKind :: InvalidOperation ( e. to_string ( ) ) ,
62+ None ,
63+ None ,
64+ )
65+ } ) ?;
66+ Ok ( ( ) )
67+ } else {
68+ Err ( RuntimeError :: new (
69+ RuntimeErrorKind :: InvalidOperation (
70+ "Invalid connection handle" . to_string ( ) ,
71+ ) ,
72+ None ,
73+ None ,
74+ ) )
75+ }
5476 } ) ?;
5577 Ok ( RuntimeValue :: Null )
5678 } ,
@@ -63,52 +85,68 @@ impl StdlibRegistry {
6385 name : "query" . to_string ( ) ,
6486 arity : 2 ,
6587 callback : |_ctx, args| {
66- let ptr = args[ 0 ] . try_into_int ( ) . map_err ( |_| {
88+ let id = args[ 0 ] . try_into_int ( ) . map_err ( |_| {
6789 RuntimeError :: new (
6890 RuntimeErrorKind :: InvalidOperation ( "expected int handle" . to_string ( ) ) ,
6991 None ,
7092 None ,
7193 )
7294 } ) ?;
7395 let sql = args[ 1 ] . to_string ( ) ;
74- let conn = unsafe { & mut * ( ptr as * mut rusqlite:: Connection ) } ;
75- let mut stmt = conn. prepare ( & sql) . map_err ( |e| {
76- RuntimeError :: new (
77- RuntimeErrorKind :: InvalidOperation ( e. to_string ( ) ) ,
78- None ,
79- None ,
80- )
81- } ) ?;
82- let col_count = stmt. column_count ( ) ;
83- let col_names: Vec < String > = ( 0 ..col_count)
84- . map ( |i| stmt. column_name ( i) . unwrap_or ( "?" ) . to_string ( ) )
85- . collect ( ) ;
86- let mut rows = Vec :: new ( ) ;
87- let row_iter = stmt
88- . query_map ( [ ] , |row| {
89- let mut map = IndexMap :: new ( ) ;
90- for i in 0 ..col_count {
91- let name = col_names[ i] . clone ( ) ;
92- let val: String = row. get :: < _ , String > ( i) . unwrap_or_default ( ) ;
93- map. insert ( name, RuntimeValue :: Str ( val) ) ;
96+
97+ let rows = CONNECTIONS . with ( |m| {
98+ let mut map = m. borrow_mut ( ) ;
99+ if let Some ( conn) = map. get_mut ( & id) {
100+ let mut stmt = conn. prepare ( & sql) . map_err ( |e| {
101+ RuntimeError :: new (
102+ RuntimeErrorKind :: InvalidOperation ( e. to_string ( ) ) ,
103+ None ,
104+ None ,
105+ )
106+ } ) ?;
107+ let col_count = stmt. column_count ( ) ;
108+ let col_names: Vec < String > = ( 0 ..col_count)
109+ . map ( |i| stmt. column_name ( i) . unwrap_or ( "?" ) . to_string ( ) )
110+ . collect ( ) ;
111+ let mut rows = Vec :: new ( ) ;
112+ let row_iter = stmt
113+ . query_map ( [ ] , |row| {
114+ let mut map = IndexMap :: new ( ) ;
115+ for i in 0 ..col_count {
116+ let name = col_names[ i] . clone ( ) ;
117+ let val: String =
118+ row. get :: < _ , String > ( i) . unwrap_or_default ( ) ;
119+ map. insert ( name, RuntimeValue :: Str ( val) ) ;
120+ }
121+ Ok ( map)
122+ } )
123+ . map_err ( |e| {
124+ RuntimeError :: new (
125+ RuntimeErrorKind :: InvalidOperation ( e. to_string ( ) ) ,
126+ None ,
127+ None ,
128+ )
129+ } ) ?;
130+ for row in row_iter {
131+ if let Ok ( map) = row {
132+ rows. push ( RuntimeValue :: Map {
133+ entries : Rc :: new ( RefCell :: new ( map) ) ,
134+ is_const : false ,
135+ } ) ;
136+ }
94137 }
95- Ok ( map)
96- } )
97- . map_err ( |e| {
98- RuntimeError :: new (
99- RuntimeErrorKind :: InvalidOperation ( e. to_string ( ) ) ,
138+ Ok ( rows)
139+ } else {
140+ Err ( RuntimeError :: new (
141+ RuntimeErrorKind :: InvalidOperation (
142+ "Invalid connection handle" . to_string ( ) ,
143+ ) ,
100144 None ,
101145 None ,
102- )
103- } ) ?;
104- for row in row_iter {
105- if let Ok ( map) = row {
106- rows. push ( RuntimeValue :: Map {
107- entries : Rc :: new ( RefCell :: new ( map) ) ,
108- is_const : false ,
109- } ) ;
146+ ) )
110147 }
111- }
148+ } ) ?;
149+
112150 Ok ( RuntimeValue :: List {
113151 items : Rc :: new ( RefCell :: new ( rows) ) ,
114152 is_const : false ,
@@ -123,16 +161,14 @@ impl StdlibRegistry {
123161 name : "close" . to_string ( ) ,
124162 arity : 1 ,
125163 callback : |_ctx, args| {
126- let ptr = args[ 0 ] . try_into_int ( ) . map_err ( |_| {
164+ let id = args[ 0 ] . try_into_int ( ) . map_err ( |_| {
127165 RuntimeError :: new (
128166 RuntimeErrorKind :: InvalidOperation ( "expected int handle" . to_string ( ) ) ,
129167 None ,
130168 None ,
131169 )
132170 } ) ?;
133- unsafe {
134- drop ( Box :: from_raw ( ptr as * mut rusqlite:: Connection ) ) ;
135- }
171+ CONNECTIONS . with ( |m| m. borrow_mut ( ) . remove ( & id) ) ;
136172 Ok ( RuntimeValue :: Null )
137173 } ,
138174 } ) ,
0 commit comments