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