mirror of
				https://github.com/isar/rusqlite.git
				synced 2025-11-04 08:08:55 +08:00 
			
		
		
		
	Merge branch 'master' into gwenn-functions
Conflicts: Changelog.md
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
				
			|||||||
# Version UPCOMING (TBD)
 | 
					# Version UPCOMING (TBD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Adds a variety of `..._named` methods for executing queries using named placeholder parameters.
 | 
				
			||||||
* Adds `backup` feature that exposes SQLite's online backup API.
 | 
					* Adds `backup` feature that exposes SQLite's online backup API.
 | 
				
			||||||
* Adds `functions` feature that allows user-defined scalar functions to be added to
 | 
					* Adds `functions` feature that allows user-defined scalar functions to be added to
 | 
				
			||||||
  open `SqliteConnection`s.
 | 
					  open `SqliteConnection`s.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										88
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								src/lib.rs
									
									
									
									
									
								
							@@ -82,6 +82,7 @@ pub use load_extension_guard::SqliteLoadExtensionGuard;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub mod types;
 | 
					pub mod types;
 | 
				
			||||||
mod transaction;
 | 
					mod transaction;
 | 
				
			||||||
 | 
					mod named_params;
 | 
				
			||||||
#[cfg(feature = "load_extension")]mod load_extension_guard;
 | 
					#[cfg(feature = "load_extension")]mod load_extension_guard;
 | 
				
			||||||
#[cfg(feature = "trace")]pub mod trace;
 | 
					#[cfg(feature = "trace")]pub mod trace;
 | 
				
			||||||
#[cfg(feature = "backup")]pub mod backup;
 | 
					#[cfg(feature = "backup")]pub mod backup;
 | 
				
			||||||
@@ -369,20 +370,12 @@ impl SqliteConnection {
 | 
				
			|||||||
    /// underlying SQLite call fails.
 | 
					    /// underlying SQLite call fails.
 | 
				
			||||||
    pub fn query_row<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> SqliteResult<T>
 | 
					    pub fn query_row<T, F>(&self, sql: &str, params: &[&ToSql], f: F) -> SqliteResult<T>
 | 
				
			||||||
        where F: FnOnce(SqliteRow) -> T
 | 
					        where F: FnOnce(SqliteRow) -> T
 | 
				
			||||||
        {
 | 
					    {
 | 
				
			||||||
            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));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            match rows.next() {
 | 
					        rows.get_expected_row().map(f)
 | 
				
			||||||
                Some(row) => row.map(f),
 | 
					    }
 | 
				
			||||||
                None => {
 | 
					 | 
				
			||||||
                    Err(SqliteError {
 | 
					 | 
				
			||||||
                        code: ffi::SQLITE_NOTICE,
 | 
					 | 
				
			||||||
                        message: "Query did not return a row".to_string(),
 | 
					 | 
				
			||||||
                    })
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// 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,
 | 
				
			||||||
    /// and execute a mapping via `f` on that returned row with the possibility of failure.
 | 
					    /// and execute a mapping via `f` on that returned row with the possibility of failure.
 | 
				
			||||||
@@ -408,20 +401,12 @@ impl SqliteConnection {
 | 
				
			|||||||
    pub fn query_row_and_then<T, E, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T, E>
 | 
					    pub fn query_row_and_then<T, E, F>(&self, sql: &str, params: &[&ToSql], f: F) -> Result<T, E>
 | 
				
			||||||
        where F: FnOnce(SqliteRow) -> Result<T, E>,
 | 
					        where F: FnOnce(SqliteRow) -> Result<T, E>,
 | 
				
			||||||
              E: convert::From<SqliteError>
 | 
					              E: convert::From<SqliteError>
 | 
				
			||||||
              {
 | 
					    {
 | 
				
			||||||
                  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));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                  match rows.next() {
 | 
					        rows.get_expected_row().map_err(E::from).and_then(f)
 | 
				
			||||||
                      Some(row) => row.map_err(E::from).and_then(f),
 | 
					    }
 | 
				
			||||||
                      None => {
 | 
					 | 
				
			||||||
                          Err(E::from(SqliteError {
 | 
					 | 
				
			||||||
                              code: ffi::SQLITE_NOTICE,
 | 
					 | 
				
			||||||
                              message: "Query did not return a row".to_string(),
 | 
					 | 
				
			||||||
                          }))
 | 
					 | 
				
			||||||
                      }
 | 
					 | 
				
			||||||
                  }
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// 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.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
@@ -791,29 +776,32 @@ impl<'conn> SqliteStatement<'conn> {
 | 
				
			|||||||
    pub fn execute(&mut self, params: &[&ToSql]) -> SqliteResult<c_int> {
 | 
					    pub fn execute(&mut self, params: &[&ToSql]) -> SqliteResult<c_int> {
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            try!(self.bind_parameters(params));
 | 
					            try!(self.bind_parameters(params));
 | 
				
			||||||
 | 
					            self.execute_()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let r = ffi::sqlite3_step(self.stmt);
 | 
					    unsafe fn execute_(&mut self) -> SqliteResult<c_int> {
 | 
				
			||||||
            ffi::sqlite3_reset(self.stmt);
 | 
					        let r = ffi::sqlite3_step(self.stmt);
 | 
				
			||||||
            match r {
 | 
					        ffi::sqlite3_reset(self.stmt);
 | 
				
			||||||
                ffi::SQLITE_DONE => {
 | 
					        match r {
 | 
				
			||||||
                    if self.column_count != 0 {
 | 
					            ffi::SQLITE_DONE => {
 | 
				
			||||||
                        Err(SqliteError {
 | 
					                if self.column_count != 0 {
 | 
				
			||||||
                            code: ffi::SQLITE_MISUSE,
 | 
					 | 
				
			||||||
                            message: "Unexpected column count - did you mean to call query?"
 | 
					 | 
				
			||||||
                            .to_string(),
 | 
					 | 
				
			||||||
                        })
 | 
					 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        Ok(self.conn.changes())
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                ffi::SQLITE_ROW => {
 | 
					 | 
				
			||||||
                    Err(SqliteError {
 | 
					                    Err(SqliteError {
 | 
				
			||||||
                        code: r,
 | 
					                        code: ffi::SQLITE_MISUSE,
 | 
				
			||||||
                        message: "Unexpected row result - did you mean to call query?".to_string(),
 | 
					                        message: "Unexpected column count - did you mean to call query?"
 | 
				
			||||||
 | 
					                        .to_string(),
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    Ok(self.conn.changes())
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                _ => Err(self.conn.decode_result(r).unwrap_err()),
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            ffi::SQLITE_ROW => {
 | 
				
			||||||
 | 
					                Err(SqliteError {
 | 
				
			||||||
 | 
					                    code: r,
 | 
				
			||||||
 | 
					                    message: "Unexpected row result - did you mean to call query?".to_string(),
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ => Err(self.conn.decode_result(r).unwrap_err()),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1046,6 +1034,18 @@ impl<'stmt> SqliteRows<'stmt> {
 | 
				
			|||||||
            failed: false,
 | 
					            failed: false,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn get_expected_row(&mut self) -> SqliteResult<SqliteRow<'stmt>> {
 | 
				
			||||||
 | 
					        match self.next() {
 | 
				
			||||||
 | 
					            Some(row) => row,
 | 
				
			||||||
 | 
					            None => {
 | 
				
			||||||
 | 
					                Err(SqliteError {
 | 
				
			||||||
 | 
					                    code: ffi::SQLITE_NOTICE,
 | 
				
			||||||
 | 
					                    message: "Query did not return a row".to_string(),
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'stmt> Iterator for SqliteRows<'stmt> {
 | 
					impl<'stmt> Iterator for SqliteRows<'stmt> {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										224
									
								
								src/named_params.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								src/named_params.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,224 @@
 | 
				
			|||||||
 | 
					use libc::c_int;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::ffi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use {SqliteResult, SqliteError, SqliteConnection, SqliteStatement, SqliteRows, SqliteRow,
 | 
				
			||||||
 | 
					     str_to_cstring};
 | 
				
			||||||
 | 
					use types::ToSql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl SqliteConnection {
 | 
				
			||||||
 | 
					    /// Convenience method to prepare and execute a single SQL statement with named parameter(s).
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// 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 insert(conn: &SqliteConnection) -> SqliteResult<i32> {
 | 
				
			||||||
 | 
					    ///     conn.execute_named("INSERT INTO test (name) VALUES (:name)", &[(":name", &"one")])
 | 
				
			||||||
 | 
					    /// }
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Failure
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
 | 
				
			||||||
 | 
					    /// underlying SQLite call fails.
 | 
				
			||||||
 | 
					    pub fn execute_named(&self, sql: &str, params: &[(&str, &ToSql)]) -> SqliteResult<c_int> {
 | 
				
			||||||
 | 
					        self.prepare(sql).and_then(|mut stmt| stmt.execute_named(params))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Convenience method to execute a query with named parameter(s) 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 `sql` cannot be converted to a C-compatible string or if the
 | 
				
			||||||
 | 
					    /// underlying SQLite call fails.
 | 
				
			||||||
 | 
					    pub fn query_row_named<T, F>(&self,
 | 
				
			||||||
 | 
					                                 sql: &str,
 | 
				
			||||||
 | 
					                                 params: &[(&str, &ToSql)],
 | 
				
			||||||
 | 
					                                 f: F)
 | 
				
			||||||
 | 
					                                 -> SqliteResult<T>
 | 
				
			||||||
 | 
					        where F: FnOnce(SqliteRow) -> T
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let mut stmt = try!(self.prepare(sql));
 | 
				
			||||||
 | 
					        let mut rows = try!(stmt.query_named(params));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows.get_expected_row().map(f)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'conn> SqliteStatement<'conn> {
 | 
				
			||||||
 | 
					    /// Return the index of an SQL parameter given its name.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Failure
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Will return Err if `name` is invalid. Will return Ok(None) if the name
 | 
				
			||||||
 | 
					    /// is valid but not a bound parameter of this statement.
 | 
				
			||||||
 | 
					    pub fn parameter_index(&self, name: &str) -> SqliteResult<Option<i32>> {
 | 
				
			||||||
 | 
					        let c_name = try!(str_to_cstring(name));
 | 
				
			||||||
 | 
					        let c_index = unsafe { ffi::sqlite3_bind_parameter_index(self.stmt, c_name.as_ptr()) };
 | 
				
			||||||
 | 
					        Ok(match c_index {
 | 
				
			||||||
 | 
					            0 => None, // A zero is returned if no matching parameter is found.
 | 
				
			||||||
 | 
					            n => Some(n),
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Execute the prepared statement with named parameter(s). If any parameters
 | 
				
			||||||
 | 
					    /// that were in the prepared statement are not included in `params`, they
 | 
				
			||||||
 | 
					    /// will continue to use the most-recently bound value from a previous call
 | 
				
			||||||
 | 
					    /// to `execute_named`, or `NULL` if they have never been bound.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// 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 insert(conn: &SqliteConnection) -> SqliteResult<i32> {
 | 
				
			||||||
 | 
					    ///     let mut stmt = try!(conn.prepare("INSERT INTO test (name) VALUES (:name)"));
 | 
				
			||||||
 | 
					    ///     stmt.execute_named(&[(":name", &"one")])
 | 
				
			||||||
 | 
					    /// }
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Failure
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// 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_named(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<c_int> {
 | 
				
			||||||
 | 
					        try!(self.bind_parameters_named(params));
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            self.execute_()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Execute the prepared statement with named parameter(s), returning an iterator over the
 | 
				
			||||||
 | 
					    /// resulting rows. If any parameters that were in the prepared statement are not included in
 | 
				
			||||||
 | 
					    /// `params`, they will continue to use the most-recently bound value from a previous call to
 | 
				
			||||||
 | 
					    /// `query_named`, or `NULL` if they have never been bound.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// ## Example
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// ```rust,no_run
 | 
				
			||||||
 | 
					    /// # use rusqlite::{SqliteConnection, SqliteResult, SqliteRows};
 | 
				
			||||||
 | 
					    /// fn query(conn: &SqliteConnection) -> SqliteResult<()> {
 | 
				
			||||||
 | 
					    ///     let mut stmt = try!(conn.prepare("SELECT * FROM test where name = :name"));
 | 
				
			||||||
 | 
					    ///     let mut rows = try!(stmt.query_named(&[(":name", &"one")]));
 | 
				
			||||||
 | 
					    ///     for row in rows {
 | 
				
			||||||
 | 
					    ///         // ...
 | 
				
			||||||
 | 
					    ///     }
 | 
				
			||||||
 | 
					    ///     Ok(())
 | 
				
			||||||
 | 
					    /// }
 | 
				
			||||||
 | 
					    /// ```
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Failure
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Will return `Err` if binding parameters fails.
 | 
				
			||||||
 | 
					    pub fn query_named<'a>(&'a mut self,
 | 
				
			||||||
 | 
					                           params: &[(&str, &ToSql)])
 | 
				
			||||||
 | 
					                           -> SqliteResult<SqliteRows<'a>> {
 | 
				
			||||||
 | 
					        self.reset_if_needed();
 | 
				
			||||||
 | 
					        try!(self.bind_parameters_named(params));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.needs_reset = true;
 | 
				
			||||||
 | 
					        Ok(SqliteRows::new(self))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn bind_parameters_named(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<()> {
 | 
				
			||||||
 | 
					        for &(name, value) in params {
 | 
				
			||||||
 | 
					            if let Some(i) = try!(self.parameter_index(name)) {
 | 
				
			||||||
 | 
					                try!(self.conn.decode_result(unsafe { value.bind_parameter(self.stmt, i) }));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return Err(SqliteError {
 | 
				
			||||||
 | 
					                    code: ffi::SQLITE_MISUSE,
 | 
				
			||||||
 | 
					                    message: format!("Invalid parameter name: {}", name),
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod test {
 | 
				
			||||||
 | 
					    use SqliteConnection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_execute_named() {
 | 
				
			||||||
 | 
					        let db = SqliteConnection::open_in_memory().unwrap();
 | 
				
			||||||
 | 
					        db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)]).unwrap(),
 | 
				
			||||||
 | 
					                   1);
 | 
				
			||||||
 | 
					        assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &2i32)]).unwrap(),
 | 
				
			||||||
 | 
					                   1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_eq!(3i32,
 | 
				
			||||||
 | 
					                   db.query_row_named("SELECT SUM(x) FROM foo WHERE x > :x",
 | 
				
			||||||
 | 
					                                      &[(":x", &0i32)],
 | 
				
			||||||
 | 
					                                      |r| r.get(0))
 | 
				
			||||||
 | 
					                     .unwrap());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_stmt_execute_named() {
 | 
				
			||||||
 | 
					        let db = SqliteConnection::open_in_memory().unwrap();
 | 
				
			||||||
 | 
					        let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
 | 
				
			||||||
 | 
					                   INTEGER)";
 | 
				
			||||||
 | 
					        db.execute_batch(sql).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut stmt = db.prepare("INSERT INTO test (name) VALUES (:name)").unwrap();
 | 
				
			||||||
 | 
					        stmt.execute_named(&[(":name", &"one")]).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert_eq!(1i32,
 | 
				
			||||||
 | 
					                   db.query_row_named("SELECT COUNT(*) FROM test WHERE name = :name",
 | 
				
			||||||
 | 
					                                      &[(":name", &"one")],
 | 
				
			||||||
 | 
					                                      |r| r.get(0))
 | 
				
			||||||
 | 
					                     .unwrap());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_query_named() {
 | 
				
			||||||
 | 
					        let db = SqliteConnection::open_in_memory().unwrap();
 | 
				
			||||||
 | 
					        let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
 | 
				
			||||||
 | 
					                   INTEGER)";
 | 
				
			||||||
 | 
					        db.execute_batch(sql).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut stmt = db.prepare("SELECT * FROM test where name = :name").unwrap();
 | 
				
			||||||
 | 
					        stmt.query_named(&[(":name", &"one")]).unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_unbound_parameters_are_null() {
 | 
				
			||||||
 | 
					        let db = SqliteConnection::open_in_memory().unwrap();
 | 
				
			||||||
 | 
					        let sql = "CREATE TABLE test (x TEXT, y TEXT)";
 | 
				
			||||||
 | 
					        db.execute_batch(sql).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)").unwrap();
 | 
				
			||||||
 | 
					        stmt.execute_named(&[(":x", &"one")]).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let result = db.query_row("SELECT y FROM test WHERE x = 'one'", &[],
 | 
				
			||||||
 | 
					                                  |row| row.get::<Option<String>>(0)).unwrap();
 | 
				
			||||||
 | 
					        assert!(result.is_none());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_unbound_parameters_are_reused() {
 | 
				
			||||||
 | 
					        let db = SqliteConnection::open_in_memory().unwrap();
 | 
				
			||||||
 | 
					        let sql = "CREATE TABLE test (x TEXT, y TEXT)";
 | 
				
			||||||
 | 
					        db.execute_batch(sql).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)").unwrap();
 | 
				
			||||||
 | 
					        stmt.execute_named(&[(":x", &"one")]).unwrap();
 | 
				
			||||||
 | 
					        stmt.execute_named(&[(":y", &"two")]).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let result = db.query_row("SELECT x FROM test WHERE y = 'two'", &[],
 | 
				
			||||||
 | 
					                                  |row| row.get::<String>(0)).unwrap();
 | 
				
			||||||
 | 
					        assert_eq!(result, "one");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user