@@ -13,24 +13,32 @@ mod column;
13
13
mod de;
14
14
mod error;
15
15
mod row;
16
+ mod statement;
16
17
mod value;
17
18
18
19
pub use column:: { Columns , DataType } ;
19
20
pub use error:: { Error , Result } ;
20
- pub use row:: Row ;
21
+ pub use params:: { IntoParams , Params , Value as ParamValue } ;
22
+ pub use row:: { IntoValueIndex , Row , ValueIndex } ;
23
+ pub use statement:: Statement ;
21
24
pub use value:: Value ;
22
25
23
26
use crossdb_sys:: * ;
24
- use params :: { IntoParams , Value as ParamValue } ;
27
+ use lru :: LruCache ;
25
28
use std:: ffi:: { CStr , CString } ;
26
29
use std:: fmt:: Display ;
30
+ use std:: num:: NonZeroUsize ;
27
31
mod params;
28
32
29
33
#[ derive( Debug ) ]
30
34
pub struct Connection {
31
35
ptr : * mut xdb_conn_t ,
36
+ cache : LruCache < CString , Statement > ,
32
37
}
33
38
39
+ unsafe impl Send for Connection { }
40
+ unsafe impl Sync for Connection { }
41
+
34
42
impl Drop for Connection {
35
43
fn drop ( & mut self ) {
36
44
unsafe {
@@ -43,30 +51,29 @@ impl Connection {
43
51
pub fn open < P : AsRef < str > > ( path : P ) -> Result < Self > {
44
52
let path = CString :: new ( path. as_ref ( ) ) ?;
45
53
let ptr = unsafe { xdb_open ( path. as_ptr ( ) ) } ;
46
- Ok ( Self { ptr } )
54
+ let cap = NonZeroUsize :: new ( 256 ) . unwrap ( ) ;
55
+ Ok ( Self {
56
+ ptr,
57
+ cache : LruCache :: new ( cap) ,
58
+ } )
47
59
}
48
60
49
61
pub fn open_with_memory ( ) -> Result < Self > {
50
62
Self :: open ( ":memory:" )
51
63
}
52
64
53
- pub fn exec < S : AsRef < str > > ( & self , sql : S ) -> Result < ExecResult > {
65
+ pub fn query < S : AsRef < str > > ( & self , sql : S ) -> Result < Query > {
54
66
let sql = CString :: new ( sql. as_ref ( ) ) ?;
55
67
unsafe {
56
68
let ptr = xdb_exec ( self . ptr , sql. as_ptr ( ) ) ;
57
- let res = * ptr;
58
- if res. errcode as u32 != xdb_errno_e_XDB_OK {
59
- let msg = CStr :: from_ptr ( xdb_errmsg ( ptr) ) . to_str ( ) ?. to_string ( ) ;
60
- return Err ( Error :: Query ( res. errcode , msg) ) ;
61
- }
62
- Ok ( ExecResult {
63
- res,
64
- ptr,
65
- columns : Columns :: from_res ( ptr) ,
66
- } )
69
+ Query :: from_res ( ptr)
67
70
}
68
71
}
69
72
73
+ pub fn execute < S : AsRef < str > > ( & self , sql : S ) -> Result < u64 > {
74
+ self . query ( sql) . map ( |q| q. affected_rows ( ) )
75
+ }
76
+
70
77
pub fn begin ( & self ) -> bool {
71
78
unsafe { xdb_begin ( self . ptr ) == 0 }
72
79
}
@@ -79,67 +86,53 @@ impl Connection {
79
86
unsafe { xdb_rollback ( self . ptr ) == 0 }
80
87
}
81
88
82
- // TODO: LRU cache
83
- pub fn prepare < S : AsRef < str > > ( & mut self , sql : S ) -> Result < Stmt > {
84
- unsafe {
85
- let sql = CString :: new ( sql. as_ref ( ) ) ?;
86
- let ptr = xdb_stmt_prepare ( self . ptr , sql. as_ptr ( ) ) ;
87
- Ok ( Stmt { ptr } )
88
- }
89
- }
90
- }
91
-
92
- pub struct Stmt {
93
- ptr : * mut xdb_stmt_t ,
94
- }
95
-
96
- impl Drop for Stmt {
97
- fn drop ( & mut self ) {
98
- unsafe {
99
- xdb_stmt_close ( self . ptr ) ;
100
- }
89
+ pub fn prepare < S : AsRef < str > > ( & mut self , sql : S ) -> Result < & Statement > {
90
+ let sql = CString :: new ( sql. as_ref ( ) ) ?;
91
+ let sql_ptr = sql. as_ptr ( ) ;
92
+ let stmt = self . cache . get_or_insert ( sql, || {
93
+ let ptr = unsafe { xdb_stmt_prepare ( self . ptr , sql_ptr) } ;
94
+ Statement { ptr }
95
+ } ) ;
96
+ Ok ( stmt)
101
97
}
102
- }
103
98
104
- impl Stmt {
105
- pub fn exec ( & self , params : impl IntoParams ) -> Result < ExecResult > {
106
- unsafe {
107
- let ret = xdb_clear_bindings ( self . ptr ) ;
108
- if ret != 0 {
109
- return Err ( Error :: ClearBindings ) ;
110
- }
111
- params. into_params ( ) ?. bind ( self . ptr ) ?;
112
- let ptr = xdb_stmt_exec ( self . ptr ) ;
113
- let res = * ptr;
114
- if res. errcode as u32 != xdb_errno_e_XDB_OK {
115
- let msg = CStr :: from_ptr ( xdb_errmsg ( ptr) ) . to_str ( ) ?. to_string ( ) ;
116
- return Err ( Error :: Query ( res. errcode , msg) ) ;
117
- }
118
- Ok ( ExecResult {
119
- res,
120
- ptr,
121
- columns : Columns :: from_res ( ptr) ,
122
- } )
123
- }
99
+ pub fn clear_statement_cache ( & mut self ) {
100
+ self . cache . clear ( ) ;
124
101
}
125
102
}
126
103
127
104
#[ derive( Debug ) ]
128
- pub struct ExecResult {
105
+ pub struct Query {
129
106
res : xdb_res_t ,
130
107
ptr : * mut xdb_res_t ,
131
108
columns : Columns ,
132
109
}
133
110
134
- impl Drop for ExecResult {
111
+ impl Drop for Query {
135
112
fn drop ( & mut self ) {
136
113
unsafe {
137
114
xdb_free_result ( self . ptr ) ;
138
115
}
139
116
}
140
117
}
141
118
142
- impl ExecResult {
119
+ unsafe impl Send for Query { }
120
+ unsafe impl Sync for Query { }
121
+
122
+ impl Query {
123
+ pub ( crate ) unsafe fn from_res ( ptr : * mut xdb_res_t ) -> Result < Self > {
124
+ let res = * ptr;
125
+ if res. errcode as u32 != xdb_errno_e_XDB_OK {
126
+ let msg = CStr :: from_ptr ( xdb_errmsg ( ptr) ) . to_str ( ) ?. to_string ( ) ;
127
+ return Err ( Error :: Query ( res. errcode , msg) ) ;
128
+ }
129
+ Ok ( Self {
130
+ res,
131
+ ptr,
132
+ columns : Columns :: from_res ( ptr) ,
133
+ } )
134
+ }
135
+
143
136
pub fn column_count ( & self ) -> usize {
144
137
self . res . col_count as usize
145
138
}
0 commit comments