1#![allow(unsafe_code)] // ffi calls
2#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3extern crate libsqlite3_sys as ffi;
45#[cfg(all(target_family = "wasm", target_os = "unknown"))]
6use sqlite_wasm_rs as ffi;
78use core::cell::Ref;
9use core::ptr::NonNull;
10use core::{slice, str};
1112use crate::sqlite::SqliteType;
1314use super::owned_row::OwnedSqliteRow;
15use super::row::PrivateSqliteRow;
1617/// Raw sqlite value as received from the database
18///
19/// Use the `read_*` functions to access the actual
20/// value or use existing `FromSql` implementations
21/// to convert this into rust values
22#[allow(missing_debug_implementations, missing_copy_implementations)]
23pub struct SqliteValue<'row, 'stmt, 'query> {
24// This field exists to ensure that nobody
25 // can modify the underlying row while we are
26 // holding a reference to some row value here
27_row: Option<Ref<'row, PrivateSqliteRow<'stmt, 'query>>>,
28// we extract the raw value pointer as part of the constructor
29 // to safe the match statements for each method
30 // According to benchmarks this leads to a ~20-30% speedup
31 //
32 // This is sound as long as nobody calls `stmt.step()`
33 // while holding this value. We ensure this by including
34 // a reference to the row above.
35value: NonNull<ffi::sqlite3_value>,
36// An optional storage for a string that is
37 // created from an non-utf8 blob value via `read_str`
38 // This field mostly exists for as we cannot
39 // return an error in that case as the API is
40 // stable and doesn't return a `Result`. We instead
41 // use `String::from_utf8_lossy` there and need
42 // to store the potential owned result here
43string_ref: Option<alloc::boxed::Box<str>>,
44}
4546#[derive(#[automatically_derived]
impl ::core::fmt::Debug for OwnedSqliteValue {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"OwnedSqliteValue", "value", &&self.value)
}
}Debug)]
47#[repr(transparent)]
48pub(super) struct OwnedSqliteValue {
49pub(super) value: NonNull<ffi::sqlite3_value>,
50}
5152impl Dropfor OwnedSqliteValue {
53fn drop(&mut self) {
54unsafe { ffi::sqlite3_value_free(self.value.as_ptr()) }
55 }
56}
5758// Unsafe Send impl safe since sqlite3_value is built with sqlite3_value_dup
59// see https://www.sqlite.org/c3ref/value.html
60unsafe impl Sendfor OwnedSqliteValue {}
6162impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> {
63pub(super) fn new(
64 row: Ref<'row, PrivateSqliteRow<'stmt, 'query>>,
65 col_idx: usize,
66 ) -> Option<SqliteValue<'row, 'stmt, 'query>> {
67let value = match &*row {
68 PrivateSqliteRow::Direct(stmt) => stmt.column_value(
69col_idx70 .try_into()
71 .expect("Diesel expects to run at least on a 32 bit platform"),
72 )?,
73 PrivateSqliteRow::Duplicated { values, .. } => {
74values.get(col_idx).and_then(|v| v.as_ref())?.value
75 }
76 };
7778let ret = Self {
79 _row: Some(row),
80value,
81 string_ref: None,
82 };
83if ret.value_type().is_none() {
84None85 } else {
86Some(ret)
87 }
88 }
8990pub(super) fn from_owned_row(
91 row: &'row OwnedSqliteRow,
92 col_idx: usize,
93 ) -> Option<SqliteValue<'row, 'stmt, 'query>> {
94let value = row.values.get(col_idx).and_then(|v| v.as_ref())?.value;
95let ret = Self {
96 _row: None,
97value,
98 string_ref: None,
99 };
100if ret.value_type().is_none() {
101None102 } else {
103Some(ret)
104 }
105 }
106107pub(super) fn from_function_row(
108 row: &'row [Option<OwnedSqliteValue>],
109 col_idx: usize,
110 ) -> Option<SqliteValue<'row, 'stmt, 'query>> {
111let value = row.get(col_idx).and_then(|v| v.as_ref())?.value;
112let ret = Self {
113 _row: None,
114value,
115 string_ref: None,
116 };
117if ret.value_type().is_none() {
118None119 } else {
120Some(ret)
121 }
122 }
123124pub(crate) fn as_byte_string(&mut self) -> &'row [u8] {
125unsafe {
126// https://sqlite.org/c3ref/value_blob.html
127 // Please pay particular attention to the fact that the pointer returned
128 // from sqlite3_value_blob(), sqlite3_value_text(), or sqlite3_value_text16()
129 // can be invalidated by a subsequent call to sqlite3_value_bytes(), sqlite3_value_bytes16(),
130 // sqlite3_value_text(), or sqlite3_value_text16().
131let len = ffi::sqlite3_value_bytes(self.value.as_ptr());
132let ptr = ffi::sqlite3_value_text(self.value.as_ptr());
133 slice::from_raw_parts(
134ptr,
135len.try_into()
136 .expect("Diesel expects to run at least on a 32 bit platform"),
137 )
138 }
139 }
140141pub(crate) fn as_utf8_str(&mut self) -> Result<&'row str, core::str::Utf8Error> {
142 str::from_utf8(self.as_byte_string())
143 }
144145pub(crate) fn parse_string<'value, R>(&'value mut self, f: impl FnOnce(&'value str) -> R) -> R {
146let bytes = self.as_byte_string();
147// For blobs this might return non-utf values
148 //
149 // The sqlite documentation there seems to be at least inaccurate
150let s = match alloc::string::String::from_utf8_lossy(bytes) {
151 alloc::borrow::Cow::Borrowed(s) => s,
152 alloc::borrow::Cow::Owned(b) => {
153self.string_ref = Some(b.into_boxed_str());
154self.string_ref
155 .as_deref()
156 .expect("We initialised it literally above")
157 }
158 };
159f(s)
160 }
161162/// Read the underlying value as string
163 ///
164 /// If the underlying value is not a string sqlite will convert it
165 /// into a string and return that value instead.
166 ///
167 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
168 /// type of the value.
169 ///
170 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
171pub fn read_text(&mut self) -> &str {
172self.parse_string(|s| s)
173 }
174175/// Read the underlying value as blob
176 ///
177 /// If the underlying value is not a blob sqlite will convert it
178 /// into a blob and return that value instead.
179 ///
180 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
181 /// type of the value.
182 ///
183 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
184pub fn read_blob(&mut self) -> &'row [u8] {
185unsafe {
186// https://sqlite.org/c3ref/value_blob.html
187 // Please pay particular attention to the fact that the pointer returned
188 // from sqlite3_value_blob(), sqlite3_value_text(), or sqlite3_value_text16()
189 // can be invalidated by a subsequent call to sqlite3_value_bytes(), sqlite3_value_bytes16(),
190 // sqlite3_value_text(), or sqlite3_value_text16().
191let len = ffi::sqlite3_value_bytes(self.value.as_ptr());
192let ptr = ffi::sqlite3_value_blob(self.value.as_ptr());
193if len == 0 {
194// rusts std-lib has an debug_assert that prevents creating
195 // slices without elements from a pointer
196&[]
197 } else {
198 slice::from_raw_parts(
199ptras *const u8,
200len.try_into()
201 .expect("Diesel expects to run at least on a 32 bit platform"),
202 )
203 }
204 }
205 }
206207/// Read the underlying value as 32 bit integer
208 ///
209 /// If the underlying value is not an integer sqlite will convert it
210 /// into an integer and return that value instead.
211 ///
212 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
213 /// type of the value.
214 ///
215 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
216pub fn read_integer(&mut self) -> i32 {
217unsafe { ffi::sqlite3_value_int(self.value.as_ptr()) }
218 }
219220/// Read the underlying value as 64 bit integer
221 ///
222 /// If the underlying value is not a string sqlite will convert it
223 /// into a string and return that value instead.
224 ///
225 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
226 /// type of the value.
227 ///
228 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
229pub fn read_long(&mut self) -> i64 {
230unsafe { ffi::sqlite3_value_int64(self.value.as_ptr()) }
231 }
232233/// Read the underlying value as 64 bit float
234 ///
235 /// If the underlying value is not a string sqlite will convert it
236 /// into a string and return that value instead.
237 ///
238 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
239 /// type of the value.
240 ///
241 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
242pub fn read_double(&mut self) -> f64 {
243unsafe { ffi::sqlite3_value_double(self.value.as_ptr()) }
244 }
245246/// Get the type of the value as returned by sqlite
247pub fn value_type(&self) -> Option<SqliteType> {
248let tpe = unsafe { ffi::sqlite3_value_type(self.value.as_ptr()) };
249match tpe {
250 ffi::SQLITE_TEXT => Some(SqliteType::Text),
251 ffi::SQLITE_INTEGER => Some(SqliteType::Long),
252 ffi::SQLITE_FLOAT => Some(SqliteType::Double),
253 ffi::SQLITE_BLOB => Some(SqliteType::Binary),
254 ffi::SQLITE_NULL => None,
255_ => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Sqlite\'s documentation state that this case ({0}) is not reachable. If you ever see this error message please open an issue at https://github.com/diesel-rs/diesel.",
tpe)));
}unreachable!(
256"Sqlite's documentation state that this case ({}) is not reachable. \
257 If you ever see this error message please open an issue at \
258 https://github.com/diesel-rs/diesel.",
259 tpe
260 ),
261 }
262 }
263}
264265impl OwnedSqliteValue {
266pub(super) fn copy_from_ptr(ptr: NonNull<ffi::sqlite3_value>) -> Option<OwnedSqliteValue> {
267let tpe = unsafe { ffi::sqlite3_value_type(ptr.as_ptr()) };
268if ffi::SQLITE_NULL == tpe {
269return None;
270 }
271let value = unsafe { ffi::sqlite3_value_dup(ptr.as_ptr()) };
272Some(Self {
273 value: NonNull::new(value)?,
274 })
275 }
276277pub(super) fn duplicate(&self) -> OwnedSqliteValue {
278// self.value is a `NonNull` ptr so this cannot be null
279let value = unsafe { ffi::sqlite3_value_dup(self.value.as_ptr()) };
280let value = NonNull::new(value).expect(
281"Sqlite documentation states this returns only null if value is null \
282 or OOM. If you ever see this panic message please open an issue at \
283 https://github.com/diesel-rs/diesel.",
284 );
285OwnedSqliteValue { value }
286 }
287}
288289#[cfg(test)]
290mod tests {
291use crate::connection::{LoadConnection, SimpleConnection};
292use crate::row::Field;
293use crate::row::Row;
294use crate::sql_types::{Blob, Double, Int4, Text};
295use crate::*;
296297#[expect(clippy::approx_constant)] // we really want to use 3.14
298#[diesel_test_helper::test]
299fn can_convert_all_values() {
300let mut conn = SqliteConnection::establish(":memory:").unwrap();
301302 conn.batch_execute("CREATE TABLE tests(int INTEGER, text TEXT, blob BLOB, float FLOAT)")
303 .unwrap();
304305 diesel::sql_query("INSERT INTO tests(int, text, blob, float) VALUES(?, ?, ?, ?)")
306 .bind::<Int4, _>(42)
307 .bind::<Text, _>("foo")
308 .bind::<Blob, _>([0xFF_u8, 0xFE, 0xFD])
309 .bind::<Double, _>(3.14)
310 .execute(&mut conn)
311 .unwrap();
312313let mut res = conn
314 .load(diesel::sql_query(
315"SELECT int, text, blob, float FROM tests",
316 ))
317 .unwrap();
318let row = res.next().unwrap().unwrap();
319let int_field = row.get(0).unwrap();
320let text_field = row.get(1).unwrap();
321let blob_field = row.get(2).unwrap();
322let float_field = row.get(3).unwrap();
323324let mut int_value = int_field.value().unwrap();
325assert_eq!(int_value.read_integer(), 42);
326let mut int_value = int_field.value().unwrap();
327assert_eq!(int_value.read_long(), 42);
328let mut int_value = int_field.value().unwrap();
329assert_eq!(int_value.read_double(), 42.0);
330let mut int_value = int_field.value().unwrap();
331assert_eq!(int_value.read_text(), "42");
332let mut int_value = int_field.value().unwrap();
333assert_eq!(int_value.read_blob(), b"42");
334335let mut text_value = text_field.value().unwrap();
336assert_eq!(text_value.read_integer(), 0);
337let mut text_value = text_field.value().unwrap();
338assert_eq!(text_value.read_long(), 0);
339let mut text_value = text_field.value().unwrap();
340assert_eq!(text_value.read_double(), 0.0);
341let mut text_value = text_field.value().unwrap();
342assert_eq!(text_value.read_text(), "foo");
343let mut text_value = text_field.value().unwrap();
344assert_eq!(text_value.read_blob(), b"foo");
345346let mut blob_value = blob_field.value().unwrap();
347assert_eq!(blob_value.read_integer(), 0);
348let mut blob_value = blob_field.value().unwrap();
349assert_eq!(blob_value.read_long(), 0);
350let mut blob_value = blob_field.value().unwrap();
351assert_eq!(blob_value.read_double(), 0.0);
352let mut blob_value = blob_field.value().unwrap();
353assert_eq!(blob_value.read_text(), "\u{fffd}\u{fffd}\u{fffd}"); // ���
354let mut blob_value = blob_field.value().unwrap();
355assert_eq!(blob_value.read_blob(), [0xFF, 0xFE, 0xFD]);
356357let mut float_value = float_field.value().unwrap();
358assert_eq!(float_value.read_integer(), 3);
359let mut float_value = float_field.value().unwrap();
360assert_eq!(float_value.read_long(), 3);
361let mut float_value = float_field.value().unwrap();
362assert_eq!(float_value.read_double(), 3.14);
363let mut float_value = float_field.value().unwrap();
364assert_eq!(float_value.read_text(), "3.14");
365let mut float_value = float_field.value().unwrap();
366assert_eq!(float_value.read_blob(), b"3.14");
367 }
368}