• 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`](enum.Value.html) 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.
data_type(&self) -> Type24     pub fn data_type(&self) -> Type {
25         match *self {
26             ValueRef::Null => Type::Null,
27             ValueRef::Integer(_) => Type::Integer,
28             ValueRef::Real(_) => Type::Real,
29             ValueRef::Text(_) => Type::Text,
30             ValueRef::Blob(_) => Type::Blob,
31         }
32     }
33 }
34 
35 impl<'a> ValueRef<'a> {
36     /// If `self` is case `Integer`, returns the integral value. Otherwise,
37     /// returns `Err(Error::InvalidColumnType)`.
as_i64(&self) -> FromSqlResult<i64>38     pub fn as_i64(&self) -> FromSqlResult<i64> {
39         match *self {
40             ValueRef::Integer(i) => Ok(i),
41             _ => Err(FromSqlError::InvalidType),
42         }
43     }
44 
45     /// If `self` is case `Real`, returns the floating point value. Otherwise,
46     /// returns `Err(Error::InvalidColumnType)`.
as_f64(&self) -> FromSqlResult<f64>47     pub fn as_f64(&self) -> FromSqlResult<f64> {
48         match *self {
49             ValueRef::Real(f) => Ok(f),
50             _ => Err(FromSqlError::InvalidType),
51         }
52     }
53 
54     /// If `self` is case `Text`, returns the string value. Otherwise, returns
55     /// `Err(Error::InvalidColumnType)`.
as_str(&self) -> FromSqlResult<&'a str>56     pub fn as_str(&self) -> FromSqlResult<&'a str> {
57         match *self {
58             ValueRef::Text(t) => {
59                 std::str::from_utf8(t).map_err(|e| FromSqlError::Other(Box::new(e)))
60             }
61             _ => Err(FromSqlError::InvalidType),
62         }
63     }
64 
65     /// If `self` is case `Blob`, returns the byte slice. Otherwise, returns
66     /// `Err(Error::InvalidColumnType)`.
as_blob(&self) -> FromSqlResult<&'a [u8]>67     pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> {
68         match *self {
69             ValueRef::Blob(b) => Ok(b),
70             _ => Err(FromSqlError::InvalidType),
71         }
72     }
73 }
74 
75 impl From<ValueRef<'_>> for Value {
from(borrowed: ValueRef<'_>) -> Value76     fn from(borrowed: ValueRef<'_>) -> Value {
77         match borrowed {
78             ValueRef::Null => Value::Null,
79             ValueRef::Integer(i) => Value::Integer(i),
80             ValueRef::Real(r) => Value::Real(r),
81             ValueRef::Text(s) => {
82                 let s = std::str::from_utf8(s).expect("invalid UTF-8");
83                 Value::Text(s.to_string())
84             }
85             ValueRef::Blob(b) => Value::Blob(b.to_vec()),
86         }
87     }
88 }
89 
90 impl<'a> From<&'a str> for ValueRef<'a> {
from(s: &str) -> ValueRef<'_>91     fn from(s: &str) -> ValueRef<'_> {
92         ValueRef::Text(s.as_bytes())
93     }
94 }
95 
96 impl<'a> From<&'a [u8]> for ValueRef<'a> {
from(s: &[u8]) -> ValueRef<'_>97     fn from(s: &[u8]) -> ValueRef<'_> {
98         ValueRef::Blob(s)
99     }
100 }
101 
102 impl<'a> From<&'a Value> for ValueRef<'a> {
from(value: &'a Value) -> ValueRef<'a>103     fn from(value: &'a Value) -> ValueRef<'a> {
104         match *value {
105             Value::Null => ValueRef::Null,
106             Value::Integer(i) => ValueRef::Integer(i),
107             Value::Real(r) => ValueRef::Real(r),
108             Value::Text(ref s) => ValueRef::Text(s.as_bytes()),
109             Value::Blob(ref b) => ValueRef::Blob(b),
110         }
111     }
112 }
113 
114 impl<'a, T> From<Option<T>> for ValueRef<'a>
115 where
116     T: Into<ValueRef<'a>>,
117 {
from(s: Option<T>) -> ValueRef<'a>118     fn from(s: Option<T>) -> ValueRef<'a> {
119         match s {
120             Some(x) => x.into(),
121             None => ValueRef::Null,
122         }
123     }
124 }
125 
126 #[cfg(any(feature = "functions", feature = "session", feature = "vtab"))]
127 impl<'a> ValueRef<'a> {
from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a>128     pub(crate) unsafe fn from_value(value: *mut crate::ffi::sqlite3_value) -> ValueRef<'a> {
129         use crate::ffi;
130         use std::slice::from_raw_parts;
131 
132         match ffi::sqlite3_value_type(value) {
133             ffi::SQLITE_NULL => ValueRef::Null,
134             ffi::SQLITE_INTEGER => ValueRef::Integer(ffi::sqlite3_value_int64(value)),
135             ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)),
136             ffi::SQLITE_TEXT => {
137                 let text = ffi::sqlite3_value_text(value);
138                 let len = ffi::sqlite3_value_bytes(value);
139                 assert!(
140                     !text.is_null(),
141                     "unexpected SQLITE_TEXT value type with NULL data"
142                 );
143                 let s = from_raw_parts(text as *const u8, len as usize);
144                 ValueRef::Text(s)
145             }
146             ffi::SQLITE_BLOB => {
147                 let (blob, len) = (
148                     ffi::sqlite3_value_blob(value),
149                     ffi::sqlite3_value_bytes(value),
150                 );
151 
152                 assert!(
153                     len >= 0,
154                     "unexpected negative return from sqlite3_value_bytes"
155                 );
156                 if len > 0 {
157                     assert!(
158                         !blob.is_null(),
159                         "unexpected SQLITE_BLOB value type with NULL data"
160                     );
161                     ValueRef::Blob(from_raw_parts(blob as *const u8, len as usize))
162                 } else {
163                     // The return value from sqlite3_value_blob() for a zero-length BLOB
164                     // is a NULL pointer.
165                     ValueRef::Blob(&[])
166                 }
167             }
168             _ => unreachable!("sqlite3_value_type returned invalid value"),
169         }
170     }
171 }
172