mirror of
https://github.com/isar/rusqlite.git
synced 2025-12-13 15:02:24 +08:00
Merge branch 'master' into gwenn-invalid-column-type
This commit is contained in:
@@ -4,23 +4,21 @@ extern crate chrono;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use self::chrono::{NaiveDate, NaiveTime, NaiveDateTime, DateTime, TimeZone, UTC, Local};
|
||||
use libc::c_int;
|
||||
|
||||
use types::{FromSql, FromSqlError, ToSql, ValueRef};
|
||||
|
||||
use ffi::sqlite3_stmt;
|
||||
use ::Result;
|
||||
use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
||||
|
||||
/// ISO 8601 calendar date without timezone => "YYYY-MM-DD"
|
||||
impl ToSql for NaiveDate {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
let date_str = self.format("%Y-%m-%d").to_string();
|
||||
date_str.bind_parameter(stmt, col)
|
||||
Ok(ToSqlOutput::from(date_str))
|
||||
}
|
||||
}
|
||||
|
||||
/// "YYYY-MM-DD" => ISO 8601 calendar date without timezone.
|
||||
impl FromSql for NaiveDate {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
value.as_str().and_then(|s| match NaiveDate::parse_from_str(s, "%Y-%m-%d") {
|
||||
Ok(dt) => Ok(dt),
|
||||
Err(err) => Err(FromSqlError::Other(Box::new(err))),
|
||||
@@ -30,15 +28,15 @@ impl FromSql for NaiveDate {
|
||||
|
||||
/// ISO 8601 time without timezone => "HH:MM:SS.SSS"
|
||||
impl ToSql for NaiveTime {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
let date_str = self.format("%H:%M:%S%.f").to_string();
|
||||
date_str.bind_parameter(stmt, col)
|
||||
Ok(ToSqlOutput::from(date_str))
|
||||
}
|
||||
}
|
||||
|
||||
/// "HH:MM"/"HH:MM:SS"/"HH:MM:SS.SSS" => ISO 8601 time without timezone.
|
||||
impl FromSql for NaiveTime {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
value.as_str().and_then(|s| {
|
||||
let fmt = match s.len() {
|
||||
5 => "%H:%M",
|
||||
@@ -55,16 +53,16 @@ impl FromSql for NaiveTime {
|
||||
|
||||
/// ISO 8601 combined date and time without timezone => "YYYY-MM-DD HH:MM:SS.SSS"
|
||||
impl ToSql for NaiveDateTime {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
let date_str = self.format("%Y-%m-%dT%H:%M:%S%.f").to_string();
|
||||
date_str.bind_parameter(stmt, col)
|
||||
Ok(ToSqlOutput::from(date_str))
|
||||
}
|
||||
}
|
||||
|
||||
/// "YYYY-MM-DD HH:MM:SS"/"YYYY-MM-DD HH:MM:SS.SSS" => ISO 8601 combined date and time
|
||||
/// without timezone. ("YYYY-MM-DDTHH:MM:SS"/"YYYY-MM-DDTHH:MM:SS.SSS" also supported)
|
||||
impl FromSql for NaiveDateTime {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
value.as_str().and_then(|s| {
|
||||
let fmt = if s.len() >= 11 && s.as_bytes()[10] == b'T' {
|
||||
"%Y-%m-%dT%H:%M:%S%.f"
|
||||
@@ -82,15 +80,14 @@ impl FromSql for NaiveDateTime {
|
||||
|
||||
/// Date and time with time zone => UTC RFC3339 timestamp ("YYYY-MM-DDTHH:MM:SS.SSS+00:00").
|
||||
impl<Tz: TimeZone> ToSql for DateTime<Tz> {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
let utc_dt = self.with_timezone(&UTC);
|
||||
utc_dt.to_rfc3339().bind_parameter(stmt, col)
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
Ok(ToSqlOutput::from(self.with_timezone(&UTC).to_rfc3339()))
|
||||
}
|
||||
}
|
||||
|
||||
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into DateTime<UTC>.
|
||||
impl FromSql for DateTime<UTC> {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
{
|
||||
// Try to parse value as rfc3339 first.
|
||||
let s = try!(value.as_str());
|
||||
@@ -120,7 +117,7 @@ impl FromSql for DateTime<UTC> {
|
||||
|
||||
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into DateTime<Local>.
|
||||
impl FromSql for DateTime<Local> {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
let utc_dt = try!(DateTime::<UTC>::column_result(value));
|
||||
Ok(utc_dt.with_timezone(&Local))
|
||||
}
|
||||
|
||||
@@ -38,26 +38,28 @@ impl Error for FromSqlError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Result type for implementors of the `FromSql` trait.
|
||||
pub type FromSqlResult<T> = Result<T, FromSqlError>;
|
||||
|
||||
/// A trait for types that can be created from a SQLite value.
|
||||
pub trait FromSql: Sized {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError>;
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self>;
|
||||
}
|
||||
|
||||
impl FromSql for i32 {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
i64::column_result(value).map(|i| i as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for i64 {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
value.as_i64()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for f64 {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
match value {
|
||||
ValueRef::Integer(i) => Ok(i as f64),
|
||||
ValueRef::Real(f) => Ok(f),
|
||||
@@ -67,7 +69,7 @@ impl FromSql for f64 {
|
||||
}
|
||||
|
||||
impl FromSql for bool {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
i64::column_result(value).map(|i| match i {
|
||||
0 => false,
|
||||
_ => true,
|
||||
@@ -76,19 +78,19 @@ impl FromSql for bool {
|
||||
}
|
||||
|
||||
impl FromSql for String {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
value.as_str().map(|s| s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for Vec<u8> {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
value.as_blob().map(|b| b.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromSql> FromSql for Option<T> {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
match value {
|
||||
ValueRef::Null => Ok(None),
|
||||
_ => FromSql::column_result(value).map(Some),
|
||||
@@ -97,7 +99,7 @@ impl<T: FromSql> FromSql for Option<T> {
|
||||
}
|
||||
|
||||
impl FromSql for Value {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
Ok(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,14 +50,14 @@
|
||||
//! `FromSql` for the cases where you want to know if a value was NULL (which gets translated to
|
||||
//! `None`).
|
||||
|
||||
pub use ffi::sqlite3_stmt;
|
||||
|
||||
pub use self::from_sql::{FromSql, FromSqlError};
|
||||
pub use self::to_sql::ToSql;
|
||||
pub use self::from_sql::{FromSql, FromSqlError, FromSqlResult};
|
||||
pub use self::to_sql::{ToSql, ToSqlOutput};
|
||||
pub use self::value::Value;
|
||||
pub use self::value_ref::ValueRef;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
mod value;
|
||||
mod value_ref;
|
||||
mod from_sql;
|
||||
mod to_sql;
|
||||
@@ -86,36 +86,6 @@ mod serde_json;
|
||||
#[derive(Copy,Clone)]
|
||||
pub struct Null;
|
||||
|
||||
/// Owning [dynamic type value](http://sqlite.org/datatype3.html). Value's type is typically
|
||||
/// dictated by SQLite (not by the caller).
|
||||
///
|
||||
/// See [`ValueRef`](enum.ValueRef.html) for a non-owning dynamic type value.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub enum Value {
|
||||
/// The value is a `NULL` value.
|
||||
Null,
|
||||
/// The value is a signed integer.
|
||||
Integer(i64),
|
||||
/// The value is a floating point number.
|
||||
Real(f64),
|
||||
/// The value is a text string.
|
||||
Text(String),
|
||||
/// The value is a blob of data
|
||||
Blob(Vec<u8>),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn data_type(&self) -> Type {
|
||||
match *self {
|
||||
Value::Null => Type::Null,
|
||||
Value::Integer(_) => Type::Integer,
|
||||
Value::Real(_) => Type::Real,
|
||||
Value::Text(_) => Type::Text,
|
||||
Value::Blob(_) => Type::Blob,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub enum Type {
|
||||
Null,
|
||||
@@ -146,6 +116,7 @@ mod test {
|
||||
use Error;
|
||||
use libc::{c_int, c_double};
|
||||
use std::f64::EPSILON;
|
||||
use super::Value;
|
||||
|
||||
fn checked_memory_handle() -> Connection {
|
||||
let db = Connection::open_in_memory().unwrap();
|
||||
@@ -164,10 +135,32 @@ mod test {
|
||||
assert_eq!(v, v1234);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_blob() {
|
||||
let db = checked_memory_handle();
|
||||
|
||||
let empty = vec![];
|
||||
db.execute("INSERT INTO foo(b) VALUES (?)", &[&empty]).unwrap();
|
||||
|
||||
let v: Vec<u8> = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)).unwrap();
|
||||
assert_eq!(v, empty);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_str() {
|
||||
let db = checked_memory_handle();
|
||||
|
||||
let s = "hello, world!";
|
||||
db.execute("INSERT INTO foo(t) VALUES (?)", &[&s]).unwrap();
|
||||
|
||||
let from: String = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap();
|
||||
assert_eq!(from, s);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string() {
|
||||
let db = checked_memory_handle();
|
||||
|
||||
let s = "hello, world!";
|
||||
db.execute("INSERT INTO foo(t) VALUES (?)", &[&s.to_owned()]).unwrap();
|
||||
|
||||
@@ -175,6 +168,16 @@ mod test {
|
||||
assert_eq!(from, s);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_value() {
|
||||
let db = checked_memory_handle();
|
||||
|
||||
db.execute("INSERT INTO foo(i) VALUES (?)", &[&Value::Integer(10)]).unwrap();
|
||||
|
||||
assert_eq!(10i64,
|
||||
db.query_row("SELECT i FROM foo", &[], |r| r.get(0)).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_option() {
|
||||
let db = checked_memory_handle();
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
//! `ToSql` and `FromSql` implementation for JSON `Value`.
|
||||
extern crate serde_json;
|
||||
|
||||
use libc::c_int;
|
||||
use self::serde_json::Value;
|
||||
|
||||
use types::{FromSql, FromSqlError, ToSql, ValueRef};
|
||||
|
||||
use ffi::sqlite3_stmt;
|
||||
use ::Result;
|
||||
use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
||||
|
||||
/// Serialize JSON `Value` to text.
|
||||
impl ToSql for Value {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
let s = serde_json::to_string(self).unwrap();
|
||||
s.bind_parameter(stmt, col)
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
Ok(ToSqlOutput::from(serde_json::to_string(self).unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize text/blob to JSON `Value`.
|
||||
impl FromSql for Value {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
match value {
|
||||
ValueRef::Text(ref s) => serde_json::from_str(s),
|
||||
ValueRef::Blob(ref b) => serde_json::from_slice(b),
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
extern crate time;
|
||||
|
||||
use libc::c_int;
|
||||
use types::{FromSql, FromSqlError, ToSql, ValueRef};
|
||||
|
||||
use ffi::sqlite3_stmt;
|
||||
use Result;
|
||||
use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
||||
|
||||
const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S";
|
||||
|
||||
impl ToSql for time::Timespec {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
let time_str = time::at_utc(*self).strftime(SQLITE_DATETIME_FMT).unwrap().to_string();
|
||||
time_str.bind_parameter(stmt, col)
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
let time_string = time::at_utc(*self).strftime(SQLITE_DATETIME_FMT).unwrap().to_string();
|
||||
Ok(ToSqlOutput::from(time_string))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for time::Timespec {
|
||||
fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
value.as_str().and_then(|s| match time::strptime(s, SQLITE_DATETIME_FMT) {
|
||||
Ok(tm) => Ok(tm.to_timespec()),
|
||||
Err(err) => Err(FromSqlError::Other(Box::new(err))),
|
||||
|
||||
@@ -1,95 +1,97 @@
|
||||
use std::mem;
|
||||
use super::{Null, Value, ValueRef};
|
||||
use ::Result;
|
||||
|
||||
use libc::{c_double, c_int};
|
||||
/// `ToSqlOutput` represents the possible output types for implementors of the `ToSql` trait.
|
||||
pub enum ToSqlOutput<'a> {
|
||||
/// A borrowed SQLite-representable value.
|
||||
Borrowed(ValueRef<'a>),
|
||||
|
||||
use super::Null;
|
||||
use ::{ffi, str_to_cstring};
|
||||
use ffi::sqlite3_stmt;
|
||||
/// An owned SQLite-representable value.
|
||||
Owned(Value),
|
||||
|
||||
/// A BLOB of the given length that is filled with zeroes.
|
||||
#[cfg(feature = "blob")]
|
||||
ZeroBlob(i32),
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> From<&'a T> for ToSqlOutput<'a>
|
||||
where &'a T: Into<ValueRef<'a>>
|
||||
{
|
||||
fn from(t: &'a T) -> Self {
|
||||
ToSqlOutput::Borrowed(t.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Into<Value>> From<T> for ToSqlOutput<'a> {
|
||||
fn from(t: T) -> Self {
|
||||
ToSqlOutput::Owned(t.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for types that can be converted into SQLite values.
|
||||
pub trait ToSql {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int;
|
||||
fn to_sql(&self) -> Result<ToSqlOutput>;
|
||||
}
|
||||
|
||||
macro_rules! raw_to_impl(
|
||||
($t:ty, $f:ident) => (
|
||||
// We should be able to use a generic impl like this:
|
||||
//
|
||||
// impl<T: Copy> ToSql for T where T: Into<Value> {
|
||||
// fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
// Ok(ToSqlOutput::from((*self).into()))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// instead of the following macro, but this runs afoul of
|
||||
// https://github.com/rust-lang/rust/issues/30191 and reports conflicting
|
||||
// implementations even when there aren't any.
|
||||
|
||||
macro_rules! to_sql_self(
|
||||
($t:ty) => (
|
||||
impl ToSql for $t {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
ffi::$f(stmt, col, *self)
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
Ok(ToSqlOutput::from(*self))
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
raw_to_impl!(c_int, sqlite3_bind_int); // i32
|
||||
raw_to_impl!(i64, sqlite3_bind_int64);
|
||||
raw_to_impl!(c_double, sqlite3_bind_double);
|
||||
to_sql_self!(Null);
|
||||
to_sql_self!(bool);
|
||||
to_sql_self!(i32);
|
||||
to_sql_self!(i64);
|
||||
to_sql_self!(f64);
|
||||
|
||||
impl ToSql for bool {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
if *self {
|
||||
ffi::sqlite3_bind_int(stmt, col, 1)
|
||||
} else {
|
||||
ffi::sqlite3_bind_int(stmt, col, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToSql for &'a str {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
let length = self.len();
|
||||
if length > ::std::i32::MAX as usize {
|
||||
return ffi::SQLITE_TOOBIG;
|
||||
}
|
||||
match str_to_cstring(self) {
|
||||
Ok(c_str) => {
|
||||
ffi::sqlite3_bind_text(stmt,
|
||||
col,
|
||||
c_str.as_ptr(),
|
||||
length as c_int,
|
||||
ffi::SQLITE_TRANSIENT())
|
||||
}
|
||||
Err(_) => ffi::SQLITE_MISUSE,
|
||||
}
|
||||
impl<'a, T: ?Sized> ToSql for &'a T
|
||||
where &'a T: Into<ToSqlOutput<'a>>
|
||||
{
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
Ok(ToSqlOutput::from((*self).into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql for String {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
(&self[..]).bind_parameter(stmt, col)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToSql for &'a [u8] {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
if self.len() > ::std::i32::MAX as usize {
|
||||
return ffi::SQLITE_TOOBIG;
|
||||
}
|
||||
ffi::sqlite3_bind_blob(stmt,
|
||||
col,
|
||||
mem::transmute(self.as_ptr()),
|
||||
self.len() as c_int,
|
||||
ffi::SQLITE_TRANSIENT())
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
Ok(ToSqlOutput::from(self.as_str()))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql for Vec<u8> {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
(&self[..]).bind_parameter(stmt, col)
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
Ok(ToSqlOutput::from(self.as_slice()))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql for Value {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
Ok(ToSqlOutput::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToSql> ToSql for Option<T> {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
match *self {
|
||||
None => ffi::sqlite3_bind_null(stmt, col),
|
||||
Some(ref t) => t.bind_parameter(stmt, col),
|
||||
None => Ok(ToSqlOutput::from(Null)),
|
||||
Some(ref t) => t.to_sql(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql for Null {
|
||||
unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
|
||||
ffi::sqlite3_bind_null(stmt, col)
|
||||
}
|
||||
}
|
||||
|
||||
73
src/types/value.rs
Normal file
73
src/types/value.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use super::{Null, Type};
|
||||
|
||||
/// Owning [dynamic type value](http://sqlite.org/datatype3.html). Value's type is typically
|
||||
/// dictated by SQLite (not by the caller).
|
||||
///
|
||||
/// See [`ValueRef`](enum.ValueRef.html) for a non-owning dynamic type value.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub enum Value {
|
||||
/// The value is a `NULL` value.
|
||||
Null,
|
||||
/// The value is a signed integer.
|
||||
Integer(i64),
|
||||
/// The value is a floating point number.
|
||||
Real(f64),
|
||||
/// The value is a text string.
|
||||
Text(String),
|
||||
/// The value is a blob of data
|
||||
Blob(Vec<u8>),
|
||||
}
|
||||
|
||||
impl From<Null> for Value {
|
||||
fn from(_: Null) -> Value {
|
||||
Value::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Value {
|
||||
fn from(i: bool) -> Value {
|
||||
Value::Integer(i as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Value {
|
||||
fn from(i: i32) -> Value {
|
||||
Value::Integer(i as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Value {
|
||||
fn from(i: i64) -> Value {
|
||||
Value::Integer(i)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Value {
|
||||
fn from(f: f64) -> Value {
|
||||
Value::Real(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Value {
|
||||
fn from(s: String) -> Value {
|
||||
Value::Text(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for Value {
|
||||
fn from(v: Vec<u8>) -> Value {
|
||||
Value::Blob(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn data_type(&self) -> Type {
|
||||
match *self {
|
||||
Value::Null => Type::Null,
|
||||
Value::Integer(_) => Type::Integer,
|
||||
Value::Real(_) => Type::Real,
|
||||
Value::Text(_) => Type::Text,
|
||||
Value::Blob(_) => Type::Blob,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use ::types::FromSqlError;
|
||||
use ::types::{FromSqlError, FromSqlResult};
|
||||
use super::{Value, Type};
|
||||
|
||||
/// A non-owning [dynamic type value](http://sqlite.org/datatype3.html). Typically the
|
||||
@@ -34,7 +34,7 @@ impl<'a> ValueRef<'a> {
|
||||
impl<'a> ValueRef<'a> {
|
||||
/// If `self` is case `Integer`, returns the integral value. Otherwise, returns
|
||||
/// `Err(Error::InvalidColumnType)`.
|
||||
pub fn as_i64(&self) -> Result<i64, FromSqlError> {
|
||||
pub fn as_i64(&self) -> FromSqlResult<i64> {
|
||||
match *self {
|
||||
ValueRef::Integer(i) => Ok(i),
|
||||
_ => Err(FromSqlError::InvalidType),
|
||||
@@ -43,7 +43,7 @@ impl<'a> ValueRef<'a> {
|
||||
|
||||
/// If `self` is case `Real`, returns the floating point value. Otherwise, returns
|
||||
/// `Err(Error::InvalidColumnType)`.
|
||||
pub fn as_f64(&self) -> Result<f64, FromSqlError> {
|
||||
pub fn as_f64(&self) -> FromSqlResult<f64> {
|
||||
match *self {
|
||||
ValueRef::Real(f) => Ok(f),
|
||||
_ => Err(FromSqlError::InvalidType),
|
||||
@@ -52,7 +52,7 @@ impl<'a> ValueRef<'a> {
|
||||
|
||||
/// If `self` is case `Text`, returns the string value. Otherwise, returns
|
||||
/// `Err(Error::InvalidColumnType)`.
|
||||
pub fn as_str(&self) -> Result<&str, FromSqlError> {
|
||||
pub fn as_str(&self) -> FromSqlResult<&str> {
|
||||
match *self {
|
||||
ValueRef::Text(ref t) => Ok(t),
|
||||
_ => Err(FromSqlError::InvalidType),
|
||||
@@ -61,7 +61,7 @@ impl<'a> ValueRef<'a> {
|
||||
|
||||
/// If `self` is case `Blob`, returns the byte slice. Otherwise, returns
|
||||
/// `Err(Error::InvalidColumnType)`.
|
||||
pub fn as_blob(&self) -> Result<&[u8], FromSqlError> {
|
||||
pub fn as_blob(&self) -> FromSqlResult<&[u8]> {
|
||||
match *self {
|
||||
ValueRef::Blob(ref b) => Ok(b),
|
||||
_ => Err(FromSqlError::InvalidType),
|
||||
@@ -81,6 +81,18 @@ impl<'a> From<ValueRef<'a>> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for ValueRef<'a> {
|
||||
fn from(s: &str) -> ValueRef {
|
||||
ValueRef::Text(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8]> for ValueRef<'a> {
|
||||
fn from(s: &[u8]) -> ValueRef {
|
||||
ValueRef::Blob(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Value> for ValueRef<'a> {
|
||||
fn from(value: &'a Value) -> ValueRef<'a> {
|
||||
match *value {
|
||||
|
||||
Reference in New Issue
Block a user