rusqlite/
context.rs

1//! Code related to `sqlite3_context` common to `functions` and `vtab` modules.
2
3use std::os::raw::{c_int, c_void};
4#[cfg(feature = "array")]
5use std::rc::Rc;
6
7use crate::ffi;
8use crate::ffi::sqlite3_context;
9
10use crate::str_for_sqlite;
11use crate::types::{ToSqlOutput, ValueRef};
12#[cfg(feature = "array")]
13use 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]
19pub(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() as *const c_void,
66                    length as c_int,
67                    ffi::SQLITE_TRANSIENT(),
68                );
69            }
70        }
71    }
72}