1#![allow(unsafe_code)] // ffi calls
2extern crate libsqlite3_sys as ffi;
34use std::cell::Ref;
5use std::ptr::NonNull;
6use std::{slice, str};
78use crate::sqlite::SqliteType;
910use super::owned_row::OwnedSqliteRow;
11use super::row::PrivateSqliteRow;
1213/// Raw sqlite value as received from the database
14///
15/// Use the `read_*` functions to access the actual
16/// value or use existing `FromSql` implementations
17/// to convert this into rust values
18#[allow(missing_debug_implementations, missing_copy_implementations)]
19pub struct SqliteValue<'row, 'stmt, 'query> {
20// This field exists to ensure that nobody
21 // can modify the underlying row while we are
22 // holding a reference to some row value here
23_row: Option<Ref<'row, PrivateSqliteRow<'stmt, 'query>>>,
24// we extract the raw value pointer as part of the constructor
25 // to safe the match statements for each method
26 // According to benchmarks this leads to a ~20-30% speedup
27 //
28 // This is sound as long as nobody calls `stmt.step()`
29 // while holding this value. We ensure this by including
30 // a reference to the row above.
31value: NonNull<ffi::sqlite3_value>,
32}
3334#[derive(Debug)]
35#[repr(transparent)]
36pub(super) struct OwnedSqliteValue {
37pub(super) value: NonNull<ffi::sqlite3_value>,
38}
3940impl Drop for OwnedSqliteValue {
41fn drop(&mut self) {
42unsafe { ffi::sqlite3_value_free(self.value.as_ptr()) }
43 }
44}
4546// Unsafe Send impl safe since sqlite3_value is built with sqlite3_value_dup
47// see https://www.sqlite.org/c3ref/value.html
48unsafe impl Send for OwnedSqliteValue {}
4950impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> {
51pub(super) fn new(
52 row: Ref<'row, PrivateSqliteRow<'stmt, 'query>>,
53 col_idx: usize,
54 ) -> Option<SqliteValue<'row, 'stmt, 'query>> {
55let value = match &*row {
56 PrivateSqliteRow::Direct(stmt) => stmt.column_value(
57 col_idx
58 .try_into()
59 .expect("Diesel expects to run at least on a 32 bit platform"),
60 )?,
61 PrivateSqliteRow::Duplicated { values, .. } => {
62 values.get(col_idx).and_then(|v| v.as_ref())?.value
63 }
64 };
6566let ret = Self {
67 _row: Some(row),
68 value,
69 };
70if ret.value_type().is_none() {
71None
72} else {
73Some(ret)
74 }
75 }
7677pub(super) fn from_owned_row(
78 row: &'row OwnedSqliteRow,
79 col_idx: usize,
80 ) -> Option<SqliteValue<'row, 'stmt, 'query>> {
81let value = row.values.get(col_idx).and_then(|v| v.as_ref())?.value;
82let ret = Self { _row: None, value };
83if ret.value_type().is_none() {
84None
85} else {
86Some(ret)
87 }
88 }
8990pub(crate) fn parse_string<'value, R>(&'value mut self, f: impl FnOnce(&'value str) -> R) -> R {
91let s = unsafe {
92let ptr = ffi::sqlite3_value_text(self.value.as_ptr());
93let len = ffi::sqlite3_value_bytes(self.value.as_ptr());
94let bytes = slice::from_raw_parts(
95 ptr,
96 len.try_into()
97 .expect("Diesel expects to run at least on a 32 bit platform"),
98 );
99// The string is guaranteed to be utf8 according to
100 // https://www.sqlite.org/c3ref/value_blob.html
101str::from_utf8_unchecked(bytes)
102 };
103 f(s)
104 }
105106/// Read the underlying value as string
107 ///
108 /// If the underlying value is not a string sqlite will convert it
109 /// into a string and return that value instead.
110 ///
111 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
112 /// type of the value.
113 ///
114 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
115pub fn read_text(&mut self) -> &str {
116self.parse_string(|s| s)
117 }
118119/// Read the underlying value as blob
120 ///
121 /// If the underlying value is not a blob sqlite will convert it
122 /// into a blob and return that value instead.
123 ///
124 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
125 /// type of the value.
126 ///
127 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
128pub fn read_blob(&mut self) -> &[u8] {
129unsafe {
130let ptr = ffi::sqlite3_value_blob(self.value.as_ptr());
131let len = ffi::sqlite3_value_bytes(self.value.as_ptr());
132if len == 0 {
133// rusts std-lib has an debug_assert that prevents creating
134 // slices without elements from a pointer
135&[]
136 } else {
137 slice::from_raw_parts(
138 ptr as *const u8,
139 len.try_into()
140 .expect("Diesel expects to run at least on a 32 bit platform"),
141 )
142 }
143 }
144 }
145146/// Read the underlying value as 32 bit integer
147 ///
148 /// If the underlying value is not an integer sqlite will convert it
149 /// into an integer and return that value instead.
150 ///
151 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
152 /// type of the value.
153 ///
154 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
155pub fn read_integer(&mut self) -> i32 {
156unsafe { ffi::sqlite3_value_int(self.value.as_ptr()) }
157 }
158159/// Read the underlying value as 64 bit integer
160 ///
161 /// If the underlying value is not a string sqlite will convert it
162 /// into a string and return that value instead.
163 ///
164 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
165 /// type of the value.
166 ///
167 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
168pub fn read_long(&mut self) -> i64 {
169unsafe { ffi::sqlite3_value_int64(self.value.as_ptr()) }
170 }
171172/// Read the underlying value as 64 bit float
173 ///
174 /// If the underlying value is not a string sqlite will convert it
175 /// into a string and return that value instead.
176 ///
177 /// Use the [`value_type()`](Self::value_type()) function to determine the actual
178 /// type of the value.
179 ///
180 /// See <https://www.sqlite.org/c3ref/value_blob.html> for details
181pub fn read_double(&mut self) -> f64 {
182unsafe { ffi::sqlite3_value_double(self.value.as_ptr()) }
183 }
184185/// Get the type of the value as returned by sqlite
186pub fn value_type(&self) -> Option<SqliteType> {
187let tpe = unsafe { ffi::sqlite3_value_type(self.value.as_ptr()) };
188match tpe {
189 ffi::SQLITE_TEXT => Some(SqliteType::Text),
190 ffi::SQLITE_INTEGER => Some(SqliteType::Long),
191 ffi::SQLITE_FLOAT => Some(SqliteType::Double),
192 ffi::SQLITE_BLOB => Some(SqliteType::Binary),
193 ffi::SQLITE_NULL => None,
194_ => unreachable!(
195"Sqlite's documentation state that this case ({}) is not reachable. \
196 If you ever see this error message please open an issue at \
197 https://github.com/diesel-rs/diesel.",
198 tpe
199 ),
200 }
201 }
202}
203204impl OwnedSqliteValue {
205pub(super) fn copy_from_ptr(ptr: NonNull<ffi::sqlite3_value>) -> Option<OwnedSqliteValue> {
206let tpe = unsafe { ffi::sqlite3_value_type(ptr.as_ptr()) };
207if ffi::SQLITE_NULL == tpe {
208return None;
209 }
210let value = unsafe { ffi::sqlite3_value_dup(ptr.as_ptr()) };
211Some(Self {
212 value: NonNull::new(value)?,
213 })
214 }
215216pub(super) fn duplicate(&self) -> OwnedSqliteValue {
217// self.value is a `NonNull` ptr so this cannot be null
218let value = unsafe { ffi::sqlite3_value_dup(self.value.as_ptr()) };
219let value = NonNull::new(value).expect(
220"Sqlite documentation states this returns only null if value is null \
221 or OOM. If you ever see this panic message please open an issue at \
222 https://github.com/diesel-rs/diesel.",
223 );
224 OwnedSqliteValue { value }
225 }
226}
227228#[cfg(test)]
229mod tests {
230use crate::connection::{LoadConnection, SimpleConnection};
231use crate::row::Field;
232use crate::row::Row;
233use crate::sql_types::{Blob, Double, Int4, Text};
234use crate::*;
235236#[expect(clippy::approx_constant)] // we really want to use 3.14
237#[test]
238fn can_convert_all_values() {
239let mut conn = SqliteConnection::establish(":memory:").unwrap();
240241 conn.batch_execute("CREATE TABLE tests(int INTEGER, text TEXT, blob BLOB, float FLOAT)")
242 .unwrap();
243244 diesel::sql_query("INSERT INTO tests(int, text, blob, float) VALUES(?, ?, ?, ?)")
245 .bind::<Int4, _>(42)
246 .bind::<Text, _>("foo")
247 .bind::<Blob, _>(b"foo")
248 .bind::<Double, _>(3.14)
249 .execute(&mut conn)
250 .unwrap();
251252let mut res = conn
253 .load(diesel::sql_query(
254"SELECT int, text, blob, float FROM tests",
255 ))
256 .unwrap();
257let row = res.next().unwrap().unwrap();
258let int_field = row.get(0).unwrap();
259let text_field = row.get(1).unwrap();
260let blob_field = row.get(2).unwrap();
261let float_field = row.get(3).unwrap();
262263let mut int_value = int_field.value().unwrap();
264assert_eq!(int_value.read_integer(), 42);
265let mut int_value = int_field.value().unwrap();
266assert_eq!(int_value.read_long(), 42);
267let mut int_value = int_field.value().unwrap();
268assert_eq!(int_value.read_double(), 42.0);
269let mut int_value = int_field.value().unwrap();
270assert_eq!(int_value.read_text(), "42");
271let mut int_value = int_field.value().unwrap();
272assert_eq!(int_value.read_blob(), b"42");
273274let mut text_value = text_field.value().unwrap();
275assert_eq!(text_value.read_integer(), 0);
276let mut text_value = text_field.value().unwrap();
277assert_eq!(text_value.read_long(), 0);
278let mut text_value = text_field.value().unwrap();
279assert_eq!(text_value.read_double(), 0.0);
280let mut text_value = text_field.value().unwrap();
281assert_eq!(text_value.read_text(), "foo");
282let mut text_value = text_field.value().unwrap();
283assert_eq!(text_value.read_blob(), b"foo");
284285let mut blob_value = blob_field.value().unwrap();
286assert_eq!(blob_value.read_integer(), 0);
287let mut blob_value = blob_field.value().unwrap();
288assert_eq!(blob_value.read_long(), 0);
289let mut blob_value = blob_field.value().unwrap();
290assert_eq!(blob_value.read_double(), 0.0);
291let mut blob_value = blob_field.value().unwrap();
292assert_eq!(blob_value.read_text(), "foo");
293let mut blob_value = blob_field.value().unwrap();
294assert_eq!(blob_value.read_blob(), b"foo");
295296let mut float_value = float_field.value().unwrap();
297assert_eq!(float_value.read_integer(), 3);
298let mut float_value = float_field.value().unwrap();
299assert_eq!(float_value.read_long(), 3);
300let mut float_value = float_field.value().unwrap();
301assert_eq!(float_value.read_double(), 3.14);
302let mut float_value = float_field.value().unwrap();
303assert_eq!(float_value.read_text(), "3.14");
304let mut float_value = float_field.value().unwrap();
305assert_eq!(float_value.read_blob(), b"3.14");
306 }
307}