2015-08-08 22:33:08 +08:00
|
|
|
//! Prepared statements cache for faster execution.
|
2015-08-02 18:07:49 +08:00
|
|
|
|
2018-10-31 03:11:35 +08:00
|
|
|
use crate::raw_statement::RawStatement;
|
2023-06-03 17:17:19 +08:00
|
|
|
use crate::{Connection, PrepFlags, Result, Statement};
|
2020-10-06 03:38:40 +08:00
|
|
|
use hashlink::LruCache;
|
2018-08-11 18:48:21 +08:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::ops::{Deref, DerefMut};
|
2020-04-16 23:22:47 +08:00
|
|
|
use std::sync::Arc;
|
2015-08-02 18:07:49 +08:00
|
|
|
|
2016-05-18 01:11:25 +08:00
|
|
|
impl Connection {
|
2018-08-17 00:29:46 +08:00
|
|
|
/// Prepare a SQL statement for execution, returning a previously prepared
|
|
|
|
/// (but not currently in-use) statement if one is available. The
|
|
|
|
/// returned statement will be cached for reuse by future calls to
|
2020-11-22 16:34:03 +08:00
|
|
|
/// [`prepare_cached`](Connection::prepare_cached) once it is dropped.
|
2016-05-18 01:11:25 +08:00
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// # use rusqlite::{Connection, Result};
|
|
|
|
/// fn insert_new_people(conn: &Connection) -> Result<()> {
|
|
|
|
/// {
|
2022-11-27 16:38:06 +08:00
|
|
|
/// let mut stmt = conn.prepare_cached("INSERT INTO People (name) VALUES (?1)")?;
|
2021-01-20 04:16:08 +08:00
|
|
|
/// stmt.execute(["Joe Smith"])?;
|
2016-05-18 01:11:25 +08:00
|
|
|
/// }
|
|
|
|
/// {
|
|
|
|
/// // This will return the same underlying SQLite statement handle without
|
|
|
|
/// // having to prepare it again.
|
2022-11-27 16:38:06 +08:00
|
|
|
/// let mut stmt = conn.prepare_cached("INSERT INTO People (name) VALUES (?1)")?;
|
2021-01-20 04:16:08 +08:00
|
|
|
/// stmt.execute(["Bob Jones"])?;
|
2016-05-18 01:11:25 +08:00
|
|
|
/// }
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// # Failure
|
|
|
|
///
|
2018-08-17 00:29:46 +08:00
|
|
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
|
|
|
/// or if the underlying SQLite call fails.
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2019-02-02 18:08:04 +08:00
|
|
|
pub fn prepare_cached(&self, sql: &str) -> Result<CachedStatement<'_>> {
|
2016-05-20 04:03:01 +08:00
|
|
|
self.cache.get(self, sql)
|
2016-05-18 01:11:25 +08:00
|
|
|
}
|
2016-05-18 03:20:56 +08:00
|
|
|
|
2018-08-17 00:29:46 +08:00
|
|
|
/// Set the maximum number of cached prepared statements this connection
|
|
|
|
/// will hold. By default, a connection will hold a relatively small
|
|
|
|
/// number of cached statements. If you need more, or know that you
|
|
|
|
/// will not use cached statements, you
|
|
|
|
/// can set the capacity manually using this method.
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2016-05-18 03:20:56 +08:00
|
|
|
pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) {
|
2022-01-06 02:53:49 +08:00
|
|
|
self.cache.set_capacity(capacity);
|
2016-05-18 03:20:56 +08:00
|
|
|
}
|
2016-11-05 03:47:28 +08:00
|
|
|
|
2018-02-17 17:11:39 +08:00
|
|
|
/// Remove/finalize all prepared statements currently in the cache.
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2016-11-05 03:47:28 +08:00
|
|
|
pub fn flush_prepared_statement_cache(&self) {
|
2022-01-06 02:53:49 +08:00
|
|
|
self.cache.flush();
|
2016-11-05 03:47:28 +08:00
|
|
|
}
|
2016-05-18 01:11:25 +08:00
|
|
|
}
|
|
|
|
|
2015-12-20 00:14:06 +08:00
|
|
|
/// Prepared statements LRU cache.
|
2020-10-06 03:38:40 +08:00
|
|
|
// #[derive(Debug)] // FIXME: https://github.com/kyren/hashlink/pull/4
|
2020-04-16 23:22:47 +08:00
|
|
|
pub struct StatementCache(RefCell<LruCache<Arc<str>, RawStatement>>);
|
2015-08-02 18:07:49 +08:00
|
|
|
|
2021-12-04 17:07:56 +08:00
|
|
|
#[allow(clippy::non_send_fields_in_send_ty)]
|
|
|
|
unsafe impl Send for StatementCache {}
|
|
|
|
|
2015-12-20 00:14:06 +08:00
|
|
|
/// Cacheable statement.
|
|
|
|
///
|
|
|
|
/// Statement will return automatically to the cache by default.
|
2021-04-03 17:03:50 +08:00
|
|
|
/// If you want the statement to be discarded, call
|
|
|
|
/// [`discard()`](CachedStatement::discard) on it.
|
2016-05-18 01:13:51 +08:00
|
|
|
pub struct CachedStatement<'conn> {
|
|
|
|
stmt: Option<Statement<'conn>>,
|
|
|
|
cache: &'conn StatementCache,
|
2015-12-17 02:42:03 +08:00
|
|
|
}
|
|
|
|
|
2016-05-18 01:13:51 +08:00
|
|
|
impl<'conn> Deref for CachedStatement<'conn> {
|
|
|
|
type Target = Statement<'conn>;
|
2015-12-18 03:33:34 +08:00
|
|
|
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2016-05-18 01:13:51 +08:00
|
|
|
fn deref(&self) -> &Statement<'conn> {
|
2015-12-18 03:33:34 +08:00
|
|
|
self.stmt.as_ref().unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-18 01:13:51 +08:00
|
|
|
impl<'conn> DerefMut for CachedStatement<'conn> {
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2016-05-18 01:13:51 +08:00
|
|
|
fn deref_mut(&mut self) -> &mut Statement<'conn> {
|
2015-12-18 03:33:34 +08:00
|
|
|
self.stmt.as_mut().unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-03 18:02:38 +08:00
|
|
|
impl Drop for CachedStatement<'_> {
|
2015-12-17 02:42:03 +08:00
|
|
|
#[allow(unused_must_use)]
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2015-12-17 02:42:03 +08:00
|
|
|
fn drop(&mut self) {
|
2016-01-08 00:24:20 +08:00
|
|
|
if let Some(stmt) = self.stmt.take() {
|
2020-06-07 08:27:14 +08:00
|
|
|
self.cache.cache_stmt(unsafe { stmt.into_raw() });
|
2015-12-17 02:42:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-03 18:02:38 +08:00
|
|
|
impl CachedStatement<'_> {
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2019-02-03 18:02:38 +08:00
|
|
|
fn new<'conn>(stmt: Statement<'conn>, cache: &'conn StatementCache) -> CachedStatement<'conn> {
|
2015-12-18 03:33:34 +08:00
|
|
|
CachedStatement {
|
|
|
|
stmt: Some(stmt),
|
2018-05-05 01:55:55 +08:00
|
|
|
cache,
|
2015-12-18 03:33:34 +08:00
|
|
|
}
|
|
|
|
}
|
2016-01-08 00:24:20 +08:00
|
|
|
|
2018-08-17 00:29:46 +08:00
|
|
|
/// Discard the statement, preventing it from being returned to its
|
2020-11-22 16:34:03 +08:00
|
|
|
/// [`Connection`]'s collection of cached statements.
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2016-01-08 00:24:20 +08:00
|
|
|
pub fn discard(mut self) {
|
|
|
|
self.stmt = None;
|
|
|
|
}
|
2015-12-18 03:33:34 +08:00
|
|
|
}
|
|
|
|
|
2016-05-18 00:59:54 +08:00
|
|
|
impl StatementCache {
|
2015-08-08 22:33:08 +08:00
|
|
|
/// Create a statement cache.
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2016-05-18 00:59:54 +08:00
|
|
|
pub fn with_capacity(capacity: usize) -> StatementCache {
|
2016-05-18 01:26:17 +08:00
|
|
|
StatementCache(RefCell::new(LruCache::new(capacity)))
|
2015-08-02 18:07:49 +08:00
|
|
|
}
|
|
|
|
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2016-05-18 03:20:56 +08:00
|
|
|
fn set_capacity(&self, capacity: usize) {
|
2022-01-06 02:53:49 +08:00
|
|
|
self.0.borrow_mut().set_capacity(capacity);
|
2016-05-18 03:20:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Search the cache for a prepared-statement object that implements `sql`.
|
|
|
|
// If no such prepared-statement can be found, allocate and prepare a new one.
|
|
|
|
//
|
|
|
|
// # Failure
|
|
|
|
//
|
2018-08-17 00:29:46 +08:00
|
|
|
// Will return `Err` if no cached statement can be found and the underlying
|
|
|
|
// SQLite prepare call fails.
|
2018-08-11 18:48:21 +08:00
|
|
|
fn get<'conn>(
|
|
|
|
&'conn self,
|
|
|
|
conn: &'conn Connection,
|
|
|
|
sql: &str,
|
|
|
|
) -> Result<CachedStatement<'conn>> {
|
2020-04-16 23:22:47 +08:00
|
|
|
let trimmed = sql.trim();
|
2016-05-18 01:26:17 +08:00
|
|
|
let mut cache = self.0.borrow_mut();
|
2020-04-16 23:22:47 +08:00
|
|
|
let stmt = match cache.remove(trimmed) {
|
2016-05-18 01:26:17 +08:00
|
|
|
Some(raw_stmt) => Ok(Statement::new(conn, raw_stmt)),
|
2023-06-03 17:17:19 +08:00
|
|
|
None => conn.prepare_with_flags(trimmed, PrepFlags::SQLITE_PREPARE_PERSISTENT),
|
2015-12-18 03:33:34 +08:00
|
|
|
};
|
2020-04-16 23:22:47 +08:00
|
|
|
stmt.map(|mut stmt| {
|
|
|
|
stmt.stmt.set_statement_cache_key(trimmed);
|
|
|
|
CachedStatement::new(stmt, self)
|
|
|
|
})
|
2015-08-02 18:07:49 +08:00
|
|
|
}
|
|
|
|
|
2016-01-08 00:30:51 +08:00
|
|
|
// Return a statement to the cache.
|
2016-05-18 00:55:10 +08:00
|
|
|
fn cache_stmt(&self, stmt: RawStatement) {
|
2019-10-30 02:24:18 +08:00
|
|
|
if stmt.is_null() {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 01:26:17 +08:00
|
|
|
let mut cache = self.0.borrow_mut();
|
2015-12-16 04:49:59 +08:00
|
|
|
stmt.clear_bindings();
|
2020-04-16 23:22:47 +08:00
|
|
|
if let Some(sql) = stmt.statement_cache_key() {
|
|
|
|
cache.insert(sql, stmt);
|
|
|
|
} else {
|
|
|
|
debug_assert!(
|
|
|
|
false,
|
|
|
|
"bug in statement cache code, statement returned to cache that without key"
|
|
|
|
);
|
|
|
|
}
|
2015-08-02 18:07:49 +08:00
|
|
|
}
|
2016-11-05 03:47:28 +08:00
|
|
|
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2016-11-05 03:47:28 +08:00
|
|
|
fn flush(&self) {
|
|
|
|
let mut cache = self.0.borrow_mut();
|
2022-01-06 02:53:49 +08:00
|
|
|
cache.clear();
|
2016-11-05 03:47:28 +08:00
|
|
|
}
|
2015-08-02 18:07:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::StatementCache;
|
2020-11-06 05:14:00 +08:00
|
|
|
use crate::{Connection, Result};
|
2019-03-20 03:45:04 +08:00
|
|
|
use fallible_iterator::FallibleIterator;
|
2015-08-02 18:07:49 +08:00
|
|
|
|
2016-05-18 01:11:25 +08:00
|
|
|
impl StatementCache {
|
|
|
|
fn clear(&self) {
|
2016-05-18 01:26:17 +08:00
|
|
|
self.0.borrow_mut().clear();
|
2016-05-18 01:11:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn len(&self) -> usize {
|
2016-05-18 01:26:17 +08:00
|
|
|
self.0.borrow().len()
|
2016-05-18 01:11:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn capacity(&self) -> usize {
|
2016-05-18 01:26:17 +08:00
|
|
|
self.0.borrow().capacity()
|
2016-05-18 01:11:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 18:23:54 +08:00
|
|
|
#[test]
|
2020-11-06 05:14:00 +08:00
|
|
|
fn test_cache() -> Result<()> {
|
|
|
|
let db = Connection::open_in_memory()?;
|
2016-05-18 01:11:25 +08:00
|
|
|
let cache = &db.cache;
|
|
|
|
let initial_capacity = cache.capacity();
|
2015-12-16 04:49:59 +08:00
|
|
|
assert_eq!(0, cache.len());
|
2016-05-18 01:11:25 +08:00
|
|
|
assert!(initial_capacity > 0);
|
2015-12-16 04:49:59 +08:00
|
|
|
|
2015-08-02 18:07:49 +08:00
|
|
|
let sql = "PRAGMA schema_version";
|
2015-12-19 03:18:46 +08:00
|
|
|
{
|
2020-11-06 05:14:00 +08:00
|
|
|
let mut stmt = db.prepare_cached(sql)?;
|
2015-12-19 03:18:46 +08:00
|
|
|
assert_eq!(0, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
|
2015-12-19 03:18:46 +08:00
|
|
|
}
|
2015-12-16 04:49:59 +08:00
|
|
|
assert_eq!(1, cache.len());
|
|
|
|
|
2015-12-19 03:18:46 +08:00
|
|
|
{
|
2020-11-06 05:14:00 +08:00
|
|
|
let mut stmt = db.prepare_cached(sql)?;
|
2015-12-19 03:18:46 +08:00
|
|
|
assert_eq!(0, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
|
2015-12-19 03:18:46 +08:00
|
|
|
}
|
2015-12-18 03:02:49 +08:00
|
|
|
assert_eq!(1, cache.len());
|
2015-12-16 04:49:59 +08:00
|
|
|
|
|
|
|
cache.clear();
|
|
|
|
assert_eq!(0, cache.len());
|
2016-05-18 01:11:25 +08:00
|
|
|
assert_eq!(initial_capacity, cache.capacity());
|
2020-11-06 05:14:00 +08:00
|
|
|
Ok(())
|
2015-08-02 18:07:49 +08:00
|
|
|
}
|
2015-12-20 00:01:06 +08:00
|
|
|
|
2016-05-18 03:20:56 +08:00
|
|
|
#[test]
|
2020-11-06 05:14:00 +08:00
|
|
|
fn test_set_capacity() -> Result<()> {
|
|
|
|
let db = Connection::open_in_memory()?;
|
2016-05-18 03:20:56 +08:00
|
|
|
let cache = &db.cache;
|
|
|
|
|
|
|
|
let sql = "PRAGMA schema_version";
|
|
|
|
{
|
2020-11-06 05:14:00 +08:00
|
|
|
let mut stmt = db.prepare_cached(sql)?;
|
2016-05-18 03:20:56 +08:00
|
|
|
assert_eq!(0, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
|
2016-05-18 03:20:56 +08:00
|
|
|
}
|
|
|
|
assert_eq!(1, cache.len());
|
|
|
|
|
|
|
|
db.set_prepared_statement_cache_capacity(0);
|
|
|
|
assert_eq!(0, cache.len());
|
|
|
|
|
|
|
|
{
|
2020-11-06 05:14:00 +08:00
|
|
|
let mut stmt = db.prepare_cached(sql)?;
|
2016-05-18 03:20:56 +08:00
|
|
|
assert_eq!(0, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
|
2016-05-18 03:20:56 +08:00
|
|
|
}
|
|
|
|
assert_eq!(0, cache.len());
|
|
|
|
|
|
|
|
db.set_prepared_statement_cache_capacity(8);
|
|
|
|
{
|
2020-11-06 05:14:00 +08:00
|
|
|
let mut stmt = db.prepare_cached(sql)?;
|
2016-05-18 03:20:56 +08:00
|
|
|
assert_eq!(0, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
|
2016-05-18 03:20:56 +08:00
|
|
|
}
|
|
|
|
assert_eq!(1, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
Ok(())
|
2016-05-18 03:20:56 +08:00
|
|
|
}
|
|
|
|
|
2015-12-20 00:01:06 +08:00
|
|
|
#[test]
|
2020-11-06 05:14:00 +08:00
|
|
|
fn test_discard() -> Result<()> {
|
|
|
|
let db = Connection::open_in_memory()?;
|
2016-05-18 01:11:25 +08:00
|
|
|
let cache = &db.cache;
|
2015-12-20 00:01:06 +08:00
|
|
|
|
|
|
|
let sql = "PRAGMA schema_version";
|
|
|
|
{
|
2020-11-06 05:14:00 +08:00
|
|
|
let mut stmt = db.prepare_cached(sql)?;
|
2015-12-20 00:01:06 +08:00
|
|
|
assert_eq!(0, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
|
2016-01-08 00:24:20 +08:00
|
|
|
stmt.discard();
|
2015-12-20 00:01:06 +08:00
|
|
|
}
|
|
|
|
assert_eq!(0, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
Ok(())
|
2015-12-20 00:01:06 +08:00
|
|
|
}
|
2016-05-19 11:19:04 +08:00
|
|
|
|
|
|
|
#[test]
|
2020-11-06 05:14:00 +08:00
|
|
|
fn test_ddl() -> Result<()> {
|
|
|
|
let db = Connection::open_in_memory()?;
|
2018-08-11 18:48:21 +08:00
|
|
|
db.execute_batch(
|
|
|
|
r#"
|
2016-05-19 11:19:04 +08:00
|
|
|
CREATE TABLE foo (x INT);
|
|
|
|
INSERT INTO foo VALUES (1);
|
2018-08-11 18:48:21 +08:00
|
|
|
"#,
|
2020-11-06 05:14:00 +08:00
|
|
|
)?;
|
2016-05-19 11:19:04 +08:00
|
|
|
|
|
|
|
let sql = "SELECT * FROM foo";
|
|
|
|
|
|
|
|
{
|
2020-11-06 05:14:00 +08:00
|
|
|
let mut stmt = db.prepare_cached(sql)?;
|
|
|
|
assert_eq!(Ok(Some(1i32)), stmt.query([])?.map(|r| r.get(0)).next());
|
2016-05-19 11:19:04 +08:00
|
|
|
}
|
|
|
|
|
2018-08-11 18:48:21 +08:00
|
|
|
db.execute_batch(
|
|
|
|
r#"
|
2016-05-19 11:19:04 +08:00
|
|
|
ALTER TABLE foo ADD COLUMN y INT;
|
|
|
|
UPDATE foo SET y = 2;
|
2018-08-11 18:48:21 +08:00
|
|
|
"#,
|
2020-11-06 05:14:00 +08:00
|
|
|
)?;
|
2016-05-19 11:19:04 +08:00
|
|
|
|
|
|
|
{
|
2020-11-06 05:14:00 +08:00
|
|
|
let mut stmt = db.prepare_cached(sql)?;
|
2018-08-11 18:48:21 +08:00
|
|
|
assert_eq!(
|
2019-03-10 19:58:20 +08:00
|
|
|
Ok(Some((1i32, 2i32))),
|
2020-11-06 05:14:00 +08:00
|
|
|
stmt.query([])?.map(|r| Ok((r.get(0)?, r.get(1)?))).next()
|
2018-08-11 18:48:21 +08:00
|
|
|
);
|
2016-05-19 11:19:04 +08:00
|
|
|
}
|
2020-11-06 05:14:00 +08:00
|
|
|
Ok(())
|
2016-05-19 11:19:04 +08:00
|
|
|
}
|
2016-11-05 03:47:28 +08:00
|
|
|
|
|
|
|
#[test]
|
2020-11-06 05:14:00 +08:00
|
|
|
fn test_connection_close() -> Result<()> {
|
|
|
|
let conn = Connection::open_in_memory()?;
|
|
|
|
conn.prepare_cached("SELECT * FROM sqlite_master;")?;
|
2016-11-05 03:47:28 +08:00
|
|
|
|
|
|
|
conn.close().expect("connection not closed");
|
2020-11-06 05:14:00 +08:00
|
|
|
Ok(())
|
2016-11-05 03:47:28 +08:00
|
|
|
}
|
2018-02-17 17:11:39 +08:00
|
|
|
|
|
|
|
#[test]
|
2020-11-06 05:14:00 +08:00
|
|
|
fn test_cache_key() -> Result<()> {
|
|
|
|
let db = Connection::open_in_memory()?;
|
2018-02-17 17:11:39 +08:00
|
|
|
let cache = &db.cache;
|
|
|
|
assert_eq!(0, cache.len());
|
|
|
|
|
|
|
|
//let sql = " PRAGMA schema_version; -- comment";
|
|
|
|
let sql = "PRAGMA schema_version; ";
|
|
|
|
{
|
2020-11-06 05:14:00 +08:00
|
|
|
let mut stmt = db.prepare_cached(sql)?;
|
2018-02-17 17:11:39 +08:00
|
|
|
assert_eq!(0, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
|
2018-02-17 17:11:39 +08:00
|
|
|
}
|
|
|
|
assert_eq!(1, cache.len());
|
|
|
|
|
|
|
|
{
|
2020-11-06 05:14:00 +08:00
|
|
|
let mut stmt = db.prepare_cached(sql)?;
|
2018-02-17 17:11:39 +08:00
|
|
|
assert_eq!(0, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
assert_eq!(0, stmt.query_row([], |r| r.get::<_, i64>(0))?);
|
2018-02-17 17:11:39 +08:00
|
|
|
}
|
|
|
|
assert_eq!(1, cache.len());
|
2020-11-06 05:14:00 +08:00
|
|
|
Ok(())
|
2018-02-17 17:11:39 +08:00
|
|
|
}
|
2019-10-30 02:24:18 +08:00
|
|
|
|
|
|
|
#[test]
|
2020-11-06 05:14:00 +08:00
|
|
|
fn test_empty_stmt() -> Result<()> {
|
|
|
|
let conn = Connection::open_in_memory()?;
|
|
|
|
conn.prepare_cached("")?;
|
|
|
|
Ok(())
|
2019-10-30 02:24:18 +08:00
|
|
|
}
|
2015-08-02 18:07:49 +08:00
|
|
|
}
|