• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             return ffi::sqlite3_result_zeroblob(ctx, len);
27         }
28         #[cfg(feature = "array")]
29         ToSqlOutput::Array(ref a) => {
30             return ffi::sqlite3_result_pointer(
31                 ctx,
32                 Rc::into_raw(a.clone()) as *mut c_void,
33                 ARRAY_TYPE,
34                 Some(free_array),
35             );
36         }
37     };
38 
39     match value {
40         ValueRef::Null => ffi::sqlite3_result_null(ctx),
41         ValueRef::Integer(i) => ffi::sqlite3_result_int64(ctx, i),
42         ValueRef::Real(r) => ffi::sqlite3_result_double(ctx, r),
43         ValueRef::Text(s) => {
44             let length = s.len();
45             if length > c_int::max_value() as usize {
46                 ffi::sqlite3_result_error_toobig(ctx);
47             } else {
48                 let (c_str, len, destructor) = match str_for_sqlite(s) {
49                     Ok(c_str) => c_str,
50                     // TODO sqlite3_result_error
51                     Err(_) => return ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE),
52                 };
53                 ffi::sqlite3_result_text(ctx, c_str, len, destructor);
54             }
55         }
56         ValueRef::Blob(b) => {
57             let length = b.len();
58             if length > c_int::max_value() as usize {
59                 ffi::sqlite3_result_error_toobig(ctx);
60             } else if length == 0 {
61                 ffi::sqlite3_result_zeroblob(ctx, 0);
62             } else {
63                 ffi::sqlite3_result_blob(
64                     ctx,
65                     b.as_ptr().cast::<c_void>(),
66                     length as c_int,
67                     ffi::SQLITE_TRANSIENT(),
68                 );
69             }
70         }
71     }
72 }
73