mirror of
https://github.com/isar/rusqlite.git
synced 2025-08-20 21:09:31 +08:00
Merge remote-tracking branch 'remotes/jgallagher/master' into vtab
This commit is contained in:
@@ -75,6 +75,9 @@ pub enum Error {
|
||||
#[allow(dead_code)]
|
||||
UserFunctionError(Box<error::Error + Send + Sync>),
|
||||
|
||||
/// Error available for the implementors of the `ToSql` trait.
|
||||
ToSqlConversionFailure(Box<error::Error + Send + Sync>),
|
||||
|
||||
/// An error case available for implementors of custom modules (e.g.,
|
||||
/// `create_module`).
|
||||
#[cfg(feature = "vtab")]
|
||||
@@ -134,6 +137,7 @@ impl fmt::Display for Error {
|
||||
}
|
||||
#[cfg(feature = "functions")]
|
||||
Error::UserFunctionError(ref err) => err.fmt(f),
|
||||
Error::ToSqlConversionFailure(ref err) => err.fmt(f),
|
||||
#[cfg(feature = "vtab")]
|
||||
Error::ModuleError(ref desc) => write!(f, "{}", desc),
|
||||
}
|
||||
@@ -163,6 +167,7 @@ impl error::Error for Error {
|
||||
Error::InvalidFunctionParameterType(_, _) => "invalid function parameter type",
|
||||
#[cfg(feature = "functions")]
|
||||
Error::UserFunctionError(ref err) => err.description(),
|
||||
Error::ToSqlConversionFailure(ref err) => err.description(),
|
||||
#[cfg(feature = "vtab")]
|
||||
Error::ModuleError(ref desc) => desc,
|
||||
}
|
||||
@@ -171,7 +176,6 @@ impl error::Error for Error {
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match *self {
|
||||
Error::SqliteFailure(ref err, _) => Some(err),
|
||||
Error::FromSqlConversionFailure(_, _, ref err) => Some(&**err),
|
||||
Error::Utf8Error(ref err) => Some(err),
|
||||
Error::NulError(ref err) => Some(err),
|
||||
|
||||
@@ -191,6 +195,9 @@ impl error::Error for Error {
|
||||
|
||||
#[cfg(feature = "functions")]
|
||||
Error::UserFunctionError(ref err) => Some(&**err),
|
||||
|
||||
Error::FromSqlConversionFailure(_, _, ref err) |
|
||||
Error::ToSqlConversionFailure(ref err) => Some(&**err),
|
||||
#[cfg(feature = "vtab")]
|
||||
Error::ModuleError(_) => None,
|
||||
}
|
||||
|
47
src/lib.rs
47
src/lib.rs
@@ -82,7 +82,7 @@ use cache::StatementCache;
|
||||
pub use statement::Statement;
|
||||
use statement::StatementCrateImpl;
|
||||
|
||||
pub use row::{Row, Rows, MappedRows, AndThenRows};
|
||||
pub use row::{Row, Rows, MappedRows, AndThenRows, RowIndex};
|
||||
use row::RowsCrateImpl;
|
||||
|
||||
#[allow(deprecated)]
|
||||
@@ -144,7 +144,7 @@ fn str_to_cstring(s: &str) -> Result<CString> {
|
||||
}
|
||||
|
||||
fn path_to_cstring(p: &Path) -> Result<CString> {
|
||||
let s = try!(p.to_str().ok_or(Error::InvalidPath(p.to_owned())));
|
||||
let s = try!(p.to_str().ok_or_else(|| Error::InvalidPath(p.to_owned())));
|
||||
str_to_cstring(s)
|
||||
}
|
||||
|
||||
@@ -187,6 +187,12 @@ pub struct Connection {
|
||||
|
||||
unsafe impl Send for Connection {}
|
||||
|
||||
impl Drop for Connection {
|
||||
fn drop(&mut self) {
|
||||
self.flush_prepared_statement_cache();
|
||||
}
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
/// Open a new connection to a SQLite database.
|
||||
///
|
||||
@@ -590,18 +596,19 @@ bitflags! {
|
||||
const SQLITE_OPEN_READ_ONLY = ffi::SQLITE_OPEN_READONLY;
|
||||
const SQLITE_OPEN_READ_WRITE = ffi::SQLITE_OPEN_READWRITE;
|
||||
const SQLITE_OPEN_CREATE = ffi::SQLITE_OPEN_CREATE;
|
||||
const SQLITE_OPEN_URI = 0x00000040;
|
||||
const SQLITE_OPEN_MEMORY = 0x00000080;
|
||||
const SQLITE_OPEN_URI = 0x0000_0040;
|
||||
const SQLITE_OPEN_MEMORY = 0x0000_0080;
|
||||
const SQLITE_OPEN_NO_MUTEX = ffi::SQLITE_OPEN_NOMUTEX;
|
||||
const SQLITE_OPEN_FULL_MUTEX = ffi::SQLITE_OPEN_FULLMUTEX;
|
||||
const SQLITE_OPEN_SHARED_CACHE = 0x00020000;
|
||||
const SQLITE_OPEN_PRIVATE_CACHE = 0x00040000;
|
||||
const SQLITE_OPEN_SHARED_CACHE = 0x0002_0000;
|
||||
const SQLITE_OPEN_PRIVATE_CACHE = 0x0004_0000;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OpenFlags {
|
||||
fn default() -> OpenFlags {
|
||||
SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NO_MUTEX | SQLITE_OPEN_URI
|
||||
OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE |
|
||||
OpenFlags::SQLITE_OPEN_NO_MUTEX | OpenFlags::SQLITE_OPEN_URI
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,7 +647,7 @@ fn ensure_valid_sqlite_version() {
|
||||
let version_number = version_number();
|
||||
|
||||
// Check our hard floor.
|
||||
if version_number < 3006008 {
|
||||
if version_number < 3_006_008 {
|
||||
panic!("rusqlite requires SQLite 3.6.8 or newer");
|
||||
}
|
||||
|
||||
@@ -693,7 +700,7 @@ fn ensure_safe_sqlite_threading_mode() -> Result<()> {
|
||||
// will fail if someone else has already initialized SQLite even if they initialized it
|
||||
// safely. That's not ideal either, which is why we expose bypass_sqlite_initialization
|
||||
// above.
|
||||
if version_number() >= 3007000 {
|
||||
if version_number() >= 3_007_000 {
|
||||
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
|
||||
let is_singlethreaded = unsafe {
|
||||
let mutex_ptr = ffi::sqlite3_mutex_alloc(0);
|
||||
@@ -739,9 +746,9 @@ impl InnerConnection {
|
||||
|
||||
// Replicate the check for sane open flags from SQLite, because the check in SQLite itself
|
||||
// wasn't added until version 3.7.3.
|
||||
debug_assert!(1 << SQLITE_OPEN_READ_ONLY.bits == 0x02);
|
||||
debug_assert!(1 << SQLITE_OPEN_READ_WRITE.bits == 0x04);
|
||||
debug_assert!(1 << (SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE).bits == 0x40);
|
||||
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_ONLY.bits, 0x02);
|
||||
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_WRITE.bits, 0x04);
|
||||
debug_assert_eq!(1 << (OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE).bits, 0x40);
|
||||
if (1 << (flags.bits & 0x7)) & 0x46 == 0 {
|
||||
return Err(Error::SqliteFailure(ffi::Error::new(ffi::SQLITE_MISUSE), None));
|
||||
}
|
||||
@@ -869,7 +876,15 @@ impl InnerConnection {
|
||||
impl Drop for InnerConnection {
|
||||
#[allow(unused_must_use)]
|
||||
fn drop(&mut self) {
|
||||
self.close();
|
||||
use std::thread::panicking;
|
||||
|
||||
if let Err(e) = self.close() {
|
||||
if panicking() {
|
||||
eprintln!("Error while closing SQLite connection: {:?}", e);
|
||||
} else {
|
||||
panic!("Error while closing SQLite connection: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -920,7 +935,7 @@ mod test {
|
||||
CREATE TABLE foo(x INTEGER);
|
||||
INSERT INTO foo VALUES(42);
|
||||
END;";
|
||||
db.execute_batch(sql).unwrap();
|
||||
db.execute_batch(sql).unwrap();
|
||||
}
|
||||
|
||||
let path_string = path.to_str().unwrap();
|
||||
@@ -978,8 +993,8 @@ mod test {
|
||||
#[test]
|
||||
fn test_open_with_flags() {
|
||||
for bad_flags in &[OpenFlags::empty(),
|
||||
SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_READ_WRITE,
|
||||
SQLITE_OPEN_READ_ONLY | SQLITE_OPEN_CREATE] {
|
||||
OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_READ_WRITE,
|
||||
OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_CREATE] {
|
||||
assert!(Connection::open_in_memory_with_flags(*bad_flags).is_err());
|
||||
}
|
||||
}
|
||||
|
30
src/row.rs
30
src/row.rs
@@ -30,21 +30,21 @@ impl<'stmt> Rows<'stmt> {
|
||||
pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> {
|
||||
self.stmt
|
||||
.and_then(|stmt| match stmt.step() {
|
||||
Ok(true) => {
|
||||
Some(Ok(Row {
|
||||
stmt: stmt,
|
||||
phantom: PhantomData,
|
||||
}))
|
||||
}
|
||||
Ok(false) => {
|
||||
self.reset();
|
||||
None
|
||||
}
|
||||
Err(err) => {
|
||||
self.reset();
|
||||
Some(Err(err))
|
||||
}
|
||||
})
|
||||
Ok(true) => {
|
||||
Some(Ok(Row {
|
||||
stmt: stmt,
|
||||
phantom: PhantomData,
|
||||
}))
|
||||
}
|
||||
Ok(false) => {
|
||||
self.reset();
|
||||
None
|
||||
}
|
||||
Err(err) => {
|
||||
self.reset();
|
||||
Some(Err(err))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -368,7 +368,7 @@ impl<'conn> Statement<'conn> {
|
||||
}
|
||||
|
||||
fn bind_parameters(&mut self, params: &[&ToSql]) -> Result<()> {
|
||||
assert!(params.len() as c_int == self.stmt.bind_parameter_count(),
|
||||
assert_eq!(params.len() as c_int, self.stmt.bind_parameter_count(),
|
||||
"incorrect number of parameters to query(): expected {}, got {}",
|
||||
self.stmt.bind_parameter_count(),
|
||||
params.len());
|
||||
|
@@ -3,7 +3,7 @@ extern crate chrono;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use self::chrono::{NaiveDate, NaiveTime, NaiveDateTime, DateTime, TimeZone, UTC, Local};
|
||||
use self::chrono::{NaiveDate, NaiveTime, NaiveDateTime, DateTime, TimeZone, Utc, Local};
|
||||
|
||||
use Result;
|
||||
use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
||||
@@ -87,12 +87,12 @@ 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> {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
Ok(ToSqlOutput::from(self.with_timezone(&UTC).to_rfc3339()))
|
||||
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> {
|
||||
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into `DateTime<Utc>`.
|
||||
impl FromSql for DateTime<Utc> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
{
|
||||
// Try to parse value as rfc3339 first.
|
||||
@@ -111,19 +111,19 @@ impl FromSql for DateTime<UTC> {
|
||||
};
|
||||
|
||||
if let Ok(dt) = DateTime::parse_from_rfc3339(&s) {
|
||||
return Ok(dt.with_timezone(&UTC));
|
||||
return Ok(dt.with_timezone(&Utc));
|
||||
}
|
||||
}
|
||||
|
||||
// Couldn't parse as rfc3339 - fall back to NaiveDateTime.
|
||||
NaiveDateTime::column_result(value).map(|dt| UTC.from_utc_datetime(&dt))
|
||||
NaiveDateTime::column_result(value).map(|dt| Utc.from_utc_datetime(&dt))
|
||||
}
|
||||
}
|
||||
|
||||
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into DateTime<Local>.
|
||||
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into `DateTime<Local>`.
|
||||
impl FromSql for DateTime<Local> {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
let utc_dt = try!(DateTime::<UTC>::column_result(value));
|
||||
let utc_dt = try!(DateTime::<Utc>::column_result(value));
|
||||
Ok(utc_dt.with_timezone(&Local))
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ impl FromSql for DateTime<Local> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use Connection;
|
||||
use super::chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, UTC,
|
||||
use super::chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc,
|
||||
Duration};
|
||||
|
||||
fn checked_memory_handle() -> Connection {
|
||||
@@ -201,7 +201,7 @@ mod test {
|
||||
let date = NaiveDate::from_ymd(2016, 2, 23);
|
||||
let time = NaiveTime::from_hms_milli(23, 56, 4, 789);
|
||||
let dt = NaiveDateTime::new(date, time);
|
||||
let utc = UTC.from_utc_datetime(&dt);
|
||||
let utc = Utc.from_utc_datetime(&dt);
|
||||
|
||||
db.execute("INSERT INTO foo (t) VALUES (?)", &[&utc])
|
||||
.unwrap();
|
||||
@@ -210,19 +210,19 @@ mod test {
|
||||
.unwrap();
|
||||
assert_eq!("2016-02-23T23:56:04.789+00:00", s);
|
||||
|
||||
let v1: DateTime<UTC> = db.query_row("SELECT t FROM foo", &[], |r| r.get(0))
|
||||
let v1: DateTime<Utc> = db.query_row("SELECT t FROM foo", &[], |r| r.get(0))
|
||||
.unwrap();
|
||||
assert_eq!(utc, v1);
|
||||
|
||||
let v2: DateTime<UTC> = db.query_row("SELECT '2016-02-23 23:56:04.789'", &[], |r| r.get(0))
|
||||
let v2: DateTime<Utc> = db.query_row("SELECT '2016-02-23 23:56:04.789'", &[], |r| r.get(0))
|
||||
.unwrap();
|
||||
assert_eq!(utc, v2);
|
||||
|
||||
let v3: DateTime<UTC> = db.query_row("SELECT '2016-02-23 23:56:04'", &[], |r| r.get(0))
|
||||
let v3: DateTime<Utc> = db.query_row("SELECT '2016-02-23 23:56:04'", &[], |r| r.get(0))
|
||||
.unwrap();
|
||||
assert_eq!(utc - Duration::milliseconds(789), v3);
|
||||
|
||||
let v4: DateTime<UTC> =
|
||||
let v4: DateTime<Utc> =
|
||||
db.query_row("SELECT '2016-02-23 23:56:04.789+00:00'", &[], |r| r.get(0))
|
||||
.unwrap();
|
||||
assert_eq!(utc, v4);
|
||||
|
@@ -61,12 +61,24 @@ pub trait FromSql: Sized {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self>;
|
||||
}
|
||||
|
||||
impl FromSql for isize {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
i64::column_result(value).and_then(|i| {
|
||||
if i < isize::min_value() as i64 || i > isize::max_value() as i64 {
|
||||
Err(FromSqlError::OutOfRange(i))
|
||||
} else {
|
||||
Ok(i as isize)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! from_sql_integral(
|
||||
($t:ident) => (
|
||||
impl FromSql for $t {
|
||||
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
|
||||
i64::column_result(value).and_then(|i| {
|
||||
if i < $t::min_value() as i64 || i > $t::max_value() as i64 {
|
||||
if i < i64::from($t::min_value()) || i > i64::from($t::max_value()) {
|
||||
Err(FromSqlError::OutOfRange(i))
|
||||
} else {
|
||||
Ok(i as $t)
|
||||
@@ -80,7 +92,6 @@ macro_rules! from_sql_integral(
|
||||
from_sql_integral!(i8);
|
||||
from_sql_integral!(i16);
|
||||
from_sql_integral!(i32);
|
||||
from_sql_integral!(isize);
|
||||
from_sql_integral!(u8);
|
||||
from_sql_integral!(u16);
|
||||
from_sql_integral!(u32);
|
||||
|
@@ -3,7 +3,7 @@ extern crate time;
|
||||
use Result;
|
||||
use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
|
||||
|
||||
const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S";
|
||||
const SQLITE_DATETIME_FMT: &str = "%Y-%m-%d %H:%M:%S:%f %Z";
|
||||
|
||||
impl ToSql for time::Timespec {
|
||||
fn to_sql(&self) -> Result<ToSqlOutput> {
|
||||
@@ -42,15 +42,27 @@ mod test {
|
||||
fn test_timespec() {
|
||||
let db = checked_memory_handle();
|
||||
|
||||
let ts = time::Timespec {
|
||||
sec: 10_000,
|
||||
nsec: 0,
|
||||
};
|
||||
db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts])
|
||||
.unwrap();
|
||||
let mut ts_vec = vec![];
|
||||
|
||||
ts_vec.push(time::Timespec::new(10_000, 0));//January 1, 1970 2:46:40 AM
|
||||
ts_vec.push(time::Timespec::new(10_000, 1000));//January 1, 1970 2:46:40 AM (and one microsecond)
|
||||
ts_vec.push(time::Timespec::new(1500391124, 1_000_000));//July 18, 2017
|
||||
ts_vec.push(time::Timespec::new(2000000000, 2_000_000));//May 18, 2033
|
||||
ts_vec.push(time::Timespec::new(3000000000, 999_999_999));//January 24, 2065
|
||||
ts_vec.push(time::Timespec::new(10000000000, 0));//November 20, 2286
|
||||
|
||||
for ts in ts_vec {
|
||||
|
||||
db.execute("INSERT INTO foo(t) VALUES (?)", &[&ts])
|
||||
.unwrap();
|
||||
|
||||
let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0))
|
||||
.unwrap();
|
||||
|
||||
db.execute("DELETE FROM foo", &[]).unwrap();
|
||||
|
||||
assert_eq!(from, ts);
|
||||
}
|
||||
|
||||
let from: time::Timespec = db.query_row("SELECT t FROM foo", &[], |r| r.get(0))
|
||||
.unwrap();
|
||||
assert_eq!(from, ts);
|
||||
}
|
||||
}
|
||||
|
@@ -84,7 +84,7 @@ 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()))
|
||||
Ok((*self).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -30,11 +30,15 @@ impl From<bool> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<isize> for Value {
|
||||
fn from(i: isize) -> Value { Value::Integer(i as i64) }
|
||||
}
|
||||
|
||||
macro_rules! from_i64(
|
||||
($t:ty) => (
|
||||
impl From<$t> for Value {
|
||||
fn from(i: $t) -> Value {
|
||||
Value::Integer(i as i64)
|
||||
Value::Integer(i64::from(i))
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -43,7 +47,6 @@ macro_rules! from_i64(
|
||||
from_i64!(i8);
|
||||
from_i64!(i16);
|
||||
from_i64!(i32);
|
||||
from_i64!(isize);
|
||||
from_i64!(u8);
|
||||
from_i64!(u16);
|
||||
from_i64!(u32);
|
||||
|
@@ -3,14 +3,14 @@ use std::ffi::CStr;
|
||||
|
||||
/// Returns the SQLite version as an integer; e.g., `3016002` for version 3.16.2.
|
||||
///
|
||||
/// See [sqlite3_libversion_number()](https://www.sqlite.org/c3ref/libversion.html).
|
||||
/// See [`sqlite3_libversion_number()`](https://www.sqlite.org/c3ref/libversion.html).
|
||||
pub fn version_number() -> i32 {
|
||||
unsafe { ffi::sqlite3_libversion_number() }
|
||||
}
|
||||
|
||||
/// Returns the SQLite version as a string; e.g., `"3.16.2"` for version 3.16.2.
|
||||
///
|
||||
/// See [sqlite3_libversion()](https://www.sqlite.org/c3ref/libversion.html).
|
||||
/// See [`sqlite3_libversion()`](https://www.sqlite.org/c3ref/libversion.html).
|
||||
pub fn version() -> &'static str {
|
||||
let cstr = unsafe { CStr::from_ptr(ffi::sqlite3_libversion()) };
|
||||
cstr.to_str()
|
||||
|
Reference in New Issue
Block a user