diesel/sqlite/connection/
sqlite_value.rs1#![allow(unsafe_code)] #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3extern crate libsqlite3_sys as ffi;
4
5#[cfg(all(target_family = "wasm", target_os = "unknown"))]
6use sqlite_wasm_rs as ffi;
7
8use std::cell::Ref;
9use std::ptr::NonNull;
10use std::{slice, str};
11
12use crate::sqlite::SqliteType;
13
14use super::owned_row::OwnedSqliteRow;
15use super::row::PrivateSqliteRow;
16
17#[allow(missing_debug_implementations, missing_copy_implementations)]
23pub struct SqliteValue<'row, 'stmt, 'query> {
24 _row: Option<Ref<'row, PrivateSqliteRow<'stmt, 'query>>>,
28 value: NonNull<ffi::sqlite3_value>,
36 string_ref: Option<Box<str>>,
44}
45
46#[derive(Debug)]
47#[repr(transparent)]
48pub(super) struct OwnedSqliteValue {
49 pub(super) value: NonNull<ffi::sqlite3_value>,
50}
51
52impl Drop for OwnedSqliteValue {
53 fn drop(&mut self) {
54 unsafe { ffi::sqlite3_value_free(self.value.as_ptr()) }
55 }
56}
57
58unsafe impl Send for OwnedSqliteValue {}
61
62impl<'row, 'stmt, 'query> SqliteValue<'row, 'stmt, 'query> {
63 pub(super) fn new(
64 row: Ref<'row, PrivateSqliteRow<'stmt, 'query>>,
65 col_idx: usize,
66 ) -> Option<SqliteValue<'row, 'stmt, 'query>> {
67 let value = match &*row {
68 PrivateSqliteRow::Direct(stmt) => stmt.column_value(
69 col_idx
70 .try_into()
71 .expect("Diesel expects to run at least on a 32 bit platform"),
72 )?,
73 PrivateSqliteRow::Duplicated { values, .. } => {
74 values.get(col_idx).and_then(|v| v.as_ref())?.value
75 }
76 };
77
78 let ret = Self {
79 _row: Some(row),
80 value,
81 string_ref: None,
82 };
83 if ret.value_type().is_none() {
84 None
85 } else {
86 Some(ret)
87 }
88 }
89
90 pub(super) fn from_owned_row(
91 row: &'row OwnedSqliteRow,
92 col_idx: usize,
93 ) -> Option<SqliteValue<'row, 'stmt, 'query>> {
94 let value = row.values.get(col_idx).and_then(|v| v.as_ref())?.value;
95 let ret = Self {
96 _row: None,
97 value,
98 string_ref: None,
99 };
100 if ret.value_type().is_none() {
101 None
102 } else {
103 Some(ret)
104 }
105 }
106
107 pub(super) fn from_function_row(
108 row: &'row [Option<OwnedSqliteValue>],
109 col_idx: usize,
110 ) -> Option<SqliteValue<'row, 'stmt, 'query>> {
111 let value = row.get(col_idx).and_then(|v| v.as_ref())?.value;
112 let ret = Self {
113 _row: None,
114 value,
115 string_ref: None,
116 };
117 if ret.value_type().is_none() {
118 None
119 } else {
120 Some(ret)
121 }
122 }
123
124 pub(crate) fn as_byte_string(&mut self) -> &'row [u8] {
125 unsafe {
126 let len = ffi::sqlite3_value_bytes(self.value.as_ptr());
132 let ptr = ffi::sqlite3_value_text(self.value.as_ptr());
133 slice::from_raw_parts(
134 ptr,
135 len.try_into()
136 .expect("Diesel expects to run at least on a 32 bit platform"),
137 )
138 }
139 }
140
141 pub(crate) fn as_utf8_str(&mut self) -> Result<&'row str, core::str::Utf8Error> {
142 str::from_utf8(self.as_byte_string())
143 }
144
145 pub(crate) fn parse_string<'value, R>(&'value mut self, f: impl FnOnce(&'value str) -> R) -> R {
146 let bytes = self.as_byte_string();
147 let s = match String::from_utf8_lossy(bytes) {
151 std::borrow::Cow::Borrowed(s) => s,
152 std::borrow::Cow::Owned(b) => {
153 self.string_ref = Some(b.into_boxed_str());
154 self.string_ref
155 .as_deref()
156 .expect("We initialised it literally above")
157 }
158 };
159 f(s)
160 }
161
162 pub fn read_text(&mut self) -> &str {
172 self.parse_string(|s| s)
173 }
174
175 pub fn read_blob(&mut self) -> &'row [u8] {
185 unsafe {
186 let len = ffi::sqlite3_value_bytes(self.value.as_ptr());
192 let ptr = ffi::sqlite3_value_blob(self.value.as_ptr());
193 if len == 0 {
194 &[]
197 } else {
198 slice::from_raw_parts(
199 ptr as *const u8,
200 len.try_into()
201 .expect("Diesel expects to run at least on a 32 bit platform"),
202 )
203 }
204 }
205 }
206
207 pub fn read_integer(&mut self) -> i32 {
217 unsafe { ffi::sqlite3_value_int(self.value.as_ptr()) }
218 }
219
220 pub fn read_long(&mut self) -> i64 {
230 unsafe { ffi::sqlite3_value_int64(self.value.as_ptr()) }
231 }
232
233 pub fn read_double(&mut self) -> f64 {
243 unsafe { ffi::sqlite3_value_double(self.value.as_ptr()) }
244 }
245
246 pub fn value_type(&self) -> Option<SqliteType> {
248 let tpe = unsafe { ffi::sqlite3_value_type(self.value.as_ptr()) };
249 match 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 _ => 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}
264
265impl OwnedSqliteValue {
266 pub(super) fn copy_from_ptr(ptr: NonNull<ffi::sqlite3_value>) -> Option<OwnedSqliteValue> {
267 let tpe = unsafe { ffi::sqlite3_value_type(ptr.as_ptr()) };
268 if ffi::SQLITE_NULL == tpe {
269 return None;
270 }
271 let value = unsafe { ffi::sqlite3_value_dup(ptr.as_ptr()) };
272 Some(Self {
273 value: NonNull::new(value)?,
274 })
275 }
276
277 pub(super) fn duplicate(&self) -> OwnedSqliteValue {
278 let value = unsafe { ffi::sqlite3_value_dup(self.value.as_ptr()) };
280 let 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 );
285 OwnedSqliteValue { value }
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use crate::connection::{LoadConnection, SimpleConnection};
292 use crate::row::Field;
293 use crate::row::Row;
294 use crate::sql_types::{Blob, Double, Int4, Text};
295 use crate::*;
296
297 #[expect(clippy::approx_constant)] #[diesel_test_helper::test]
299 fn can_convert_all_values() {
300 let mut conn = SqliteConnection::establish(":memory:").unwrap();
301
302 conn.batch_execute("CREATE TABLE tests(int INTEGER, text TEXT, blob BLOB, float FLOAT)")
303 .unwrap();
304
305 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();
312
313 let mut res = conn
314 .load(diesel::sql_query(
315 "SELECT int, text, blob, float FROM tests",
316 ))
317 .unwrap();
318 let row = res.next().unwrap().unwrap();
319 let int_field = row.get(0).unwrap();
320 let text_field = row.get(1).unwrap();
321 let blob_field = row.get(2).unwrap();
322 let float_field = row.get(3).unwrap();
323
324 let mut int_value = int_field.value().unwrap();
325 assert_eq!(int_value.read_integer(), 42);
326 let mut int_value = int_field.value().unwrap();
327 assert_eq!(int_value.read_long(), 42);
328 let mut int_value = int_field.value().unwrap();
329 assert_eq!(int_value.read_double(), 42.0);
330 let mut int_value = int_field.value().unwrap();
331 assert_eq!(int_value.read_text(), "42");
332 let mut int_value = int_field.value().unwrap();
333 assert_eq!(int_value.read_blob(), b"42");
334
335 let mut text_value = text_field.value().unwrap();
336 assert_eq!(text_value.read_integer(), 0);
337 let mut text_value = text_field.value().unwrap();
338 assert_eq!(text_value.read_long(), 0);
339 let mut text_value = text_field.value().unwrap();
340 assert_eq!(text_value.read_double(), 0.0);
341 let mut text_value = text_field.value().unwrap();
342 assert_eq!(text_value.read_text(), "foo");
343 let mut text_value = text_field.value().unwrap();
344 assert_eq!(text_value.read_blob(), b"foo");
345
346 let mut blob_value = blob_field.value().unwrap();
347 assert_eq!(blob_value.read_integer(), 0);
348 let mut blob_value = blob_field.value().unwrap();
349 assert_eq!(blob_value.read_long(), 0);
350 let mut blob_value = blob_field.value().unwrap();
351 assert_eq!(blob_value.read_double(), 0.0);
352 let mut blob_value = blob_field.value().unwrap();
353 assert_eq!(blob_value.read_text(), "\u{fffd}\u{fffd}\u{fffd}"); let mut blob_value = blob_field.value().unwrap();
355 assert_eq!(blob_value.read_blob(), [0xFF, 0xFE, 0xFD]);
356
357 let mut float_value = float_field.value().unwrap();
358 assert_eq!(float_value.read_integer(), 3);
359 let mut float_value = float_field.value().unwrap();
360 assert_eq!(float_value.read_long(), 3);
361 let mut float_value = float_field.value().unwrap();
362 assert_eq!(float_value.read_double(), 3.14);
363 let mut float_value = float_field.value().unwrap();
364 assert_eq!(float_value.read_text(), "3.14");
365 let mut float_value = float_field.value().unwrap();
366 assert_eq!(float_value.read_blob(), b"3.14");
367 }
368}