//! Code related to `sqlite3_context` common to `functions` and `vtab` modules. use std::ffi::CStr; use std::os::raw::{c_char, c_int, c_void}; #[cfg(feature = "array")] use std::rc::Rc; use crate::ffi; use crate::ffi::sqlite3_context; use crate::ffi::sqlite3_value; use crate::str_to_cstring; use crate::types::{ToSqlOutput, ValueRef}; #[cfg(feature = "array")] use crate::vtab::array::{free_array, ARRAY_TYPE}; pub(crate) unsafe fn set_result<'a>(ctx: *mut sqlite3_context, result: &ToSqlOutput<'a>) { let value = match *result { ToSqlOutput::Borrowed(v) => v, ToSqlOutput::Owned(ref v) => ValueRef::from(v), #[cfg(feature = "blob")] ToSqlOutput::ZeroBlob(len) => { return ffi::sqlite3_result_zeroblob(ctx, len); } #[cfg(feature = "array")] ToSqlOutput::Array(ref a) => { return ffi::sqlite3_result_pointer( ctx, Rc::into_raw(a.clone()) as *mut c_void, ARRAY_TYPE, Some(free_array), ); } }; match value { ValueRef::Null => ffi::sqlite3_result_null(ctx), ValueRef::Integer(i) => ffi::sqlite3_result_int64(ctx, i), ValueRef::Real(r) => ffi::sqlite3_result_double(ctx, r), ValueRef::Text(s) => { let length = s.len(); if length > ::std::i32::MAX as usize { ffi::sqlite3_result_error_toobig(ctx); } else { let c_str = match str_to_cstring(s) { Ok(c_str) => c_str, // TODO sqlite3_result_error Err(_) => return ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), }; let destructor = if length > 0 { ffi::SQLITE_TRANSIENT() } else { ffi::SQLITE_STATIC() }; ffi::sqlite3_result_text(ctx, c_str.as_ptr(), length as c_int, destructor); } } ValueRef::Blob(b) => { let length = b.len(); if length > ::std::i32::MAX as usize { ffi::sqlite3_result_error_toobig(ctx); } else if length == 0 { ffi::sqlite3_result_zeroblob(ctx, 0) } else { ffi::sqlite3_result_blob( ctx, b.as_ptr() as *const c_void, length as c_int, ffi::SQLITE_TRANSIENT(), ); } } } }