forensic_rs/traits/
sql.rs1use crate::{prelude::ForensicResult, err::ForensicError};
2
3use super::vfs::VirtualFile;
4
5pub trait SqlDb {
6 fn list_tables(&self) -> ForensicResult<Vec<String>>;
7 fn prepare<'a>(&'a self, statement : &'a str) -> ForensicResult<Box<dyn SqlStatement + 'a>>;
8 fn from_file(&self, file: Box<dyn VirtualFile>) -> ForensicResult<Box<dyn SqlDb>>;
10}
11
12pub trait SqlStatement {
14 fn column_count(&self) -> usize;
16 fn column_name(&self, i: usize) -> Option<&str>;
18 fn column_names(&self) -> Vec<&str>;
20 fn column_type(&self, i: usize) -> ColumnType;
22 fn next(&mut self) -> ForensicResult<bool>;
24 fn read(&self, i: usize) -> ForensicResult<ColumnValue>;
26}
27
28pub trait SqlValueInto: Sized {
29 fn into(value: &ColumnValue) -> ForensicResult<Self>;
30 fn into_owned(value: ColumnValue) -> ForensicResult<Self>;
31}
32
33pub enum ColumnType {
34 Binary,
35 Float,
36 Integer,
37 String,
38 Null,
39}
40
41pub enum ColumnValue {
42 Binary(Vec<u8>),
43 Float(f64),
44 Integer(i64),
45 String(String),
46 Null,
47}
48
49impl TryInto<String> for ColumnValue {
50 type Error = ForensicError;
51
52 fn try_into(self) -> Result<String, Self::Error> {
53 Ok(match self {
54 ColumnValue::String(v) => v.clone(),
55 ColumnValue::Binary(v) => format!("{:?}",v),
56 ColumnValue::Float(v) => format!("{:?}",v),
57 ColumnValue::Integer(v) => format!("{:?}",v),
58 ColumnValue::Null => String::new()
59 })
60 }
61}
62
63impl TryInto<i64> for ColumnValue {
64 type Error = ForensicError;
65
66 fn try_into(self) -> Result<i64, Self::Error> {
67 match self {
68 ColumnValue::Integer(v) => Ok(v),
69 _ => Err(ForensicError::CastError)
70 }
71 }
72}
73
74impl TryInto<usize> for ColumnValue {
75 type Error = ForensicError;
76
77 fn try_into(self) -> Result<usize, Self::Error> {
78 match self {
79 ColumnValue::Integer(v) => Ok(v as usize),
80 _ => Err(ForensicError::CastError)
81 }
82 }
83}
84
85impl TryInto<f64> for ColumnValue {
86 type Error = ForensicError;
87
88 fn try_into(self) -> Result<f64, Self::Error> {
89 match self {
90 ColumnValue::Float(v) => Ok(v),
91 _ => Err(ForensicError::CastError)
92 }
93 }
94}
95
96impl TryInto<Vec<u8>> for ColumnValue {
97 type Error = ForensicError;
98
99 fn try_into(self) -> Result<Vec<u8>, Self::Error> {
100 match self {
101 ColumnValue::Binary(v) => Ok(v),
102 _ => Err(ForensicError::CastError)
103 }
104 }
105}
106
107impl Into<ColumnValue> for f32 {
108 fn into(self) -> ColumnValue {
109 ColumnValue::Float(self as f64)
110 }
111}
112
113impl Into<ColumnValue> for f64 {
114 fn into(self) -> ColumnValue {
115 ColumnValue::Float(self)
116 }
117}
118impl Into<ColumnValue> for u64 {
119 fn into(self) -> ColumnValue {
120 ColumnValue::Integer(self as i64)
121 }
122}
123impl Into<ColumnValue> for i64 {
124 fn into(self) -> ColumnValue {
125 ColumnValue::Integer(self as i64)
126 }
127}
128impl Into<ColumnValue> for u32 {
129 fn into(self) -> ColumnValue {
130 ColumnValue::Integer(self as i64)
131 }
132}
133impl Into<ColumnValue> for i32 {
134 fn into(self) -> ColumnValue {
135 ColumnValue::Integer(self as i64)
136 }
137}
138impl Into<ColumnValue> for usize {
139 fn into(self) -> ColumnValue {
140 ColumnValue::Integer(self as i64)
141 }
142}
143impl Into<ColumnValue> for Vec<u8> {
144 fn into(self) -> ColumnValue {
145 ColumnValue::Binary(self)
146 }
147}
148impl Into<ColumnValue> for &Vec<u8> {
149 fn into(self) -> ColumnValue {
150 ColumnValue::Binary(self.clone())
151 }
152}
153impl Into<ColumnValue> for () {
154 fn into(self) -> ColumnValue {
155 ColumnValue::Null
156 }
157}
158impl Into<ColumnValue> for &[u8] {
159 fn into(self) -> ColumnValue {
160 let mut vc = Vec::with_capacity(self.len());
161 for v in self {
162 vc.push(*v);
163 }
164 ColumnValue::Binary(vc)
165 }
166}
167impl Into<ColumnValue> for &str {
168 fn into(self) -> ColumnValue {
169 ColumnValue::String(self.to_string())
170 }
171}
172impl Into<ColumnValue> for &String {
173 fn into(self) -> ColumnValue {
174 ColumnValue::String(self.to_string())
175 }
176}
177impl Into<ColumnValue> for String {
178 fn into(self) -> ColumnValue {
179 ColumnValue::String(self)
180 }
181}
182
183#[cfg(test)]
184mod sql_tests {
185 extern crate sqlite;
186
187 use crate::prelude::{ForensicResult, ForensicError};
188 use self::sqlite::{Connection, Statement};
189 use super::{SqlStatement, ColumnValue, SqlDb};
190
191 struct SqliteWDB {
192 conn : Connection
193 }
194
195 impl SqliteWDB{
196 pub fn new(conn : Connection) -> SqliteWDB {
197 SqliteWDB {
198 conn
199 }
200 }
201 }
202
203 impl SqlDb for SqliteWDB {
204 fn prepare<'a>(&'a self, statement : &'a str) -> ForensicResult<Box<dyn SqlStatement +'a>> {
205 Ok(Box::new(SqliteStatement::new( &self.conn, statement)?))
206 }
207
208 fn from_file(&self, _file: Box<dyn crate::traits::vfs::VirtualFile>) -> ForensicResult<Box<dyn SqlDb>> {
209 match sqlite::open(":memory:") {
210 Ok(v) => Ok(Box::new(Self::new(v))),
211 Err(e) => Err(ForensicError::Other(e.to_string()))
212 }
213 }
214
215 fn list_tables(&self) -> ForensicResult<Vec<String>> {
216 let mut ret = Vec::with_capacity(32);
217 let mut sts = self.prepare(r#"SELECT
218 name
219 FROM
220 sqlite_schema
221 WHERE
222 type ='table' AND
223 name NOT LIKE 'sqlite_%';"#)?;
224 loop {
225 if !sts.next()? {
226 break;
227 }
228 let name : String = sts.read(0)?.try_into()?;
229 ret.push(name);
230 }
231 Ok(ret)
232 }
233 }
234
235 pub struct SqliteStatement<'conn> {
236 stmt: Statement<'conn>
237 }
238 impl<'conn> SqliteStatement<'conn>{
239 pub fn new(conn : &'conn Connection, statement : &str) -> ForensicResult<SqliteStatement<'conn>>{
240 Ok(Self { stmt : match conn.prepare(statement) {
241 Ok(st) => st,
242 Err(e) => return Err(ForensicError::Other(e.to_string()))
243 }
244 })
245 }
246 }
247
248 impl<'conn> SqlStatement for SqliteStatement<'conn>{
249 fn column_count(&self) -> usize {
250 self.stmt.column_count()
251 }
252
253 fn column_name(&self, i: usize) -> Option<&str> {
254 Some(self.stmt.column_name(i))
255 }
256
257 fn column_names(&self) -> Vec<&str> {
258 self.stmt.column_names()
259 }
260
261 fn column_type(&self, i: usize) -> super::ColumnType {
262 match self.stmt.column_type(i) {
263 sqlite::Type::Binary => super::ColumnType::Binary,
264 sqlite::Type::Float => super::ColumnType::Float,
265 sqlite::Type::Integer => super::ColumnType::Integer,
266 sqlite::Type::String => super::ColumnType::String,
267 sqlite::Type::Null => super::ColumnType::Null,
268 }
269 }
270
271 fn next(&mut self) -> ForensicResult<bool> {
272 match self.stmt.next() {
273 Ok(v) => Ok(match v {
274 sqlite::State::Row => true,
275 sqlite::State::Done => false,
276 }),
277 Err(e) => Err(ForensicError::Other(e.to_string())),
278 }
279 }
280
281 fn read(&self, i: usize) -> ForensicResult<ColumnValue> {
282 match self.stmt.column_type(i) {
283 sqlite::Type::Binary => match self.stmt.read(i) {
284 Ok(v) => Ok(ColumnValue::Binary(v)),
285 Err(e) => Err(ForensicError::Other(e.to_string())),
286 },
287 sqlite::Type::Float => match self.stmt.read(i) {
288 Ok(v) => Ok(ColumnValue::Float(v)),
289 Err(e) => Err(ForensicError::Other(e.to_string())),
290 },
291 sqlite::Type::Integer => match self.stmt.read(i) {
292 Ok(v) => Ok(ColumnValue::Integer(v)),
293 Err(e) => Err(ForensicError::Other(e.to_string())),
294 },
295 sqlite::Type::String => match self.stmt.read(i) {
296 Ok(v) => Ok(ColumnValue::String(v)),
297 Err(e) => Err(ForensicError::Other(e.to_string())),
298 },
299 sqlite::Type::Null => Ok(ColumnValue::Null),
300 }
301 }
302
303 }
304
305 fn prepare_db() -> Connection {
306 let connection = sqlite::open(":memory:").unwrap();
307 connection
308 .execute(
309 "
310 CREATE TABLE users (name TEXT, age INTEGER);
311 INSERT INTO users VALUES ('Alice', 42);
312 INSERT INTO users VALUES ('Bob', 69);
313 ",
314 )
315 .unwrap();
316 connection
317 }
318 fn prepare_wrapper(connection :Connection) -> SqliteWDB{
319 SqliteWDB::new(connection)
320 }
321
322
323 #[test]
324 fn test_sqlite_wrapper() {
325 let conn = prepare_db();
326 let w_conn = prepare_wrapper(conn);
327 let mut statement = w_conn.prepare("SELECT name, age FROM users;").unwrap();
328 test_database_content(statement.as_mut()).expect("Should not return error");
329
330 }
331
332 fn test_database_content<'a>(statement : &mut dyn SqlStatement) -> ForensicResult<()> {
333 assert!(statement.next()?);
334 let name : String = statement.read(0)?.try_into()?;
335 let age : usize = statement.read(1)?.try_into()?;
336 assert_eq!("Alice", name);
337 assert_eq!(42, age);
338 assert!(statement.next()?);
339 let name : String = statement.read(0)?.try_into()?;
340 let age : usize = statement.read(1)?.try_into()?;
341 assert_eq!("Bob", name);
342 assert_eq!(69, age);
343 assert!(!statement.next()?);
344 Ok(())
345 }
346}