mirror of
				https://github.com/isar/rusqlite.git
				synced 2025-11-04 08:08:55 +08:00 
			
		
		
		
	Merge branch 'master' into gwenn-invalid-column-type
This commit is contained in:
		@@ -1,6 +1,6 @@
 | 
				
			|||||||
[package]
 | 
					[package]
 | 
				
			||||||
name = "rusqlite"
 | 
					name = "rusqlite"
 | 
				
			||||||
version = "0.7.2"
 | 
					version = "0.7.3"
 | 
				
			||||||
authors = ["John Gallagher <jgallagher@bignerdranch.com>"]
 | 
					authors = ["John Gallagher <jgallagher@bignerdranch.com>"]
 | 
				
			||||||
description = "Ergonomic wrapper for SQLite"
 | 
					description = "Ergonomic wrapper for SQLite"
 | 
				
			||||||
repository = "https://github.com/jgallagher/rusqlite"
 | 
					repository = "https://github.com/jgallagher/rusqlite"
 | 
				
			||||||
@@ -22,9 +22,8 @@ trace = []
 | 
				
			|||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
time = "~0.1.0"
 | 
					time = "~0.1.0"
 | 
				
			||||||
bitflags = "0.7"
 | 
					bitflags = "0.7"
 | 
				
			||||||
lru-cache = "0.0.7"
 | 
					lru-cache = "0.1.0"
 | 
				
			||||||
libc = "~0.2"
 | 
					libc = "~0.2"
 | 
				
			||||||
clippy = {version = "~0.0.58", optional = true}
 | 
					 | 
				
			||||||
chrono = { version = "~0.2", optional = true }
 | 
					chrono = { version = "~0.2", optional = true }
 | 
				
			||||||
serde_json = { version = "0.6", optional = true }
 | 
					serde_json = { version = "0.6", optional = true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								Changelog.md
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								Changelog.md
									
									
									
									
									
								
							@@ -3,6 +3,23 @@
 | 
				
			|||||||
* BREAKING CHANGE: The `FromSql` trait has been redesigned. It now requires a single, safe
 | 
					* BREAKING CHANGE: The `FromSql` trait has been redesigned. It now requires a single, safe
 | 
				
			||||||
  method instead of the previous definition which required implementing one or two unsafe
 | 
					  method instead of the previous definition which required implementing one or two unsafe
 | 
				
			||||||
  methods.
 | 
					  methods.
 | 
				
			||||||
 | 
					* BREAKING CHANGE: The `ToSql` trait has been redesigned. It can now be implemented without
 | 
				
			||||||
 | 
					  `unsafe`, and implementors can choose to return either borrowed or owned results.
 | 
				
			||||||
 | 
					* BREAKING CHANGE: The closure passed to `query_row`, `query_row_and_then`, `query_row_safe`,
 | 
				
			||||||
 | 
					  and `query_row_named` now expects a `&Row` instead of a `Row`. The vast majority of calls
 | 
				
			||||||
 | 
					  to these functions will probably not need to change; see
 | 
				
			||||||
 | 
					  https://github.com/jgallagher/rusqlite/pull/184.
 | 
				
			||||||
 | 
					* Added `#[deprecated(since = "...", note = "...")]` flags (new in Rust 1.9 for libraries) to
 | 
				
			||||||
 | 
					  all deprecated APIs.
 | 
				
			||||||
 | 
					* Added `query_row` convenience function to `Statement`.
 | 
				
			||||||
 | 
					* Fixed a bug where using cached prepared statements resulted in attempting to close a connection
 | 
				
			||||||
 | 
					  failing with `DatabaseBusy`; see https://github.com/jgallagher/rusqlite/issues/186.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Version 0.7.3 (2016-06-01)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Fixes an incorrect failure from the `insert()` convenience function when back-to-back inserts to
 | 
				
			||||||
 | 
					  different tables both returned the same row ID
 | 
				
			||||||
 | 
					  ([#171](https://github.com/jgallagher/rusqlite/issues/171)).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Version 0.7.2 (2016-05-19)
 | 
					# Version 0.7.2 (2016-05-19)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
# Rusqlite
 | 
					# Rusqlite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://travis-ci.org/jgallagher/rusqlite)
 | 
					[](https://travis-ci.org/jgallagher/rusqlite)
 | 
				
			||||||
[](https://ci.appveyor.com/project/jgallagher/rusqlite)
 | 
					[](https://ci.appveyor.com/project/jgallagher/rusqlite) [](https://crates.io/crates/rusqlite)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose
 | 
					Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose
 | 
				
			||||||
an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres). View the full
 | 
					an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres). View the full
 | 
				
			||||||
@@ -38,7 +38,7 @@ fn main() {
 | 
				
			|||||||
        data: None
 | 
					        data: None
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    conn.execute("INSERT INTO person (name, time_created, data)
 | 
					    conn.execute("INSERT INTO person (name, time_created, data)
 | 
				
			||||||
                  VALUES ($1, $2, $3)",
 | 
					                  VALUES (?1, ?2, ?3)",
 | 
				
			||||||
                 &[&me.name, &me.time_created, &me.data]).unwrap();
 | 
					                 &[&me.name, &me.time_created, &me.data]).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut stmt = conn.prepare("SELECT id, name, time_created, data FROM person").unwrap();
 | 
					    let mut stmt = conn.prepare("SELECT id, name, time_created, data FROM person").unwrap();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
environment:
 | 
					environment:
 | 
				
			||||||
  TARGET: 1.8.0-x86_64-pc-windows-gnu
 | 
					  TARGET: 1.9.0-x86_64-pc-windows-gnu
 | 
				
			||||||
  MSYS2_BITS: 64
 | 
					  MSYS2_BITS: 64
 | 
				
			||||||
install:
 | 
					install:
 | 
				
			||||||
  - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe"
 | 
					  - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,10 +52,9 @@ use std::io;
 | 
				
			|||||||
use std::cmp::min;
 | 
					use std::cmp::min;
 | 
				
			||||||
use std::mem;
 | 
					use std::mem;
 | 
				
			||||||
use std::ptr;
 | 
					use std::ptr;
 | 
				
			||||||
use libc::c_int;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::ffi;
 | 
					use super::ffi;
 | 
				
			||||||
use super::types::ToSql;
 | 
					use super::types::{ToSql, ToSqlOutput};
 | 
				
			||||||
use {Result, Connection, DatabaseName};
 | 
					use {Result, Connection, DatabaseName};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Handle to an open BLOB.
 | 
					/// Handle to an open BLOB.
 | 
				
			||||||
@@ -244,9 +243,9 @@ impl<'conn> Drop for Blob<'conn> {
 | 
				
			|||||||
pub struct ZeroBlob(pub i32);
 | 
					pub struct ZeroBlob(pub i32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ToSql for ZeroBlob {
 | 
					impl ToSql for ZeroBlob {
 | 
				
			||||||
    unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
 | 
					    fn to_sql(&self) -> Result<ToSqlOutput> {
 | 
				
			||||||
        let ZeroBlob(length) = *self;
 | 
					        let ZeroBlob(length) = *self;
 | 
				
			||||||
        ffi::sqlite3_bind_zeroblob(stmt, col, length)
 | 
					        Ok(ToSqlOutput::ZeroBlob(length))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								src/cache.rs
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								src/cache.rs
									
									
									
									
									
								
							@@ -44,6 +44,10 @@ impl Connection {
 | 
				
			|||||||
    pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) {
 | 
					    pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) {
 | 
				
			||||||
        self.cache.set_capacity(capacity)
 | 
					        self.cache.set_capacity(capacity)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn flush_prepared_statement_cache(&self) {
 | 
				
			||||||
 | 
					        self.cache.flush()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Prepared statements LRU cache.
 | 
					/// Prepared statements LRU cache.
 | 
				
			||||||
@@ -133,6 +137,11 @@ impl StatementCache {
 | 
				
			|||||||
        let sql = String::from_utf8_lossy(stmt.sql().to_bytes()).to_string();
 | 
					        let sql = String::from_utf8_lossy(stmt.sql().to_bytes()).to_string();
 | 
				
			||||||
        cache.insert(sql, stmt);
 | 
					        cache.insert(sql, stmt);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn flush(&self) {
 | 
				
			||||||
 | 
					        let mut cache = self.0.borrow_mut();
 | 
				
			||||||
 | 
					        cache.clear()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
@@ -268,4 +277,12 @@ mod test {
 | 
				
			|||||||
                           .unwrap());
 | 
					                           .unwrap());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_connection_close() {
 | 
				
			||||||
 | 
					        let conn = Connection::open_in_memory().unwrap();
 | 
				
			||||||
 | 
					        conn.prepare_cached("SELECT * FROM sqlite_master;").unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        conn.close().expect("connection not closed");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,23 @@
 | 
				
			|||||||
use {Error, Result, Statement};
 | 
					use {Error, Result, Row, Statement};
 | 
				
			||||||
use types::ToSql;
 | 
					use types::ToSql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'conn> Statement<'conn> {
 | 
					impl<'conn> Statement<'conn> {
 | 
				
			||||||
    /// Execute an INSERT and return the ROWID.
 | 
					    /// Execute an INSERT and return the ROWID.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Note
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This function is a convenience wrapper around `execute()` intended for queries that
 | 
				
			||||||
 | 
					    /// insert a single item. It is possible to misuse this function in a way that it cannot
 | 
				
			||||||
 | 
					    /// detect, such as by calling it on a statement which _updates_ a single item rather than
 | 
				
			||||||
 | 
					    /// inserting one. Please don't do that.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
    /// # Failure
 | 
					    /// # Failure
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
    /// Will return `Err` if no row is inserted or many rows are inserted.
 | 
					    /// Will return `Err` if no row is inserted or many rows are inserted.
 | 
				
			||||||
    pub fn insert(&mut self, params: &[&ToSql]) -> Result<i64> {
 | 
					    pub fn insert(&mut self, params: &[&ToSql]) -> Result<i64> {
 | 
				
			||||||
        // Some non-insertion queries could still return 1 change (an UPDATE, for example), so
 | 
					 | 
				
			||||||
        // to guard against that we can check that the connection's last_insert_rowid() changes
 | 
					 | 
				
			||||||
        // after we execute the statement.
 | 
					 | 
				
			||||||
        let prev_rowid = self.conn.last_insert_rowid();
 | 
					 | 
				
			||||||
        let changes = try!(self.execute(params));
 | 
					        let changes = try!(self.execute(params));
 | 
				
			||||||
        let new_rowid = self.conn.last_insert_rowid();
 | 
					 | 
				
			||||||
        match changes {
 | 
					        match changes {
 | 
				
			||||||
            1 if prev_rowid != new_rowid => Ok(new_rowid),
 | 
					            1 => Ok(self.conn.last_insert_rowid()),
 | 
				
			||||||
            1 if prev_rowid == new_rowid => Err(Error::StatementFailedToInsertRow),
 | 
					 | 
				
			||||||
            _ => Err(Error::StatementChangedRows(changes)),
 | 
					            _ => Err(Error::StatementChangedRows(changes)),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -32,11 +34,26 @@ impl<'conn> Statement<'conn> {
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
        Ok(exists)
 | 
					        Ok(exists)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Convenience method to execute a query that is expected to return a single row.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// If the query returns more than one row, all rows except the first are ignored.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Failure
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Will return `Err` if the underlying SQLite call fails.
 | 
				
			||||||
 | 
					    pub fn query_row<T, F>(&mut self, params: &[&ToSql], f: F) -> Result<T>
 | 
				
			||||||
 | 
					        where F: FnOnce(&Row) -> T
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let mut rows = try!(self.query(params));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows.get_expected_row().map(|r| f(&r))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod test {
 | 
					mod test {
 | 
				
			||||||
    use {Connection, Error};
 | 
					    use {Connection, Error, Result};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_insert() {
 | 
					    fn test_insert() {
 | 
				
			||||||
@@ -57,18 +74,19 @@ mod test {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_insert_failures() {
 | 
					    fn test_insert_different_tables() {
 | 
				
			||||||
 | 
					        // Test for https://github.com/jgallagher/rusqlite/issues/171
 | 
				
			||||||
        let db = Connection::open_in_memory().unwrap();
 | 
					        let db = Connection::open_in_memory().unwrap();
 | 
				
			||||||
        db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)").unwrap();
 | 
					        db.execute_batch(r"
 | 
				
			||||||
        let mut insert = db.prepare("INSERT INTO foo (x) VALUES (?)").unwrap();
 | 
					            CREATE TABLE foo(x INTEGER);
 | 
				
			||||||
        let mut update = db.prepare("UPDATE foo SET x = ?").unwrap();
 | 
					            CREATE TABLE bar(x INTEGER);
 | 
				
			||||||
 | 
					        ")
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(insert.insert(&[&1i32]).unwrap(), 1);
 | 
					        assert_eq!(db.prepare("INSERT INTO foo VALUES (10)").unwrap().insert(&[]).unwrap(),
 | 
				
			||||||
 | 
					                   1);
 | 
				
			||||||
        match update.insert(&[&2i32]) {
 | 
					        assert_eq!(db.prepare("INSERT INTO bar VALUES (10)").unwrap().insert(&[]).unwrap(),
 | 
				
			||||||
            Err(Error::StatementFailedToInsertRow) => (),
 | 
					                   1);
 | 
				
			||||||
            r => panic!("Unexpected result {:?}", r),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
@@ -85,4 +103,18 @@ mod test {
 | 
				
			|||||||
        assert!(stmt.exists(&[&2i32]).unwrap());
 | 
					        assert!(stmt.exists(&[&2i32]).unwrap());
 | 
				
			||||||
        assert!(!stmt.exists(&[&0i32]).unwrap());
 | 
					        assert!(!stmt.exists(&[&0i32]).unwrap());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_query_row() {
 | 
				
			||||||
 | 
					        let db = Connection::open_in_memory().unwrap();
 | 
				
			||||||
 | 
					        let sql = "BEGIN;
 | 
				
			||||||
 | 
					                   CREATE TABLE foo(x INTEGER, y INTEGER);
 | 
				
			||||||
 | 
					                   INSERT INTO foo VALUES(1, 3);
 | 
				
			||||||
 | 
					                   INSERT INTO foo VALUES(2, 4);
 | 
				
			||||||
 | 
					                   END;";
 | 
				
			||||||
 | 
					        db.execute_batch(sql).unwrap();
 | 
				
			||||||
 | 
					        let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?").unwrap();
 | 
				
			||||||
 | 
					        let y: Result<i64> = stmt.query_row(&[&1i32], |r| r.get(0));
 | 
				
			||||||
 | 
					        assert_eq!(3i64, y.unwrap());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								src/error.rs
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/error.rs
									
									
									
									
									
								
							@@ -7,6 +7,7 @@ use {ffi, errmsg_to_string};
 | 
				
			|||||||
use types::Type;
 | 
					use types::Type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Old name for `Error`. `SqliteError` is deprecated.
 | 
					/// Old name for `Error`. `SqliteError` is deprecated.
 | 
				
			||||||
 | 
					#[deprecated(since = "0.6.0", note = "Use Error instead")]
 | 
				
			||||||
pub type SqliteError = Error;
 | 
					pub type SqliteError = Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Enum listing possible errors from rusqlite.
 | 
					/// Enum listing possible errors from rusqlite.
 | 
				
			||||||
@@ -57,10 +58,6 @@ pub enum Error {
 | 
				
			|||||||
    /// Error when a query that was expected to insert one row did not insert any or insert many.
 | 
					    /// Error when a query that was expected to insert one row did not insert any or insert many.
 | 
				
			||||||
    StatementChangedRows(c_int),
 | 
					    StatementChangedRows(c_int),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Error when a query that was expected to insert a row did not change the connection's
 | 
					 | 
				
			||||||
    /// last_insert_rowid().
 | 
					 | 
				
			||||||
    StatementFailedToInsertRow,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Error returned by `functions::Context::get` when the function argument cannot be converted
 | 
					    /// Error returned by `functions::Context::get` when the function argument cannot be converted
 | 
				
			||||||
    /// to the requested type.
 | 
					    /// to the requested type.
 | 
				
			||||||
    #[cfg(feature = "functions")]
 | 
					    #[cfg(feature = "functions")]
 | 
				
			||||||
@@ -115,7 +112,6 @@ impl fmt::Display for Error {
 | 
				
			|||||||
                write!(f, "Invalid column type {} at index: {}", t, i)
 | 
					                write!(f, "Invalid column type {} at index: {}", t, i)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),
 | 
					            Error::StatementChangedRows(i) => write!(f, "Query changed {} rows", i),
 | 
				
			||||||
            Error::StatementFailedToInsertRow => write!(f, "Statement failed to insert new row"),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #[cfg(feature = "functions")]
 | 
					            #[cfg(feature = "functions")]
 | 
				
			||||||
            Error::InvalidFunctionParameterType(i, ref t) => {
 | 
					            Error::InvalidFunctionParameterType(i, ref t) => {
 | 
				
			||||||
@@ -148,7 +144,6 @@ impl error::Error for Error {
 | 
				
			|||||||
            Error::InvalidColumnName(_) => "invalid column name",
 | 
					            Error::InvalidColumnName(_) => "invalid column name",
 | 
				
			||||||
            Error::InvalidColumnType(_, _) => "invalid column type",
 | 
					            Error::InvalidColumnType(_, _) => "invalid column type",
 | 
				
			||||||
            Error::StatementChangedRows(_) => "query inserted zero or more than one row",
 | 
					            Error::StatementChangedRows(_) => "query inserted zero or more than one row",
 | 
				
			||||||
            Error::StatementFailedToInsertRow => "statement failed to insert new row",
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #[cfg(feature = "functions")]
 | 
					            #[cfg(feature = "functions")]
 | 
				
			||||||
            Error::InvalidFunctionParameterType(_, _) => "invalid function parameter type",
 | 
					            Error::InvalidFunctionParameterType(_, _) => "invalid function parameter type",
 | 
				
			||||||
@@ -173,8 +168,7 @@ impl error::Error for Error {
 | 
				
			|||||||
            Error::InvalidColumnName(_) |
 | 
					            Error::InvalidColumnName(_) |
 | 
				
			||||||
            Error::InvalidColumnType(_, _) |
 | 
					            Error::InvalidColumnType(_, _) |
 | 
				
			||||||
            Error::InvalidPath(_) |
 | 
					            Error::InvalidPath(_) |
 | 
				
			||||||
            Error::StatementChangedRows(_) |
 | 
					            Error::StatementChangedRows(_) => None,
 | 
				
			||||||
            Error::StatementFailedToInsertRow => None,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #[cfg(feature = "functions")]
 | 
					            #[cfg(feature = "functions")]
 | 
				
			||||||
            Error::InvalidFunctionParameterType(_, _) => None,
 | 
					            Error::InvalidFunctionParameterType(_, _) => None,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										225
									
								
								src/functions.rs
									
									
									
									
									
								
							
							
						
						
									
										225
									
								
								src/functions.rs
									
									
									
									
									
								
							@@ -54,105 +54,79 @@ use std::ffi::CStr;
 | 
				
			|||||||
use std::mem;
 | 
					use std::mem;
 | 
				
			||||||
use std::ptr;
 | 
					use std::ptr;
 | 
				
			||||||
use std::slice;
 | 
					use std::slice;
 | 
				
			||||||
use libc::{c_int, c_double, c_char, c_void};
 | 
					use libc::{c_int, c_char, c_void};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use ffi;
 | 
					use ffi;
 | 
				
			||||||
pub use ffi::sqlite3_context;
 | 
					use ffi::sqlite3_context;
 | 
				
			||||||
pub use ffi::sqlite3_value;
 | 
					use ffi::sqlite3_value;
 | 
				
			||||||
pub use ffi::sqlite3_value_type;
 | 
					 | 
				
			||||||
pub use ffi::sqlite3_value_numeric_type;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use types::{Null, FromSql, FromSqlError, ValueRef};
 | 
					use types::{ToSql, ToSqlOutput, FromSql, FromSqlError, ValueRef};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use {Result, Error, Connection, str_to_cstring, InnerConnection};
 | 
					use {Result, Error, Connection, str_to_cstring, InnerConnection};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A trait for types that can be converted into the result of an SQL function.
 | 
					fn set_result<'a>(ctx: *mut sqlite3_context, result: &ToSqlOutput<'a>) {
 | 
				
			||||||
pub trait ToResult {
 | 
					    let value = match *result {
 | 
				
			||||||
    unsafe fn set_result(&self, ctx: *mut sqlite3_context);
 | 
					        ToSqlOutput::Borrowed(v) => v,
 | 
				
			||||||
}
 | 
					        ToSqlOutput::Owned(ref v) => ValueRef::from(v),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro_rules! raw_to_impl(
 | 
					        #[cfg(feature = "blob")]
 | 
				
			||||||
    ($t:ty, $f:ident) => (
 | 
					        ToSqlOutput::ZeroBlob(len) => {
 | 
				
			||||||
        impl ToResult for $t {
 | 
					            return unsafe { ffi::sqlite3_result_zeroblob(ctx, len) };
 | 
				
			||||||
            unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
 | 
					        }
 | 
				
			||||||
                ffi::$f(ctx, *self)
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    match value {
 | 
				
			||||||
 | 
					        ValueRef::Null => unsafe { ffi::sqlite3_result_null(ctx) },
 | 
				
			||||||
 | 
					        ValueRef::Integer(i) => unsafe { ffi::sqlite3_result_int64(ctx, i) },
 | 
				
			||||||
 | 
					        ValueRef::Real(r) => unsafe { ffi::sqlite3_result_double(ctx, r) },
 | 
				
			||||||
 | 
					        ValueRef::Text(ref s) => unsafe {
 | 
				
			||||||
 | 
					            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(ref b) => unsafe {
 | 
				
			||||||
);
 | 
					            let length = b.len();
 | 
				
			||||||
 | 
					            if length > ::std::i32::MAX as usize {
 | 
				
			||||||
raw_to_impl!(c_int, sqlite3_result_int);
 | 
					                ffi::sqlite3_result_error_toobig(ctx);
 | 
				
			||||||
raw_to_impl!(i64, sqlite3_result_int64);
 | 
					            } else if length == 0 {
 | 
				
			||||||
raw_to_impl!(c_double, sqlite3_result_double);
 | 
					                ffi::sqlite3_result_zeroblob(ctx, 0)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
impl<'a> ToResult for bool {
 | 
					                ffi::sqlite3_result_blob(ctx,
 | 
				
			||||||
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
 | 
					                                         b.as_ptr() as *const c_void,
 | 
				
			||||||
        if *self {
 | 
					 | 
				
			||||||
            ffi::sqlite3_result_int(ctx, 1)
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            ffi::sqlite3_result_int(ctx, 0)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'a> ToResult for &'a str {
 | 
					 | 
				
			||||||
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
 | 
					 | 
				
			||||||
        let length = self.len();
 | 
					 | 
				
			||||||
        if length > ::std::i32::MAX as usize {
 | 
					 | 
				
			||||||
            ffi::sqlite3_result_error_toobig(ctx);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        match str_to_cstring(self) {
 | 
					 | 
				
			||||||
            Ok(c_str) => {
 | 
					 | 
				
			||||||
                ffi::sqlite3_result_text(ctx,
 | 
					 | 
				
			||||||
                                         c_str.as_ptr(),
 | 
					 | 
				
			||||||
                                         length as c_int,
 | 
					                                         length as c_int,
 | 
				
			||||||
                                         ffi::SQLITE_TRANSIENT())
 | 
					                                         ffi::SQLITE_TRANSIENT());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) {
 | 
				
			||||||
 | 
					    match err {
 | 
				
			||||||
 | 
					        &Error::SqliteFailure(ref err, ref s) => {
 | 
				
			||||||
 | 
					            ffi::sqlite3_result_error_code(ctx, err.extended_code);
 | 
				
			||||||
 | 
					            if let Some(Ok(cstr)) = s.as_ref().map(|s| str_to_cstring(s)) {
 | 
				
			||||||
 | 
					                ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            // TODO sqlite3_result_error
 | 
					 | 
				
			||||||
            Err(_) => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE),
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					        _ => {
 | 
				
			||||||
}
 | 
					            ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_CONSTRAINT_FUNCTION);
 | 
				
			||||||
 | 
					            if let Ok(cstr) = str_to_cstring(err.description()) {
 | 
				
			||||||
impl ToResult for String {
 | 
					                ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
 | 
				
			||||||
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
 | 
					            }
 | 
				
			||||||
        (&self[..]).set_result(ctx)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'a> ToResult for &'a [u8] {
 | 
					 | 
				
			||||||
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
 | 
					 | 
				
			||||||
        if self.len() > ::std::i32::MAX as usize {
 | 
					 | 
				
			||||||
            ffi::sqlite3_result_error_toobig(ctx);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        ffi::sqlite3_result_blob(ctx,
 | 
					 | 
				
			||||||
                                 mem::transmute(self.as_ptr()),
 | 
					 | 
				
			||||||
                                 self.len() as c_int,
 | 
					 | 
				
			||||||
                                 ffi::SQLITE_TRANSIENT())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ToResult for Vec<u8> {
 | 
					 | 
				
			||||||
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
 | 
					 | 
				
			||||||
        (&self[..]).set_result(ctx)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T: ToResult> ToResult for Option<T> {
 | 
					 | 
				
			||||||
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            None => ffi::sqlite3_result_null(ctx),
 | 
					 | 
				
			||||||
            Some(ref t) => t.set_result(ctx),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ToResult for Null {
 | 
					 | 
				
			||||||
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
 | 
					 | 
				
			||||||
        ffi::sqlite3_result_null(ctx)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -166,7 +140,8 @@ impl<'a> ValueRef<'a> {
 | 
				
			|||||||
            ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)),
 | 
					            ffi::SQLITE_FLOAT => ValueRef::Real(ffi::sqlite3_value_double(value)),
 | 
				
			||||||
            ffi::SQLITE_TEXT => {
 | 
					            ffi::SQLITE_TEXT => {
 | 
				
			||||||
                let text = ffi::sqlite3_value_text(value);
 | 
					                let text = ffi::sqlite3_value_text(value);
 | 
				
			||||||
                assert!(!text.is_null(), "unexpected SQLITE_TEXT value type with NULL data");
 | 
					                assert!(!text.is_null(),
 | 
				
			||||||
 | 
					                        "unexpected SQLITE_TEXT value type with NULL data");
 | 
				
			||||||
                let s = CStr::from_ptr(text as *const c_char);
 | 
					                let s = CStr::from_ptr(text as *const c_char);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // sqlite3_value_text returns UTF8 data, so our unwrap here should be fine.
 | 
					                // sqlite3_value_text returns UTF8 data, so our unwrap here should be fine.
 | 
				
			||||||
@@ -175,10 +150,12 @@ impl<'a> ValueRef<'a> {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            ffi::SQLITE_BLOB => {
 | 
					            ffi::SQLITE_BLOB => {
 | 
				
			||||||
                let blob = ffi::sqlite3_value_blob(value);
 | 
					                let blob = ffi::sqlite3_value_blob(value);
 | 
				
			||||||
                assert!(!blob.is_null(), "unexpected SQLITE_BLOB value type with NULL data");
 | 
					                assert!(!blob.is_null(),
 | 
				
			||||||
 | 
					                        "unexpected SQLITE_BLOB value type with NULL data");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let len = ffi::sqlite3_value_bytes(value);
 | 
					                let len = ffi::sqlite3_value_bytes(value);
 | 
				
			||||||
                assert!(len >= 0, "unexpected negative return from sqlite3_value_bytes");
 | 
					                assert!(len >= 0,
 | 
				
			||||||
 | 
					                        "unexpected negative return from sqlite3_value_bytes");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                ValueRef::Blob(from_raw_parts(blob as *const u8, len as usize))
 | 
					                ValueRef::Blob(from_raw_parts(blob as *const u8, len as usize))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -263,7 +240,7 @@ impl<'a> Context<'a> {
 | 
				
			|||||||
/// `A` is the type of the aggregation context and `T` is the type of the final result.
 | 
					/// `A` is the type of the aggregation context and `T` is the type of the final result.
 | 
				
			||||||
/// Implementations should be stateless.
 | 
					/// Implementations should be stateless.
 | 
				
			||||||
pub trait Aggregate<A, T>
 | 
					pub trait Aggregate<A, T>
 | 
				
			||||||
    where T: ToResult
 | 
					    where T: ToSql
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /// Initializes the aggregation context. Will be called prior to the first call
 | 
					    /// Initializes the aggregation context. Will be called prior to the first call
 | 
				
			||||||
    /// to `step()` to set up the context for an invocation of the function. (Note:
 | 
					    /// to `step()` to set up the context for an invocation of the function. (Note:
 | 
				
			||||||
@@ -320,7 +297,7 @@ impl Connection {
 | 
				
			|||||||
                                        x_func: F)
 | 
					                                        x_func: F)
 | 
				
			||||||
                                        -> Result<()>
 | 
					                                        -> Result<()>
 | 
				
			||||||
        where F: FnMut(&Context) -> Result<T>,
 | 
					        where F: FnMut(&Context) -> Result<T>,
 | 
				
			||||||
              T: ToResult
 | 
					              T: ToSql
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func)
 | 
					        self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -337,7 +314,7 @@ impl Connection {
 | 
				
			|||||||
                                              aggr: D)
 | 
					                                              aggr: D)
 | 
				
			||||||
                                              -> Result<()>
 | 
					                                              -> Result<()>
 | 
				
			||||||
        where D: Aggregate<A, T>,
 | 
					        where D: Aggregate<A, T>,
 | 
				
			||||||
              T: ToResult
 | 
					              T: ToSql
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        self.db
 | 
					        self.db
 | 
				
			||||||
            .borrow_mut()
 | 
					            .borrow_mut()
 | 
				
			||||||
@@ -365,13 +342,13 @@ impl InnerConnection {
 | 
				
			|||||||
                                    x_func: F)
 | 
					                                    x_func: F)
 | 
				
			||||||
                                    -> Result<()>
 | 
					                                    -> Result<()>
 | 
				
			||||||
        where F: FnMut(&Context) -> Result<T>,
 | 
					        where F: FnMut(&Context) -> Result<T>,
 | 
				
			||||||
              T: ToResult
 | 
					              T: ToSql
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsafe extern "C" fn call_boxed_closure<F, T>(ctx: *mut sqlite3_context,
 | 
					        unsafe extern "C" fn call_boxed_closure<F, T>(ctx: *mut sqlite3_context,
 | 
				
			||||||
                                                      argc: c_int,
 | 
					                                                      argc: c_int,
 | 
				
			||||||
                                                      argv: *mut *mut sqlite3_value)
 | 
					                                                      argv: *mut *mut sqlite3_value)
 | 
				
			||||||
            where F: FnMut(&Context) -> Result<T>,
 | 
					            where F: FnMut(&Context) -> Result<T>,
 | 
				
			||||||
                  T: ToResult
 | 
					                  T: ToSql
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            let ctx = Context {
 | 
					            let ctx = Context {
 | 
				
			||||||
                ctx: ctx,
 | 
					                ctx: ctx,
 | 
				
			||||||
@@ -379,20 +356,14 @@ impl InnerConnection {
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
            let boxed_f: *mut F = mem::transmute(ffi::sqlite3_user_data(ctx.ctx));
 | 
					            let boxed_f: *mut F = mem::transmute(ffi::sqlite3_user_data(ctx.ctx));
 | 
				
			||||||
            assert!(!boxed_f.is_null(), "Internal error - null function pointer");
 | 
					            assert!(!boxed_f.is_null(), "Internal error - null function pointer");
 | 
				
			||||||
            match (*boxed_f)(&ctx) {
 | 
					
 | 
				
			||||||
                Ok(r) => r.set_result(ctx.ctx),
 | 
					            let t = (*boxed_f)(&ctx);
 | 
				
			||||||
                Err(Error::SqliteFailure(err, s)) => {
 | 
					            let t = t.as_ref().map(|t| ToSql::to_sql(t));
 | 
				
			||||||
                    ffi::sqlite3_result_error_code(ctx.ctx, err.extended_code);
 | 
					
 | 
				
			||||||
                    if let Some(Ok(cstr)) = s.map(|s| str_to_cstring(&s)) {
 | 
					            match t {
 | 
				
			||||||
                        ffi::sqlite3_result_error(ctx.ctx, cstr.as_ptr(), -1);
 | 
					                Ok(Ok(ref value)) => set_result(ctx.ctx, value),
 | 
				
			||||||
                    }
 | 
					                Ok(Err(err)) => report_error(ctx.ctx, &err),
 | 
				
			||||||
                }
 | 
					                Err(err) => report_error(ctx.ctx, err),
 | 
				
			||||||
                Err(err) => {
 | 
					 | 
				
			||||||
                    ffi::sqlite3_result_error_code(ctx.ctx, ffi::SQLITE_CONSTRAINT_FUNCTION);
 | 
					 | 
				
			||||||
                    if let Ok(cstr) = str_to_cstring(err.description()) {
 | 
					 | 
				
			||||||
                        ffi::sqlite3_result_error(ctx.ctx, cstr.as_ptr(), -1);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -423,7 +394,7 @@ impl InnerConnection {
 | 
				
			|||||||
                                          aggr: D)
 | 
					                                          aggr: D)
 | 
				
			||||||
                                          -> Result<()>
 | 
					                                          -> Result<()>
 | 
				
			||||||
        where D: Aggregate<A, T>,
 | 
					        where D: Aggregate<A, T>,
 | 
				
			||||||
              T: ToResult
 | 
					              T: ToSql
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        unsafe fn aggregate_context<A>(ctx: *mut sqlite3_context,
 | 
					        unsafe fn aggregate_context<A>(ctx: *mut sqlite3_context,
 | 
				
			||||||
                                       bytes: usize)
 | 
					                                       bytes: usize)
 | 
				
			||||||
@@ -435,28 +406,11 @@ impl InnerConnection {
 | 
				
			|||||||
            Some(pac)
 | 
					            Some(pac)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        unsafe fn report_aggregate_error(ctx: *mut sqlite3_context, err: Error) {
 | 
					 | 
				
			||||||
            match err {
 | 
					 | 
				
			||||||
                Error::SqliteFailure(err, s) => {
 | 
					 | 
				
			||||||
                    ffi::sqlite3_result_error_code(ctx, err.extended_code);
 | 
					 | 
				
			||||||
                    if let Some(Ok(cstr)) = s.map(|s| str_to_cstring(&s)) {
 | 
					 | 
				
			||||||
                        ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                _ => {
 | 
					 | 
				
			||||||
                    ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_CONSTRAINT_FUNCTION);
 | 
					 | 
				
			||||||
                    if let Ok(cstr) = str_to_cstring(err.description()) {
 | 
					 | 
				
			||||||
                        ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        unsafe extern "C" fn call_boxed_step<A, D, T>(ctx: *mut sqlite3_context,
 | 
					        unsafe extern "C" fn call_boxed_step<A, D, T>(ctx: *mut sqlite3_context,
 | 
				
			||||||
                                                      argc: c_int,
 | 
					                                                      argc: c_int,
 | 
				
			||||||
                                                      argv: *mut *mut sqlite3_value)
 | 
					                                                      argv: *mut *mut sqlite3_value)
 | 
				
			||||||
            where D: Aggregate<A, T>,
 | 
					            where D: Aggregate<A, T>,
 | 
				
			||||||
                  T: ToResult
 | 
					                  T: ToSql
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            let boxed_aggr: *mut D = mem::transmute(ffi::sqlite3_user_data(ctx));
 | 
					            let boxed_aggr: *mut D = mem::transmute(ffi::sqlite3_user_data(ctx));
 | 
				
			||||||
            assert!(!boxed_aggr.is_null(),
 | 
					            assert!(!boxed_aggr.is_null(),
 | 
				
			||||||
@@ -481,13 +435,13 @@ impl InnerConnection {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            match (*boxed_aggr).step(&mut ctx, &mut **pac) {
 | 
					            match (*boxed_aggr).step(&mut ctx, &mut **pac) {
 | 
				
			||||||
                Ok(_) => {}
 | 
					                Ok(_) => {}
 | 
				
			||||||
                Err(err) => report_aggregate_error(ctx.ctx, err),
 | 
					                Err(err) => report_error(ctx.ctx, &err),
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        unsafe extern "C" fn call_boxed_final<A, D, T>(ctx: *mut sqlite3_context)
 | 
					        unsafe extern "C" fn call_boxed_final<A, D, T>(ctx: *mut sqlite3_context)
 | 
				
			||||||
            where D: Aggregate<A, T>,
 | 
					            where D: Aggregate<A, T>,
 | 
				
			||||||
                  T: ToResult
 | 
					                  T: ToSql
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            let boxed_aggr: *mut D = mem::transmute(ffi::sqlite3_user_data(ctx));
 | 
					            let boxed_aggr: *mut D = mem::transmute(ffi::sqlite3_user_data(ctx));
 | 
				
			||||||
            assert!(!boxed_aggr.is_null(),
 | 
					            assert!(!boxed_aggr.is_null(),
 | 
				
			||||||
@@ -507,10 +461,13 @@ impl InnerConnection {
 | 
				
			|||||||
                None => None,
 | 
					                None => None,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            match (*boxed_aggr).finalize(a) {
 | 
					            let t = (*boxed_aggr).finalize(a);
 | 
				
			||||||
                Ok(r) => r.set_result(ctx),
 | 
					            let t = t.as_ref().map(|t| ToSql::to_sql(t));
 | 
				
			||||||
                Err(err) => report_aggregate_error(ctx, err),
 | 
					            match t {
 | 
				
			||||||
            };
 | 
					                Ok(Ok(ref value)) => set_result(ctx, value),
 | 
				
			||||||
 | 
					                Ok(Err(err)) => report_error(ctx, &err),
 | 
				
			||||||
 | 
					                Err(err) => report_error(ctx, err),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let boxed_aggr: *mut D = Box::into_raw(Box::new(aggr));
 | 
					        let boxed_aggr: *mut D = Box::into_raw(Box::new(aggr));
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										100
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								src/lib.rs
									
									
									
									
									
								
							@@ -32,7 +32,7 @@
 | 
				
			|||||||
//!         data: None
 | 
					//!         data: None
 | 
				
			||||||
//!     };
 | 
					//!     };
 | 
				
			||||||
//!     conn.execute("INSERT INTO person (name, time_created, data)
 | 
					//!     conn.execute("INSERT INTO person (name, time_created, data)
 | 
				
			||||||
//!                   VALUES ($1, $2, $3)",
 | 
					//!                   VALUES (?1, ?2, ?3)",
 | 
				
			||||||
//!                  &[&me.name, &me.time_created, &me.data]).unwrap();
 | 
					//!                  &[&me.name, &me.time_created, &me.data]).unwrap();
 | 
				
			||||||
//!
 | 
					//!
 | 
				
			||||||
//!     let mut stmt = conn.prepare("SELECT id, name, time_created, data FROM person").unwrap();
 | 
					//!     let mut stmt = conn.prepare("SELECT id, name, time_created, data FROM person").unwrap();
 | 
				
			||||||
@@ -50,8 +50,6 @@
 | 
				
			|||||||
//!     }
 | 
					//!     }
 | 
				
			||||||
//! }
 | 
					//! }
 | 
				
			||||||
//! ```
 | 
					//! ```
 | 
				
			||||||
#![cfg_attr(feature="clippy", feature(plugin))]
 | 
					 | 
				
			||||||
#![cfg_attr(feature="clippy", plugin(clippy))]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern crate libc;
 | 
					extern crate libc;
 | 
				
			||||||
extern crate libsqlite3_sys as ffi;
 | 
					extern crate libsqlite3_sys as ffi;
 | 
				
			||||||
@@ -73,9 +71,9 @@ use std::cell::RefCell;
 | 
				
			|||||||
use std::ffi::{CStr, CString};
 | 
					use std::ffi::{CStr, CString};
 | 
				
			||||||
use std::result;
 | 
					use std::result;
 | 
				
			||||||
use std::str;
 | 
					use std::str;
 | 
				
			||||||
use libc::{c_int, c_char};
 | 
					use libc::{c_int, c_char, c_void};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use types::{ToSql, FromSql, FromSqlError, ValueRef};
 | 
					use types::{ToSql, ToSqlOutput, FromSql, FromSqlError, ValueRef};
 | 
				
			||||||
use error::{error_from_sqlite_code, error_from_handle};
 | 
					use error::{error_from_sqlite_code, error_from_handle};
 | 
				
			||||||
use raw_statement::RawStatement;
 | 
					use raw_statement::RawStatement;
 | 
				
			||||||
use cache::StatementCache;
 | 
					use cache::StatementCache;
 | 
				
			||||||
@@ -105,6 +103,7 @@ mod raw_statement;
 | 
				
			|||||||
const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
 | 
					const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Old name for `Result`. `SqliteResult` is deprecated.
 | 
					/// Old name for `Result`. `SqliteResult` is deprecated.
 | 
				
			||||||
 | 
					#[deprecated(since = "0.6.0", note = "Use Result instead")]
 | 
				
			||||||
pub type SqliteResult<T> = Result<T>;
 | 
					pub type SqliteResult<T> = Result<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A typedef of the result returned by many methods.
 | 
					/// A typedef of the result returned by many methods.
 | 
				
			||||||
@@ -151,6 +150,7 @@ impl<'a> DatabaseName<'a> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Old name for `Connection`. `SqliteConnection` is deprecated.
 | 
					/// Old name for `Connection`. `SqliteConnection` is deprecated.
 | 
				
			||||||
 | 
					#[deprecated(since = "0.6.0", note = "Use Connection instead")]
 | 
				
			||||||
pub type SqliteConnection = Connection;
 | 
					pub type SqliteConnection = Connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A connection to a SQLite database.
 | 
					/// A connection to a SQLite database.
 | 
				
			||||||
@@ -303,12 +303,10 @@ impl Connection {
 | 
				
			|||||||
    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
 | 
					    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
 | 
				
			||||||
    /// underlying SQLite call fails.
 | 
					    /// underlying SQLite call fails.
 | 
				
			||||||
    pub fn query_row<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
 | 
					    pub fn query_row<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
 | 
				
			||||||
        where F: FnOnce(Row) -> T
 | 
					        where F: FnOnce(&Row) -> T
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let mut stmt = try!(self.prepare(sql));
 | 
					        let mut stmt = try!(self.prepare(sql));
 | 
				
			||||||
        let mut rows = try!(stmt.query(params));
 | 
					        stmt.query_row(params, f)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        rows.get_expected_row().map(f)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Convenience method to execute a query that is expected to return a single row,
 | 
					    /// Convenience method to execute a query that is expected to return a single row,
 | 
				
			||||||
@@ -339,13 +337,13 @@ impl Connection {
 | 
				
			|||||||
                                       params: &[&ToSql],
 | 
					                                       params: &[&ToSql],
 | 
				
			||||||
                                       f: F)
 | 
					                                       f: F)
 | 
				
			||||||
                                       -> result::Result<T, E>
 | 
					                                       -> result::Result<T, E>
 | 
				
			||||||
        where F: FnOnce(Row) -> result::Result<T, E>,
 | 
					        where F: FnOnce(&Row) -> result::Result<T, E>,
 | 
				
			||||||
              E: convert::From<Error>
 | 
					              E: convert::From<Error>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let mut stmt = try!(self.prepare(sql));
 | 
					        let mut stmt = try!(self.prepare(sql));
 | 
				
			||||||
        let mut rows = try!(stmt.query(params));
 | 
					        let mut rows = try!(stmt.query(params));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        rows.get_expected_row().map_err(E::from).and_then(f)
 | 
					        rows.get_expected_row().map_err(E::from).and_then(|r| f(&r))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Convenience method to execute a query that is expected to return a single row.
 | 
					    /// Convenience method to execute a query that is expected to return a single row.
 | 
				
			||||||
@@ -367,8 +365,9 @@ impl Connection {
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// This method should be considered deprecated. Use `query_row` instead, which now
 | 
					    /// This method should be considered deprecated. Use `query_row` instead, which now
 | 
				
			||||||
    /// does exactly the same thing.
 | 
					    /// does exactly the same thing.
 | 
				
			||||||
 | 
					    #[deprecated(since = "0.1.0", note = "Use query_row instead")]
 | 
				
			||||||
    pub fn query_row_safe<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
 | 
					    pub fn query_row_safe<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T>
 | 
				
			||||||
        where F: FnOnce(Row) -> T
 | 
					        where F: FnOnce(&Row) -> T
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        self.query_row(sql, params, f)
 | 
					        self.query_row(sql, params, f)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -404,6 +403,7 @@ impl Connection {
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Will return `Err` if the underlying SQLite call fails.
 | 
					    /// Will return `Err` if the underlying SQLite call fails.
 | 
				
			||||||
    pub fn close(self) -> Result<()> {
 | 
					    pub fn close(self) -> Result<()> {
 | 
				
			||||||
 | 
					        self.flush_prepared_statement_cache();
 | 
				
			||||||
        let mut db = self.db.borrow_mut();
 | 
					        let mut db = self.db.borrow_mut();
 | 
				
			||||||
        db.close()
 | 
					        db.close()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -507,6 +507,7 @@ struct InnerConnection {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Old name for `OpenFlags`. `SqliteOpenFlags` is deprecated.
 | 
					/// Old name for `OpenFlags`. `SqliteOpenFlags` is deprecated.
 | 
				
			||||||
 | 
					#[deprecated(since = "0.6.0", note = "Use OpenFlags instead")]
 | 
				
			||||||
pub type SqliteOpenFlags = OpenFlags;
 | 
					pub type SqliteOpenFlags = OpenFlags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bitflags! {
 | 
					bitflags! {
 | 
				
			||||||
@@ -678,6 +679,7 @@ impl Drop for InnerConnection {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Old name for `Statement`. `SqliteStatement` is deprecated.
 | 
					/// Old name for `Statement`. `SqliteStatement` is deprecated.
 | 
				
			||||||
 | 
					#[deprecated(since = "0.6.0", note = "Use Statement instead")]
 | 
				
			||||||
pub type SqliteStatement<'conn> = Statement<'conn>;
 | 
					pub type SqliteStatement<'conn> = Statement<'conn>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A prepared statement.
 | 
					/// A prepared statement.
 | 
				
			||||||
@@ -874,6 +876,55 @@ impl<'conn> Statement<'conn> {
 | 
				
			|||||||
        self.finalize_()
 | 
					        self.finalize_()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn bind_parameter(&self, param: &ToSql, col: c_int) -> Result<()> {
 | 
				
			||||||
 | 
					        let value = try!(param.to_sql());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let ptr = unsafe { self.stmt.ptr() };
 | 
				
			||||||
 | 
					        let value = match value {
 | 
				
			||||||
 | 
					            ToSqlOutput::Borrowed(v) => v,
 | 
				
			||||||
 | 
					            ToSqlOutput::Owned(ref v) => ValueRef::from(v),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #[cfg(feature = "blob")]
 | 
				
			||||||
 | 
					            ToSqlOutput::ZeroBlob(len) => {
 | 
				
			||||||
 | 
					                return self.conn
 | 
				
			||||||
 | 
					                    .decode_result(unsafe { ffi::sqlite3_bind_zeroblob(ptr, col, len) });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        self.conn.decode_result(match value {
 | 
				
			||||||
 | 
					            ValueRef::Null => unsafe { ffi::sqlite3_bind_null(ptr, col) },
 | 
				
			||||||
 | 
					            ValueRef::Integer(i) => unsafe { ffi::sqlite3_bind_int64(ptr, col, i) },
 | 
				
			||||||
 | 
					            ValueRef::Real(r) => unsafe { ffi::sqlite3_bind_double(ptr, col, r) },
 | 
				
			||||||
 | 
					            ValueRef::Text(ref s) => unsafe {
 | 
				
			||||||
 | 
					                let length = s.len();
 | 
				
			||||||
 | 
					                if length > ::std::i32::MAX as usize {
 | 
				
			||||||
 | 
					                    ffi::SQLITE_TOOBIG
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    let c_str = try!(str_to_cstring(s));
 | 
				
			||||||
 | 
					                    let destructor = if length > 0 {
 | 
				
			||||||
 | 
					                        ffi::SQLITE_TRANSIENT()
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        ffi::SQLITE_STATIC()
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    ffi::sqlite3_bind_text(ptr, col, c_str.as_ptr(), length as c_int, destructor)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            ValueRef::Blob(ref b) => unsafe {
 | 
				
			||||||
 | 
					                let length = b.len();
 | 
				
			||||||
 | 
					                if length > ::std::i32::MAX as usize {
 | 
				
			||||||
 | 
					                    ffi::SQLITE_TOOBIG
 | 
				
			||||||
 | 
					                } else if length == 0 {
 | 
				
			||||||
 | 
					                    ffi::sqlite3_bind_zeroblob(ptr, col, 0)
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    ffi::sqlite3_bind_blob(ptr,
 | 
				
			||||||
 | 
					                                           col,
 | 
				
			||||||
 | 
					                                           b.as_ptr() as *const c_void,
 | 
				
			||||||
 | 
					                                           length as c_int,
 | 
				
			||||||
 | 
					                                           ffi::SQLITE_TRANSIENT())
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn bind_parameters(&mut self, params: &[&ToSql]) -> Result<()> {
 | 
					    fn bind_parameters(&mut self, params: &[&ToSql]) -> Result<()> {
 | 
				
			||||||
        assert!(params.len() as c_int == self.stmt.bind_parameter_count(),
 | 
					        assert!(params.len() as c_int == self.stmt.bind_parameter_count(),
 | 
				
			||||||
                "incorrect number of parameters to query(): expected {}, got {}",
 | 
					                "incorrect number of parameters to query(): expected {}, got {}",
 | 
				
			||||||
@@ -881,14 +932,7 @@ impl<'conn> Statement<'conn> {
 | 
				
			|||||||
                params.len());
 | 
					                params.len());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (i, p) in params.iter().enumerate() {
 | 
					        for (i, p) in params.iter().enumerate() {
 | 
				
			||||||
            try!(unsafe {
 | 
					            try!(self.bind_parameter(*p, (i + 1) as c_int));
 | 
				
			||||||
                self.conn.decode_result(
 | 
					 | 
				
			||||||
                    // This should be
 | 
					 | 
				
			||||||
                    // `p.bind_parameter(self.stmt.ptr(), (i + 1) as c_int)`
 | 
					 | 
				
			||||||
                    // but that doesn't compile until Rust 1.9 due to a compiler bug.
 | 
					 | 
				
			||||||
                    ToSql::bind_parameter(*p, self.stmt.ptr(), (i + 1) as c_int)
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
@@ -967,6 +1011,7 @@ impl<'stmt, T, E, F> Iterator for AndThenRows<'stmt, F>
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Old name for `Rows`. `SqliteRows` is deprecated.
 | 
					/// Old name for `Rows`. `SqliteRows` is deprecated.
 | 
				
			||||||
 | 
					#[deprecated(since = "0.6.0", note = "Use Rows instead")]
 | 
				
			||||||
pub type SqliteRows<'stmt> = Rows<'stmt>;
 | 
					pub type SqliteRows<'stmt> = Rows<'stmt>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// An handle for the resulting rows of a query.
 | 
					/// An handle for the resulting rows of a query.
 | 
				
			||||||
@@ -1031,6 +1076,7 @@ impl<'stmt> Drop for Rows<'stmt> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Old name for `Row`. `SqliteRow` is deprecated.
 | 
					/// Old name for `Row`. `SqliteRow` is deprecated.
 | 
				
			||||||
 | 
					#[deprecated(since = "0.6.0", note = "Use Row instead")]
 | 
				
			||||||
pub type SqliteRow<'a, 'stmt> = Row<'a, 'stmt>;
 | 
					pub type SqliteRow<'a, 'stmt> = Row<'a, 'stmt>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A single result row of a query.
 | 
					/// A single result row of a query.
 | 
				
			||||||
@@ -1127,14 +1173,16 @@ impl<'a> ValueRef<'a> {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            ffi::SQLITE_BLOB => {
 | 
					            ffi::SQLITE_BLOB => {
 | 
				
			||||||
                let blob = ffi::sqlite3_column_blob(raw, col);
 | 
					                let blob = ffi::sqlite3_column_blob(raw, col);
 | 
				
			||||||
                assert!(!blob.is_null(),
 | 
					 | 
				
			||||||
                        "unexpected SQLITE_BLOB column type with NULL data");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let len = ffi::sqlite3_column_bytes(raw, col);
 | 
					                let len = ffi::sqlite3_column_bytes(raw, col);
 | 
				
			||||||
                assert!(len >= 0,
 | 
					                assert!(len >= 0, "unexpected negative return from sqlite3_column_bytes");
 | 
				
			||||||
                        "unexpected negative return from sqlite3_column_bytes");
 | 
					                if len > 0 {
 | 
				
			||||||
 | 
					                    assert!(!blob.is_null(), "unexpected SQLITE_BLOB column type with NULL data");
 | 
				
			||||||
                ValueRef::Blob(from_raw_parts(blob as *const u8, len as usize))
 | 
					                    ValueRef::Blob(from_raw_parts(blob as *const u8, len as usize))
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    // The return value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
 | 
				
			||||||
 | 
					                    ValueRef::Blob(&[])
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            _ => unreachable!("sqlite3_column_type returned invalid value"),
 | 
					            _ => unreachable!("sqlite3_column_type returned invalid value"),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
use {Result, Connection};
 | 
					use {Result, Connection};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Old name for `LoadExtensionGuard`. `SqliteLoadExtensionGuard` is deprecated.
 | 
					/// Old name for `LoadExtensionGuard`. `SqliteLoadExtensionGuard` is deprecated.
 | 
				
			||||||
 | 
					#[deprecated(since = "0.6.0", note = "Use LoadExtensionGuard instead")]
 | 
				
			||||||
pub type SqliteLoadExtensionGuard<'conn> = LoadExtensionGuard<'conn>;
 | 
					pub type SqliteLoadExtensionGuard<'conn> = LoadExtensionGuard<'conn>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// RAII guard temporarily enabling SQLite extensions to be loaded.
 | 
					/// RAII guard temporarily enabling SQLite extensions to be loaded.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,12 +38,12 @@ impl Connection {
 | 
				
			|||||||
    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
 | 
					    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
 | 
				
			||||||
    /// underlying SQLite call fails.
 | 
					    /// underlying SQLite call fails.
 | 
				
			||||||
    pub fn query_row_named<T, F>(&self, sql: &str, params: &[(&str, &ToSql)], f: F) -> Result<T>
 | 
					    pub fn query_row_named<T, F>(&self, sql: &str, params: &[(&str, &ToSql)], f: F) -> Result<T>
 | 
				
			||||||
        where F: FnOnce(Row) -> T
 | 
					        where F: FnOnce(&Row) -> T
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let mut stmt = try!(self.prepare(sql));
 | 
					        let mut stmt = try!(self.prepare(sql));
 | 
				
			||||||
        let mut rows = try!(stmt.query_named(params));
 | 
					        let mut rows = try!(stmt.query_named(params));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        rows.get_expected_row().map(f)
 | 
					        rows.get_expected_row().map(|r| f(&r))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -204,12 +204,7 @@ impl<'conn> Statement<'conn> {
 | 
				
			|||||||
    fn bind_parameters_named(&mut self, params: &[(&str, &ToSql)]) -> Result<()> {
 | 
					    fn bind_parameters_named(&mut self, params: &[(&str, &ToSql)]) -> Result<()> {
 | 
				
			||||||
        for &(name, value) in params {
 | 
					        for &(name, value) in params {
 | 
				
			||||||
            if let Some(i) = try!(self.parameter_index(name)) {
 | 
					            if let Some(i) = try!(self.parameter_index(name)) {
 | 
				
			||||||
                try!(self.conn.decode_result(unsafe {
 | 
					                try!(self.bind_parameter(value, i));
 | 
				
			||||||
                    // This should be
 | 
					 | 
				
			||||||
                    // `value.bind_parameter(self.stmt.ptr(), i)`
 | 
					 | 
				
			||||||
                    // but that doesn't compile until Rust 1.9 due to a compiler bug.
 | 
					 | 
				
			||||||
                    ToSql::bind_parameter(value, self.stmt.ptr(), i)
 | 
					 | 
				
			||||||
                }));
 | 
					 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                return Err(Error::InvalidParameterName(name.into()));
 | 
					                return Err(Error::InvalidParameterName(name.into()));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ use std::ops::Deref;
 | 
				
			|||||||
use {Result, Connection};
 | 
					use {Result, Connection};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Old name for `TransactionBehavior`. `SqliteTransactionBehavior` is deprecated.
 | 
					/// Old name for `TransactionBehavior`. `SqliteTransactionBehavior` is deprecated.
 | 
				
			||||||
 | 
					#[deprecated(since = "0.6.0", note = "Use TransactionBehavior instead")]
 | 
				
			||||||
pub type SqliteTransactionBehavior = TransactionBehavior;
 | 
					pub type SqliteTransactionBehavior = TransactionBehavior;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Options for transaction behavior. See [BEGIN
 | 
					/// Options for transaction behavior. See [BEGIN
 | 
				
			||||||
@@ -28,6 +29,7 @@ pub enum DropBehavior {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Old name for `Transaction`. `SqliteTransaction` is deprecated.
 | 
					/// Old name for `Transaction`. `SqliteTransaction` is deprecated.
 | 
				
			||||||
 | 
					#[deprecated(since = "0.6.0", note = "Use Transaction instead")]
 | 
				
			||||||
pub type SqliteTransaction<'conn> = Transaction<'conn>;
 | 
					pub type SqliteTransaction<'conn> = Transaction<'conn>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Represents a transaction on a database connection.
 | 
					/// Represents a transaction on a database connection.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,23 +4,21 @@ extern crate chrono;
 | 
				
			|||||||
use std::borrow::Cow;
 | 
					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 libc::c_int;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use types::{FromSql, FromSqlError, ToSql, ValueRef};
 | 
					use ::Result;
 | 
				
			||||||
 | 
					use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
 | 
				
			||||||
use ffi::sqlite3_stmt;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// ISO 8601 calendar date without timezone => "YYYY-MM-DD"
 | 
					/// ISO 8601 calendar date without timezone => "YYYY-MM-DD"
 | 
				
			||||||
impl ToSql for NaiveDate {
 | 
					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();
 | 
					        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.
 | 
					/// "YYYY-MM-DD" => ISO 8601 calendar date without timezone.
 | 
				
			||||||
impl FromSql for NaiveDate {
 | 
					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") {
 | 
					        value.as_str().and_then(|s| match NaiveDate::parse_from_str(s, "%Y-%m-%d") {
 | 
				
			||||||
            Ok(dt) => Ok(dt),
 | 
					            Ok(dt) => Ok(dt),
 | 
				
			||||||
            Err(err) => Err(FromSqlError::Other(Box::new(err))),
 | 
					            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"
 | 
					/// ISO 8601 time without timezone => "HH:MM:SS.SSS"
 | 
				
			||||||
impl ToSql for NaiveTime {
 | 
					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();
 | 
					        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.
 | 
					/// "HH:MM"/"HH:MM:SS"/"HH:MM:SS.SSS" => ISO 8601 time without timezone.
 | 
				
			||||||
impl FromSql for NaiveTime {
 | 
					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| {
 | 
					        value.as_str().and_then(|s| {
 | 
				
			||||||
            let fmt = match s.len() {
 | 
					            let fmt = match s.len() {
 | 
				
			||||||
                5 => "%H:%M",
 | 
					                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"
 | 
					/// ISO 8601 combined date and time without timezone => "YYYY-MM-DD HH:MM:SS.SSS"
 | 
				
			||||||
impl ToSql for NaiveDateTime {
 | 
					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();
 | 
					        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
 | 
					/// "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)
 | 
					/// without timezone. ("YYYY-MM-DDTHH:MM:SS"/"YYYY-MM-DDTHH:MM:SS.SSS" also supported)
 | 
				
			||||||
impl FromSql for NaiveDateTime {
 | 
					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| {
 | 
					        value.as_str().and_then(|s| {
 | 
				
			||||||
            let fmt = if s.len() >= 11 && s.as_bytes()[10] == b'T' {
 | 
					            let fmt = if s.len() >= 11 && s.as_bytes()[10] == b'T' {
 | 
				
			||||||
                "%Y-%m-%dT%H:%M:%S%.f"
 | 
					                "%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").
 | 
					/// Date and time with time zone => UTC RFC3339 timestamp ("YYYY-MM-DDTHH:MM:SS.SSS+00:00").
 | 
				
			||||||
impl<Tz: TimeZone> ToSql for DateTime<Tz> {
 | 
					impl<Tz: TimeZone> ToSql for DateTime<Tz> {
 | 
				
			||||||
    unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
 | 
					    fn to_sql(&self) -> Result<ToSqlOutput> {
 | 
				
			||||||
        let utc_dt = self.with_timezone(&UTC);
 | 
					        Ok(ToSqlOutput::from(self.with_timezone(&UTC).to_rfc3339()))
 | 
				
			||||||
        utc_dt.to_rfc3339().bind_parameter(stmt, col)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into DateTime<UTC>.
 | 
					/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into DateTime<UTC>.
 | 
				
			||||||
impl FromSql for 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.
 | 
					            // Try to parse value as rfc3339 first.
 | 
				
			||||||
            let s = try!(value.as_str());
 | 
					            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>.
 | 
					/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into DateTime<Local>.
 | 
				
			||||||
impl FromSql for 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));
 | 
					        let utc_dt = try!(DateTime::<UTC>::column_result(value));
 | 
				
			||||||
        Ok(utc_dt.with_timezone(&Local))
 | 
					        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.
 | 
					/// A trait for types that can be created from a SQLite value.
 | 
				
			||||||
pub trait FromSql: Sized {
 | 
					pub trait FromSql: Sized {
 | 
				
			||||||
    fn column_result(value: ValueRef) -> Result<Self, FromSqlError>;
 | 
					    fn column_result(value: ValueRef) -> FromSqlResult<Self>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FromSql for i32 {
 | 
					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)
 | 
					        i64::column_result(value).map(|i| i as i32)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FromSql for i64 {
 | 
					impl FromSql for i64 {
 | 
				
			||||||
    fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
 | 
					    fn column_result(value: ValueRef) -> FromSqlResult<Self> {
 | 
				
			||||||
        value.as_i64()
 | 
					        value.as_i64()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FromSql for f64 {
 | 
					impl FromSql for f64 {
 | 
				
			||||||
    fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
 | 
					    fn column_result(value: ValueRef) -> FromSqlResult<Self> {
 | 
				
			||||||
        match value {
 | 
					        match value {
 | 
				
			||||||
            ValueRef::Integer(i) => Ok(i as f64),
 | 
					            ValueRef::Integer(i) => Ok(i as f64),
 | 
				
			||||||
            ValueRef::Real(f) => Ok(f),
 | 
					            ValueRef::Real(f) => Ok(f),
 | 
				
			||||||
@@ -67,7 +69,7 @@ impl FromSql for f64 {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FromSql for bool {
 | 
					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 {
 | 
					        i64::column_result(value).map(|i| match i {
 | 
				
			||||||
            0 => false,
 | 
					            0 => false,
 | 
				
			||||||
            _ => true,
 | 
					            _ => true,
 | 
				
			||||||
@@ -76,19 +78,19 @@ impl FromSql for bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FromSql for String {
 | 
					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())
 | 
					        value.as_str().map(|s| s.to_string())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FromSql for Vec<u8> {
 | 
					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())
 | 
					        value.as_blob().map(|b| b.to_vec())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: FromSql> FromSql for Option<T> {
 | 
					impl<T: FromSql> FromSql for Option<T> {
 | 
				
			||||||
    fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
 | 
					    fn column_result(value: ValueRef) -> FromSqlResult<Self> {
 | 
				
			||||||
        match value {
 | 
					        match value {
 | 
				
			||||||
            ValueRef::Null => Ok(None),
 | 
					            ValueRef::Null => Ok(None),
 | 
				
			||||||
            _ => FromSql::column_result(value).map(Some),
 | 
					            _ => FromSql::column_result(value).map(Some),
 | 
				
			||||||
@@ -97,7 +99,7 @@ impl<T: FromSql> FromSql for Option<T> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FromSql for Value {
 | 
					impl FromSql for Value {
 | 
				
			||||||
    fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
 | 
					    fn column_result(value: ValueRef) -> FromSqlResult<Self> {
 | 
				
			||||||
        Ok(value.into())
 | 
					        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
 | 
					//! `FromSql` for the cases where you want to know if a value was NULL (which gets translated to
 | 
				
			||||||
//! `None`).
 | 
					//! `None`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use ffi::sqlite3_stmt;
 | 
					pub use self::from_sql::{FromSql, FromSqlError, FromSqlResult};
 | 
				
			||||||
 | 
					pub use self::to_sql::{ToSql, ToSqlOutput};
 | 
				
			||||||
pub use self::from_sql::{FromSql, FromSqlError};
 | 
					pub use self::value::Value;
 | 
				
			||||||
pub use self::to_sql::ToSql;
 | 
					 | 
				
			||||||
pub use self::value_ref::ValueRef;
 | 
					pub use self::value_ref::ValueRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::fmt;
 | 
					use std::fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod value;
 | 
				
			||||||
mod value_ref;
 | 
					mod value_ref;
 | 
				
			||||||
mod from_sql;
 | 
					mod from_sql;
 | 
				
			||||||
mod to_sql;
 | 
					mod to_sql;
 | 
				
			||||||
@@ -86,36 +86,6 @@ mod serde_json;
 | 
				
			|||||||
#[derive(Copy,Clone)]
 | 
					#[derive(Copy,Clone)]
 | 
				
			||||||
pub struct Null;
 | 
					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)]
 | 
					#[derive(Clone,Debug,PartialEq)]
 | 
				
			||||||
pub enum Type {
 | 
					pub enum Type {
 | 
				
			||||||
    Null,
 | 
					    Null,
 | 
				
			||||||
@@ -146,6 +116,7 @@ mod test {
 | 
				
			|||||||
    use Error;
 | 
					    use Error;
 | 
				
			||||||
    use libc::{c_int, c_double};
 | 
					    use libc::{c_int, c_double};
 | 
				
			||||||
    use std::f64::EPSILON;
 | 
					    use std::f64::EPSILON;
 | 
				
			||||||
 | 
					    use super::Value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn checked_memory_handle() -> Connection {
 | 
					    fn checked_memory_handle() -> Connection {
 | 
				
			||||||
        let db = Connection::open_in_memory().unwrap();
 | 
					        let db = Connection::open_in_memory().unwrap();
 | 
				
			||||||
@@ -164,10 +135,32 @@ mod test {
 | 
				
			|||||||
        assert_eq!(v, v1234);
 | 
					        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]
 | 
					    #[test]
 | 
				
			||||||
    fn test_str() {
 | 
					    fn test_str() {
 | 
				
			||||||
        let db = checked_memory_handle();
 | 
					        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!";
 | 
					        let s = "hello, world!";
 | 
				
			||||||
        db.execute("INSERT INTO foo(t) VALUES (?)", &[&s.to_owned()]).unwrap();
 | 
					        db.execute("INSERT INTO foo(t) VALUES (?)", &[&s.to_owned()]).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -175,6 +168,16 @@ mod test {
 | 
				
			|||||||
        assert_eq!(from, s);
 | 
					        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]
 | 
					    #[test]
 | 
				
			||||||
    fn test_option() {
 | 
					    fn test_option() {
 | 
				
			||||||
        let db = checked_memory_handle();
 | 
					        let db = checked_memory_handle();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,24 +1,21 @@
 | 
				
			|||||||
//! `ToSql` and `FromSql` implementation for JSON `Value`.
 | 
					//! `ToSql` and `FromSql` implementation for JSON `Value`.
 | 
				
			||||||
extern crate serde_json;
 | 
					extern crate serde_json;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use libc::c_int;
 | 
					 | 
				
			||||||
use self::serde_json::Value;
 | 
					use self::serde_json::Value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use types::{FromSql, FromSqlError, ToSql, ValueRef};
 | 
					use ::Result;
 | 
				
			||||||
 | 
					use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
 | 
				
			||||||
use ffi::sqlite3_stmt;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Serialize JSON `Value` to text.
 | 
					/// Serialize JSON `Value` to text.
 | 
				
			||||||
impl ToSql for Value {
 | 
					impl ToSql for Value {
 | 
				
			||||||
    unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
 | 
					    fn to_sql(&self) -> Result<ToSqlOutput> {
 | 
				
			||||||
        let s = serde_json::to_string(self).unwrap();
 | 
					        Ok(ToSqlOutput::from(serde_json::to_string(self).unwrap()))
 | 
				
			||||||
        s.bind_parameter(stmt, col)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Deserialize text/blob to JSON `Value`.
 | 
					/// Deserialize text/blob to JSON `Value`.
 | 
				
			||||||
impl FromSql for Value {
 | 
					impl FromSql for Value {
 | 
				
			||||||
    fn column_result(value: ValueRef) -> Result<Self, FromSqlError> {
 | 
					    fn column_result(value: ValueRef) -> FromSqlResult<Self> {
 | 
				
			||||||
        match value {
 | 
					        match value {
 | 
				
			||||||
                ValueRef::Text(ref s) => serde_json::from_str(s),
 | 
					                ValueRef::Text(ref s) => serde_json::from_str(s),
 | 
				
			||||||
                ValueRef::Blob(ref b) => serde_json::from_slice(b),
 | 
					                ValueRef::Blob(ref b) => serde_json::from_slice(b),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,19 @@
 | 
				
			|||||||
extern crate time;
 | 
					extern crate time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use libc::c_int;
 | 
					use Result;
 | 
				
			||||||
use types::{FromSql, FromSqlError, ToSql, ValueRef};
 | 
					use types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
 | 
				
			||||||
 | 
					 | 
				
			||||||
use ffi::sqlite3_stmt;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S";
 | 
					const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ToSql for time::Timespec {
 | 
					impl ToSql for time::Timespec {
 | 
				
			||||||
    unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
 | 
					    fn to_sql(&self) -> Result<ToSqlOutput> {
 | 
				
			||||||
        let time_str = time::at_utc(*self).strftime(SQLITE_DATETIME_FMT).unwrap().to_string();
 | 
					        let time_string = time::at_utc(*self).strftime(SQLITE_DATETIME_FMT).unwrap().to_string();
 | 
				
			||||||
        time_str.bind_parameter(stmt, col)
 | 
					        Ok(ToSqlOutput::from(time_string))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FromSql for time::Timespec {
 | 
					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) {
 | 
					        value.as_str().and_then(|s| match time::strptime(s, SQLITE_DATETIME_FMT) {
 | 
				
			||||||
            Ok(tm) => Ok(tm.to_timespec()),
 | 
					            Ok(tm) => Ok(tm.to_timespec()),
 | 
				
			||||||
            Err(err) => Err(FromSqlError::Other(Box::new(err))),
 | 
					            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;
 | 
					    /// An owned SQLite-representable value.
 | 
				
			||||||
use ::{ffi, str_to_cstring};
 | 
					    Owned(Value),
 | 
				
			||||||
use ffi::sqlite3_stmt;
 | 
					
 | 
				
			||||||
 | 
					    /// 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.
 | 
					/// A trait for types that can be converted into SQLite values.
 | 
				
			||||||
pub trait ToSql {
 | 
					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(
 | 
					// We should be able to use a generic impl like this:
 | 
				
			||||||
    ($t:ty, $f:ident) => (
 | 
					//
 | 
				
			||||||
 | 
					// 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 {
 | 
					        impl ToSql for $t {
 | 
				
			||||||
            unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
 | 
					            fn to_sql(&self) -> Result<ToSqlOutput> {
 | 
				
			||||||
                ffi::$f(stmt, col, *self)
 | 
					                Ok(ToSqlOutput::from(*self))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
raw_to_impl!(c_int, sqlite3_bind_int); // i32
 | 
					to_sql_self!(Null);
 | 
				
			||||||
raw_to_impl!(i64, sqlite3_bind_int64);
 | 
					to_sql_self!(bool);
 | 
				
			||||||
raw_to_impl!(c_double, sqlite3_bind_double);
 | 
					to_sql_self!(i32);
 | 
				
			||||||
 | 
					to_sql_self!(i64);
 | 
				
			||||||
 | 
					to_sql_self!(f64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ToSql for bool {
 | 
					impl<'a, T: ?Sized> ToSql for &'a T
 | 
				
			||||||
    unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
 | 
					    where &'a T: Into<ToSqlOutput<'a>>
 | 
				
			||||||
        if *self {
 | 
					{
 | 
				
			||||||
            ffi::sqlite3_bind_int(stmt, col, 1)
 | 
					    fn to_sql(&self) -> Result<ToSqlOutput> {
 | 
				
			||||||
        } else {
 | 
					        Ok(ToSqlOutput::from((*self).into()))
 | 
				
			||||||
            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 ToSql for String {
 | 
					impl ToSql for String {
 | 
				
			||||||
    unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
 | 
					    fn to_sql(&self) -> Result<ToSqlOutput> {
 | 
				
			||||||
        (&self[..]).bind_parameter(stmt, col)
 | 
					        Ok(ToSqlOutput::from(self.as_str()))
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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())
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ToSql for Vec<u8> {
 | 
					impl ToSql for Vec<u8> {
 | 
				
			||||||
    unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
 | 
					    fn to_sql(&self) -> Result<ToSqlOutput> {
 | 
				
			||||||
        (&self[..]).bind_parameter(stmt, col)
 | 
					        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> {
 | 
					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 {
 | 
					        match *self {
 | 
				
			||||||
            None => ffi::sqlite3_bind_null(stmt, col),
 | 
					            None => Ok(ToSqlOutput::from(Null)),
 | 
				
			||||||
            Some(ref t) => t.bind_parameter(stmt, col),
 | 
					            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};
 | 
					use super::{Value, Type};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A non-owning [dynamic type value](http://sqlite.org/datatype3.html). Typically the
 | 
					/// 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> {
 | 
					impl<'a> ValueRef<'a> {
 | 
				
			||||||
    /// If `self` is case `Integer`, returns the integral value. Otherwise, returns
 | 
					    /// If `self` is case `Integer`, returns the integral value. Otherwise, returns
 | 
				
			||||||
    /// `Err(Error::InvalidColumnType)`.
 | 
					    /// `Err(Error::InvalidColumnType)`.
 | 
				
			||||||
    pub fn as_i64(&self) -> Result<i64, FromSqlError> {
 | 
					    pub fn as_i64(&self) -> FromSqlResult<i64> {
 | 
				
			||||||
        match *self {
 | 
					        match *self {
 | 
				
			||||||
            ValueRef::Integer(i) => Ok(i),
 | 
					            ValueRef::Integer(i) => Ok(i),
 | 
				
			||||||
            _ => Err(FromSqlError::InvalidType),
 | 
					            _ => Err(FromSqlError::InvalidType),
 | 
				
			||||||
@@ -43,7 +43,7 @@ impl<'a> ValueRef<'a> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// If `self` is case `Real`, returns the floating point value. Otherwise, returns
 | 
					    /// If `self` is case `Real`, returns the floating point value. Otherwise, returns
 | 
				
			||||||
    /// `Err(Error::InvalidColumnType)`.
 | 
					    /// `Err(Error::InvalidColumnType)`.
 | 
				
			||||||
    pub fn as_f64(&self) -> Result<f64, FromSqlError> {
 | 
					    pub fn as_f64(&self) -> FromSqlResult<f64> {
 | 
				
			||||||
        match *self {
 | 
					        match *self {
 | 
				
			||||||
            ValueRef::Real(f) => Ok(f),
 | 
					            ValueRef::Real(f) => Ok(f),
 | 
				
			||||||
            _ => Err(FromSqlError::InvalidType),
 | 
					            _ => Err(FromSqlError::InvalidType),
 | 
				
			||||||
@@ -52,7 +52,7 @@ impl<'a> ValueRef<'a> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// If `self` is case `Text`, returns the string value. Otherwise, returns
 | 
					    /// If `self` is case `Text`, returns the string value. Otherwise, returns
 | 
				
			||||||
    /// `Err(Error::InvalidColumnType)`.
 | 
					    /// `Err(Error::InvalidColumnType)`.
 | 
				
			||||||
    pub fn as_str(&self) -> Result<&str, FromSqlError> {
 | 
					    pub fn as_str(&self) -> FromSqlResult<&str> {
 | 
				
			||||||
        match *self {
 | 
					        match *self {
 | 
				
			||||||
            ValueRef::Text(ref t) => Ok(t),
 | 
					            ValueRef::Text(ref t) => Ok(t),
 | 
				
			||||||
            _ => Err(FromSqlError::InvalidType),
 | 
					            _ => Err(FromSqlError::InvalidType),
 | 
				
			||||||
@@ -61,7 +61,7 @@ impl<'a> ValueRef<'a> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// If `self` is case `Blob`, returns the byte slice. Otherwise, returns
 | 
					    /// If `self` is case `Blob`, returns the byte slice. Otherwise, returns
 | 
				
			||||||
    /// `Err(Error::InvalidColumnType)`.
 | 
					    /// `Err(Error::InvalidColumnType)`.
 | 
				
			||||||
    pub fn as_blob(&self) -> Result<&[u8], FromSqlError> {
 | 
					    pub fn as_blob(&self) -> FromSqlResult<&[u8]> {
 | 
				
			||||||
        match *self {
 | 
					        match *self {
 | 
				
			||||||
            ValueRef::Blob(ref b) => Ok(b),
 | 
					            ValueRef::Blob(ref b) => Ok(b),
 | 
				
			||||||
            _ => Err(FromSqlError::InvalidType),
 | 
					            _ => 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> {
 | 
					impl<'a> From<&'a Value> for ValueRef<'a> {
 | 
				
			||||||
    fn from(value: &'a Value) -> ValueRef<'a> {
 | 
					    fn from(value: &'a Value) -> ValueRef<'a> {
 | 
				
			||||||
        match *value {
 | 
					        match *value {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user