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