1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
use super::{ffi, sqlite3_match_version, types::*};
pub use blob::*;
pub use passed_ref::*;
use std::{marker::PhantomData, ptr, slice, str};
pub use unsafe_ptr::*;
pub use value_list::*;

mod blob;
mod passed_ref;
mod test;
mod unsafe_ptr;
mod value_list;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ValueType {
    Integer,
    Float,
    Text,
    Blob,
    Null,
}

impl ValueType {
    pub(crate) fn from_sqlite(val: i32) -> ValueType {
        match val {
            ffi::SQLITE_INTEGER => ValueType::Integer,
            ffi::SQLITE_FLOAT => ValueType::Float,
            ffi::SQLITE_TEXT => ValueType::Text,
            ffi::SQLITE_BLOB => ValueType::Blob,
            ffi::SQLITE_NULL => ValueType::Null,
            _ => unreachable!(),
        }
    }
}

/// Allows access to an underlying SQLite value.
// This trait isn't really useful as a trait bound anywhere, and only serves to ensure that
// ValueRef and Column provide a similar interface. Column could Deref to Value, but this
// actually involves an internal conversion of the held value (the MEM_Static flag becomes
// MEM_Ephem), and I'm not sure what kind of performance penalty that would bring.
pub trait FromValue {
    /// Returns the data type of the ValueRef. Note that calling get methods on the
    /// ValueRef may cause a conversion to a different data type, but this is not
    /// guaranteed.
    fn value_type(&self) -> ValueType;

    /// Convenience method equivalent to `self.value_type() == ValueType::Null`.
    fn is_null(&self) -> bool {
        self.value_type() == ValueType::Null
    }

    /// Interpret this value as i32.
    fn get_i32(&self) -> i32;

    /// Interpret this value as i64.
    fn get_i64(&self) -> i64;

    /// Interpret this value as f64.
    fn get_f64(&self) -> f64;

    /// Get the bytes of this BLOB value.
    ///
    /// # Safety
    ///
    /// If the type of this value is not BLOB, the behavior of this function is undefined.
    unsafe fn get_blob_unchecked(&self) -> &[u8];

    /// Interpret this value as a BLOB.
    fn get_blob(&mut self) -> Result<&[u8]>;

    /// Attempt to interpret this value as a BLOB, without converting. If the underlying
    /// data type is not a BLOB, this function will fail with Err([SQLITE_MISMATCH]).
    fn try_get_blob(&self) -> Result<&[u8]> {
        match self.value_type() {
            ValueType::Blob => Ok(unsafe { self.get_blob_unchecked() }),
            _ => Err(SQLITE_MISMATCH),
        }
    }

    /// Get the underlying TEXT value.
    ///
    /// This method will fail if the value has invalid UTF-8.
    ///
    /// # Safety
    ///
    /// If the type of this value is not TEXT, the behavior of this function is undefined.
    unsafe fn get_str_unchecked(&self) -> Result<&str> {
        Ok(str::from_utf8(self.get_blob_unchecked())?)
    }

    /// Interpret the value as TEXT.
    ///
    /// This method will fail if SQLite runs out of memory while converting the value, or
    /// if the value has invalid UTF-8.
    fn get_str(&mut self) -> Result<&str> {
        Ok(str::from_utf8(self.get_blob()?)?)
    }

    /// Attempt to interpret this value as TEXT, without converting. If the underlying data
    /// type is not TEXT, this function will fail with Err([SQLITE_MISMATCH]). This
    /// function can also fail if the string has invalid UTF-8.
    fn try_get_str(&self) -> Result<&str> {
        match self.value_type() {
            ValueType::Text => unsafe { self.get_str_unchecked() },
            _ => Err(SQLITE_MISMATCH),
        }
    }

    /// Clone the value, returning a [Value].
    fn to_owned(&self) -> Result<Value> {
        match self.value_type() {
            ValueType::Integer => Ok(Value::from(self.get_i64())),
            ValueType::Float => Ok(Value::from(self.get_f64())),
            ValueType::Text => unsafe { Ok(Value::from(self.get_str_unchecked()?.to_owned())) },
            ValueType::Blob => unsafe { Ok(Value::from(Blob::from(self.get_blob_unchecked()))) },
            ValueType::Null => Ok(Value::Null),
        }
    }
}

/// A protected SQL value.
///
/// SQLite always owns all value objects. Consequently, this struct is never owned by Rust
/// code, but instead always borrowed. A "protected" value means that SQLite holds a mutex for
/// the lifetime of the reference.
///
/// SQLite automatically converts data to any requested type where possible. This conversion is
/// typically done in-place, which is why many of the conversion methods of this type require
/// `&mut`.
#[repr(transparent)]
pub struct ValueRef {
    base: ffi::sqlite3_value,
    // Values are not safe to send between threads.
    phantom: PhantomData<*const ffi::sqlite3_value>,
}

impl ValueRef {
    #[cfg_attr(not(modern_sqlite), allow(unused))]
    pub(crate) unsafe fn from_ptr<'a>(p: *mut ffi::sqlite3_value) -> &'a mut ValueRef {
        &mut *(p as *mut ValueRef)
    }

    /// Get the underlying SQLite handle.
    ///
    /// # Safety
    ///
    /// Invoking SQLite methods on the returned value may invalidate existing references
    /// previously returned by this object. This is safe as long as a mutable reference to
    /// this ValueRef is held.
    pub unsafe fn as_ptr(&self) -> *mut ffi::sqlite3_value {
        &self.base as *const ffi::sqlite3_value as _
    }

    /// Attempt to convert the ValueRef to a numeric data type, and return the resulting
    /// data type. This conversion will only happen if it is losles, otherwise the
    /// underlying value will remain its original type.
    pub fn numeric_type(&mut self) -> ValueType {
        unsafe { ValueType::from_sqlite(ffi::sqlite3_value_numeric_type(self.as_ptr())) }
    }

    /// Returns true if this ValueRef originated from one of the sqlite3_bind interfaces.
    /// If it comes from an SQL literal value, or a table column, or an expression, then
    /// this method returns false.
    ///
    /// Requires SQLite 3.28.0. On earlier versions, this method always returns false.
    pub fn is_from_bind(&self) -> bool {
        sqlite3_match_version! {
            3_028_000 => unsafe { ffi::sqlite3_value_frombind(self.as_ptr()) != 0 },
            _ => false,
        }
    }

    /// 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:
    ///
    /// - this ValueRef is a parameter to an [UpdateVTab](crate::vtab::UpdateVTab) method;
    /// - during the corresponding call to
    ///   [VTabCursor::column](crate::vtab::VTabCursor::column),
    ///   [ColumnContext::nochange](crate::vtab::ColumnContext::nochange) returned true; and
    /// - the column method failed with [Error::NoChange](crate::Error::NoChange).
    ///
    /// If this method returns true under these circumstances, then the value will appear to be SQL NULL, and the UpdateVTab method
    /// must not change the underlying value.
    ///
    /// Requires SQLite 3.22.0. On earlier versions of SQLite, this function will always
    /// return false.
    pub fn nochange(&self) -> bool {
        sqlite3_match_version! {
            3_022_000 => (unsafe { ffi::sqlite3_value_nochange(self.as_ptr()) } != 0),
            _ => false,
        }
    }

    // Caller is responsible for enforcing Rust pointer aliasing rules.
    unsafe fn get_ref_internal<T: 'static>(&self) -> Option<&mut PassedRef<T>> {
        sqlite3_match_version! {
            3_020_000 => (ffi::sqlite3_value_pointer(self.as_ptr(), POINTER_TAG) as *mut PassedRef<T>).as_mut(),
            _ => None,
        }
    }

    /// Get the [PassedRef] stored in this value.
    ///
    /// This is a safe way of passing arbitrary Rust objects through SQLite, however it
    /// requires SQLite 3.20.0 to work. On older versions of SQLite, this function will
    /// always return None.
    ///
    /// Requires SQLite 3.20.0. On earlier versions of SQLite, this function will always
    /// return None.
    pub fn get_ref<T: 'static>(&self) -> Option<&T> {
        unsafe { self.get_ref_internal::<T>() }
            .map(|x| PassedRef::get(x))
            .unwrap_or(None)
    }
}

impl FromValue for ValueRef {
    fn value_type(&self) -> ValueType {
        unsafe { ValueType::from_sqlite(ffi::sqlite3_value_type(self.as_ptr())) }
    }

    fn get_i32(&self) -> i32 {
        unsafe { ffi::sqlite3_value_int(self.as_ptr()) }
    }

    fn get_i64(&self) -> i64 {
        unsafe { ffi::sqlite3_value_int64(self.as_ptr()) }
    }

    fn get_f64(&self) -> f64 {
        unsafe { ffi::sqlite3_value_double(self.as_ptr()) }
    }

    unsafe fn get_blob_unchecked(&self) -> &[u8] {
        let len = ffi::sqlite3_value_bytes(self.as_ptr());
        if len == 0 {
            return &[];
        }
        let data = ffi::sqlite3_value_blob(self.as_ptr());
        slice::from_raw_parts(data as _, len as _)
    }

    fn get_blob(&mut self) -> Result<&[u8]> {
        unsafe {
            let len = ffi::sqlite3_value_bytes(self.as_ptr());
            if len == 0 {
                return Ok(&[]);
            }
            let data = ffi::sqlite3_value_blob(self.as_ptr());
            if data.is_null() {
                return Err(SQLITE_NOMEM);
            } else {
                Ok(slice::from_raw_parts(data as _, len as _))
            }
        }
    }
}

impl PartialEq for ValueRef {
    /// Compare the underlying values of two ValueRefs. This function follows SQL equality
    /// semantics, meaning that NULL != NULL.
    fn eq(&self, other: &Self) -> bool {
        if self.value_type() != other.value_type() {
            return false;
        }
        match self.value_type() {
            ValueType::Integer => self.get_i64() == other.get_i64(),
            ValueType::Float => self.get_f64() == other.get_f64(),
            ValueType::Text | ValueType::Blob => unsafe {
                self.get_blob_unchecked() == other.get_blob_unchecked()
            },
            ValueType::Null => false,
        }
    }
}

impl std::fmt::Debug for ValueRef {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        match self.value_type() {
            ValueType::Integer => f.debug_tuple("Integer").field(&self.get_i64()).finish(),
            ValueType::Float => f.debug_tuple("Float").field(&self.get_f64()).finish(),
            ValueType::Text => f
                .debug_tuple("Text")
                .field(unsafe { &self.get_str_unchecked() })
                .finish(),
            ValueType::Blob => f
                .debug_tuple("Blob")
                .field(unsafe { &self.get_blob_unchecked() })
                .finish(),
            ValueType::Null => {
                if let Some(r) = unsafe { self.get_ref_internal::<()>() } {
                    f.debug_tuple("Null").field(&r).finish()
                } else {
                    f.debug_tuple("Null").finish()
                }
            }
        }
    }
}

/// Stores an SQLite-compatible value owned by Rust code.
#[derive(Debug, PartialEq, Clone)]
pub enum Value {
    Integer(i64),
    Float(f64),
    Text(String),
    Blob(Blob),
    Null,
}

macro_rules! value_from {
    ($ty:ty as ($x:ident) => $impl:expr) => {
        impl From<$ty> for Value {
            fn from($x: $ty) -> Value {
                $impl
            }
        }
    };
}

value_from!(i32 as (x) => Value::Integer(x as _));
value_from!(i64 as (x) => Value::Integer(x));
value_from!(f64 as (x) => Value::Float(x));
value_from!(String as (x) => Value::Text(x));
value_from!(Blob as (x) => Value::Blob(x));
value_from!(() as (_x) => Value::Null);