mirror of
				https://github.com/isar/rusqlite.git
				synced 2025-10-31 22:08:55 +08:00 
			
		
		
		
	Merge branch 'master' into remove-rows-iterator-impl
This commit is contained in:
		
							
								
								
									
										130
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -55,6 +55,7 @@ | ||||
|  | ||||
| extern crate libc; | ||||
| extern crate libsqlite3_sys as ffi; | ||||
| extern crate lru_cache; | ||||
| #[macro_use] | ||||
| extern crate bitflags; | ||||
| #[cfg(test)] | ||||
| @@ -76,24 +77,32 @@ use libc::{c_int, c_char}; | ||||
|  | ||||
| use types::{ToSql, FromSql}; | ||||
| use error::{error_from_sqlite_code, error_from_handle}; | ||||
| use raw_statement::RawStatement; | ||||
| use cache::StatementCache; | ||||
|  | ||||
| pub use transaction::{SqliteTransaction, Transaction, TransactionBehavior}; | ||||
| pub use error::{SqliteError, Error}; | ||||
| pub use cache::CachedStatement; | ||||
|  | ||||
| #[cfg(feature = "load_extension")] | ||||
| pub use load_extension_guard::{SqliteLoadExtensionGuard, LoadExtensionGuard}; | ||||
|  | ||||
| pub mod types; | ||||
| mod transaction; | ||||
| mod cache; | ||||
| mod named_params; | ||||
| mod error; | ||||
| mod convenient; | ||||
| mod raw_statement; | ||||
| #[cfg(feature = "load_extension")]mod load_extension_guard; | ||||
| #[cfg(feature = "trace")]pub mod trace; | ||||
| #[cfg(feature = "backup")]pub mod backup; | ||||
| #[cfg(feature = "functions")]pub mod functions; | ||||
| #[cfg(feature = "blob")]pub mod blob; | ||||
|  | ||||
| // Number of cached prepared statements we'll hold on to. | ||||
| const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16; | ||||
|  | ||||
| /// Old name for `Result`. `SqliteResult` is deprecated. | ||||
| pub type SqliteResult<T> = Result<T>; | ||||
|  | ||||
| @@ -146,6 +155,7 @@ pub type SqliteConnection = Connection; | ||||
| /// A connection to a SQLite database. | ||||
| pub struct Connection { | ||||
|     db: RefCell<InnerConnection>, | ||||
|     cache: StatementCache, | ||||
|     path: Option<PathBuf>, | ||||
| } | ||||
|  | ||||
| @@ -190,6 +200,7 @@ impl Connection { | ||||
|         InnerConnection::open_with_flags(&c_path, flags).map(|db| { | ||||
|             Connection { | ||||
|                 db: RefCell::new(db), | ||||
|                 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), | ||||
|                 path: Some(path.as_ref().to_path_buf()), | ||||
|             } | ||||
|         }) | ||||
| @@ -208,50 +219,12 @@ impl Connection { | ||||
|         InnerConnection::open_with_flags(&c_memory, flags).map(|db| { | ||||
|             Connection { | ||||
|                 db: RefCell::new(db), | ||||
|                 cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), | ||||
|                 path: None, | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     /// 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::{Connection, Result}; | ||||
|     /// # fn do_queries_part_1(conn: &Connection) -> Result<()> { Ok(()) } | ||||
|     /// # fn do_queries_part_2(conn: &Connection) -> Result<()> { Ok(()) } | ||||
|     /// fn perform_queries(conn: &Connection) -> Result<()> { | ||||
|     ///     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() | ||||
|     /// } | ||||
|     /// ``` | ||||
|     /// | ||||
|     /// # Failure | ||||
|     /// | ||||
|     /// Will return `Err` if the underlying SQLite call fails. | ||||
|     pub fn transaction(&mut self) -> Result<Transaction> { | ||||
|         Transaction::new(self, TransactionBehavior::Deferred) | ||||
|     } | ||||
|  | ||||
|     /// Begin a new transaction with a specified behavior. | ||||
|     /// | ||||
|     /// See `transaction`. | ||||
|     /// | ||||
|     /// # Failure | ||||
|     /// | ||||
|     /// Will return `Err` if the underlying SQLite call fails. | ||||
|     pub fn transaction_with_behavior(&mut self, behavior: TransactionBehavior) -> Result<Transaction> { | ||||
|         Transaction::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. | ||||
| @@ -686,7 +659,7 @@ impl InnerConnection { | ||||
|                                     &mut c_stmt, | ||||
|                                     ptr::null_mut()) | ||||
|         }; | ||||
|         self.decode_result(r).map(|_| Statement::new(conn, c_stmt)) | ||||
|         self.decode_result(r).map(|_| Statement::new(conn, RawStatement::new(c_stmt))) | ||||
|     } | ||||
|  | ||||
|     fn changes(&mut self) -> c_int { | ||||
| @@ -707,25 +680,23 @@ pub type SqliteStatement<'conn> = Statement<'conn>; | ||||
| /// A prepared statement. | ||||
| pub struct Statement<'conn> { | ||||
|     conn: &'conn Connection, | ||||
|     stmt: *mut ffi::sqlite3_stmt, | ||||
|     column_count: c_int, | ||||
|     stmt: RawStatement, | ||||
| } | ||||
|  | ||||
| impl<'conn> Statement<'conn> { | ||||
|     fn new(conn: &Connection, stmt: *mut ffi::sqlite3_stmt) -> Statement { | ||||
|     fn new(conn: &Connection, stmt: RawStatement) -> Statement { | ||||
|         Statement { | ||||
|             conn: conn, | ||||
|             stmt: stmt, | ||||
|             column_count: unsafe { ffi::sqlite3_column_count(stmt) }, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Get all the column names in the result set of the prepared statement. | ||||
|     pub fn column_names(&self) -> Vec<&str> { | ||||
|         let n = self.column_count; | ||||
|         let n = self.column_count(); | ||||
|         let mut cols = Vec::with_capacity(n as usize); | ||||
|         for i in 0..n { | ||||
|             let slice = unsafe { CStr::from_ptr(ffi::sqlite3_column_name(self.stmt, i)) }; | ||||
|             let slice = self.stmt.column_name(i); | ||||
|             let s = str::from_utf8(slice.to_bytes()).unwrap(); | ||||
|             cols.push(s); | ||||
|         } | ||||
| @@ -734,7 +705,7 @@ impl<'conn> Statement<'conn> { | ||||
|  | ||||
|     /// Return the number of columns in the result set returned by the prepared statement. | ||||
|     pub fn column_count(&self) -> i32 { | ||||
|         self.column_count | ||||
|         self.stmt.column_count() | ||||
|     } | ||||
|  | ||||
|     /// Returns the column index in the result set for a given column name. | ||||
| @@ -744,10 +715,9 @@ impl<'conn> Statement<'conn> { | ||||
|     /// Will return an `Error::InvalidColumnName` when there is no column with the specified `name`. | ||||
|     pub fn column_index(&self, name: &str) -> Result<i32> { | ||||
|         let bytes = name.as_bytes(); | ||||
|         let n = self.column_count; | ||||
|         let n = self.column_count(); | ||||
|         for i in 0..n { | ||||
|             let slice = unsafe { CStr::from_ptr(ffi::sqlite3_column_name(self.stmt, i)) }; | ||||
|             if bytes == slice.to_bytes() { | ||||
|             if bytes == self.stmt.column_name(i).to_bytes() { | ||||
|                 return Ok(i); | ||||
|             } | ||||
|         } | ||||
| @@ -778,18 +748,16 @@ impl<'conn> Statement<'conn> { | ||||
|     /// Will return `Err` if binding parameters fails, the executed statement returns rows (in | ||||
|     /// which case `query` should be used instead), or the underling SQLite call fails. | ||||
|     pub fn execute(&mut self, params: &[&ToSql]) -> Result<c_int> { | ||||
|         unsafe { | ||||
|             try!(self.bind_parameters(params)); | ||||
|             self.execute_() | ||||
|         } | ||||
|         try!(self.bind_parameters(params)); | ||||
|         self.execute_() | ||||
|     } | ||||
|  | ||||
|     unsafe fn execute_(&mut self) -> Result<c_int> { | ||||
|         let r = ffi::sqlite3_step(self.stmt); | ||||
|         ffi::sqlite3_reset(self.stmt); | ||||
|     fn execute_(&mut self) -> Result<c_int> { | ||||
|         let r = self.stmt.step(); | ||||
|         self.stmt.reset(); | ||||
|         match r { | ||||
|             ffi::SQLITE_DONE => { | ||||
|                 if self.column_count == 0 { | ||||
|                 if self.column_count() == 0 { | ||||
|                     Ok(self.conn.changes()) | ||||
|                 } else { | ||||
|                     Err(Error::ExecuteReturnedResults) | ||||
| @@ -828,10 +796,7 @@ impl<'conn> Statement<'conn> { | ||||
|     /// | ||||
|     /// Will return `Err` if binding parameters fails. | ||||
|     pub fn query<'a>(&'a mut self, params: &[&ToSql]) -> Result<Rows<'a>> { | ||||
|         unsafe { | ||||
|             try!(self.bind_parameters(params)); | ||||
|         } | ||||
|  | ||||
|         try!(self.bind_parameters(params)); | ||||
|         Ok(Rows::new(self)) | ||||
|     } | ||||
|  | ||||
| @@ -903,32 +868,39 @@ impl<'conn> Statement<'conn> { | ||||
|         self.finalize_() | ||||
|     } | ||||
|  | ||||
|     unsafe fn bind_parameters(&mut self, params: &[&ToSql]) -> Result<()> { | ||||
|         assert!(params.len() as c_int == ffi::sqlite3_bind_parameter_count(self.stmt), | ||||
|     fn bind_parameters(&mut self, params: &[&ToSql]) -> Result<()> { | ||||
|         assert!(params.len() as c_int == self.stmt.bind_parameter_count(), | ||||
|                 "incorrect number of parameters to query(): expected {}, got {}", | ||||
|                 ffi::sqlite3_bind_parameter_count(self.stmt), | ||||
|                 self.stmt.bind_parameter_count(), | ||||
|                 params.len()); | ||||
|  | ||||
|         for (i, p) in params.iter().enumerate() { | ||||
|             try!(self.conn.decode_result(p.bind_parameter(self.stmt, (i + 1) as c_int))); | ||||
|             try!(unsafe { | ||||
|                 self.conn.decode_result(p.bind_parameter(self.stmt.ptr(), (i + 1) as c_int)) | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn finalize_(&mut self) -> Result<()> { | ||||
|         let r = unsafe { ffi::sqlite3_finalize(self.stmt) }; | ||||
|         self.stmt = ptr::null_mut(); | ||||
|         self.conn.decode_result(r) | ||||
|         let mut stmt = RawStatement::new(ptr::null_mut()); | ||||
|         mem::swap(&mut stmt, &mut self.stmt); | ||||
|         self.conn.decode_result(stmt.finalize()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'conn> Into<RawStatement> for Statement<'conn> { | ||||
|     fn into(mut self) -> RawStatement { | ||||
|         let mut stmt = RawStatement::new(ptr::null_mut()); | ||||
|         mem::swap(&mut stmt, &mut self.stmt); | ||||
|         stmt | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'conn> fmt::Debug for Statement<'conn> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         let sql = unsafe { | ||||
|             let c_slice = CStr::from_ptr(ffi::sqlite3_sql(self.stmt)).to_bytes(); | ||||
|             str::from_utf8(c_slice) | ||||
|         }; | ||||
|         let sql = str::from_utf8(self.stmt.sql().to_bytes()); | ||||
|         f.debug_struct("Statement") | ||||
|             .field("conn", self.conn) | ||||
|             .field("stmt", &self.stmt) | ||||
| @@ -1007,9 +979,7 @@ impl<'stmt> Rows<'stmt> { | ||||
|  | ||||
|     fn reset(&mut self) { | ||||
|         if let Some(stmt) = self.stmt.take() { | ||||
|             unsafe { | ||||
|                 ffi::sqlite3_reset(stmt.stmt); | ||||
|             } | ||||
|             stmt.stmt.reset(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -1025,7 +995,7 @@ impl<'stmt> Rows<'stmt> { | ||||
|     /// or `query_and_then` instead, which return types that implement `Iterator`. | ||||
|     pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> { | ||||
|         self.stmt.and_then(|stmt| { | ||||
|             match unsafe { ffi::sqlite3_step(stmt.stmt) } { | ||||
|             match stmt.stmt.step() { | ||||
|                 ffi::SQLITE_ROW => { | ||||
|                     Some(Ok(Row { | ||||
|                         stmt: stmt, | ||||
| @@ -1088,8 +1058,8 @@ impl<'a, 'stmt> Row<'a, 'stmt> { | ||||
|         unsafe { | ||||
|             let idx = try!(idx.idx(self.stmt)); | ||||
|  | ||||
|             if T::column_has_valid_sqlite_type(self.stmt.stmt, idx) { | ||||
|                 FromSql::column_result(self.stmt.stmt, idx) | ||||
|             if T::column_has_valid_sqlite_type(self.stmt.stmt.ptr(), idx) { | ||||
|                 FromSql::column_result(self.stmt.stmt.ptr(), idx) | ||||
|             } else { | ||||
|                 Err(Error::InvalidColumnType) | ||||
|             } | ||||
| @@ -1112,7 +1082,7 @@ pub trait RowIndex { | ||||
| impl RowIndex for i32 { | ||||
|     #[inline] | ||||
|     fn idx(&self, stmt: &Statement) -> Result<i32> { | ||||
|         if *self < 0 || *self >= stmt.column_count { | ||||
|         if *self < 0 || *self >= stmt.column_count() { | ||||
|             Err(Error::InvalidColumnIndex(*self)) | ||||
|         } else { | ||||
|             Ok(*self) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user