1 //! Code related to `sqlite3_context` common to `functions` and `vtab` modules.
2
3 use std::os::raw::{c_int, c_void};
4 #[cfg(feature = "array")]
5 use std::rc::Rc;
6
7 use crate::ffi;
8 use crate::ffi::sqlite3_context;
9
10 use crate::str_for_sqlite;
11 use crate::types::{ToSqlOutput, ValueRef};
12 #[cfg(feature = "array")]
13 use crate::vtab::array::{free_array, ARRAY_TYPE};
14
15 // This function is inline despite it's size because what's in the ToSqlOutput
16 // is often known to the compiler, and thus const prop/DCE can substantially
17 // simplify the function.
18 #[inline]
set_result(ctx: *mut sqlite3_context, result: &ToSqlOutput<'_>)19 pub(super) unsafe fn set_result(ctx: *mut sqlite3_context, result: &ToSqlOutput<'_>) {
20 let value = match *result {
21 ToSqlOutput::Borrowed(v) => v,
22 ToSqlOutput::Owned(ref v) => ValueRef::from(v),
23
24 #[cfg(feature = "blob")]
25 ToSqlOutput::ZeroBlob(len) => {
26 // TODO sqlite3_result_zeroblob64 // 3.8.11
27 return ffi::sqlite3_result_zeroblob(ctx, len);
28 }
29 #[cfg(feature = "array")]
30 ToSqlOutput::Array(ref a) => {
31 return ffi::sqlite3_result_pointer(
32 ctx,
33 Rc::into_raw(a.clone()) as *mut c_void,
34 ARRAY_TYPE,
35 Some(free_array),
36 );
37 }
38 };
39
40 match value {
41 ValueRef::Null => ffi::sqlite3_result_null(ctx),
42 ValueRef::Integer(i) => ffi::sqlite3_result_int64(ctx, i),
43 ValueRef::Real(r) => ffi::sqlite3_result_double(ctx, r),
44 ValueRef::Text(s) => {
45 let length = s.len();
46 if length > c_int::MAX as usize {
47 ffi::sqlite3_result_error_toobig(ctx);
48 } else {
49 let (c_str, len, destructor) = match str_for_sqlite(s) {
50 Ok(c_str) => c_str,
51 // TODO sqlite3_result_error
52 Err(_) => return ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE),
53 };
54 // TODO sqlite3_result_text64 // 3.8.7
55 ffi::sqlite3_result_text(ctx, c_str, len, destructor);
56 }
57 }
58 ValueRef::Blob(b) => {
59 let length = b.len();
60 if length > c_int::MAX as usize {
61 ffi::sqlite3_result_error_toobig(ctx);
62 } else if length == 0 {
63 ffi::sqlite3_result_zeroblob(ctx, 0);
64 } else {
65 // TODO sqlite3_result_blob64 // 3.8.7
66 ffi::sqlite3_result_blob(
67 ctx,
68 b.as_ptr().cast::<c_void>(),
69 length as c_int,
70 ffi::SQLITE_TRANSIENT(),
71 );
72 }
73 }
74 }
75 }
76