• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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