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::export as ffi;
78use std::cell::Ref;
9use std::ptr::NonNull;
10use std::{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}
3738#[derive(Debug)]
39#[repr(transparent)]
40pub(super) struct OwnedSqliteValue {
41pub(super) value: NonNull<ffi::sqlite3_value>,
42}
4344impl Drop for OwnedSqliteValue {
45fn drop(&mut self) {
46unsafe { ffi::sqlite3_value_free(self.value.as_ptr()) }
47 }
48}
4950// Unsafe Send impl safe since sqlite3_value is built with sqlite3_value_dup
51// see https://www.sqlite.org/c3ref/value.html
52unsafe impl Send for OwnedSqliteValue {}
5354impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> {
55pub(super) fn new(
56 row: Ref<'row, PrivateSqliteRow<'stmt, 'query>>,
57 col_idx: usize,
58 ) -> Option<SqliteValue<'row, 'stmt, 'query>> {
59let value = match &*row {
60 PrivateSqliteRow::Direct(stmt) => stmt.column_value(
61 col_idx
62 .try_into()
63 .expect("Diesel expects to run at least on a 32 bit platform"),
64 )?,
65 PrivateSqliteRow::Duplicated { values, .. } => {
66 values.get(col_idx).and_then(|v| v.as_ref())?.value
67 }
68 };
6970let ret = Self {
71 _row: Some(row),
72 value,
73 };
74if ret.value_type().is_none() {
75None
76} else {
77Some(ret)
78 }
79 }
8081pub(super) fn from_owned_row(
82 row: &'row OwnedSqliteRow,
83 col_idx: usize,
84 ) -> Option<SqliteValue<'row, 'stmt, 'query>> {
85let value = row.values.get(col_idx).and_then(|v| v.as_ref())?.value;
86let ret = Self { _row: None, value };
87if ret.value_type().is_none() {
88None
89} else {
90Some(ret)
91 }
92 }
9394pub(crate) fn parse_string<'value, R>(&'value mut self, f: impl FnOnce(&'value str) -> R) -> R {
95let s = unsafe {
96let ptr = ffi::sqlite3_value_text(self.value.as_ptr());
97let len = ffi::sqlite3_value_bytes(self.value.as_ptr());
98let bytes = slice::from_raw_parts(
99 ptr,
100 len.try_into()
101 .expect("Diesel expects to run at least on a 32 bit platform"),
102 );
103// The string is guaranteed to be utf8 according to
104 // https://www.sqlite.org/c3ref/value_blob.html
105str::from_utf8_unchecked(bytes)
106 };
107 f(s)
108 }
109110/// Read the underlying value as string
111 ///
112 /// If the underlying value is not a string sqlite will convert it
113 /// into a string and return that value instead.
114 ///
115 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
116 /// type of the value.
117 ///
118 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
119pub fn read_text(&mut self) -> &str {
120self.parse_string(|s| s)
121 }
122123/// Read the underlying value as blob
124 ///
125 /// If the underlying value is not a blob sqlite will convert it
126 /// into a blob and return that value instead.
127 ///
128 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
129 /// type of the value.
130 ///
131 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
132pub fn read_blob(&mut self) -> &[u8] {
133unsafe {
134let ptr = ffi::sqlite3_value_blob(self.value.as_ptr());
135let len = ffi::sqlite3_value_bytes(self.value.as_ptr());
136if len == 0 {
137// rusts std-lib has an debug_assert that prevents creating
138 // slices without elements from a pointer
139&[]
140 } else {
141 slice::from_raw_parts(
142 ptr as *const u8,
143 len.try_into()
144 .expect("Diesel expects to run at least on a 32 bit platform"),
145 )
146 }
147 }
148 }
149150/// Read the underlying value as 32 bit integer
151 ///
152 /// If the underlying value is not an integer sqlite will convert it
153 /// into an integer and return that value instead.
154 ///
155 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
156 /// type of the value.
157 ///
158 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
159pub fn read_integer(&mut self) -> i32 {
160unsafe { ffi::sqlite3_value_int(self.value.as_ptr()) }
161 }
162163/// Read the underlying value as 64 bit integer
164 ///
165 /// If the underlying value is not a string sqlite will convert it
166 /// into a string and return that value instead.
167 ///
168 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
169 /// type of the value.
170 ///
171 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
172pub fn read_long(&mut self) -> i64 {
173unsafe { ffi::sqlite3_value_int64(self.value.as_ptr()) }
174 }
175176/// Read the underlying value as 64 bit float
177 ///
178 /// If the underlying value is not a string sqlite will convert it
179 /// into a string and return that value instead.
180 ///
181 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
182 /// type of the value.
183 ///
184 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
185pub fn read_double(&mut self) -> f64 {
186unsafe { ffi::sqlite3_value_double(self.value.as_ptr()) }
187 }
188189/// Get the type of the value as returned by sqlite
190pub fn value_type(&self) -> Option<SqliteType> {
191let tpe = unsafe { ffi::sqlite3_value_type(self.value.as_ptr()) };
192match tpe {
193 ffi::SQLITE_TEXT => Some(SqliteType::Text),
194 ffi::SQLITE_INTEGER => Some(SqliteType::Long),
195 ffi::SQLITE_FLOAT => Some(SqliteType::Double),
196 ffi::SQLITE_BLOB => Some(SqliteType::Binary),
197 ffi::SQLITE_NULL => None,
198_ => unreachable!(
199"Sqlite's documentation state that this case ({}) is not reachable. \
200 If you ever see this error message please open an issue at \
201 https://github.com/diesel-rs/diesel.",
202 tpe
203 ),
204 }
205 }
206}
207208impl OwnedSqliteValue {
209pub(super) fn copy_from_ptr(ptr: NonNull<ffi::sqlite3_value>) -> Option<OwnedSqliteValue> {
210let tpe = unsafe { ffi::sqlite3_value_type(ptr.as_ptr()) };
211if ffi::SQLITE_NULL == tpe {
212return None;
213 }
214let value = unsafe { ffi::sqlite3_value_dup(ptr.as_ptr()) };
215Some(Self {
216 value: NonNull::new(value)?,
217 })
218 }
219220pub(super) fn duplicate(&self) -> OwnedSqliteValue {
221// self.value is a `NonNull` ptr so this cannot be null
222let value = unsafe { ffi::sqlite3_value_dup(self.value.as_ptr()) };
223let value = NonNull::new(value).expect(
224"Sqlite documentation states this returns only null if value is null \
225 or OOM. If you ever see this panic message please open an issue at \
226 https://github.com/diesel-rs/diesel.",
227 );
228 OwnedSqliteValue { value }
229 }
230}
231232#[cfg(test)]
233mod tests {
234use crate::connection::{LoadConnection, SimpleConnection};
235use crate::row::Field;
236use crate::row::Row;
237use crate::sql_types::{Blob, Double, Int4, Text};
238use crate::*;
239240#[expect(clippy::approx_constant)] // we really want to use 3.14
241#[diesel_test_helper::test]
242fn can_convert_all_values() {
243let mut conn = SqliteConnection::establish(":memory:").unwrap();
244245 conn.batch_execute("CREATE TABLE tests(int INTEGER, text TEXT, blob BLOB, float FLOAT)")
246 .unwrap();
247248 diesel::sql_query("INSERT INTO tests(int, text, blob, float) VALUES(?, ?, ?, ?)")
249 .bind::<Int4, _>(42)
250 .bind::<Text, _>("foo")
251 .bind::<Blob, _>(b"foo")
252 .bind::<Double, _>(3.14)
253 .execute(&mut conn)
254 .unwrap();
255256let mut res = conn
257 .load(diesel::sql_query(
258"SELECT int, text, blob, float FROM tests",
259 ))
260 .unwrap();
261let row = res.next().unwrap().unwrap();
262let int_field = row.get(0).unwrap();
263let text_field = row.get(1).unwrap();
264let blob_field = row.get(2).unwrap();
265let float_field = row.get(3).unwrap();
266267let mut int_value = int_field.value().unwrap();
268assert_eq!(int_value.read_integer(), 42);
269let mut int_value = int_field.value().unwrap();
270assert_eq!(int_value.read_long(), 42);
271let mut int_value = int_field.value().unwrap();
272assert_eq!(int_value.read_double(), 42.0);
273let mut int_value = int_field.value().unwrap();
274assert_eq!(int_value.read_text(), "42");
275let mut int_value = int_field.value().unwrap();
276assert_eq!(int_value.read_blob(), b"42");
277278let mut text_value = text_field.value().unwrap();
279assert_eq!(text_value.read_integer(), 0);
280let mut text_value = text_field.value().unwrap();
281assert_eq!(text_value.read_long(), 0);
282let mut text_value = text_field.value().unwrap();
283assert_eq!(text_value.read_double(), 0.0);
284let mut text_value = text_field.value().unwrap();
285assert_eq!(text_value.read_text(), "foo");
286let mut text_value = text_field.value().unwrap();
287assert_eq!(text_value.read_blob(), b"foo");
288289let mut blob_value = blob_field.value().unwrap();
290assert_eq!(blob_value.read_integer(), 0);
291let mut blob_value = blob_field.value().unwrap();
292assert_eq!(blob_value.read_long(), 0);
293let mut blob_value = blob_field.value().unwrap();
294assert_eq!(blob_value.read_double(), 0.0);
295let mut blob_value = blob_field.value().unwrap();
296assert_eq!(blob_value.read_text(), "foo");
297let mut blob_value = blob_field.value().unwrap();
298assert_eq!(blob_value.read_blob(), b"foo");
299300let mut float_value = float_field.value().unwrap();
301assert_eq!(float_value.read_integer(), 3);
302let mut float_value = float_field.value().unwrap();
303assert_eq!(float_value.read_long(), 3);
304let mut float_value = float_field.value().unwrap();
305assert_eq!(float_value.read_double(), 3.14);
306let mut float_value = float_field.value().unwrap();
307assert_eq!(float_value.read_text(), "3.14");
308let mut float_value = float_field.value().unwrap();
309assert_eq!(float_value.read_blob(), b"3.14");
310 }
311}