1use super::{Value, ValueRef};
2use std::convert::TryInto;
3use std::error::Error;
4use std::fmt;
5
6#[derive(Debug)]
8#[non_exhaustive]
9pub enum FromSqlError {
10 InvalidType,
13
14 OutOfRange(i64),
17
18 #[cfg(feature = "i128_blob")]
22 InvalidI128Size(usize),
23
24 #[cfg(feature = "uuid")]
27 InvalidUuidSize(usize),
28
29 Other(Box<dyn Error + Send + Sync + 'static>),
31}
32
33impl PartialEq for FromSqlError {
34 fn eq(&self, other: &FromSqlError) -> bool {
35 match (self, other) {
36 (FromSqlError::InvalidType, FromSqlError::InvalidType) => true,
37 (FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2,
38 #[cfg(feature = "i128_blob")]
39 (FromSqlError::InvalidI128Size(s1), FromSqlError::InvalidI128Size(s2)) => s1 == s2,
40 #[cfg(feature = "uuid")]
41 (FromSqlError::InvalidUuidSize(s1), FromSqlError::InvalidUuidSize(s2)) => s1 == s2,
42 (..) => false,
43 }
44 }
45}
46
47impl fmt::Display for FromSqlError {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match *self {
50 FromSqlError::InvalidType => write!(f, "Invalid type"),
51 FromSqlError::OutOfRange(i) => write!(f, "Value {} out of range", i),
52 #[cfg(feature = "i128_blob")]
53 FromSqlError::InvalidI128Size(s) => {
54 write!(f, "Cannot read 128bit value out of {} byte blob", s)
55 }
56 #[cfg(feature = "uuid")]
57 FromSqlError::InvalidUuidSize(s) => {
58 write!(f, "Cannot read UUID value out of {} byte blob", s)
59 }
60 FromSqlError::Other(ref err) => err.fmt(f),
61 }
62 }
63}
64
65impl Error for FromSqlError {
66 fn source(&self) -> Option<&(dyn Error + 'static)> {
67 if let FromSqlError::Other(ref err) = self {
68 Some(&**err)
69 } else {
70 None
71 }
72 }
73}
74
75pub type FromSqlResult<T> = Result<T, FromSqlError>;
77
78pub trait FromSql: Sized {
80 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>;
82}
83
84macro_rules! from_sql_integral(
85 ($t:ident) => (
86 impl FromSql for $t {
87 #[inline]
88 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
89 let i = i64::column_result(value)?;
90 i.try_into().map_err(|_| FromSqlError::OutOfRange(i))
91 }
92 }
93 )
94);
95
96from_sql_integral!(i8);
97from_sql_integral!(i16);
98from_sql_integral!(i32);
99from_sql_integral!(isize);
101from_sql_integral!(u8);
102from_sql_integral!(u16);
103from_sql_integral!(u32);
104from_sql_integral!(u64);
105from_sql_integral!(usize);
106
107impl FromSql for i64 {
108 #[inline]
109 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
110 value.as_i64()
111 }
112}
113
114impl FromSql for f32 {
115 #[inline]
116 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
117 match value {
118 ValueRef::Integer(i) => Ok(i as f32),
119 ValueRef::Real(f) => Ok(f as f32),
120 _ => Err(FromSqlError::InvalidType),
121 }
122 }
123}
124
125impl FromSql for f64 {
126 #[inline]
127 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
128 match value {
129 ValueRef::Integer(i) => Ok(i as f64),
130 ValueRef::Real(f) => Ok(f),
131 _ => Err(FromSqlError::InvalidType),
132 }
133 }
134}
135
136impl FromSql for bool {
137 #[inline]
138 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
139 i64::column_result(value).map(|i| !matches!(i, 0))
140 }
141}
142
143impl FromSql for String {
144 #[inline]
145 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
146 value.as_str().map(ToString::to_string)
147 }
148}
149
150impl FromSql for Box<str> {
151 #[inline]
152 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
153 value.as_str().map(Into::into)
154 }
155}
156
157impl FromSql for std::rc::Rc<str> {
158 #[inline]
159 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
160 value.as_str().map(Into::into)
161 }
162}
163
164impl FromSql for std::sync::Arc<str> {
165 #[inline]
166 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
167 value.as_str().map(Into::into)
168 }
169}
170
171impl FromSql for Vec<u8> {
172 #[inline]
173 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
174 value.as_blob().map(|b| b.to_vec())
175 }
176}
177
178#[cfg(feature = "i128_blob")]
179impl FromSql for i128 {
180 #[inline]
181 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
182 use byteorder::{BigEndian, ByteOrder};
183
184 value.as_blob().and_then(|bytes| {
185 if bytes.len() == 16 {
186 Ok(BigEndian::read_i128(bytes) ^ (1i128 << 127))
187 } else {
188 Err(FromSqlError::InvalidI128Size(bytes.len()))
189 }
190 })
191 }
192}
193
194#[cfg(feature = "uuid")]
195impl FromSql for uuid::Uuid {
196 #[inline]
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
208impl<T: FromSql> FromSql for Option<T> {
209 #[inline]
210 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
211 match value {
212 ValueRef::Null => Ok(None),
213 _ => FromSql::column_result(value).map(Some),
214 }
215 }
216}
217
218impl FromSql for Value {
219 #[inline]
220 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
221 Ok(value.into())
222 }
223}
224
225#[cfg(test)]
226mod test {
227 use super::FromSql;
228 use crate::{Connection, Error, Result};
229
230 #[test]
231 fn test_integral_ranges() -> Result<()> {
232 let db = Connection::open_in_memory()?;
233
234 fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64])
235 where
236 T: Into<i64> + FromSql + ::std::fmt::Debug,
237 {
238 for n in out_of_range {
239 let err = db
240 .query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
241 .unwrap_err();
242 match err {
243 Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value),
244 _ => panic!("unexpected error: {}", err),
245 }
246 }
247 for n in in_range {
248 assert_eq!(
249 *n,
250 db.query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
251 .unwrap()
252 .into()
253 );
254 }
255 }
256
257 check_ranges::<i8>(&db, &[-129, 128], &[-128, 0, 1, 127]);
258 check_ranges::<i16>(&db, &[-32769, 32768], &[-32768, -1, 0, 1, 32767]);
259 check_ranges::<i32>(
260 &db,
261 &[-2_147_483_649, 2_147_483_648],
262 &[-2_147_483_648, -1, 0, 1, 2_147_483_647],
263 );
264 check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]);
265 check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]);
266 check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
267 Ok(())
268 }
269}