sqlx_sqlite/
value.rs

1use std::borrow::Cow;
2use std::marker::PhantomData;
3use std::ptr::NonNull;
4use std::slice::from_raw_parts;
5use std::str::from_utf8;
6use std::sync::Arc;
7
8use libsqlite3_sys::{
9    sqlite3_value, sqlite3_value_blob, sqlite3_value_bytes, sqlite3_value_double,
10    sqlite3_value_dup, sqlite3_value_free, sqlite3_value_int64, sqlite3_value_type, SQLITE_NULL,
11};
12
13pub(crate) use sqlx_core::value::{Value, ValueRef};
14
15use crate::error::BoxDynError;
16use crate::type_info::DataType;
17use crate::{Sqlite, SqliteTypeInfo};
18
19enum SqliteValueData<'r> {
20    Value(&'r SqliteValue),
21    BorrowedHandle(ValueHandle<'r>),
22}
23
24pub struct SqliteValueRef<'r>(SqliteValueData<'r>);
25
26impl<'r> SqliteValueRef<'r> {
27    pub(crate) fn value(value: &'r SqliteValue) -> Self {
28        Self(SqliteValueData::Value(value))
29    }
30
31    // SAFETY: The supplied sqlite3_value must not be null and SQLite must free it. It will not be freed on drop.
32    // The lifetime on this struct should tie it to whatever scope it's valid for before SQLite frees it.
33    #[allow(unused)]
34    pub(crate) unsafe fn borrowed(value: *mut sqlite3_value, type_info: SqliteTypeInfo) -> Self {
35        debug_assert!(!value.is_null());
36        let handle = ValueHandle::new_borrowed(NonNull::new_unchecked(value), type_info);
37        Self(SqliteValueData::BorrowedHandle(handle))
38    }
39
40    // NOTE: `int()` is deliberately omitted because it will silently truncate a wider value,
41    // which is likely to cause bugs:
42    // https://github.com/launchbadge/sqlx/issues/3179
43    // (Similar bug in Postgres): https://github.com/launchbadge/sqlx/issues/3161
44    pub(super) fn int64(&self) -> i64 {
45        match &self.0 {
46            SqliteValueData::Value(v) => v.0.int64(),
47            SqliteValueData::BorrowedHandle(v) => v.int64(),
48        }
49    }
50
51    pub(super) fn double(&self) -> f64 {
52        match &self.0 {
53            SqliteValueData::Value(v) => v.0.double(),
54            SqliteValueData::BorrowedHandle(v) => v.double(),
55        }
56    }
57
58    pub(super) fn blob(&self) -> &'r [u8] {
59        match &self.0 {
60            SqliteValueData::Value(v) => v.0.blob(),
61            SqliteValueData::BorrowedHandle(v) => v.blob(),
62        }
63    }
64
65    pub(super) fn text(&self) -> Result<&'r str, BoxDynError> {
66        match &self.0 {
67            SqliteValueData::Value(v) => v.0.text(),
68            SqliteValueData::BorrowedHandle(v) => v.text(),
69        }
70    }
71}
72
73impl<'r> ValueRef<'r> for SqliteValueRef<'r> {
74    type Database = Sqlite;
75
76    fn to_owned(&self) -> SqliteValue {
77        match &self.0 {
78            SqliteValueData::Value(v) => (*v).clone(),
79            SqliteValueData::BorrowedHandle(v) => unsafe {
80                SqliteValue::new(v.value.as_ptr(), v.type_info.clone())
81            },
82        }
83    }
84
85    fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {
86        match &self.0 {
87            SqliteValueData::Value(v) => v.type_info(),
88            SqliteValueData::BorrowedHandle(v) => v.type_info(),
89        }
90    }
91
92    fn is_null(&self) -> bool {
93        match &self.0 {
94            SqliteValueData::Value(v) => v.is_null(),
95            SqliteValueData::BorrowedHandle(v) => v.is_null(),
96        }
97    }
98}
99
100#[derive(Clone)]
101pub struct SqliteValue(Arc<ValueHandle<'static>>);
102
103pub(crate) struct ValueHandle<'a> {
104    value: NonNull<sqlite3_value>,
105    type_info: SqliteTypeInfo,
106    free_on_drop: bool,
107    _sqlite_value_lifetime: PhantomData<&'a ()>,
108}
109
110// SAFE: only protected value objects are stored in SqliteValue
111unsafe impl<'a> Send for ValueHandle<'a> {}
112unsafe impl<'a> Sync for ValueHandle<'a> {}
113
114impl ValueHandle<'static> {
115    fn new_owned(value: NonNull<sqlite3_value>, type_info: SqliteTypeInfo) -> Self {
116        Self {
117            value,
118            type_info,
119            free_on_drop: true,
120            _sqlite_value_lifetime: PhantomData,
121        }
122    }
123}
124
125impl<'a> ValueHandle<'a> {
126    fn new_borrowed(value: NonNull<sqlite3_value>, type_info: SqliteTypeInfo) -> Self {
127        Self {
128            value,
129            type_info,
130            free_on_drop: false,
131            _sqlite_value_lifetime: PhantomData,
132        }
133    }
134
135    fn type_info_opt(&self) -> Option<SqliteTypeInfo> {
136        let dt = DataType::from_code(unsafe { sqlite3_value_type(self.value.as_ptr()) });
137
138        if let DataType::Null = dt {
139            None
140        } else {
141            Some(SqliteTypeInfo(dt))
142        }
143    }
144
145    fn int64(&self) -> i64 {
146        unsafe { sqlite3_value_int64(self.value.as_ptr()) }
147    }
148
149    fn double(&self) -> f64 {
150        unsafe { sqlite3_value_double(self.value.as_ptr()) }
151    }
152
153    fn blob<'b>(&self) -> &'b [u8] {
154        let len = unsafe { sqlite3_value_bytes(self.value.as_ptr()) };
155
156        // This likely means UB in SQLite itself or our usage of it;
157        // signed integer overflow is UB in the C standard.
158        let len = usize::try_from(len).unwrap_or_else(|_| {
159            panic!("sqlite3_value_bytes() returned value out of range for usize: {len}")
160        });
161
162        if len == 0 {
163            // empty blobs are NULL so just return an empty slice
164            return &[];
165        }
166
167        let ptr = unsafe { sqlite3_value_blob(self.value.as_ptr()) } as *const u8;
168        debug_assert!(!ptr.is_null());
169
170        unsafe { from_raw_parts(ptr, len) }
171    }
172
173    fn text<'b>(&self) -> Result<&'b str, BoxDynError> {
174        Ok(from_utf8(self.blob())?)
175    }
176
177    fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {
178        self.type_info_opt()
179            .map(Cow::Owned)
180            .unwrap_or(Cow::Borrowed(&self.type_info))
181    }
182
183    fn is_null(&self) -> bool {
184        unsafe { sqlite3_value_type(self.value.as_ptr()) == SQLITE_NULL }
185    }
186}
187
188impl<'a> Drop for ValueHandle<'a> {
189    fn drop(&mut self) {
190        if self.free_on_drop {
191            unsafe {
192                sqlite3_value_free(self.value.as_ptr());
193            }
194        }
195    }
196}
197
198impl SqliteValue {
199    // SAFETY: The sqlite3_value must be non-null and SQLite must not free it. It will be freed on drop.
200    pub(crate) unsafe fn new(value: *mut sqlite3_value, type_info: SqliteTypeInfo) -> Self {
201        debug_assert!(!value.is_null());
202        let handle =
203            ValueHandle::new_owned(NonNull::new_unchecked(sqlite3_value_dup(value)), type_info);
204        Self(Arc::new(handle))
205    }
206}
207
208impl Value for SqliteValue {
209    type Database = Sqlite;
210
211    fn as_ref(&self) -> SqliteValueRef<'_> {
212        SqliteValueRef::value(self)
213    }
214
215    fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {
216        self.0.type_info()
217    }
218
219    fn is_null(&self) -> bool {
220        self.0.is_null()
221    }
222}
223
224// #[cfg(feature = "any")]
225// impl<'r> From<SqliteValueRef<'r>> for crate::any::AnyValueRef<'r> {
226//     #[inline]
227//     fn from(value: SqliteValueRef<'r>) -> Self {
228//         crate::any::AnyValueRef {
229//             type_info: value.type_info().clone().into_owned().into(),
230//             kind: crate::any::value::AnyValueRefKind::Sqlite(value),
231//         }
232//     }
233// }
234//
235// #[cfg(feature = "any")]
236// impl From<SqliteValue> for crate::any::AnyValue {
237//     #[inline]
238//     fn from(value: SqliteValue) -> Self {
239//         crate::any::AnyValue {
240//             type_info: value.type_info().clone().into_owned().into(),
241//             kind: crate::any::value::AnyValueKind::Sqlite(value),
242//         }
243//     }
244// }