1 use super::{Value, ValueRef}; 2 use std::error::Error; 3 use std::fmt; 4 5 /// Enum listing possible errors from `FromSql` trait. 6 #[derive(Debug)] 7 #[non_exhaustive] 8 pub enum FromSqlError { 9 /// Error when an SQLite value is requested, but the type of the result 10 /// cannot be converted to the requested Rust type. 11 InvalidType, 12 13 /// Error when the i64 value returned by SQLite cannot be stored into the 14 /// requested type. 15 OutOfRange(i64), 16 17 /// `feature = "i128_blob"` Error returned when reading an `i128` from a 18 /// blob with a size other than 16. Only available when the `i128_blob` 19 /// feature is enabled. 20 #[cfg(feature = "i128_blob")] 21 InvalidI128Size(usize), 22 23 /// `feature = "uuid"` Error returned when reading a `uuid` from a blob with 24 /// a size other than 16. Only available when the `uuid` feature is enabled. 25 #[cfg(feature = "uuid")] 26 InvalidUuidSize(usize), 27 28 /// An error case available for implementors of the `FromSql` trait. 29 Other(Box<dyn Error + Send + Sync + 'static>), 30 } 31 32 impl PartialEq for FromSqlError { eq(&self, other: &FromSqlError) -> bool33 fn eq(&self, other: &FromSqlError) -> bool { 34 match (self, other) { 35 (FromSqlError::InvalidType, FromSqlError::InvalidType) => true, 36 (FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2, 37 #[cfg(feature = "i128_blob")] 38 (FromSqlError::InvalidI128Size(s1), FromSqlError::InvalidI128Size(s2)) => s1 == s2, 39 #[cfg(feature = "uuid")] 40 (FromSqlError::InvalidUuidSize(s1), FromSqlError::InvalidUuidSize(s2)) => s1 == s2, 41 (..) => false, 42 } 43 } 44 } 45 46 impl fmt::Display for FromSqlError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 48 match *self { 49 FromSqlError::InvalidType => write!(f, "Invalid type"), 50 FromSqlError::OutOfRange(i) => write!(f, "Value {} out of range", i), 51 #[cfg(feature = "i128_blob")] 52 FromSqlError::InvalidI128Size(s) => { 53 write!(f, "Cannot read 128bit value out of {} byte blob", s) 54 } 55 #[cfg(feature = "uuid")] 56 FromSqlError::InvalidUuidSize(s) => { 57 write!(f, "Cannot read UUID value out of {} byte blob", s) 58 } 59 FromSqlError::Other(ref err) => err.fmt(f), 60 } 61 } 62 } 63 64 impl Error for FromSqlError { source(&self) -> Option<&(dyn Error + 'static)>65 fn source(&self) -> Option<&(dyn Error + 'static)> { 66 if let FromSqlError::Other(ref err) = self { 67 Some(&**err) 68 } else { 69 None 70 } 71 } 72 } 73 74 /// Result type for implementors of the `FromSql` trait. 75 pub type FromSqlResult<T> = Result<T, FromSqlError>; 76 77 /// A trait for types that can be created from a SQLite value. 78 /// 79 /// Note that `FromSql` and `ToSql` are defined for most integral types, but 80 /// not `u64` or `usize`. This is intentional; SQLite returns integers as 81 /// signed 64-bit values, which cannot fully represent the range of these 82 /// types. Rusqlite would have to 83 /// decide how to handle negative values: return an error or reinterpret as a 84 /// very large postive numbers, neither of which 85 /// is guaranteed to be correct for everyone. Callers can work around this by 86 /// fetching values as i64 and then doing the interpretation themselves or by 87 /// defining a newtype and implementing `FromSql`/`ToSql` for it. 88 pub trait FromSql: Sized { 89 /// Converts SQLite value into Rust value. column_result(value: ValueRef<'_>) -> FromSqlResult<Self>90 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>; 91 } 92 93 impl FromSql for isize { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>94 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 95 i64::column_result(value).and_then(|i| { 96 if i < isize::min_value() as i64 || i > isize::max_value() as i64 { 97 Err(FromSqlError::OutOfRange(i)) 98 } else { 99 Ok(i as isize) 100 } 101 }) 102 } 103 } 104 105 macro_rules! from_sql_integral( 106 ($t:ident) => ( 107 impl FromSql for $t { 108 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 109 i64::column_result(value).and_then(|i| { 110 if i < i64::from($t::min_value()) || i > i64::from($t::max_value()) { 111 Err(FromSqlError::OutOfRange(i)) 112 } else { 113 Ok(i as $t) 114 } 115 }) 116 } 117 } 118 ) 119 ); 120 121 from_sql_integral!(i8); 122 from_sql_integral!(i16); 123 from_sql_integral!(i32); 124 from_sql_integral!(u8); 125 from_sql_integral!(u16); 126 from_sql_integral!(u32); 127 128 impl FromSql for i64 { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>129 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 130 value.as_i64() 131 } 132 } 133 134 impl FromSql for f64 { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>135 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 136 match value { 137 ValueRef::Integer(i) => Ok(i as f64), 138 ValueRef::Real(f) => Ok(f), 139 _ => Err(FromSqlError::InvalidType), 140 } 141 } 142 } 143 144 impl FromSql for bool { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>145 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 146 i64::column_result(value).map(|i| !matches!(i, 0)) 147 } 148 } 149 150 impl FromSql for String { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>151 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 152 value.as_str().map(ToString::to_string) 153 } 154 } 155 156 impl FromSql for Box<str> { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>157 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 158 value.as_str().map(Into::into) 159 } 160 } 161 162 impl FromSql for std::rc::Rc<str> { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>163 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 164 value.as_str().map(Into::into) 165 } 166 } 167 168 impl FromSql for std::sync::Arc<str> { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>169 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 170 value.as_str().map(Into::into) 171 } 172 } 173 174 impl FromSql for Vec<u8> { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>175 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 176 value.as_blob().map(|b| b.to_vec()) 177 } 178 } 179 180 #[cfg(feature = "i128_blob")] 181 impl FromSql for i128 { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>182 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 183 use byteorder::{BigEndian, ByteOrder}; 184 185 value.as_blob().and_then(|bytes| { 186 if bytes.len() == 16 { 187 Ok(BigEndian::read_i128(bytes) ^ (1i128 << 127)) 188 } else { 189 Err(FromSqlError::InvalidI128Size(bytes.len())) 190 } 191 }) 192 } 193 } 194 195 #[cfg(feature = "uuid")] 196 impl FromSql for uuid::Uuid { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>197 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 198 value 199 .as_blob() 200 .and_then(|bytes| { 201 uuid::Builder::from_slice(bytes) 202 .map_err(|_| FromSqlError::InvalidUuidSize(bytes.len())) 203 }) 204 .map(|mut builder| builder.build()) 205 } 206 } 207 208 impl<T: FromSql> FromSql for Option<T> { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>209 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 210 match value { 211 ValueRef::Null => Ok(None), 212 _ => FromSql::column_result(value).map(Some), 213 } 214 } 215 } 216 217 impl FromSql for Value { column_result(value: ValueRef<'_>) -> FromSqlResult<Self>218 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 219 Ok(value.into()) 220 } 221 } 222 223 #[cfg(test)] 224 mod test { 225 use super::FromSql; 226 use crate::{Connection, Error}; 227 checked_memory_handle() -> Connection228 fn checked_memory_handle() -> Connection { 229 Connection::open_in_memory().unwrap() 230 } 231 232 #[test] test_integral_ranges()233 fn test_integral_ranges() { 234 let db = checked_memory_handle(); 235 236 fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64]) 237 where 238 T: Into<i64> + FromSql + ::std::fmt::Debug, 239 { 240 for n in out_of_range { 241 let err = db 242 .query_row("SELECT ?", &[n], |r| r.get::<_, T>(0)) 243 .unwrap_err(); 244 match err { 245 Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value), 246 _ => panic!("unexpected error: {}", err), 247 } 248 } 249 for n in in_range { 250 assert_eq!( 251 *n, 252 db.query_row("SELECT ?", &[n], |r| r.get::<_, T>(0)) 253 .unwrap() 254 .into() 255 ); 256 } 257 } 258 259 check_ranges::<i8>(&db, &[-129, 128], &[-128, 0, 1, 127]); 260 check_ranges::<i16>(&db, &[-32769, 32768], &[-32768, -1, 0, 1, 32767]); 261 check_ranges::<i32>( 262 &db, 263 &[-2_147_483_649, 2_147_483_648], 264 &[-2_147_483_648, -1, 0, 1, 2_147_483_647], 265 ); 266 check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]); 267 check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]); 268 check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]); 269 } 270 } 271