mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-24 09:59:19 +08:00
Merge pull request #1339 from gwenn/prepare_with_flags
Use SQLITE_PREPARE_PERSISTENT for CachedStatement
This commit is contained in:
commit
371e60ab6f
@ -506,6 +506,7 @@ mod bindings {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item_name(&self, original_item_name: &str) -> Option<String> {
|
fn item_name(&self, original_item_name: &str) -> Option<String> {
|
||||||
original_item_name
|
original_item_name
|
||||||
.strip_prefix("sqlite3_index_info_")
|
.strip_prefix("sqlite3_index_info_")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Prepared statements cache for faster execution.
|
//! Prepared statements cache for faster execution.
|
||||||
|
|
||||||
use crate::raw_statement::RawStatement;
|
use crate::raw_statement::RawStatement;
|
||||||
use crate::{Connection, Result, Statement};
|
use crate::{Connection, PrepFlags, Result, Statement};
|
||||||
use hashlink::LruCache;
|
use hashlink::LruCache;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
@ -144,7 +144,7 @@ impl StatementCache {
|
|||||||
let mut cache = self.0.borrow_mut();
|
let mut cache = self.0.borrow_mut();
|
||||||
let stmt = match cache.remove(trimmed) {
|
let stmt = match cache.remove(trimmed) {
|
||||||
Some(raw_stmt) => Ok(Statement::new(conn, raw_stmt)),
|
Some(raw_stmt) => Ok(Statement::new(conn, raw_stmt)),
|
||||||
None => conn.prepare(trimmed),
|
None => conn.prepare_with_flags(trimmed, PrepFlags::SQLITE_PREPARE_PERSISTENT),
|
||||||
};
|
};
|
||||||
stmt.map(|mut stmt| {
|
stmt.map(|mut stmt| {
|
||||||
stmt.stmt.set_statement_cache_key(trimmed);
|
stmt.stmt.set_statement_cache_key(trimmed);
|
||||||
|
@ -61,7 +61,8 @@ pub enum DbConfig {
|
|||||||
/// sqlite_master tables) are untainted by malicious content.
|
/// sqlite_master tables) are untainted by malicious content.
|
||||||
#[cfg(feature = "modern_sqlite")]
|
#[cfg(feature = "modern_sqlite")]
|
||||||
SQLITE_DBCONFIG_TRUSTED_SCHEMA = 1017, // 3.31.0
|
SQLITE_DBCONFIG_TRUSTED_SCHEMA = 1017, // 3.31.0
|
||||||
/// Sets or clears a flag that enables collection of the sqlite3_stmt_scanstatus_v2() statistics
|
/// Sets or clears a flag that enables collection of the
|
||||||
|
/// sqlite3_stmt_scanstatus_v2() statistics
|
||||||
#[cfg(feature = "modern_sqlite")]
|
#[cfg(feature = "modern_sqlite")]
|
||||||
SQLITE_DBCONFIG_STMT_SCANSTATUS = 1018, // 3.42.0
|
SQLITE_DBCONFIG_STMT_SCANSTATUS = 1018, // 3.42.0
|
||||||
/// Changes the default order in which tables and indexes are scanned
|
/// Changes the default order in which tables and indexes are scanned
|
||||||
|
@ -9,7 +9,7 @@ use std::sync::{Arc, Mutex};
|
|||||||
|
|
||||||
use super::ffi;
|
use super::ffi;
|
||||||
use super::str_for_sqlite;
|
use super::str_for_sqlite;
|
||||||
use super::{Connection, InterruptHandle, OpenFlags, Result};
|
use super::{Connection, InterruptHandle, OpenFlags, PrepFlags, Result};
|
||||||
use crate::error::{error_from_handle, error_from_sqlite_code, error_with_offset, Error};
|
use crate::error::{error_from_handle, error_from_sqlite_code, error_with_offset, Error};
|
||||||
use crate::raw_statement::RawStatement;
|
use crate::raw_statement::RawStatement;
|
||||||
use crate::statement::Statement;
|
use crate::statement::Statement;
|
||||||
@ -218,33 +218,24 @@ impl InnerConnection {
|
|||||||
unsafe { ffi::sqlite3_last_insert_rowid(self.db()) }
|
unsafe { ffi::sqlite3_last_insert_rowid(self.db()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare<'a>(&mut self, conn: &'a Connection, sql: &str) -> Result<Statement<'a>> {
|
pub fn prepare<'a>(
|
||||||
let mut c_stmt = ptr::null_mut();
|
&mut self,
|
||||||
|
conn: &'a Connection,
|
||||||
|
sql: &str,
|
||||||
|
flags: PrepFlags,
|
||||||
|
) -> Result<Statement<'a>> {
|
||||||
|
let mut c_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut();
|
||||||
let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?;
|
let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?;
|
||||||
let mut c_tail = ptr::null();
|
let mut c_tail: *const c_char = ptr::null();
|
||||||
// TODO sqlite3_prepare_v3 (https://sqlite.org/c3ref/c_prepare_normalize.html) // 3.20.0, #728
|
// TODO sqlite3_prepare_v3 (https://sqlite.org/c3ref/c_prepare_normalize.html) // 3.20.0, #728
|
||||||
#[cfg(not(feature = "unlock_notify"))]
|
#[cfg(not(feature = "unlock_notify"))]
|
||||||
let r = unsafe {
|
let r = unsafe { self.prepare_(c_sql, len, flags, &mut c_stmt, &mut c_tail) };
|
||||||
ffi::sqlite3_prepare_v2(
|
|
||||||
self.db(),
|
|
||||||
c_sql,
|
|
||||||
len,
|
|
||||||
&mut c_stmt as *mut *mut ffi::sqlite3_stmt,
|
|
||||||
&mut c_tail as *mut *const c_char,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
#[cfg(feature = "unlock_notify")]
|
#[cfg(feature = "unlock_notify")]
|
||||||
let r = unsafe {
|
let r = unsafe {
|
||||||
use crate::unlock_notify;
|
use crate::unlock_notify;
|
||||||
let mut rc;
|
let mut rc;
|
||||||
loop {
|
loop {
|
||||||
rc = ffi::sqlite3_prepare_v2(
|
rc = self.prepare_(c_sql, len, flags, &mut c_stmt, &mut c_tail);
|
||||||
self.db(),
|
|
||||||
c_sql,
|
|
||||||
len,
|
|
||||||
&mut c_stmt as *mut *mut ffi::sqlite3_stmt,
|
|
||||||
&mut c_tail as *mut *const c_char,
|
|
||||||
);
|
|
||||||
if !unlock_notify::is_locked(self.db, rc) {
|
if !unlock_notify::is_locked(self.db, rc) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -261,8 +252,6 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
// If the input text contains no SQL (if the input is an empty string or a
|
// If the input text contains no SQL (if the input is an empty string or a
|
||||||
// comment) then *ppStmt is set to NULL.
|
// comment) then *ppStmt is set to NULL.
|
||||||
let c_stmt: *mut ffi::sqlite3_stmt = c_stmt;
|
|
||||||
let c_tail: *const c_char = c_tail;
|
|
||||||
let tail = if c_tail.is_null() {
|
let tail = if c_tail.is_null() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
@ -278,6 +267,32 @@ impl InnerConnection {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(feature = "modern_sqlite"))]
|
||||||
|
unsafe fn prepare_(
|
||||||
|
&self,
|
||||||
|
z_sql: *const c_char,
|
||||||
|
n_byte: c_int,
|
||||||
|
_: PrepFlags,
|
||||||
|
pp_stmt: *mut *mut ffi::sqlite3_stmt,
|
||||||
|
pz_tail: *mut *const c_char,
|
||||||
|
) -> c_int {
|
||||||
|
ffi::sqlite3_prepare_v2(self.db(), z_sql, n_byte, pp_stmt, pz_tail)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "modern_sqlite")]
|
||||||
|
unsafe fn prepare_(
|
||||||
|
&self,
|
||||||
|
z_sql: *const c_char,
|
||||||
|
n_byte: c_int,
|
||||||
|
flags: PrepFlags,
|
||||||
|
pp_stmt: *mut *mut ffi::sqlite3_stmt,
|
||||||
|
pz_tail: *mut *const c_char,
|
||||||
|
) -> c_int {
|
||||||
|
ffi::sqlite3_prepare_v3(self.db(), z_sql, n_byte, flags.bits(), pp_stmt, pz_tail)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn changes(&self) -> u64 {
|
pub fn changes(&self) -> u64 {
|
||||||
#[cfg(not(feature = "modern_sqlite"))]
|
#[cfg(not(feature = "modern_sqlite"))]
|
||||||
|
29
src/lib.rs
29
src/lib.rs
@ -711,7 +711,18 @@ impl Connection {
|
|||||||
/// or if the underlying SQLite call fails.
|
/// or if the underlying SQLite call fails.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
|
pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
|
||||||
self.db.borrow_mut().prepare(self, sql)
|
self.prepare_with_flags(sql, PrepFlags::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepare a SQL statement for execution.
|
||||||
|
///
|
||||||
|
/// # Failure
|
||||||
|
///
|
||||||
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||||
|
/// or if the underlying SQLite call fails.
|
||||||
|
#[inline]
|
||||||
|
pub fn prepare_with_flags(&self, sql: &str, flags: PrepFlags) -> Result<Statement<'_>> {
|
||||||
|
self.db.borrow_mut().prepare(self, sql, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Close the SQLite connection.
|
/// Close the SQLite connection.
|
||||||
@ -897,7 +908,8 @@ impl Connection {
|
|||||||
///
|
///
|
||||||
/// This function is unsafe because improper use may impact the Connection.
|
/// This function is unsafe because improper use may impact the Connection.
|
||||||
/// In particular, it should only be called on connections created
|
/// In particular, it should only be called on connections created
|
||||||
/// and owned by the caller, e.g. as a result of calling ffi::sqlite3_open().
|
/// and owned by the caller, e.g. as a result of calling
|
||||||
|
/// ffi::sqlite3_open().
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Connection> {
|
pub unsafe fn from_handle_owned(db: *mut ffi::sqlite3) -> Result<Connection> {
|
||||||
let db = InnerConnection::new(db, true);
|
let db = InnerConnection::new(db, true);
|
||||||
@ -1106,6 +1118,19 @@ impl Default for OpenFlags {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
/// Prepare flags. See
|
||||||
|
/// [sqlite3_prepare_v3](https://sqlite.org/c3ref/c_prepare_normalize.html) for details.
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PrepFlags: ::std::os::raw::c_uint {
|
||||||
|
/// A hint to the query planner that the prepared statement will be retained for a long time and probably reused many times.
|
||||||
|
const SQLITE_PREPARE_PERSISTENT = 0x01;
|
||||||
|
/// Causes the SQL compiler to return an error (error code SQLITE_ERROR) if the statement uses any virtual tables.
|
||||||
|
const SQLITE_PREPARE_NO_VTAB = 0x04;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// rusqlite's check for a safe SQLite threading mode requires SQLite 3.7.0 or
|
/// rusqlite's check for a safe SQLite threading mode requires SQLite 3.7.0 or
|
||||||
/// later. If you are running against a SQLite older than that, rusqlite
|
/// later. If you are running against a SQLite older than that, rusqlite
|
||||||
/// attempts to ensure safety by performing configuration and initialization of
|
/// attempts to ensure safety by performing configuration and initialization of
|
||||||
|
Loading…
Reference in New Issue
Block a user