1use super::{Value, ValueRef};
2use std::error::Error;
3use std::fmt;
4
5#[derive(Debug)]
7#[non_exhaustive]
8pub enum FromSqlError {
9 InvalidType,
12
13 OutOfRange(i64),
16
17 InvalidBlobSize {
20 expected_size: usize,
22 blob_size: usize,
24 },
25
26 Other(Box<dyn Error + Send + Sync + 'static>),
28}
29
30impl PartialEq for FromSqlError {
31 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
50impl fmt::Display for FromSqlError {
51 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
69impl Error for FromSqlError {
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
79pub type FromSqlResult<T> = Result<T, FromSqlError>;
81
82pub trait FromSql: Sized {
84 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>;
86}
87
88macro_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
109from_sql_integral!(i8);
110from_sql_integral!(i16);
111from_sql_integral!(i32);
112from_sql_integral!(isize);
114from_sql_integral!(u8);
115from_sql_integral!(u16);
116from_sql_integral!(u32);
117from_sql_integral!(u64);
118from_sql_integral!(usize);
119
120from_sql_integral!(non_zero std::num::NonZeroIsize, isize);
121from_sql_integral!(non_zero std::num::NonZeroI8, i8);
122from_sql_integral!(non_zero std::num::NonZeroI16, i16);
123from_sql_integral!(non_zero std::num::NonZeroI32, i32);
124from_sql_integral!(non_zero std::num::NonZeroI64, i64);
125#[cfg(feature = "i128_blob")]
126#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
127from_sql_integral!(non_zero std::num::NonZeroI128, i128);
128
129from_sql_integral!(non_zero std::num::NonZeroUsize, usize);
130from_sql_integral!(non_zero std::num::NonZeroU8, u8);
131from_sql_integral!(non_zero std::num::NonZeroU16, u16);
132from_sql_integral!(non_zero std::num::NonZeroU32, u32);
133from_sql_integral!(non_zero std::num::NonZeroU64, u64);
134impl FromSql for i64 {
137 #[inline]
138 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
139 value.as_i64()
140 }
141}
142
143impl FromSql for f32 {
144 #[inline]
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
154impl FromSql for f64 {
155 #[inline]
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
165impl FromSql for bool {
166 #[inline]
167 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
168 i64::column_result(value).map(|i| i != 0)
169 }
170}
171
172impl FromSql for String {
173 #[inline]
174 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
175 value.as_str().map(ToString::to_string)
176 }
177}
178
179impl FromSql for Box<str> {
180 #[inline]
181 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
182 value.as_str().map(Into::into)
183 }
184}
185
186impl FromSql for std::rc::Rc<str> {
187 #[inline]
188 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
189 value.as_str().map(Into::into)
190 }
191}
192
193impl FromSql for std::sync::Arc<str> {
194 #[inline]
195 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
196 value.as_str().map(Into::into)
197 }
198}
199
200impl FromSql for Vec<u8> {
201 #[inline]
202 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
203 value.as_blob().map(<[u8]>::to_vec)
204 }
205}
206
207impl<const N: usize> FromSql for [u8; N] {
208 #[inline]
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")))]
220impl FromSql for i128 {
221 #[inline]
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")))]
230impl FromSql for uuid::Uuid {
231 #[inline]
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
238impl<T: FromSql> FromSql for Option<T> {
239 #[inline]
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
248impl FromSql for Value {
249 #[inline]
250 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
251 Ok(value.into())
252 }
253}
254
255#[cfg(test)]
256mod test {
257 use super::FromSql;
258 use crate::{Connection, Error, Result};
259
260 #[test]
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]
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}