mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-26 19:41:37 +08:00
Remove functions::FromValue.
With the new definition of FromSql, we can reuse it since we can convert a sqlite3_value into a BorrowedValue.
This commit is contained in:
parent
4662b9b932
commit
0fbfad2452
134
src/functions.rs
134
src/functions.rs
@ -54,7 +54,6 @@ use std::ffi::CStr;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::str;
|
|
||||||
use libc::{c_int, c_double, c_char, c_void};
|
use libc::{c_int, c_double, c_char, c_void};
|
||||||
|
|
||||||
use ffi;
|
use ffi;
|
||||||
@ -63,7 +62,7 @@ pub use ffi::sqlite3_value;
|
|||||||
pub use ffi::sqlite3_value_type;
|
pub use ffi::sqlite3_value_type;
|
||||||
pub use ffi::sqlite3_value_numeric_type;
|
pub use ffi::sqlite3_value_numeric_type;
|
||||||
|
|
||||||
use types::Null;
|
use types::{Null, FromSql, BorrowedValue};
|
||||||
|
|
||||||
use {Result, Error, Connection, str_to_cstring, InnerConnection};
|
use {Result, Error, Connection, str_to_cstring, InnerConnection};
|
||||||
|
|
||||||
@ -157,108 +156,35 @@ impl ToResult for Null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait for types that can be created from a SQLite function parameter value.
|
impl<'a> BorrowedValue<'a> {
|
||||||
pub trait FromValue: Sized {
|
unsafe fn from_value(value: *mut sqlite3_value) -> BorrowedValue<'a> {
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<Self>;
|
|
||||||
|
|
||||||
/// FromValue types can implement this method and use sqlite3_value_type to check that
|
|
||||||
/// the type reported by SQLite matches a type suitable for Self. This method is used
|
|
||||||
/// by `Context::get` to confirm that the parameter contains a valid type before
|
|
||||||
/// attempting to retrieve the value.
|
|
||||||
unsafe fn parameter_has_valid_sqlite_type(_: *mut sqlite3_value) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
macro_rules! raw_from_impl(
|
|
||||||
($t:ty, $f:ident, $c:expr) => (
|
|
||||||
impl FromValue for $t {
|
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<$t> {
|
|
||||||
Ok(ffi::$f(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
|
|
||||||
sqlite3_value_numeric_type(v) == $c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
raw_from_impl!(c_int, sqlite3_value_int, ffi::SQLITE_INTEGER);
|
|
||||||
raw_from_impl!(i64, sqlite3_value_int64, ffi::SQLITE_INTEGER);
|
|
||||||
|
|
||||||
impl FromValue for bool {
|
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<bool> {
|
|
||||||
match ffi::sqlite3_value_int(v) {
|
|
||||||
0 => Ok(false),
|
|
||||||
_ => Ok(true),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
|
|
||||||
sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromValue for c_double {
|
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<c_double> {
|
|
||||||
Ok(ffi::sqlite3_value_double(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
|
|
||||||
sqlite3_value_numeric_type(v) == ffi::SQLITE_FLOAT ||
|
|
||||||
sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromValue for String {
|
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<String> {
|
|
||||||
let c_text = ffi::sqlite3_value_text(v);
|
|
||||||
if c_text.is_null() {
|
|
||||||
Ok("".to_owned())
|
|
||||||
} else {
|
|
||||||
let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes();
|
|
||||||
let utf8_str = try!(str::from_utf8(c_slice));
|
|
||||||
Ok(utf8_str.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
|
|
||||||
sqlite3_value_type(v) == ffi::SQLITE_TEXT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromValue for Vec<u8> {
|
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<Vec<u8>> {
|
|
||||||
use std::slice::from_raw_parts;
|
use std::slice::from_raw_parts;
|
||||||
let c_blob = ffi::sqlite3_value_blob(v);
|
|
||||||
let len = ffi::sqlite3_value_bytes(v);
|
|
||||||
|
|
||||||
assert!(len >= 0,
|
match ffi::sqlite3_value_type(value) {
|
||||||
"unexpected negative return from sqlite3_value_bytes");
|
ffi::SQLITE_NULL => BorrowedValue::Null,
|
||||||
let len = len as usize;
|
ffi::SQLITE_INTEGER => BorrowedValue::Integer(ffi::sqlite3_value_int64(value)),
|
||||||
|
ffi::SQLITE_FLOAT => BorrowedValue::Real(ffi::sqlite3_value_double(value)),
|
||||||
|
ffi::SQLITE_TEXT => {
|
||||||
|
let text = ffi::sqlite3_value_text(value);
|
||||||
|
assert!(!text.is_null(), "unexpected SQLITE_TEXT value type with NULL data");
|
||||||
|
let s = CStr::from_ptr(text as *const c_char);
|
||||||
|
|
||||||
Ok(from_raw_parts(mem::transmute(c_blob), len).to_vec())
|
// sqlite3_value_text returns UTF8 data, so our unwrap here should be fine.
|
||||||
}
|
let s = s.to_str().expect("sqlite3_value_text returned invalid UTF-8");
|
||||||
|
BorrowedValue::Text(s)
|
||||||
|
}
|
||||||
|
ffi::SQLITE_BLOB => {
|
||||||
|
let blob = ffi::sqlite3_value_blob(value);
|
||||||
|
assert!(!blob.is_null(), "unexpected SQLITE_BLOB value type with NULL data");
|
||||||
|
|
||||||
unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
|
let len = ffi::sqlite3_value_bytes(value);
|
||||||
sqlite3_value_type(v) == ffi::SQLITE_BLOB
|
assert!(len >= 0, "unexpected negative return from sqlite3_value_bytes");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: FromValue> FromValue for Option<T> {
|
BorrowedValue::Blob(from_raw_parts(blob as *const u8, len as usize))
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<Option<T>> {
|
}
|
||||||
if sqlite3_value_type(v) == ffi::SQLITE_NULL {
|
_ => unreachable!("sqlite3_value_type returned invalid value")
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
FromValue::parameter_value(v).map(Some)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
|
|
||||||
sqlite3_value_type(v) == ffi::SQLITE_NULL || T::parameter_has_valid_sqlite_type(v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
|
unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
|
||||||
@ -288,15 +214,13 @@ impl<'a> Context<'a> {
|
|||||||
/// Will panic if `idx` is greater than or equal to `self.len()`.
|
/// Will panic if `idx` is greater than or equal to `self.len()`.
|
||||||
///
|
///
|
||||||
/// Will return Err if the underlying SQLite type cannot be converted to a `T`.
|
/// Will return Err if the underlying SQLite type cannot be converted to a `T`.
|
||||||
pub fn get<T: FromValue>(&self, idx: usize) -> Result<T> {
|
pub fn get<T: FromSql>(&self, idx: usize) -> Result<T> {
|
||||||
let arg = self.args[idx];
|
let arg = self.args[idx];
|
||||||
unsafe {
|
let value = unsafe { BorrowedValue::from_value(arg) };
|
||||||
if T::parameter_has_valid_sqlite_type(arg) {
|
FromSql::column_result(value).map_err(|err| match err {
|
||||||
T::parameter_value(arg)
|
Error::InvalidColumnType => Error::InvalidFunctionParameterType,
|
||||||
} else {
|
_ => err
|
||||||
Err(Error::InvalidFunctionParameterType)
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the auxilliary data associated with a particular parameter. See
|
/// Sets the auxilliary data associated with a particular parameter. See
|
||||||
|
Loading…
Reference in New Issue
Block a user