1 use super::{Value, ValueRef}; 2 use std::convert::TryInto; 3 use std::error::Error; 4 use std::fmt; 5 6 /// Enum listing possible errors from [`FromSql`] trait. 7 #[derive(Debug)] 8 #[non_exhaustive] 9 pub enum FromSqlError { 10 /// Error when an SQLite value is requested, but the type of the result 11 /// cannot be converted to the requested Rust type. 12 InvalidType, 13 14 /// Error when the i64 value returned by SQLite cannot be stored into the 15 /// requested type. 16 OutOfRange(i64), 17 18 /// Error when the blob result returned by SQLite cannot be stored into the 19 /// requested type due to a size mismatch. 20 InvalidBlobSize { 21 /// The expected size of the blob. 22 expected_size: usize, 23 /// The actual size of the blob that was returned. 24 blob_size: usize, 25 }, 26 27 /// An error case available for implementors of the [`FromSql`] trait. 28 Other(Box<dyn Error + Send + Sync + 'static>), 29 } 30 31 impl PartialEq for FromSqlError { eq(&self, other: &FromSqlError) -> bool32 fn eq(&self, other: &FromSqlError) -> bool { 33 match (self, other) { 34 (FromSqlError::InvalidType, FromSqlError::InvalidType) => true, 35 (FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2, 36 ( 37 FromSqlError::InvalidBlobSize { 38 expected_size: es1, 39 blob_size: bs1, 40 }, 41 FromSqlError::InvalidBlobSize { 42 expected_size: es2, 43 blob_size: bs2, 44 }, 45 ) => es1 == es2 && bs1 == bs2, 46 (..) => false, 47 } 48 } 49 } 50 51 impl fmt::Display for FromSqlError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 53 match *self { 54 FromSqlError::InvalidType => write!(f, "Invalid type"), 55 FromSqlError::OutOfRange(i) => write!(f, "Value {i} out of range"), 56 FromSqlError::InvalidBlobSize { 57 expected_size, 58 blob_size, 59 } => { 60 write!( 61 f, 62 "Cannot read {} byte value out of {} byte blob", 63 expected_size, blob_size 64 ) 65 } 66 FromSqlError::Other(ref err) => err.fmt(f), 67 } 68 } 69 } 70 71 impl Error for FromSqlError { source(&self) -> Option<&(dyn Error + 'static)>72 fn source(&self) -> Option<&(dyn Error + 'static)> { 73 if let FromSqlError::Other(ref err) = self { 74 Some(&**err) 75 } else { 76 None 77 } 78 } 79 } 80 81 /// Result type for implementors of the [`FromSql`] trait. 82 pub type FromSqlResult<T> = Result<T, FromSqlError>; 83 84 /// A trait for types that can be created from a SQLite value. 85 pub trait FromSql: Sized { 86 /// Converts SQLite value into Rust value. column_result(value: ValueRef<'_>) -> FromSqlResult<Self>87 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>; 88 } 89 90 macro_rules! from_sql_integral( 91 ($t:ident) => ( 92 impl FromSql for $t { 93 #[inline] 94 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 95 let i = i64::column_result(value)?; 96 i.try_into().map_err(|_| FromSqlError::OutOfRange(i)) 97 } 98 } 99 ) 100 ); 101 102 from_sql_integral!(i8); 103 from_sql_integral!(i16); 104 from_sql_integral!(i32); 105 // from_sql_integral!(i64); // Not needed because the native type is i64. 106 from_sql_integral!(isize); 107 from_sql_integral!(u8); 108 from_sql_integral!(u16); 109 from_sql_integral!(u32); 110 from_sql_integral!(u64); 111 from_sql_integral!(usize); 112 113 impl FromSql for i64 { 114 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>115 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 116 value.as_i64() 117 } 118 } 119 120 impl FromSql for f32 { 121 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>122 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 123 match value { 124 ValueRef::Integer(i) => Ok(i as f32), 125 ValueRef::Real(f) => Ok(f as f32), 126 _ => Err(FromSqlError::InvalidType), 127 } 128 } 129 } 130 131 impl FromSql for f64 { 132 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>133 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 134 match value { 135 ValueRef::Integer(i) => Ok(i as f64), 136 ValueRef::Real(f) => Ok(f), 137 _ => Err(FromSqlError::InvalidType), 138 } 139 } 140 } 141 142 impl FromSql for bool { 143 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>144 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 145 i64::column_result(value).map(|i| i != 0) 146 } 147 } 148 149 impl FromSql for String { 150 #[inline] 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> { 157 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>158 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 159 value.as_str().map(Into::into) 160 } 161 } 162 163 impl FromSql for std::rc::Rc<str> { 164 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>165 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 166 value.as_str().map(Into::into) 167 } 168 } 169 170 impl FromSql for std::sync::Arc<str> { 171 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>172 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 173 value.as_str().map(Into::into) 174 } 175 } 176 177 impl FromSql for Vec<u8> { 178 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>179 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 180 value.as_blob().map(<[u8]>::to_vec) 181 } 182 } 183 184 impl<const N: usize> FromSql for [u8; N] { 185 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>186 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 187 let slice = value.as_blob()?; 188 slice.try_into().map_err(|_| FromSqlError::InvalidBlobSize { 189 expected_size: N, 190 blob_size: slice.len(), 191 }) 192 } 193 } 194 195 #[cfg(feature = "i128_blob")] 196 #[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))] 197 impl FromSql for i128 { 198 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>199 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 200 let bytes = <[u8; 16]>::column_result(value)?; 201 Ok(i128::from_be_bytes(bytes) ^ (1_i128 << 127)) 202 } 203 } 204 205 #[cfg(feature = "uuid")] 206 #[cfg_attr(docsrs, doc(cfg(feature = "uuid")))] 207 impl FromSql for uuid::Uuid { 208 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>209 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 210 let bytes = <[u8; 16]>::column_result(value)?; 211 Ok(uuid::Uuid::from_u128(u128::from_be_bytes(bytes))) 212 } 213 } 214 215 impl<T: FromSql> FromSql for Option<T> { 216 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>217 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 218 match value { 219 ValueRef::Null => Ok(None), 220 _ => FromSql::column_result(value).map(Some), 221 } 222 } 223 } 224 225 impl FromSql for Value { 226 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>227 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 228 Ok(value.into()) 229 } 230 } 231 232 #[cfg(test)] 233 mod test { 234 use super::FromSql; 235 use crate::{Connection, Error, Result}; 236 237 #[test] test_integral_ranges() -> Result<()>238 fn test_integral_ranges() -> Result<()> { 239 let db = Connection::open_in_memory()?; 240 241 fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64]) 242 where 243 T: Into<i64> + FromSql + std::fmt::Debug, 244 { 245 for n in out_of_range { 246 let err = db 247 .query_row("SELECT ?1", [n], |r| r.get::<_, T>(0)) 248 .unwrap_err(); 249 match err { 250 Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value), 251 _ => panic!("unexpected error: {}", err), 252 } 253 } 254 for n in in_range { 255 assert_eq!( 256 *n, 257 db.query_row("SELECT ?1", [n], |r| r.get::<_, T>(0)) 258 .unwrap() 259 .into() 260 ); 261 } 262 } 263 264 check_ranges::<i8>(&db, &[-129, 128], &[-128, 0, 1, 127]); 265 check_ranges::<i16>(&db, &[-32769, 32768], &[-32768, -1, 0, 1, 32767]); 266 check_ranges::<i32>( 267 &db, 268 &[-2_147_483_649, 2_147_483_648], 269 &[-2_147_483_648, -1, 0, 1, 2_147_483_647], 270 ); 271 check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]); 272 check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]); 273 check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]); 274 Ok(()) 275 } 276 } 277