mirror of
				https://github.com/isar/rusqlite.git
				synced 2025-10-31 13:58:55 +08:00 
			
		
		
		
	Add documentation
This commit is contained in:
		
							
								
								
									
										258
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										258
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -1,3 +1,52 @@ | ||||
| //! Rusqlite is an ergonomic, semi-safe wrapper for using SQLite from Rust. It attempts to expose | ||||
| //! an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres). | ||||
| //! | ||||
| //! ```rust | ||||
| //! extern crate rusqlite; | ||||
| //! extern crate time; | ||||
| //! | ||||
| //! use time::Timespec; | ||||
| //! use rusqlite::SqliteConnection; | ||||
| //! | ||||
| //! #[deriving(Show)] | ||||
| //! struct Person { | ||||
| //!     id: i32, | ||||
| //!     name: String, | ||||
| //!     time_created: Timespec, | ||||
| //!     data: Option<Vec<u8>> | ||||
| //! } | ||||
| //! | ||||
| //! fn main() { | ||||
| //!     let conn = SqliteConnection::open(":memory:").unwrap(); | ||||
| //! | ||||
| //!     conn.execute("CREATE TABLE person ( | ||||
| //!                   id              INTEGER PRIMARY KEY, | ||||
| //!                   name            TEXT NOT NULL, | ||||
| //!                   time_created    TEXT NOT NULL, | ||||
| //!                   data            BLOB | ||||
| //!                   )", []).unwrap(); | ||||
| //!     let me = Person { | ||||
| //!         id: 0, | ||||
| //!         name: "Steven".to_string(), | ||||
| //!         time_created: time::get_time(), | ||||
| //!         data: None | ||||
| //!     }; | ||||
| //!     conn.execute("INSERT INTO person (name, time_created, data) | ||||
| //!                   VALUES ($1, $2, $3)", | ||||
| //!                  &[&me.name, &me.time_created, &me.data]).unwrap(); | ||||
| //! | ||||
| //!     let mut stmt = conn.prepare("SELECT id, name, time_created, data FROM person").unwrap(); | ||||
| //!     for row in stmt.query([]).unwrap().map(|row| row.unwrap()) { | ||||
| //!         let person = Person { | ||||
| //!             id: row.get(0), | ||||
| //!             name: row.get(1), | ||||
| //!             time_created: row.get(2), | ||||
| //!             data: row.get(3) | ||||
| //!         }; | ||||
| //!         println!("Found person {}", person); | ||||
| //!     } | ||||
| //! } | ||||
| //! ``` | ||||
| #![feature(globs)] | ||||
| #![feature(unsafe_destructor)] | ||||
| #![feature(macro_rules)] | ||||
| @@ -22,8 +71,11 @@ pub use transaction::{SqliteTransactionBehavior, | ||||
|  | ||||
| pub mod types; | ||||
| mod transaction; | ||||
|  | ||||
| /// Automatically generated FFI bindings (via [bindgen](https://github.com/crabtw/rust-bindgen)). | ||||
| #[allow(dead_code,non_snake_case,non_camel_case_types)] pub mod ffi; | ||||
|  | ||||
| /// A typedef of the result returned by many methods. | ||||
| pub type SqliteResult<T> = Result<T, SqliteError>; | ||||
|  | ||||
| unsafe fn errmsg_to_string(errmsg: *const c_char) -> String { | ||||
| @@ -31,9 +83,15 @@ unsafe fn errmsg_to_string(errmsg: *const c_char) -> String { | ||||
|     c_str.as_str().unwrap_or("Invalid error message encoding").to_string() | ||||
| } | ||||
|  | ||||
| /// Encompasses an error result from a call to the SQLite C API. | ||||
| #[deriving(Show)] | ||||
| pub struct SqliteError { | ||||
|     /// The error code returned by a SQLite C API call. See [SQLite Result | ||||
|     /// Codes](http://www.sqlite.org/rescode.html) for details. | ||||
|     pub code: c_int, | ||||
|  | ||||
|     /// The error message provided by [sqlite3_errmsg](http://www.sqlite.org/c3ref/errcode.html), | ||||
|     /// if possible, or a generic error message based on `code` otherwise. | ||||
|     pub message: String, | ||||
| } | ||||
|  | ||||
| @@ -48,53 +106,170 @@ impl SqliteError { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A connection to a SQLite database. | ||||
| /// | ||||
| /// ## Warning | ||||
| /// | ||||
| /// Note that despite the fact that most `SqliteConnection` methods take an immutable reference to | ||||
| /// `self`, `SqliteConnection` is NOT threadsafe, and using it from multiple threads may result in | ||||
| /// runtime panics or data races. The SQLite connection handle has at least two pieces of internal | ||||
| /// state (the last insertion ID and the last error message) that rusqlite uses, but wrapping these | ||||
| /// APIs in a safe way from Rust would be too restrictive (for example, you would not be able to | ||||
| /// prepare multiple statements at the same time). | ||||
| pub struct SqliteConnection { | ||||
|     db: RefCell<InnerSqliteConnection>, | ||||
| } | ||||
|  | ||||
| impl SqliteConnection { | ||||
|     /// Open a new connection to a SQLite database. | ||||
|     /// | ||||
|     /// Use the special path `:memory:` to create an in-memory database. | ||||
|     /// `SqliteConnection::open(path)` is equivalent to `SqliteConnection::open_with_flags(path, | ||||
|     /// SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE)`. | ||||
|     pub fn open(path: &str) -> SqliteResult<SqliteConnection> { | ||||
|         let flags = SQLITE_OPEN_READ_WRITE | SQLITE_OPEN_CREATE; | ||||
|         SqliteConnection::open_with_flags(path, flags) | ||||
|     } | ||||
|  | ||||
|     /// Open a new connection to a SQLite database. | ||||
|     /// | ||||
|     /// Use the special path `:memory:` to create an in-memory database. See [Opening A New | ||||
|     /// Database Connection](http://www.sqlite.org/c3ref/open.html) for a description of valid | ||||
|     /// flag combinations. | ||||
|     pub fn open_with_flags(path: &str, flags: SqliteOpenFlags) -> SqliteResult<SqliteConnection> { | ||||
|         InnerSqliteConnection::open_with_flags(path, flags).map(|db| { | ||||
|             SqliteConnection{ db: RefCell::new(db) } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// Begin a new transaction with the default behavior (DEFERRED). | ||||
|     /// | ||||
|     /// The transaction defaults to rolling back when it is dropped. If you want the transaction to | ||||
|     /// commit, you must call `commit` or `set_commit`. | ||||
|     /// | ||||
|     /// ## Example | ||||
|     /// | ||||
|     /// ```rust,no_run | ||||
|     /// # use rusqlite::{SqliteConnection, SqliteResult}; | ||||
|     /// # fn do_queries_part_1(conn: &SqliteConnection) -> SqliteResult<()> { Ok(()) } | ||||
|     /// # fn do_queries_part_2(conn: &SqliteConnection) -> SqliteResult<()> { Ok(()) } | ||||
|     /// fn perform_queries(conn: &SqliteConnection) -> SqliteResult<()> { | ||||
|     ///     let tx = try!(conn.transaction()); | ||||
|     /// | ||||
|     ///     try!(do_queries_part_1(conn)); // tx causes rollback if this fails | ||||
|     ///     try!(do_queries_part_2(conn)); // tx causes rollback if this fails | ||||
|     /// | ||||
|     ///     tx.commit() | ||||
|     /// } | ||||
|     /// ``` | ||||
|     pub fn transaction<'a>(&'a self) -> SqliteResult<SqliteTransaction<'a>> { | ||||
|         SqliteTransaction::new(self, SqliteTransactionDeferred) | ||||
|     } | ||||
|  | ||||
|     /// Begin a new transaction with a specified behavior. | ||||
|     /// | ||||
|     /// See `transaction`. | ||||
|     pub fn transaction_with_behavior<'a>(&'a self, behavior: SqliteTransactionBehavior) | ||||
|             -> SqliteResult<SqliteTransaction<'a>> { | ||||
|         SqliteTransaction::new(self, behavior) | ||||
|     } | ||||
|  | ||||
|     /// Convenience method to run multiple SQL statements (that cannot take any parameters). | ||||
|     /// | ||||
|     /// Uses [sqlite3_exec](http://www.sqlite.org/c3ref/exec.html) under the hood. | ||||
|     /// | ||||
|     /// ## Example | ||||
|     /// | ||||
|     /// ```rust,no_run | ||||
|     /// # use rusqlite::{SqliteConnection, SqliteResult}; | ||||
|     /// fn create_tables(conn: &SqliteConnection) -> SqliteResult<()> { | ||||
|     ///     conn.execute_batch("BEGIN; | ||||
|     ///                         CREATE TABLE foo(x INTEGER); | ||||
|     ///                         CREATE TABLE bar(y TEXT); | ||||
|     ///                         COMMIT;") | ||||
|     /// } | ||||
|     /// ``` | ||||
|     pub fn execute_batch(&self, sql: &str) -> SqliteResult<()> { | ||||
|         self.db.borrow_mut().execute_batch(sql) | ||||
|     } | ||||
|  | ||||
|     /// Convenience method to prepare and execute a single SQL statement. | ||||
|     /// | ||||
|     /// On success, returns the number of rows that were changed or inserted or deleted (via | ||||
|     /// `sqlite3_changes`). | ||||
|     /// | ||||
|     /// ## Example | ||||
|     /// | ||||
|     /// ```rust,no_run | ||||
|     /// # use rusqlite::{SqliteConnection}; | ||||
|     /// fn update_rows(conn: &SqliteConnection) { | ||||
|     ///     match conn.execute("UPDATE foo SET bar = 'baz' WHERE qux = ?", &[&1i32]) { | ||||
|     ///         Ok(updated) => println!("{} rows were updated", updated), | ||||
|     ///         Err(err) => println!("update failed: {}", err), | ||||
|     ///     } | ||||
|     /// } | ||||
|     /// ``` | ||||
|     pub fn execute(&self, sql: &str, params: &[&ToSql]) -> SqliteResult<uint> { | ||||
|         self.prepare(sql).and_then(|mut stmt| stmt.execute(params)) | ||||
|     } | ||||
|  | ||||
|     /// Get the SQLite rowid of the most recent successful INSERT. | ||||
|     /// | ||||
|     /// Uses [sqlite3_last_insert_rowid](https://www.sqlite.org/c3ref/last_insert_rowid.html) under | ||||
|     /// the hood. | ||||
|     pub fn last_insert_rowid(&self) -> i64 { | ||||
|         self.db.borrow_mut().last_insert_rowid() | ||||
|     } | ||||
|  | ||||
|     /// Convenience method to execute a query that is expected to return a single row. | ||||
|     /// | ||||
|     /// ## Example | ||||
|     /// | ||||
|     /// ```rust,no_run | ||||
|     /// # use rusqlite::{SqliteConnection}; | ||||
|     /// fn preferred_locale(conn: &SqliteConnection) -> String { | ||||
|     ///     conn.query_row("SELECT value FROM preferences WHERE name='locale'", [], |row| { | ||||
|     ///         row.get(0) | ||||
|     ///     }) | ||||
|     /// } | ||||
|     /// ``` | ||||
|     /// | ||||
|     /// ## Failure | ||||
|     /// | ||||
|     /// Panics if: | ||||
|     /// | ||||
|     ///   * Preparing the query fails. | ||||
|     ///   * Running the query fails (i.e., calling `query` on the prepared statement). | ||||
|     ///   * The query does not successfully return at least one row. | ||||
|     /// | ||||
|     /// If the query returns more than one row, all rows except the first are ignored. | ||||
|     pub fn query_row<T>(&self, sql: &str, params: &[&ToSql], f: |SqliteRow| -> T) -> T { | ||||
|         let mut stmt = self.prepare(sql).unwrap(); | ||||
|         let mut rows = stmt.query(params).unwrap(); | ||||
|         f(rows.next().expect("Query did not return a row").unwrap()) | ||||
|     } | ||||
|  | ||||
|     /// Prepare a SQL statement for execution. | ||||
|     /// | ||||
|     /// ## Example | ||||
|     /// | ||||
|     /// ```rust,no_run | ||||
|     /// # use rusqlite::{SqliteConnection, SqliteResult}; | ||||
|     /// fn insert_new_people(conn: &SqliteConnection) -> SqliteResult<()> { | ||||
|     ///     let mut stmt = try!(conn.prepare("INSERT INTO People (name) VALUES (?)")); | ||||
|     ///     try!(stmt.execute(&[&"Joe Smith"])); | ||||
|     ///     try!(stmt.execute(&[&"Bob Jones"])); | ||||
|     ///     Ok(()) | ||||
|     /// } | ||||
|     /// ``` | ||||
|     pub fn prepare<'a>(&'a self, sql: &str) -> SqliteResult<SqliteStatement<'a>> { | ||||
|         self.db.borrow_mut().prepare(self, sql) | ||||
|     } | ||||
|  | ||||
|     /// Close the SQLite connection. | ||||
|     /// | ||||
|     /// This is functionally equivalent to the `Drop` implementation for `SqliteConnection` except | ||||
|     /// that it returns any error encountered to the caller. | ||||
|     pub fn close(self) -> SqliteResult<()> { | ||||
|         self.db.borrow_mut().close() | ||||
|     } | ||||
| @@ -119,7 +294,10 @@ struct InnerSqliteConnection { | ||||
| } | ||||
|  | ||||
| bitflags! { | ||||
|     #[repr(C)] flags SqliteOpenFlags: c_int { | ||||
|     #[doc = "Flags for opening SQLite database connections."] | ||||
|     #[doc = "See [sqlite3_open_v2](http://www.sqlite.org/c3ref/open.html) for details."] | ||||
|     #[repr(C)] | ||||
|     flags SqliteOpenFlags: c_int { | ||||
|         const SQLITE_OPEN_READ_ONLY     = 0x00000001, | ||||
|         const SQLITE_OPEN_READ_WRITE    = 0x00000002, | ||||
|         const SQLITE_OPEN_CREATE        = 0x00000004, | ||||
| @@ -211,6 +389,7 @@ impl Drop for InnerSqliteConnection { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A prepared statement. | ||||
| pub struct SqliteStatement<'conn> { | ||||
|     conn: &'conn SqliteConnection, | ||||
|     stmt: *mut ffi::sqlite3_stmt, | ||||
| @@ -222,6 +401,24 @@ impl<'conn> SqliteStatement<'conn> { | ||||
|         SqliteStatement{ conn: conn, stmt: stmt, needs_reset: false } | ||||
|     } | ||||
|  | ||||
|     /// Execute the prepared statement. | ||||
|     /// | ||||
|     /// On success, returns the number of rows that were changed or inserted or deleted (via | ||||
|     /// `sqlite3_changes`). | ||||
|     /// | ||||
|     /// ## Example | ||||
|     /// | ||||
|     /// ```rust,no_run | ||||
|     /// # use rusqlite::{SqliteConnection, SqliteResult}; | ||||
|     /// fn update_rows(conn: &SqliteConnection) -> SqliteResult<()> { | ||||
|     ///     let mut stmt = try!(conn.prepare("UPDATE foo SET bar = 'baz' WHERE qux = ?")); | ||||
|     /// | ||||
|     ///     try!(stmt.execute(&[&1i32])); | ||||
|     ///     try!(stmt.execute(&[&2i32])); | ||||
|     /// | ||||
|     ///     Ok(()) | ||||
|     /// } | ||||
|     /// ``` | ||||
|     pub fn execute(&mut self, params: &[&ToSql]) -> SqliteResult<uint> { | ||||
|         self.reset_if_needed(); | ||||
|  | ||||
| @@ -243,6 +440,25 @@ impl<'conn> SqliteStatement<'conn> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Execute the prepared statement, returning an iterator over the resulting rows. | ||||
|     /// | ||||
|     /// ## Example | ||||
|     /// | ||||
|     /// ```rust,no_run | ||||
|     /// # use rusqlite::{SqliteConnection, SqliteResult}; | ||||
|     /// fn get_names(conn: &SqliteConnection) -> SqliteResult<Vec<String>> { | ||||
|     ///     let mut stmt = try!(conn.prepare("SELECT name FROM people")); | ||||
|     ///     let mut rows = try!(stmt.query([])); | ||||
|     /// | ||||
|     ///     let mut names = Vec::new(); | ||||
|     ///     for result_row in rows { | ||||
|     ///         let row = try!(result_row); | ||||
|     ///         names.push(row.get(0)); | ||||
|     ///     } | ||||
|     /// | ||||
|     ///     Ok(names) | ||||
|     /// } | ||||
|     /// ``` | ||||
|     pub fn query<'a>(&'a mut self, params: &[&ToSql]) -> SqliteResult<SqliteRows<'a>> { | ||||
|         self.reset_if_needed(); | ||||
|  | ||||
| @@ -258,6 +474,10 @@ impl<'conn> SqliteStatement<'conn> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Consumes the statement. | ||||
|     /// | ||||
|     /// Functionally equivalent to the `Drop` implementation, but allows callers to see any errors | ||||
|     /// that occur. | ||||
|     pub fn finalize(mut self) -> SqliteResult<()> { | ||||
|         self.finalize_() | ||||
|     } | ||||
| @@ -290,6 +510,7 @@ impl<'conn> Drop for SqliteStatement<'conn> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// An iterator over the resulting rows of a query. | ||||
| pub struct SqliteRows<'stmt> { | ||||
|     stmt: &'stmt SqliteStatement<'stmt>, | ||||
|     current_row: Rc<Cell<c_int>>, | ||||
| @@ -326,6 +547,7 @@ impl<'stmt> Iterator<SqliteResult<SqliteRow<'stmt>>> for SqliteRows<'stmt> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A single result row of a query. | ||||
| pub struct SqliteRow<'stmt> { | ||||
|     stmt: &'stmt SqliteStatement<'stmt>, | ||||
|     current_row: Rc<Cell<c_int>>, | ||||
| @@ -333,10 +555,44 @@ pub struct SqliteRow<'stmt> { | ||||
| } | ||||
|  | ||||
| impl<'stmt> SqliteRow<'stmt> { | ||||
|     /// Get the value of a particular column of the result row. | ||||
|     /// | ||||
|     /// Note that `SqliteRow` falls into the "semi-safe" category of rusqlite. When you are | ||||
|     /// retrieving the rows of a query, a row becomes stale once you have requested the next row, | ||||
|     /// and the values can no longer be retrieved. In general (when using a loop over the rows, for | ||||
|     /// example) this isn't an issue, but it means you cannot do something like this: | ||||
|     /// | ||||
|     /// ```rust,no_run | ||||
|     /// # use rusqlite::{SqliteConnection, SqliteResult}; | ||||
|     /// fn bad_function_will_panic(conn: &SqliteConnection) -> SqliteResult<i64> { | ||||
|     ///     let mut stmt = try!(conn.prepare("SELECT id FROM my_table")); | ||||
|     ///     let mut rows = try!(stmt.query([])); | ||||
|     /// | ||||
|     ///     let row0 = try!(rows.next().unwrap()); | ||||
|     ///     // row 0 is value now... | ||||
|     /// | ||||
|     ///     let row1 = try!(rows.next().unwrap()); | ||||
|     ///     // row 0 is now STALE, and row 1 is valid | ||||
|     /// | ||||
|     ///     let my_id = row0.get(0); // WILL PANIC because row 0 is stale | ||||
|     ///     Ok(my_id) | ||||
|     /// } | ||||
|     /// ``` | ||||
|     /// | ||||
|     /// ## Failure | ||||
|     /// | ||||
|     /// Panics if `idx` is outside the range of columns in the returned query or if this row | ||||
|     /// is stale. | ||||
|     pub fn get<T: FromSql>(&self, idx: c_int) -> T { | ||||
|         self.get_opt(idx).unwrap() | ||||
|     } | ||||
|  | ||||
|     /// Attempt to get the value of a particular column of the result row. | ||||
|     /// | ||||
|     /// ## Failure | ||||
|     /// | ||||
|     /// Returns a `SQLITE_MISUSE`-coded `SqliteError` if `idx` is outside the valid column range | ||||
|     /// for this row or if this row is stale. | ||||
|     pub fn get_opt<T: FromSql>(&self, idx: c_int) -> SqliteResult<T> { | ||||
|         if self.row_idx != self.current_row.get() { | ||||
|             return Err(SqliteError{ code: ffi::SQLITE_MISUSE, | ||||
|   | ||||
| @@ -1,11 +1,35 @@ | ||||
| use {SqliteResult, SqliteConnection}; | ||||
|  | ||||
| /// Options for transaction behavior. See [BEGIN | ||||
| /// TRANSACTION](http://www.sqlite.org/lang_transaction.html) for details. | ||||
| pub enum SqliteTransactionBehavior { | ||||
|     SqliteTransactionDeferred, | ||||
|     SqliteTransactionImmediate, | ||||
|     SqliteTransactionExclusive, | ||||
| } | ||||
|  | ||||
| /// Represents a transaction on a database connection. | ||||
| /// | ||||
| /// ## Note | ||||
| /// | ||||
| /// Transactions will roll back by default. Use the `set_commit` or `commit` methods to commit the | ||||
| /// transaction. | ||||
| /// | ||||
| /// ## Example | ||||
| /// | ||||
| /// ```rust,no_run | ||||
| /// # use rusqlite::{SqliteConnection, SqliteResult}; | ||||
| /// # fn do_queries_part_1(conn: &SqliteConnection) -> SqliteResult<()> { Ok(()) } | ||||
| /// # fn do_queries_part_2(conn: &SqliteConnection) -> SqliteResult<()> { Ok(()) } | ||||
| /// fn perform_queries(conn: &SqliteConnection) -> SqliteResult<()> { | ||||
| ///     let tx = try!(conn.transaction()); | ||||
| /// | ||||
| ///     try!(do_queries_part_1(conn)); // tx causes rollback if this fails | ||||
| ///     try!(do_queries_part_2(conn)); // tx causes rollback if this fails | ||||
| /// | ||||
| ///     tx.commit() | ||||
| /// } | ||||
| /// ``` | ||||
| pub struct SqliteTransaction<'conn> { | ||||
|     conn: &'conn SqliteConnection, | ||||
|     depth: u32, | ||||
| @@ -14,6 +38,7 @@ pub struct SqliteTransaction<'conn> { | ||||
| } | ||||
|  | ||||
| impl<'conn> SqliteTransaction<'conn> { | ||||
|     /// Begin a new transaction. Cannot be nested; see `savepoint` for nested transactions. | ||||
|     pub fn new(conn: &SqliteConnection, | ||||
|                behavior: SqliteTransactionBehavior) -> SqliteResult<SqliteTransaction> { | ||||
|         let query = match behavior { | ||||
| @@ -26,6 +51,32 @@ impl<'conn> SqliteTransaction<'conn> { | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// Starts a new [savepoint](http://www.sqlite.org/lang_savepoint.html), allowing nested | ||||
|     /// transactions. | ||||
|     /// | ||||
|     /// ## Note | ||||
|     /// | ||||
|     /// Just like outer level transactions, savepoint transactions rollback by default. | ||||
|     /// | ||||
|     /// ## Example | ||||
|     /// | ||||
|     /// ```rust,no_run | ||||
|     /// # use rusqlite::{SqliteConnection, SqliteResult}; | ||||
|     /// # fn perform_queries_part_1_succeeds(conn: &SqliteConnection) -> bool { true } | ||||
|     /// fn perform_queries(conn: &SqliteConnection) -> SqliteResult<()> { | ||||
|     ///     let tx = try!(conn.transaction()); | ||||
|     /// | ||||
|     ///     { | ||||
|     ///         let sp = try!(tx.savepoint()); | ||||
|     ///         if perform_queries_part_1_succeeds(conn) { | ||||
|     ///             try!(sp.commit()); | ||||
|     ///         } | ||||
|     ///         // otherwise, sp will rollback | ||||
|     ///     } | ||||
|     /// | ||||
|     ///     tx.commit() | ||||
|     /// } | ||||
|     /// ``` | ||||
|     pub fn savepoint<'a>(&'a self) -> SqliteResult<SqliteTransaction<'a>> { | ||||
|         self.conn.execute_batch("SAVEPOINT sp").map(|_| { | ||||
|             SqliteTransaction{ | ||||
| @@ -34,22 +85,27 @@ impl<'conn> SqliteTransaction<'conn> { | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// Returns whether or not the transaction is currently set to commit. | ||||
|     pub fn will_commit(&self) -> bool { | ||||
|         self.commit | ||||
|     } | ||||
|  | ||||
|     /// Returns whether or not the transaction is currently set to rollback. | ||||
|     pub fn will_rollback(&self) -> bool { | ||||
|         !self.commit | ||||
|     } | ||||
|  | ||||
|     /// Set the transaction to commit at its completion. | ||||
|     pub fn set_commit(&mut self) { | ||||
|         self.commit = true | ||||
|     } | ||||
|  | ||||
|     /// Set the transaction to rollback at its completion. | ||||
|     pub fn set_rollback(&mut self) { | ||||
|         self.commit = false | ||||
|     } | ||||
|  | ||||
|     /// A convenience method which consumes and commits a transaction. | ||||
|     pub fn commit(mut self) -> SqliteResult<()> { | ||||
|         self.commit_() | ||||
|     } | ||||
| @@ -59,6 +115,7 @@ impl<'conn> SqliteTransaction<'conn> { | ||||
|         self.conn.execute_batch(if self.depth == 0 { "COMMIT" } else { "RELEASE sp" }) | ||||
|     } | ||||
|  | ||||
|     /// A convenience method which consumes and rolls back a transaction. | ||||
|     pub fn rollback(mut self) -> SqliteResult<()> { | ||||
|         self.rollback_() | ||||
|     } | ||||
| @@ -68,6 +125,11 @@ impl<'conn> SqliteTransaction<'conn> { | ||||
|         self.conn.execute_batch(if self.depth == 0 { "ROLLBACK" } else { "ROLLBACK TO sp" }) | ||||
|     } | ||||
|  | ||||
|     /// Consumes the transaction, committing or rolling back according to the current setting | ||||
|     /// (see `will_commit`, `will_rollback`). | ||||
|     /// | ||||
|     /// Functionally equivalent to the `Drop` implementation, but allows callers to see any | ||||
|     /// errors that occur. | ||||
|     pub fn finish(mut self) -> SqliteResult<()> { | ||||
|         self.finish_() | ||||
|     } | ||||
|   | ||||
							
								
								
									
										67
									
								
								src/types.rs
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								src/types.rs
									
									
									
									
									
								
							| @@ -1,3 +1,57 @@ | ||||
| //! Traits dealing with SQLite data types. | ||||
| //! | ||||
| //! SQLite uses a [dynamic type system](https://www.sqlite.org/datatype3.html). Implementations of | ||||
| //! the `ToSql` and `FromSql` traits are provided for the basic types that SQLite provides methods | ||||
| //! for: | ||||
| //! | ||||
| //! * C integers and doubles (`c_int` and `c_double`) | ||||
| //! * Strings (`String` and `&str`) | ||||
| //! * Blobs (`Vec<u8>` and `&[u8]`) | ||||
| //! | ||||
| //! Additionally, because it is such a common data type, implementations are provided for | ||||
| //! `time::Timespec` that use a string for storage (using the same format string, | ||||
| //! `"%Y-%m-%d %H:%M:%S"`, as SQLite's builtin | ||||
| //! [datetime](https://www.sqlite.org/lang_datefunc.html) function.  Note that this storage | ||||
| //! truncates timespecs to the nearest second. If you want different storage for timespecs, you can | ||||
| //! use a newtype. For example, to store timespecs as doubles: | ||||
| //! | ||||
| //! `ToSql` and `FromSql` are also implemented for `Option<T>` where `T` implements `ToSql` or | ||||
| //! `FromSql` for the cases where you want to know if a value was NULL (which gets translated to | ||||
| //! `None`). If you get a value that was NULL in SQLite but you store it into a non-`Option` value | ||||
| //! in Rust, you will get a "sensible" zero value - 0 for numeric types (including timespecs), an | ||||
| //! empty string, or an empty vector of bytes. | ||||
| //! | ||||
| //! ```rust,ignore | ||||
| //! extern crate rusqlite; | ||||
| //! extern crate libc; | ||||
| //! | ||||
| //! use rusqlite::types::{FromSql, ToSql}; | ||||
| //! use rusqlite::{ffi, SqliteResult}; | ||||
| //! use libc::c_int; | ||||
| //! use time; | ||||
| //! | ||||
| //! pub struct TimespecSql(pub time::Timespec); | ||||
| //! | ||||
| //! impl FromSql for TimespecSql { | ||||
| //!     unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) | ||||
| //!             -> SqliteResult<TimespecSql> { | ||||
| //!         let as_f64_result = FromSql::column_result(stmt, col); | ||||
| //!         as_f64_result.map(|as_f64: f64| { | ||||
| //!             TimespecSql(time::Timespec{ sec: as_f64.trunc() as i64, | ||||
| //!                                         nsec: (as_f64.fract() * 1.0e9) as i32 }) | ||||
| //!         }) | ||||
| //!     } | ||||
| //! } | ||||
| //! | ||||
| //! impl ToSql for TimespecSql { | ||||
| //!     unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int { | ||||
| //!         let TimespecSql(ts) = *self; | ||||
| //!         let as_f64 = ts.sec as f64 + (ts.nsec as f64) / 1.0e9; | ||||
| //!         as_f64.bind_parameter(stmt, col) | ||||
| //!     } | ||||
| //! } | ||||
| //! ``` | ||||
|  | ||||
| extern crate time; | ||||
|  | ||||
| use libc::{c_int, c_double}; | ||||
| @@ -9,10 +63,12 @@ use super::{SqliteResult, SqliteError}; | ||||
|  | ||||
| const SQLITE_DATETIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S"; | ||||
|  | ||||
| /// A trait for types that can be converted into SQLite values. | ||||
| pub trait ToSql { | ||||
|     unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int; | ||||
| } | ||||
|  | ||||
| /// A trait for types that can be created from a SQLite value. | ||||
| pub trait FromSql { | ||||
|     unsafe fn column_result(stmt: *mut ffi::sqlite3_stmt, col: c_int) -> SqliteResult<Self>; | ||||
| } | ||||
| @@ -75,6 +131,17 @@ impl<T: ToSql> ToSql for Option<T> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Empty struct that can be used to fill in a query parameter as `NULL`. | ||||
| /// | ||||
| /// ## Example | ||||
| /// | ||||
| /// ```rust,no_run | ||||
| /// # use rusqlite::{SqliteConnection, SqliteResult}; | ||||
| /// # use rusqlite::types::{Null}; | ||||
| /// fn insert_null(conn: &SqliteConnection) -> SqliteResult<uint> { | ||||
| ///     conn.execute("INSERT INTO people (name) VALUES (?)", &[&Null]) | ||||
| /// } | ||||
| /// ``` | ||||
| pub struct Null; | ||||
|  | ||||
| impl ToSql for Null { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user