mirror of
				https://github.com/isar/rusqlite.git
				synced 2025-10-31 22:08:55 +08:00 
			
		
		
		
	Merge remote-tracking branch 'jgallagher/master' into vtab
This commit is contained in:
		| @@ -7,6 +7,7 @@ | ||||
| * Introduces `ZeroBlob` type under the `blob` module/feature exposing SQLite's zeroblob API. | ||||
| * Adds CI testing for Windows via AppVeyor. | ||||
| * Fixes a warning building libsqlite3-sys under Rust 1.6. | ||||
| * Adds an unsafe `handle()` method to `Connection`. Please file an issue if you actually use it. | ||||
|  | ||||
| # Version 0.6.0 (2015-12-17) | ||||
|  | ||||
|   | ||||
							
								
								
									
										39
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								README.md
									
									
									
									
									
								
							| @@ -73,45 +73,6 @@ features](http://doc.crates.io/manifest.html#the-features-section). They are: | ||||
| * [`blob`](http://jgallagher.github.io/rusqlite/rusqlite/blob/index.html) | ||||
|   gives `std::io::{Read, Write, Seek}` access to SQL BLOBs. | ||||
|  | ||||
| ### Design of Rows and Row | ||||
|  | ||||
| To retrieve the result rows from a query, SQLite requires you to call | ||||
| [sqlite3_step()](https://www.sqlite.org/c3ref/step.html) on a prepared statement. You can only | ||||
| retrieve the values of the "current" row. From the Rust point of view, this means that each row | ||||
| is only valid until the next row is fetched.  [rust-sqlite3](https://github.com/dckc/rust-sqlite3) | ||||
| solves this the correct way with lifetimes.  However, this means that the result rows do not | ||||
| satisfy the [Iterator](http://doc.rust-lang.org/std/iter/trait.Iterator.html) trait, which means | ||||
| you cannot (as easily) loop over the rows, or use many of the helpful Iterator methods like `map` | ||||
| and `filter`. | ||||
|  | ||||
| Instead, Rusqlite's `Rows` handle does conform to `Iterator`. It ensures safety by | ||||
| performing checks at runtime to ensure you do not try to retrieve the values of a "stale" row, and | ||||
| will panic if you do so. A specific example that will panic: | ||||
|  | ||||
| ```rust | ||||
| fn bad_function_will_panic(conn: &Connection) -> Result<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 valid 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) | ||||
| } | ||||
| ``` | ||||
|  | ||||
| There are other, less obvious things that may result in a panic as well, such as calling | ||||
| `collect()` on a `Rows` and then trying to use the collected rows. | ||||
|  | ||||
| Strongly consider using the method `query_map()` instead, if you can. | ||||
| `query_map()` returns an iterator over rows-mapped-to-some-type. This | ||||
| iterator does not have any of the above issues with panics due to attempting to | ||||
| access stale rows. | ||||
|  | ||||
| ## Author | ||||
|  | ||||
| John Gallagher, johnkgallagher@gmail.com | ||||
|   | ||||
							
								
								
									
										23
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -495,6 +495,18 @@ impl Connection { | ||||
|             self.db.borrow_mut().load_extension(dylib_path.as_ref(), entry_point) | ||||
|         } | ||||
|  | ||||
|     /// Get access to the underlying SQLite database connection handle. | ||||
|     /// | ||||
|     /// # Warning | ||||
|     /// | ||||
|     /// You should not need to use this function. If you do need to, please [open an issue | ||||
|     /// on the rusqlite repository](https://github.com/jgallagher/rusqlite/issues) and describe | ||||
|     /// your use case. This function is unsafe because it gives you raw access to the SQLite | ||||
|     /// connection, and what you do with it could impact the safety of this `Connection`. | ||||
|     pub unsafe fn handle(&self) -> *mut ffi::Struct_sqlite3 { | ||||
|         self.db.borrow().db() | ||||
|     } | ||||
|  | ||||
|     fn decode_result(&self, code: c_int) -> Result<()> { | ||||
|         self.db.borrow_mut().decode_result(code) | ||||
|     } | ||||
| @@ -984,6 +996,9 @@ pub type SqliteRows<'stmt> = Rows<'stmt>; | ||||
| /// | ||||
| /// ## Warning | ||||
| /// | ||||
| /// Strongly consider using `query_map` or `query_and_then` instead of `query`; the former do not | ||||
| /// suffer from the following problem. | ||||
| /// | ||||
| /// Due to the way SQLite returns result rows of a query, it is not safe to attempt to get values | ||||
| /// from a row after it has become stale (i.e., `next()` has been called again on the `Rows` | ||||
| /// iterator). For example: | ||||
| @@ -995,7 +1010,7 @@ pub type SqliteRows<'stmt> = Rows<'stmt>; | ||||
| ///     let mut rows = try!(stmt.query(&[])); | ||||
| /// | ||||
| ///     let row0 = try!(rows.next().unwrap()); | ||||
| ///     // row 0 is value now... | ||||
| ///     // row 0 is valid for now... | ||||
| /// | ||||
| ///     let row1 = try!(rows.next().unwrap()); | ||||
| ///     // row 0 is now STALE, and row 1 is valid | ||||
| @@ -1009,12 +1024,6 @@ pub type SqliteRows<'stmt> = Rows<'stmt>; | ||||
| /// (which would result in a collection of rows, only the last of which can safely be used) and | ||||
| /// `min`/`max` (which could return a stale row unless the last row happened to be the min or max, | ||||
| /// respectively). | ||||
| /// | ||||
| /// This problem could be solved by changing the signature of `next` to tie the lifetime of the | ||||
| /// returned row to the lifetime of (a mutable reference to) the result rows handle, but this would | ||||
| /// no longer implement `Iterator`, and therefore you would lose access to the majority of | ||||
| /// functions which are useful (such as support for `for ... in ...` looping, `map`, `filter`, | ||||
| /// etc.). | ||||
| pub struct Rows<'stmt> { | ||||
|     stmt: &'stmt Statement<'stmt>, | ||||
|     current_row: Rc<Cell<c_int>>, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user