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 /// Error when the blob result returned by SQLite cannot be stored into the 18 /// requested type due to a size mismatch. 19 InvalidBlobSize { 20 /// The expected size of the blob. 21 expected_size: usize, 22 /// The actual size of the blob that was returned. 23 blob_size: usize, 24 }, 25 26 /// An error case available for implementors of the [`FromSql`] trait. 27 Other(Box<dyn Error + Send + Sync + 'static>), 28 } 29 30 impl PartialEq for FromSqlError { eq(&self, other: &FromSqlError) -> bool31 fn eq(&self, other: &FromSqlError) -> bool { 32 match (self, other) { 33 (FromSqlError::InvalidType, FromSqlError::InvalidType) => true, 34 (FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2, 35 ( 36 FromSqlError::InvalidBlobSize { 37 expected_size: es1, 38 blob_size: bs1, 39 }, 40 FromSqlError::InvalidBlobSize { 41 expected_size: es2, 42 blob_size: bs2, 43 }, 44 ) => es1 == es2 && bs1 == bs2, 45 (..) => false, 46 } 47 } 48 } 49 50 impl fmt::Display for FromSqlError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 52 match *self { 53 FromSqlError::InvalidType => write!(f, "Invalid type"), 54 FromSqlError::OutOfRange(i) => write!(f, "Value {i} out of range"), 55 FromSqlError::InvalidBlobSize { 56 expected_size, 57 blob_size, 58 } => { 59 write!( 60 f, 61 "Cannot read {expected_size} byte value out of {blob_size} byte blob" 62 ) 63 } 64 FromSqlError::Other(ref err) => err.fmt(f), 65 } 66 } 67 } 68 69 impl Error for FromSqlError { source(&self) -> Option<&(dyn Error + 'static)>70 fn source(&self) -> Option<&(dyn Error + 'static)> { 71 if let FromSqlError::Other(ref err) = self { 72 Some(&**err) 73 } else { 74 None 75 } 76 } 77 } 78 79 /// Result type for implementors of the [`FromSql`] trait. 80 pub type FromSqlResult<T> = Result<T, FromSqlError>; 81 82 /// A trait for types that can be created from a SQLite value. 83 pub trait FromSql: Sized { 84 /// Converts SQLite value into Rust value. column_result(value: ValueRef<'_>) -> FromSqlResult<Self>85 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>; 86 } 87 88 macro_rules! from_sql_integral( 89 ($t:ident) => ( 90 impl FromSql for $t { 91 #[inline] 92 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 93 let i = i64::column_result(value)?; 94 i.try_into().map_err(|_| FromSqlError::OutOfRange(i)) 95 } 96 } 97 ); 98 (non_zero $nz:ty, $z:ty) => ( 99 impl FromSql for $nz { 100 #[inline] 101 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 102 let i = <$z>::column_result(value)?; 103 <$nz>::new(i).ok_or(FromSqlError::OutOfRange(0)) 104 } 105 } 106 ) 107 ); 108 109 from_sql_integral!(i8); 110 from_sql_integral!(i16); 111 from_sql_integral!(i32); 112 // from_sql_integral!(i64); // Not needed because the native type is i64. 113 from_sql_integral!(isize); 114 from_sql_integral!(u8); 115 from_sql_integral!(u16); 116 from_sql_integral!(u32); 117 from_sql_integral!(u64); 118 from_sql_integral!(usize); 119 120 from_sql_integral!(non_zero std::num::NonZeroIsize, isize); 121 from_sql_integral!(non_zero std::num::NonZeroI8, i8); 122 from_sql_integral!(non_zero std::num::NonZeroI16, i16); 123 from_sql_integral!(non_zero std::num::NonZeroI32, i32); 124 from_sql_integral!(non_zero std::num::NonZeroI64, i64); 125 #[cfg(feature = "i128_blob")] 126 #[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))] 127 from_sql_integral!(non_zero std::num::NonZeroI128, i128); 128 129 from_sql_integral!(non_zero std::num::NonZeroUsize, usize); 130 from_sql_integral!(non_zero std::num::NonZeroU8, u8); 131 from_sql_integral!(non_zero std::num::NonZeroU16, u16); 132 from_sql_integral!(non_zero std::num::NonZeroU32, u32); 133 from_sql_integral!(non_zero std::num::NonZeroU64, u64); 134 // std::num::NonZeroU128 is not supported since u128 isn't either 135 136 impl FromSql for i64 { 137 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>138 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 139 value.as_i64() 140 } 141 } 142 143 impl FromSql for f32 { 144 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>145 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 146 match value { 147 ValueRef::Integer(i) => Ok(i as f32), 148 ValueRef::Real(f) => Ok(f as f32), 149 _ => Err(FromSqlError::InvalidType), 150 } 151 } 152 } 153 154 impl FromSql for f64 { 155 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>156 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 157 match value { 158 ValueRef::Integer(i) => Ok(i as f64), 159 ValueRef::Real(f) => Ok(f), 160 _ => Err(FromSqlError::InvalidType), 161 } 162 } 163 } 164 165 impl FromSql for bool { 166 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>167 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 168 i64::column_result(value).map(|i| i != 0) 169 } 170 } 171 172 impl FromSql for String { 173 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>174 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 175 value.as_str().map(ToString::to_string) 176 } 177 } 178 179 impl FromSql for Box<str> { 180 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>181 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 182 value.as_str().map(Into::into) 183 } 184 } 185 186 impl FromSql for std::rc::Rc<str> { 187 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>188 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 189 value.as_str().map(Into::into) 190 } 191 } 192 193 impl FromSql for std::sync::Arc<str> { 194 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>195 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 196 value.as_str().map(Into::into) 197 } 198 } 199 200 impl FromSql for Vec<u8> { 201 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>202 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 203 value.as_blob().map(<[u8]>::to_vec) 204 } 205 } 206 207 impl<const N: usize> FromSql for [u8; N] { 208 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>209 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 210 let slice = value.as_blob()?; 211 slice.try_into().map_err(|_| FromSqlError::InvalidBlobSize { 212 expected_size: N, 213 blob_size: slice.len(), 214 }) 215 } 216 } 217 218 #[cfg(feature = "i128_blob")] 219 #[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))] 220 impl FromSql for i128 { 221 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>222 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 223 let bytes = <[u8; 16]>::column_result(value)?; 224 Ok(i128::from_be_bytes(bytes) ^ (1_i128 << 127)) 225 } 226 } 227 228 #[cfg(feature = "uuid")] 229 #[cfg_attr(docsrs, doc(cfg(feature = "uuid")))] 230 impl FromSql for uuid::Uuid { 231 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>232 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 233 let bytes = <[u8; 16]>::column_result(value)?; 234 Ok(uuid::Uuid::from_u128(u128::from_be_bytes(bytes))) 235 } 236 } 237 238 impl<T: FromSql> FromSql for Option<T> { 239 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>240 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 241 match value { 242 ValueRef::Null => Ok(None), 243 _ => FromSql::column_result(value).map(Some), 244 } 245 } 246 } 247 248 impl FromSql for Value { 249 #[inline] column_result(value: ValueRef<'_>) -> FromSqlResult<Self>250 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { 251 Ok(value.into()) 252 } 253 } 254 255 #[cfg(test)] 256 mod test { 257 use super::FromSql; 258 use crate::{Connection, Error, Result}; 259 260 #[test] test_integral_ranges() -> Result<()>261 fn test_integral_ranges() -> Result<()> { 262 let db = Connection::open_in_memory()?; 263 264 fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64]) 265 where 266 T: Into<i64> + FromSql + std::fmt::Debug, 267 { 268 for n in out_of_range { 269 let err = db 270 .query_row("SELECT ?1", [n], |r| r.get::<_, T>(0)) 271 .unwrap_err(); 272 match err { 273 Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value), 274 _ => panic!("unexpected error: {err}"), 275 } 276 } 277 for n in in_range { 278 assert_eq!( 279 *n, 280 db.query_row("SELECT ?1", [n], |r| r.get::<_, T>(0)) 281 .unwrap() 282 .into() 283 ); 284 } 285 } 286 287 check_ranges::<i8>(&db, &[-129, 128], &[-128, 0, 1, 127]); 288 check_ranges::<i16>(&db, &[-32769, 32768], &[-32768, -1, 0, 1, 32767]); 289 check_ranges::<i32>( 290 &db, 291 &[-2_147_483_649, 2_147_483_648], 292 &[-2_147_483_648, -1, 0, 1, 2_147_483_647], 293 ); 294 check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]); 295 check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]); 296 check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]); 297 Ok(()) 298 } 299 300 #[test] test_nonzero_ranges() -> Result<()>301 fn test_nonzero_ranges() -> Result<()> { 302 let db = Connection::open_in_memory()?; 303 304 macro_rules! check_ranges { 305 ($nz:ty, $out_of_range:expr, $in_range:expr) => { 306 for &n in $out_of_range { 307 assert_eq!( 308 db.query_row("SELECT ?1", [n], |r| r.get::<_, $nz>(0)), 309 Err(Error::IntegralValueOutOfRange(0, n)), 310 "{}", 311 std::any::type_name::<$nz>() 312 ); 313 } 314 for &n in $in_range { 315 let non_zero = <$nz>::new(n).unwrap(); 316 assert_eq!( 317 Ok(non_zero), 318 db.query_row("SELECT ?1", [non_zero], |r| r.get::<_, $nz>(0)) 319 ); 320 } 321 }; 322 } 323 324 check_ranges!(std::num::NonZeroI8, &[0, -129, 128], &[-128, 1, 127]); 325 check_ranges!( 326 std::num::NonZeroI16, 327 &[0, -32769, 32768], 328 &[-32768, -1, 1, 32767] 329 ); 330 check_ranges!( 331 std::num::NonZeroI32, 332 &[0, -2_147_483_649, 2_147_483_648], 333 &[-2_147_483_648, -1, 1, 2_147_483_647] 334 ); 335 check_ranges!( 336 std::num::NonZeroI64, 337 &[0], 338 &[-2_147_483_648, -1, 1, 2_147_483_647, i64::MAX, i64::MIN] 339 ); 340 check_ranges!( 341 std::num::NonZeroIsize, 342 &[0], 343 &[-2_147_483_648, -1, 1, 2_147_483_647] 344 ); 345 check_ranges!(std::num::NonZeroU8, &[0, -2, -1, 256], &[1, 255]); 346 check_ranges!(std::num::NonZeroU16, &[0, -2, -1, 65536], &[1, 65535]); 347 check_ranges!( 348 std::num::NonZeroU32, 349 &[0, -2, -1, 4_294_967_296], 350 &[1, 4_294_967_295] 351 ); 352 check_ranges!( 353 std::num::NonZeroU64, 354 &[0, -2, -1, -4_294_967_296], 355 &[1, 4_294_967_295, i64::MAX as u64] 356 ); 357 check_ranges!( 358 std::num::NonZeroUsize, 359 &[0, -2, -1, -4_294_967_296], 360 &[1, 4_294_967_295] 361 ); 362 363 Ok(()) 364 } 365 } 366