• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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