Skip to main content

sqlite3_ext/value/
mod.rs

1use super::{ffi, sqlite3_match_version, types::*};
2pub use blob::*;
3pub use passed_ref::*;
4use std::{marker::PhantomData, ptr, slice, str};
5pub use unsafe_ptr::*;
6pub use value_list::*;
7
8mod blob;
9mod passed_ref;
10mod test;
11mod unsafe_ptr;
12mod value_list;
13
14#[derive(Debug, Eq, PartialEq, Copy, Clone)]
15pub enum ValueType {
16    Integer,
17    Float,
18    Text,
19    Blob,
20    Null,
21}
22
23impl ValueType {
24    pub(crate) fn from_sqlite(val: i32) -> ValueType {
25        match val {
26            ffi::SQLITE_INTEGER => ValueType::Integer,
27            ffi::SQLITE_FLOAT => ValueType::Float,
28            ffi::SQLITE_TEXT => ValueType::Text,
29            ffi::SQLITE_BLOB => ValueType::Blob,
30            ffi::SQLITE_NULL => ValueType::Null,
31            _ => unreachable!(),
32        }
33    }
34}
35
36/// Allows access to an underlying SQLite value.
37// This trait isn't really useful as a trait bound anywhere, and only serves to ensure that
38// ValueRef and Column provide a similar interface. Column could Deref to Value, but this
39// actually involves an internal conversion of the held value (the MEM_Static flag becomes
40// MEM_Ephem), and I'm not sure what kind of performance penalty that would bring.
41pub trait FromValue {
42    /// Returns the data type of the ValueRef. Note that calling get methods on the
43    /// ValueRef may cause a conversion to a different data type, but this is not
44    /// guaranteed.
45    fn value_type(&self) -> ValueType;
46
47    /// Convenience method equivalent to `self.value_type() == ValueType::Null`.
48    fn is_null(&self) -> bool {
49        self.value_type() == ValueType::Null
50    }
51
52    /// Interpret this value as i32.
53    fn get_i32(&self) -> i32;
54
55    /// Interpret this value as i64.
56    fn get_i64(&self) -> i64;
57
58    /// Interpret this value as f64.
59    fn get_f64(&self) -> f64;
60
61    /// Get the bytes of this BLOB value.
62    ///
63    /// # Safety
64    ///
65    /// If the type of this value is not BLOB, the behavior of this function is undefined.
66    unsafe fn get_blob_unchecked(&self) -> &[u8];
67
68    /// Interpret this value as a BLOB.
69    fn get_blob(&mut self) -> Result<&[u8]>;
70
71    /// Attempt to interpret this value as a BLOB, without converting. If the underlying
72    /// data type is not a BLOB, this function will fail with Err([SQLITE_MISMATCH]).
73    fn try_get_blob(&self) -> Result<&[u8]> {
74        match self.value_type() {
75            ValueType::Blob => Ok(unsafe { self.get_blob_unchecked() }),
76            _ => Err(SQLITE_MISMATCH),
77        }
78    }
79
80    /// Get the underlying TEXT value.
81    ///
82    /// This method will fail if the value has invalid UTF-8.
83    ///
84    /// # Safety
85    ///
86    /// If the type of this value is not TEXT, the behavior of this function is undefined.
87    unsafe fn get_str_unchecked(&self) -> Result<&str> {
88        Ok(str::from_utf8(self.get_blob_unchecked())?)
89    }
90
91    /// Interpret the value as TEXT.
92    ///
93    /// This method will fail if SQLite runs out of memory while converting the value, or
94    /// if the value has invalid UTF-8.
95    fn get_str(&mut self) -> Result<&str> {
96        Ok(str::from_utf8(self.get_blob()?)?)
97    }
98
99    /// Attempt to interpret this value as TEXT, without converting. If the underlying data
100    /// type is not TEXT, this function will fail with Err([SQLITE_MISMATCH]). This
101    /// function can also fail if the string has invalid UTF-8.
102    fn try_get_str(&self) -> Result<&str> {
103        match self.value_type() {
104            ValueType::Text => unsafe { self.get_str_unchecked() },
105            _ => Err(SQLITE_MISMATCH),
106        }
107    }
108
109    /// Clone the value, returning a [Value].
110    fn to_owned(&self) -> Result<Value> {
111        match self.value_type() {
112            ValueType::Integer => Ok(Value::from(self.get_i64())),
113            ValueType::Float => Ok(Value::from(self.get_f64())),
114            ValueType::Text => unsafe { Ok(Value::from(self.get_str_unchecked()?.to_owned())) },
115            ValueType::Blob => unsafe { Ok(Value::from(Blob::from(self.get_blob_unchecked()))) },
116            ValueType::Null => Ok(Value::Null),
117        }
118    }
119}
120
121/// A protected SQL value.
122///
123/// SQLite always owns all value objects. Consequently, this struct is never owned by Rust
124/// code, but instead always borrowed. A "protected" value means that SQLite holds a mutex for
125/// the lifetime of the reference.
126///
127/// SQLite automatically converts data to any requested type where possible. This conversion is
128/// typically done in-place, which is why many of the conversion methods of this type require
129/// `&mut`.
130#[repr(transparent)]
131pub struct ValueRef {
132    base: ffi::sqlite3_value,
133    // Values are not safe to send between threads.
134    phantom: PhantomData<*const ffi::sqlite3_value>,
135}
136
137impl ValueRef {
138    #[cfg_attr(not(modern_sqlite), allow(unused))]
139    pub(crate) unsafe fn from_ptr<'a>(p: *mut ffi::sqlite3_value) -> &'a mut ValueRef {
140        &mut *(p as *mut ValueRef)
141    }
142
143    /// Get the underlying SQLite handle.
144    ///
145    /// # Safety
146    ///
147    /// Invoking SQLite methods on the returned value may invalidate existing references
148    /// previously returned by this object. This is safe as long as a mutable reference to
149    /// this ValueRef is held.
150    pub unsafe fn as_ptr(&self) -> *mut ffi::sqlite3_value {
151        &self.base as *const ffi::sqlite3_value as _
152    }
153
154    /// Attempt to convert the ValueRef to a numeric data type, and return the resulting
155    /// data type. This conversion will only happen if it is losles, otherwise the
156    /// underlying value will remain its original type.
157    pub fn numeric_type(&mut self) -> ValueType {
158        unsafe { ValueType::from_sqlite(ffi::sqlite3_value_numeric_type(self.as_ptr())) }
159    }
160
161    /// Returns true if this ValueRef originated from one of the sqlite3_bind interfaces.
162    /// If it comes from an SQL literal value, or a table column, or an expression, then
163    /// this method returns false.
164    ///
165    /// Requires SQLite 3.28.0. On earlier versions, this method always returns false.
166    pub fn is_from_bind(&self) -> bool {
167        sqlite3_match_version! {
168            3_028_000 => unsafe { ffi::sqlite3_value_frombind(self.as_ptr()) != 0 },
169            _ => false,
170        }
171    }
172
173    /// Return true if the value is unchanged by an UPDATE operation. Specifically, this method is guaranteed to return true if all of the following are true:
174    ///
175    /// - this ValueRef is a parameter to an [UpdateVTab](crate::vtab::UpdateVTab) method;
176    /// - during the corresponding call to
177    ///   [VTabCursor::column](crate::vtab::VTabCursor::column),
178    ///   [ColumnContext::nochange](crate::vtab::ColumnContext::nochange) returned true; and
179    /// - the column method failed with [Error::NoChange](crate::Error::NoChange).
180    ///
181    /// If this method returns true under these circumstances, then the value will appear to be SQL NULL, and the UpdateVTab method
182    /// must not change the underlying value.
183    ///
184    /// Requires SQLite 3.22.0. On earlier versions of SQLite, this function will always
185    /// return false.
186    pub fn nochange(&self) -> bool {
187        sqlite3_match_version! {
188            3_022_000 => (unsafe { ffi::sqlite3_value_nochange(self.as_ptr()) } != 0),
189            _ => false,
190        }
191    }
192
193    // Caller is responsible for enforcing Rust pointer aliasing rules.
194    unsafe fn get_ref_internal<T: 'static>(&self) -> Option<&mut PassedRef<T>> {
195        sqlite3_match_version! {
196            3_020_000 => (ffi::sqlite3_value_pointer(self.as_ptr(), POINTER_TAG) as *mut PassedRef<T>).as_mut(),
197            _ => None,
198        }
199    }
200
201    /// Get the [PassedRef] stored in this value.
202    ///
203    /// This is a safe way of passing arbitrary Rust objects through SQLite, however it
204    /// requires SQLite 3.20.0 to work. On older versions of SQLite, this function will
205    /// always return None.
206    ///
207    /// Requires SQLite 3.20.0. On earlier versions of SQLite, this function will always
208    /// return None.
209    pub fn get_ref<T: 'static>(&self) -> Option<&T> {
210        unsafe { self.get_ref_internal::<T>() }
211            .map(|x| PassedRef::get(x))
212            .unwrap_or(None)
213    }
214}
215
216impl FromValue for ValueRef {
217    fn value_type(&self) -> ValueType {
218        unsafe { ValueType::from_sqlite(ffi::sqlite3_value_type(self.as_ptr())) }
219    }
220
221    fn get_i32(&self) -> i32 {
222        unsafe { ffi::sqlite3_value_int(self.as_ptr()) }
223    }
224
225    fn get_i64(&self) -> i64 {
226        unsafe { ffi::sqlite3_value_int64(self.as_ptr()) }
227    }
228
229    fn get_f64(&self) -> f64 {
230        unsafe { ffi::sqlite3_value_double(self.as_ptr()) }
231    }
232
233    unsafe fn get_blob_unchecked(&self) -> &[u8] {
234        let len = ffi::sqlite3_value_bytes(self.as_ptr());
235        if len == 0 {
236            return &[];
237        }
238        let data = ffi::sqlite3_value_blob(self.as_ptr());
239        slice::from_raw_parts(data as _, len as _)
240    }
241
242    fn get_blob(&mut self) -> Result<&[u8]> {
243        unsafe {
244            let len = ffi::sqlite3_value_bytes(self.as_ptr());
245            if len == 0 {
246                return Ok(&[]);
247            }
248            let data = ffi::sqlite3_value_blob(self.as_ptr());
249            if data.is_null() {
250                return Err(SQLITE_NOMEM);
251            } else {
252                Ok(slice::from_raw_parts(data as _, len as _))
253            }
254        }
255    }
256}
257
258impl PartialEq for ValueRef {
259    /// Compare the underlying values of two ValueRefs. This function follows SQL equality
260    /// semantics, meaning that NULL != NULL.
261    fn eq(&self, other: &Self) -> bool {
262        if self.value_type() != other.value_type() {
263            return false;
264        }
265        match self.value_type() {
266            ValueType::Integer => self.get_i64() == other.get_i64(),
267            ValueType::Float => self.get_f64() == other.get_f64(),
268            ValueType::Text | ValueType::Blob => unsafe {
269                self.get_blob_unchecked() == other.get_blob_unchecked()
270            },
271            ValueType::Null => false,
272        }
273    }
274}
275
276impl std::fmt::Debug for ValueRef {
277    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
278        match self.value_type() {
279            ValueType::Integer => f.debug_tuple("Integer").field(&self.get_i64()).finish(),
280            ValueType::Float => f.debug_tuple("Float").field(&self.get_f64()).finish(),
281            ValueType::Text => f
282                .debug_tuple("Text")
283                .field(unsafe { &self.get_str_unchecked() })
284                .finish(),
285            ValueType::Blob => f
286                .debug_tuple("Blob")
287                .field(unsafe { &self.get_blob_unchecked() })
288                .finish(),
289            ValueType::Null => {
290                if let Some(r) = unsafe { self.get_ref_internal::<()>() } {
291                    f.debug_tuple("Null").field(&r).finish()
292                } else {
293                    f.debug_tuple("Null").finish()
294                }
295            }
296        }
297    }
298}
299
300/// Stores an SQLite-compatible value owned by Rust code.
301#[derive(Debug, PartialEq, Clone)]
302pub enum Value {
303    Integer(i64),
304    Float(f64),
305    Text(String),
306    Blob(Blob),
307    Null,
308}
309
310macro_rules! value_from {
311    ($ty:ty as ($x:ident) => $impl:expr) => {
312        impl From<$ty> for Value {
313            fn from($x: $ty) -> Value {
314                $impl
315            }
316        }
317    };
318}
319
320value_from!(i32 as (x) => Value::Integer(x as _));
321value_from!(i64 as (x) => Value::Integer(x));
322value_from!(f64 as (x) => Value::Float(x));
323value_from!(String as (x) => Value::Text(x));
324value_from!(Blob as (x) => Value::Blob(x));
325value_from!(() as (_x) => Value::Null);