1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
use super::{ffi, Connection, Error, Lesult, SqliteTypes, Value}; use std; use std::ffi::CStr; use std::os::raw::c_int; use Row; use Rows; #[derive(Debug)] pub struct Stmt<'con> { con: &'con Connection, pub stmt: *mut ffi::sqlite3_stmt, } impl<'con> Drop for Stmt<'con> { fn drop(&mut self) { let _c = unsafe { ffi::sqlite3_finalize(self.stmt) }; drop(self.con); } } impl<'con> Stmt<'con> { pub fn init(con: &'con Connection) -> Self { Self { con, stmt: unsafe { std::mem::uninitialized() }, } } pub fn prepare(&mut self, sql: &str) -> Result<&mut Self, Error> { let cstr = std::ffi::CString::new(sql) .map_err(|_e| Error::PrepareErr("Null Error".to_string()))?; let rc = unsafe { ffi::sqlite3_prepare_v2( self.con.con, cstr.as_ptr(), -1, &mut self.stmt, std::ptr::null_mut(), ) }; if rc != ffi::SQLITE_OK { return Err(Error::PrepareErr(self.con.get_last_error(rc))); } Ok(self) } fn bind_buff<T>(&mut self, v: Vec<T>, i: std::os::raw::c_int) -> c_int where std::vec::Vec<u8>: std::convert::From<std::vec::Vec<T>>, { let buf_len = v.len(); let c_string = std::ffi::CString::new(v).unwrap(); let destructor = if buf_len > 0 { ffi::SQLITE_TRANSIENT() } else { ffi::SQLITE_STATIC() }; unsafe { ffi::sqlite3_bind_text( self.stmt, i as i32, c_string.as_ptr(), buf_len as i32, destructor, ) } } pub fn bind_values<T>(&mut self, params: &Vec<T>) -> Lesult<()> where T: std::clone::Clone, Value: std::convert::From<T>, { for (i, n) in params.iter().cloned().enumerate() { self.bind(n, (i + 1) as i32)?; } Ok(()) } pub fn bind<T>(&mut self, param: T, index: i32) -> Lesult<()> where Value: std::convert::From<T>, { let param = Value::from(param); use Value::*; let res = match param { Int(v) => unsafe { ffi::sqlite3_bind_int64(self.stmt, index, v) }, Uint(v) => unsafe { ffi::sqlite3_bind_int64(self.stmt, index, v as i64) }, Float(v) => unsafe { ffi::sqlite3_bind_double(self.stmt, index, v) }, Bytes(v) => self.bind_buff(v, index), String(v) => self.bind_buff(v.into_bytes(), index), Null => unsafe { ffi::sqlite3_bind_null(self.stmt, index) }, }; if res == ffi::SQLITE_OK { Ok(()) } else { Err(Error::BindError(self.con.get_last_error(res))) } } pub fn step(&self) -> Lesult<c_int> { if self.stmt.is_null() { return Err(Error::PrepareErr( "Statement is not prepared or is null".to_string(), )); } Ok(unsafe { ffi::sqlite3_step(self.stmt) }) } pub fn execute(&self) -> Lesult<()> { let res = self.step()?; if res == ffi::SQLITE_DONE || res == ffi::SQLITE_ROW { Ok(()) } else { Err(Error::SqliteError(self.con.get_last_error(res))) } } pub fn get_rows(self) -> Rows<'con> { Rows::new(self) } pub fn get_row(&'con self) -> Lesult<Row<'con>> { let step = self.step()?; if step == ffi::SQLITE_ROW { Ok(Row::new(self)) } else if step == ffi::SQLITE_DONE { Err(Error::Empty) } else { Err(Error::SqliteError(self.con.get_last_error(step))) } } pub fn reset(&self) { unsafe { ffi::sqlite3_reset(self.stmt); } } pub fn clear_bindings(&mut self) { unsafe { ffi::sqlite3_clear_bindings(self.stmt); } } pub fn colum_count(&self) -> usize { unsafe { ffi::sqlite3_column_count(self.stmt) as usize } } pub fn colum_name(&self, index: usize) -> &str { unsafe { CStr::from_ptr(ffi::sqlite3_column_name(self.stmt, index as c_int)) } .to_str() .unwrap() } pub fn colum_index(&self, key: &str) -> Lesult<usize> { let count = self.colum_count(); for i in 0..count { if key == self.colum_name(i) { return Ok(i); } } Err(Error::IndexOutOfBounds(format!("{}", key))) } pub fn colum_type(&self, index: usize) -> Lesult<SqliteTypes> { SqliteTypes::new(unsafe { ffi::sqlite3_column_type(self.stmt, index as i32) }) } pub fn get_double(&self, index: usize) -> Value { Value::Float(unsafe { ffi::sqlite3_column_double(self.stmt, index as i32) }) } pub fn get_int32(&self, index: usize) -> Value { Value::Int(unsafe { ffi::sqlite3_column_int(self.stmt, index as i32) } as i64) } pub fn get_int64(&self, index: usize) -> Value { Value::Int(unsafe { ffi::sqlite3_column_int64(self.stmt, index as i32) } as i64) } pub fn get_blob(&self, index: usize) -> Value { let c_ptr = unsafe { ffi::sqlite3_column_blob(self.stmt, index as i32) }; let c_len = unsafe { ffi::sqlite3_column_bytes(self.stmt, index as i32) }; if c_len > 0 { let nvec = unsafe { Vec::from_raw_parts(c_ptr as *mut u8, c_len as usize, c_len as usize) }; let clone = nvec.clone(); std::mem::forget(nvec); Value::Bytes(clone) } else { Value::Bytes(vec![]) } } pub fn get_text(&self, index: usize) -> Value { let cstring = unsafe { ffi::sqlite3_column_text(self.stmt, index as i32) }; let cstring = unsafe { std::ffi::CString::from_raw(cstring as *mut i8) }; let clone = cstring.clone().into_string().unwrap(); std::mem::forget(cstring); Value::String(clone) } }