• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::{Type, Value};
2 use crate::types::{FromSqlError, FromSqlResult};
3 
4 /// A non-owning [dynamic type value](http://sqlite.org/datatype3.html). Typically, the
5 /// memory backing this value is owned by SQLite.
6 ///
7 /// See [`Value`](Value) for an owning dynamic type value.
8 #[derive(Copy, Clone, Debug, PartialEq)]
9 pub enum ValueRef<'a> {
10     /// The value is a `NULL` value.
11     Null,
12     /// The value is a signed integer.
13     Integer(i64),
14     /// The value is a floating point number.
15     Real(f64),
16     /// The value is a text string.
17     Text(&'a [u8]),
18     /// The value is a blob of data
19     Blob(&'a [u8]),
20 }
21 
22 impl ValueRef<'_> {
23     /// Returns SQLite fundamental datatype.
24     #[inline]
25     #[must_use]
data_type(&self) -> Type26     pub fn data_type(&self) -> Type {
27         match *self {
28             ValueRef::Null => Type::Null,
29             ValueRef::Integer(_) => Type::Integer,
30             ValueRef::Real(_) => Type::Real,
31             ValueRef::Text(_) => Type::Text,
32             ValueRef::Blob(_) => Type::Blob,
33         }
34     }
35 }
36 
37 impl<'a> ValueRef<'a> {
38     /// If `self` is case `Integer`, returns the integral value. Otherwise,
39     /// returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
40     #[inline]
as_i64(&self) -> FromSqlResult<i64>41     pub fn as_i64(&self) -> FromSqlResult<i64> {
42         match *self {
43             ValueRef::Integer(i) => Ok(i),
44             _ => Err(FromSqlError::InvalidType),
45         }
46     }
47 
48     /// If `self` is case `Null` returns None.
49     /// If `self` is case `Integer`, returns the integral value.
50     /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
51     #[inline]
as_i64_or_null(&self) -> FromSqlResult<Option<i64>>52     pub fn as_i64_or_null(&self) -> FromSqlResult<Option<i64>> {
53         match *self {
54             ValueRef::Null => Ok(None),
55             ValueRef::Integer(i) => Ok(Some(i)),
56             _ => Err(FromSqlError::InvalidType),
57         }
58     }
59 
60     /// If `self` is case `Real`, returns the floating point value. Otherwise,
61     /// returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
62     #[inline]
as_f64(&self) -> FromSqlResult<f64>63     pub fn as_f64(&self) -> FromSqlResult<f64> {
64         match *self {
65             ValueRef::Real(f) => Ok(f),
66             _ => Err(FromSqlError::InvalidType),
67         }
68     }
69 
70     /// If `self` is case `Null` returns None.
71     /// If `self` is case `Real`, returns the floating point value.
72     /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
73     #[inline]
as_f64_or_null(&self) -> FromSqlResult<Option<f64>>74     pub fn as_f64_or_null(&self) -> FromSqlResult<Option<f64>> {
75         match *self {
76             ValueRef::Null => Ok(None),
77             ValueRef::Real(f) => Ok(Some(f)),
78             _ => Err(FromSqlError::InvalidType),
79         }
80     }
81 
82     /// If `self` is case `Text`, returns the string value. Otherwise, returns
83     /// [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
84     #[inline]
as_str(&self) -> FromSqlResult<&'a str>85     pub fn as_str(&self) -> FromSqlResult<&'a str> {
86         match *self {
87             ValueRef::Text(t) => {
88                 std::str::from_utf8(t).map_err(|e| FromSqlError::Other(Box::new(e)))
89             }
90             _ => Err(FromSqlError::InvalidType),
91         }
92     }
93 
94     /// If `self` is case `Null` returns None.
95     /// If `self` is case `Text`, returns the string value.
96     /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
97     #[inline]
as_str_or_null(&self) -> FromSqlResult<Option<&'a str>>98     pub fn as_str_or_null(&self) -> FromSqlResult<Option<&'a str>> {
99         match *self {
100             ValueRef::Null => Ok(None),
101             ValueRef::Text(t) => std::str::from_utf8(t)
102                 .map_err(|e| FromSqlError::Other(Box::new(e)))
103                 .map(Some),
104             _ => Err(FromSqlError::InvalidType),
105         }
106     }
107 
108     /// If `self` is case `Blob`, returns the byte slice. Otherwise, returns
109     /// [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
110     #[inline]
as_blob(&self) -> FromSqlResult<&'a [u8]>111     pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> {
112         match *self {
113             ValueRef::Blob(b) => Ok(b),
114             _ => Err(FromSqlError::InvalidType),
115         }
116     }
117 
118     /// If `self` is case `Null` returns None.
119     /// If `self` is case `Blob`, returns the byte slice.
120     /// Otherwise, returns [`Err(Error::InvalidColumnType)`](crate::Error::InvalidColumnType).
121     #[inline]
as_blob_or_null(&self) -> FromSqlResult<Option<&'a [u8]>>122     pub fn as_blob_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> {
123         match *self {
124             ValueRef::Null => Ok(None),
125             ValueRef::Blob(b) => Ok(Some(b)),
126             _ => Err(FromSqlError::InvalidType),
127         }
128     }
129 
130     /// Returns the byte slice that makes up this `ValueRef` if it's either
131     /// [`ValueRef::Blob`] or [`ValueRef::Text`].
132     #[inline]
as_bytes(&self) -> FromSqlResult<&'a [u8]>133     pub fn as_bytes(&self) -> FromSqlResult<&'a [u8]> {
134         match self {
135             ValueRef::Text(s) | ValueRef::Blob(s) => Ok(s),
136             _ => Err(FromSqlError::InvalidType),
137         }
138     }
139 
140     /// If `self` is case `Null` returns None.
141     /// If `self` is [`ValueRef::Blob`] or [`ValueRef::Text`] returns the byte
142     /// slice that makes up this value
143     #[inline]
as_bytes_or_null(&self) -> FromSqlResult<Option<&'a [u8]>>144     pub fn as_bytes_or_null(&self) -> FromSqlResult<Option<&'a [u8]>> {
145         match *self {
146             ValueRef::Null => Ok(None),
147             ValueRef::Text(s) | ValueRef::Blob(s) => Ok(Some(s)),
148             _ => Err(FromSqlError::InvalidType),
149         }
150     }
151 }
152 
153 impl From<ValueRef<'_>> for Value {
154     #[inline]
155     #[track_caller]
from(borrowed: ValueRef<'_>) -> Value156     fn from(borrowed: ValueRef<'_>) -> Value {
157         match borrowed {
158             ValueRef::Null => Value::Null,
159             ValueRef::Integer(i) => Value::Integer(i),
160             ValueRef::Real(r) => Value::Real(r),
161             ValueRef::Text(s) => {
162                 let s = std::str::from_utf8(s).expect("invalid UTF-8");
163                 Value::Text(s.to_string())
164             }
165             ValueRef::Blob(b) => Value::Blob(b.to_vec()),
166         }
167     }
168 }
169 
170 impl<'a> From<&'a str> for ValueRef<'a> {
171     #[inline]
from(s: &str) -> ValueRef<'_>172     fn from(s: &str) -> ValueRef<'_> {
173         ValueRef::Text(s.as_bytes())
174     }
175 }
176 
177 impl<'a> From<&'a [u8]> for ValueRef<'a> {
178     #[inline]
from(s: &[u8]) -> ValueRef<'_>179     fn from(s: &[u8]) -> ValueRef<'_> {
180         ValueRef::Blob(s)
181     }
182 }
183 
184 impl<'a> From<&'a Value> for ValueRef<'a> {
185     #[inline]
from(value: &'a Value) -> ValueRef<'a>186     fn from(value: &'a Value) -> ValueRef<'a> {
187         match *value {
188             Value::Null => ValueRef::Null,
189             Value::Integer(i) => ValueRef::Integer(i),
190             Value::Real(r) => ValueRef::Real(r),
191             Value::Text(ref s) => ValueRef::Text(s.as_bytes()),
192             Value::Blob(ref b) => ValueRef::Blob(b),
193         }
194     }
195 }
196 
197 impl<'a, T> From<Option<T>> for ValueRef<'a>
198 where
199     T: Into<ValueRef<'a>>,
200 {
201     #[inline]
from(s: Option<T>) -> ValueRef<'a>202     fn from(s: Option<T>) -> ValueRef<'a> {
203         match s {
204             Some(x) => x.into(),
205             None => ValueRef::Null,
206         }
207     }
208 }
209 
210 #[cfg(any(
211     feature = "functions",
212     feature = "session",
213     feature = "vtab",
214     feature = "preupdate_hook"
215 ))]
216 impl<'a> ValueRef<'a> {
from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a>217     pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a> {
218         use crate::ffi;
219         use std::slice::from_raw_parts;
220 
221         match ffi::sqlite3_value_type(value) {
222             ffi::SQLITE_NULL => ValueRef::Null,
223             ffi::SQLITE_INTEGER => ValueRef::Integer(ffi::sqlite3_value_int64(value)),
224             ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)),
225             ffi::SQLITE_TEXT => {
226                 let text = ffi::sqlite3_value_text(value);
227                 let len = ffi::sqlite3_value_bytes(value);
228                 assert!(
229                     !text.is_null(),
230                     "unexpected SQLITE_TEXT value type with NULL data"
231                 );
232                 let s = from_raw_parts(text.cast::<u8>(), len as usize);
233                 ValueRef::Text(s)
234             }
235             ffi::SQLITE_BLOB => {
236                 let (blob, len) = (
237                     ffi::sqlite3_value_blob(value),
238                     ffi::sqlite3_value_bytes(value),
239                 );
240 
241                 assert!(
242                     len >= 0,
243                     "unexpected negative return from sqlite3_value_bytes"
244                 );
245                 if len > 0 {
246                     assert!(
247                         !blob.is_null(),
248                         "unexpected SQLITE_BLOB value type with NULL data"
249                     );
250                     ValueRef::Blob(from_raw_parts(blob.cast::<u8>(), len as usize))
251                 } else {
252                     // The return value from sqlite3_value_blob() for a zero-length BLOB
253                     // is a NULL pointer.
254                     ValueRef::Blob(&[])
255                 }
256             }
257             _ => unreachable!("sqlite3_value_type returned invalid value"),
258         }
259     }
260 
261     // TODO sqlite3_value_nochange // 3.22.0 & VTab xUpdate
262     // TODO sqlite3_value_frombind // 3.28.0
263 }
264 
265 #[cfg(test)]
266 mod test {
267     use super::ValueRef;
268     use crate::types::FromSqlResult;
269 
270     #[test]
as_i64() -> FromSqlResult<()>271     fn as_i64() -> FromSqlResult<()> {
272         assert!(ValueRef::Real(1.0).as_i64().is_err());
273         assert_eq!(ValueRef::Integer(1).as_i64(), Ok(1));
274         Ok(())
275     }
276     #[test]
as_i64_or_null() -> FromSqlResult<()>277     fn as_i64_or_null() -> FromSqlResult<()> {
278         assert_eq!(ValueRef::Null.as_i64_or_null(), Ok(None));
279         assert!(ValueRef::Real(1.0).as_i64_or_null().is_err());
280         assert_eq!(ValueRef::Integer(1).as_i64_or_null(), Ok(Some(1)));
281         Ok(())
282     }
283     #[test]
as_f64() -> FromSqlResult<()>284     fn as_f64() -> FromSqlResult<()> {
285         assert!(ValueRef::Integer(1).as_f64().is_err());
286         assert_eq!(ValueRef::Real(1.0).as_f64(), Ok(1.0));
287         Ok(())
288     }
289     #[test]
as_f64_or_null() -> FromSqlResult<()>290     fn as_f64_or_null() -> FromSqlResult<()> {
291         assert_eq!(ValueRef::Null.as_f64_or_null(), Ok(None));
292         assert!(ValueRef::Integer(1).as_f64_or_null().is_err());
293         assert_eq!(ValueRef::Real(1.0).as_f64_or_null(), Ok(Some(1.0)));
294         Ok(())
295     }
296     #[test]
as_str() -> FromSqlResult<()>297     fn as_str() -> FromSqlResult<()> {
298         assert!(ValueRef::Null.as_str().is_err());
299         assert_eq!(ValueRef::Text(b"").as_str(), Ok(""));
300         Ok(())
301     }
302     #[test]
as_str_or_null() -> FromSqlResult<()>303     fn as_str_or_null() -> FromSqlResult<()> {
304         assert_eq!(ValueRef::Null.as_str_or_null(), Ok(None));
305         assert!(ValueRef::Integer(1).as_str_or_null().is_err());
306         assert_eq!(ValueRef::Text(b"").as_str_or_null(), Ok(Some("")));
307         Ok(())
308     }
309     #[test]
as_blob() -> FromSqlResult<()>310     fn as_blob() -> FromSqlResult<()> {
311         assert!(ValueRef::Null.as_blob().is_err());
312         assert_eq!(ValueRef::Blob(b"").as_blob(), Ok(&b""[..]));
313         Ok(())
314     }
315     #[test]
as_blob_or_null() -> FromSqlResult<()>316     fn as_blob_or_null() -> FromSqlResult<()> {
317         assert_eq!(ValueRef::Null.as_blob_or_null(), Ok(None));
318         assert!(ValueRef::Integer(1).as_blob_or_null().is_err());
319         assert_eq!(ValueRef::Blob(b"").as_blob_or_null(), Ok(Some(&b""[..])));
320         Ok(())
321     }
322     #[test]
as_bytes() -> FromSqlResult<()>323     fn as_bytes() -> FromSqlResult<()> {
324         assert!(ValueRef::Null.as_bytes().is_err());
325         assert_eq!(ValueRef::Blob(b"").as_bytes(), Ok(&b""[..]));
326         Ok(())
327     }
328     #[test]
as_bytes_or_null() -> FromSqlResult<()>329     fn as_bytes_or_null() -> FromSqlResult<()> {
330         assert_eq!(ValueRef::Null.as_bytes_or_null(), Ok(None));
331         assert!(ValueRef::Integer(1).as_bytes_or_null().is_err());
332         assert_eq!(ValueRef::Blob(b"").as_bytes_or_null(), Ok(Some(&b""[..])));
333         Ok(())
334     }
335 }
336