@@ -9,73 +9,68 @@ pub(crate) struct PostCommitWork<'h, T> {
9
9
reward : T ,
10
10
}
11
11
12
- /// Checks outgoing stmts for readonly status
13
- #[ repr( transparent) ]
14
- pub ( crate ) struct ReadOnlyRusqliteTransaction < T > {
15
- pub ( crate ) conn : T ,
12
+ /// Exposes a rusqlite Transaction to implement ReadTransaction.
13
+ pub trait ReadOnlyTransactionAccessor {
14
+ fn readonly_transaction ( & self ) -> & rusqlite:: Transaction ;
16
15
}
17
16
18
- impl < ' t , T > ReadOnlyRusqliteTransaction < T >
19
- where
20
- T : Borrow < rusqlite:: Transaction < ' t > > ,
21
- {
22
- pub fn prepare_cached < ' a > ( & ' a self , sql : & str ) -> rusqlite:: Result < CachedStatement < ' a > >
23
- where
24
- ' t : ' a ,
25
- {
26
- let stmt = self . conn . borrow ( ) . prepare_cached ( sql) ?;
27
- assert ! ( stmt. readonly( ) ) ;
28
- Ok ( stmt)
29
- }
17
+ /// Extends rusqlite objects with stuff needed for ReadTransaction.
18
+ trait ReadOnlyRusqliteTransaction {
19
+ fn prepare_cached_readonly ( & self , sql : & str ) -> rusqlite:: Result < CachedStatement > ;
30
20
}
31
21
32
- impl ReadTransactionOwned < ' _ > {
33
- pub fn as_ref ( & self ) -> ReadTransactionRef {
34
- ReadTransactionRef {
35
- tx : ReadOnlyRusqliteTransaction {
36
- conn : & self . tx . conn ,
37
- } ,
38
- }
22
+ // This could just as easily be implemented for rusqlite::Connection too.
23
+ impl ReadOnlyRusqliteTransaction for rusqlite:: Transaction < ' _ > {
24
+ fn prepare_cached_readonly ( & self , sql : & str ) -> rusqlite:: Result < CachedStatement > {
25
+ prepare_cached_readonly ( self . borrow ( ) , sql)
39
26
}
40
27
}
41
28
42
- pub type ReadTransactionRef < ' a > = ReadTransaction < & ' a rusqlite:: Transaction < ' a > > ;
29
+ fn prepare_cached_readonly < ' a > (
30
+ conn : & ' a Connection ,
31
+ sql : & str ,
32
+ ) -> rusqlite:: Result < CachedStatement < ' a > > {
33
+ let stmt = conn. prepare_cached ( sql) ?;
34
+ assert ! ( stmt. readonly( ) ) ;
35
+ Ok ( stmt)
36
+ }
37
+
38
+ pub type ReadTransactionRef < ' a > = & ' a ReadTransactionOwned < ' a > ;
43
39
44
- pub type ReadTransactionOwned < ' a > = ReadTransaction < rusqlite:: Transaction < ' a > > ;
40
+ /// Helper type for wrapping rusqlite::Transaction to only provide ReadTransaction capabilities.
41
+ pub struct ReadTransactionOwned < ' a > ( pub ( crate ) rusqlite:: Transaction < ' a > ) ;
45
42
46
- /// Only provides methods that are known to be read only, and has a ReadOnly connection internally.
47
- # [ repr ( transparent ) ]
48
- pub struct ReadTransaction < T > {
49
- pub ( crate ) tx : ReadOnlyRusqliteTransaction < T > ,
43
+ impl ReadOnlyTransactionAccessor for ReadTransactionOwned < ' _ > {
44
+ fn readonly_transaction ( & self ) -> & rusqlite :: Transaction {
45
+ & self . 0
46
+ }
50
47
}
51
48
52
- impl < ' a , T > ReadTransaction < T >
53
- where
54
- T : Borrow < rusqlite:: Transaction < ' a > > ,
55
- {
56
- pub fn file_values (
57
- & ' a self ,
58
- file_id : FileId ,
59
- ) -> rusqlite:: Result < FileValues < CachedStatement < ' a > > > {
60
- let stmt = self . tx . prepare_cached ( & format ! (
61
- "select {} from keys where file_id=? order by file_offset" ,
62
- value_columns_sql( )
63
- ) ) ?;
49
+ /// Extra methods for types exposing a rusqlite Transaction that's allowed to do read transaction
50
+ /// stuff.
51
+ pub trait ReadTransaction : ReadOnlyTransactionAccessor {
52
+ fn file_values ( & self , file_id : FileId ) -> rusqlite:: Result < FileValues < CachedStatement > > {
53
+ let stmt = self
54
+ . readonly_transaction ( )
55
+ . prepare_cached_readonly ( & format ! (
56
+ "select {} from keys where file_id=? order by file_offset" ,
57
+ value_columns_sql( )
58
+ ) ) ?;
64
59
let iter = FileValues { stmt, file_id } ;
65
60
Ok ( iter)
66
61
}
67
62
68
- pub fn sum_value_length ( & self ) -> rusqlite:: Result < u64 > {
69
- self . tx
70
- . prepare_cached ( "select value from sums where key='value_length'" ) ?
63
+ fn sum_value_length ( & self ) -> rusqlite:: Result < u64 > {
64
+ self . readonly_transaction ( )
65
+ . prepare_cached_readonly ( "select value from sums where key='value_length'" ) ?
71
66
. query_row ( [ ] , |row| row. get ( 0 ) )
72
67
. map_err ( Into :: into)
73
68
}
74
69
75
70
/// Returns the end offset of the last active value before offset in the same file.
76
- pub fn query_last_end_offset ( & self , file_id : & FileId , offset : u64 ) -> rusqlite:: Result < u64 > {
77
- self . tx
78
- . prepare_cached (
71
+ fn query_last_end_offset ( & self , file_id : & FileId , offset : u64 ) -> rusqlite:: Result < u64 > {
72
+ self . readonly_transaction ( )
73
+ . prepare_cached_readonly (
79
74
"select max(file_offset+value_length) as last_offset \
80
75
from keys \
81
76
where file_id=? and file_offset+value_length <= ?",
@@ -89,13 +84,13 @@ where
89
84
}
90
85
91
86
/// Returns the next value offset with at least min_offset.
92
- pub fn next_value_offset (
87
+ fn next_value_offset (
93
88
& self ,
94
89
file_id : & FileId ,
95
90
min_offset : u64 ,
96
91
) -> rusqlite:: Result < Option < u64 > > {
97
- self . tx
98
- . prepare_cached (
92
+ self . readonly_transaction ( )
93
+ . prepare_cached_readonly (
99
94
"select min(file_offset) \
100
95
from keys \
101
96
where file_id=? and file_offset >= ?",
104
99
}
105
100
106
101
// TODO: Make this iterate.
107
- pub fn list_items ( & self , prefix : & [ u8 ] ) -> PubResult < Vec < Item > > {
102
+ fn list_items ( & self , prefix : & [ u8 ] ) -> PubResult < Vec < Item > > {
108
103
let range_end = {
109
104
let mut prefix = prefix. to_owned ( ) ;
110
105
if inc_big_endian_array ( & mut prefix) {
@@ -114,14 +109,16 @@ where
114
109
}
115
110
} ;
116
111
match range_end {
117
- None => self . list_items_inner (
112
+ None => list_items_inner (
113
+ self . readonly_transaction ( ) ,
118
114
& format ! (
119
115
"select {}, key from keys where key >= ?" ,
120
116
value_columns_sql( )
121
117
) ,
122
118
[ prefix] ,
123
119
) ,
124
- Some ( range_end) => self . list_items_inner (
120
+ Some ( range_end) => list_items_inner (
121
+ self . readonly_transaction ( ) ,
125
122
& format ! (
126
123
"select {}, key from keys where key >= ? and key < ?" ,
127
124
value_columns_sql( )
@@ -130,20 +127,23 @@ where
130
127
) ,
131
128
}
132
129
}
130
+ }
133
131
134
- fn list_items_inner ( & self , sql : & str , params : impl rusqlite:: Params ) -> PubResult < Vec < Item > > {
135
- self . tx
136
- . prepare_cached ( sql)
137
- . unwrap ( )
138
- . query_map ( params, |row| {
139
- Ok ( Item {
140
- value : Value :: from_row ( row) ?,
141
- key : row. get ( VALUE_COLUMN_NAMES . len ( ) ) ?,
142
- } )
143
- } ) ?
144
- . collect :: < rusqlite:: Result < Vec < _ > > > ( )
145
- . map_err ( Into :: into)
146
- }
132
+ fn list_items_inner (
133
+ tx : & rusqlite:: Transaction ,
134
+ sql : & str ,
135
+ params : impl rusqlite:: Params ,
136
+ ) -> PubResult < Vec < Item > > {
137
+ tx. prepare_cached_readonly ( sql)
138
+ . unwrap ( )
139
+ . query_map ( params, |row| {
140
+ Ok ( Item {
141
+ value : Value :: from_row ( row) ?,
142
+ key : row. get ( VALUE_COLUMN_NAMES . len ( ) ) ?,
143
+ } )
144
+ } ) ?
145
+ . collect :: < rusqlite:: Result < Vec < _ > > > ( )
146
+ . map_err ( Into :: into)
147
147
}
148
148
149
149
impl < ' h , T > PostCommitWork < ' h , T > {
@@ -172,18 +172,14 @@ pub(crate) struct Transaction<'h> {
172
172
173
173
// TODO: Try doing this with a read trait that just requires a rusqlite::Transaction be available.
174
174
175
- impl < ' h > Deref for Transaction < ' h > {
176
- type Target = ReadTransaction < rusqlite:: Transaction < ' h > > ;
177
-
178
- fn deref ( & self ) -> & Self :: Target {
179
- unsafe {
180
- std:: mem:: transmute :: < & rusqlite:: Transaction , & ReadTransaction < rusqlite:: Transaction > > (
181
- & self . tx ,
182
- )
183
- }
175
+ impl < ' t > ReadOnlyTransactionAccessor for Transaction < ' t > {
176
+ fn readonly_transaction ( & self ) -> & rusqlite:: Transaction {
177
+ & self . tx
184
178
}
185
179
}
186
180
181
+ impl < T > ReadTransaction for T where T : ReadOnlyTransactionAccessor { }
182
+
187
183
impl < ' h > Transaction < ' h > {
188
184
pub fn new ( tx : rusqlite:: Transaction < ' h > , handle : & ' h Handle ) -> Self {
189
185
Self {
0 commit comments