2018-05-13 19:03:05 +08:00
|
|
|
//! Code related to `sqlite3_context` common to `functions` and `vtab` modules.
|
|
|
|
|
2019-01-21 02:41:33 +08:00
|
|
|
use std::os::raw::{c_int, c_void};
|
2018-06-10 18:16:54 +08:00
|
|
|
#[cfg(feature = "array")]
|
|
|
|
use std::rc::Rc;
|
2018-05-13 19:03:05 +08:00
|
|
|
|
2018-10-31 03:11:35 +08:00
|
|
|
use crate::ffi;
|
|
|
|
use crate::ffi::sqlite3_context;
|
2018-05-13 19:03:05 +08:00
|
|
|
|
2019-02-27 11:38:41 +08:00
|
|
|
use crate::str_for_sqlite;
|
2018-10-31 03:11:35 +08:00
|
|
|
use crate::types::{ToSqlOutput, ValueRef};
|
2018-06-10 18:16:54 +08:00
|
|
|
#[cfg(feature = "array")]
|
2018-10-31 03:11:35 +08:00
|
|
|
use crate::vtab::array::{free_array, ARRAY_TYPE};
|
2018-05-13 19:03:05 +08:00
|
|
|
|
2020-11-04 11:10:23 +08:00
|
|
|
// This function is inline despite it's size because what's in the ToSqlOutput
|
|
|
|
// is often known to the compiler, and thus const prop/DCE can substantially
|
|
|
|
// simplify the function.
|
|
|
|
#[inline]
|
2020-05-16 16:18:25 +08:00
|
|
|
pub(super) unsafe fn set_result(ctx: *mut sqlite3_context, result: &ToSqlOutput<'_>) {
|
2018-05-13 19:03:05 +08:00
|
|
|
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);
|
|
|
|
}
|
2018-06-10 18:16:54 +08:00
|
|
|
#[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),
|
|
|
|
);
|
|
|
|
}
|
2018-05-13 19:03:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
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();
|
2019-02-27 11:38:41 +08:00
|
|
|
if length > c_int::max_value() as usize {
|
2018-05-13 19:03:05 +08:00
|
|
|
ffi::sqlite3_result_error_toobig(ctx);
|
|
|
|
} else {
|
2019-02-27 11:38:41 +08:00
|
|
|
let (c_str, len, destructor) = match str_for_sqlite(s) {
|
2018-05-13 19:03:05 +08:00
|
|
|
Ok(c_str) => c_str,
|
|
|
|
// TODO sqlite3_result_error
|
|
|
|
Err(_) => return ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE),
|
|
|
|
};
|
2019-02-27 11:38:41 +08:00
|
|
|
ffi::sqlite3_result_text(ctx, c_str, len, destructor);
|
2018-05-13 19:03:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ValueRef::Blob(b) => {
|
|
|
|
let length = b.len();
|
2019-02-27 11:38:41 +08:00
|
|
|
if length > c_int::max_value() as usize {
|
2018-05-13 19:03:05 +08:00
|
|
|
ffi::sqlite3_result_error_toobig(ctx);
|
|
|
|
} else if length == 0 {
|
2022-01-06 02:53:49 +08:00
|
|
|
ffi::sqlite3_result_zeroblob(ctx, 0);
|
2018-05-13 19:03:05 +08:00
|
|
|
} else {
|
|
|
|
ffi::sqlite3_result_blob(
|
|
|
|
ctx,
|
2022-01-06 02:50:25 +08:00
|
|
|
b.as_ptr().cast::<c_void>(),
|
2018-05-13 19:03:05 +08:00
|
|
|
length as c_int,
|
|
|
|
ffi::SQLITE_TRANSIENT(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|