mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
Merge pull request #773 from gwenn/execute_batch
Implement our own sqlite3_exec
This commit is contained in:
commit
024e2e6bf0
@ -135,6 +135,10 @@ name = "vtab"
|
|||||||
name = "cache"
|
name = "cache"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "exec"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "backup", "blob", "chrono", "collation", "functions", "limits", "load_extension", "serde_json", "trace", "url", "vtab", "window", "modern_sqlite", "column_decltype" ]
|
features = [ "backup", "blob", "chrono", "collation", "functions", "limits", "load_extension", "serde_json", "trace", "url", "vtab", "window", "modern_sqlite", "column_decltype" ]
|
||||||
all-features = false
|
all-features = false
|
||||||
|
17
benches/exec.rs
Normal file
17
benches/exec.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use bencher::{benchmark_group, benchmark_main, Bencher};
|
||||||
|
use rusqlite::{Connection, NO_PARAMS};
|
||||||
|
|
||||||
|
fn bench_execute(b: &mut Bencher) {
|
||||||
|
let db = Connection::open_in_memory().unwrap();
|
||||||
|
let sql = "PRAGMA user_version=1";
|
||||||
|
b.iter(|| db.execute(sql, NO_PARAMS).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_execute_batch(b: &mut Bencher) {
|
||||||
|
let db = Connection::open_in_memory().unwrap();
|
||||||
|
let sql = "PRAGMA user_version=1";
|
||||||
|
b.iter(|| db.execute_batch(sql).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
benchmark_group!(exec_benches, bench_execute, bench_execute_batch);
|
||||||
|
benchmark_main!(exec_benches);
|
@ -171,21 +171,6 @@ impl InnerConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_batch(&mut self, sql: &str) -> Result<()> {
|
|
||||||
// use CString instead of SmallCString because it's probably big.
|
|
||||||
let c_sql = std::ffi::CString::new(sql)?;
|
|
||||||
unsafe {
|
|
||||||
let r = ffi::sqlite3_exec(
|
|
||||||
self.db(),
|
|
||||||
c_sql.as_ptr(),
|
|
||||||
None,
|
|
||||||
ptr::null_mut(),
|
|
||||||
ptr::null_mut(),
|
|
||||||
);
|
|
||||||
self.decode_result(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "load_extension")]
|
#[cfg(feature = "load_extension")]
|
||||||
pub fn enable_load_extension(&mut self, onoff: c_int) -> Result<()> {
|
pub fn enable_load_extension(&mut self, onoff: c_int) -> Result<()> {
|
||||||
let r = unsafe { ffi::sqlite3_enable_load_extension(self.db, onoff) };
|
let r = unsafe { ffi::sqlite3_enable_load_extension(self.db, onoff) };
|
||||||
@ -262,8 +247,17 @@ impl InnerConnection {
|
|||||||
// 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_stmt: *mut ffi::sqlite3_stmt = c_stmt;
|
||||||
let c_tail: *const c_char = c_tail;
|
let c_tail: *const c_char = c_tail;
|
||||||
// TODO ignore spaces, comments, ... at the end
|
let tail = if c_tail.is_null() {
|
||||||
let tail = !c_tail.is_null() && unsafe { c_tail != c_sql.offset(len as isize) };
|
0
|
||||||
|
} else {
|
||||||
|
// TODO nightly feature ptr_offset_from #41079
|
||||||
|
let n = (c_tail as isize) - (c_sql as isize);
|
||||||
|
if n <= 0 || n >= len as isize {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
n as usize
|
||||||
|
}
|
||||||
|
};
|
||||||
Ok(Statement::new(conn, unsafe {
|
Ok(Statement::new(conn, unsafe {
|
||||||
RawStatement::new(c_stmt, tail)
|
RawStatement::new(c_stmt, tail)
|
||||||
}))
|
}))
|
||||||
|
16
src/lib.rs
16
src/lib.rs
@ -435,8 +435,6 @@ impl Connection {
|
|||||||
/// Convenience method to run multiple SQL statements (that cannot take any
|
/// Convenience method to run multiple SQL statements (that cannot take any
|
||||||
/// parameters).
|
/// parameters).
|
||||||
///
|
///
|
||||||
/// Uses [sqlite3_exec](http://www.sqlite.org/c3ref/exec.html) under the hood.
|
|
||||||
///
|
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
@ -456,7 +454,19 @@ impl Connection {
|
|||||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
|
||||||
/// or if the underlying SQLite call fails.
|
/// or if the underlying SQLite call fails.
|
||||||
pub fn execute_batch(&self, sql: &str) -> Result<()> {
|
pub fn execute_batch(&self, sql: &str) -> Result<()> {
|
||||||
self.db.borrow_mut().execute_batch(sql)
|
let mut sql = sql;
|
||||||
|
while !sql.is_empty() {
|
||||||
|
let stmt = self.prepare(sql)?;
|
||||||
|
if !stmt.stmt.is_null() && stmt.step()? {
|
||||||
|
return Err(Error::ExecuteReturnedResults);
|
||||||
|
}
|
||||||
|
let tail = stmt.stmt.tail();
|
||||||
|
if tail == 0 || tail >= sql.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sql = &sql[tail..];
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method to prepare and execute a single SQL statement.
|
/// Convenience method to prepare and execute a single SQL statement.
|
||||||
|
@ -256,8 +256,7 @@ impl Connection {
|
|||||||
// The two syntaxes yield identical results.
|
// The two syntaxes yield identical results.
|
||||||
sql.push_equal_sign();
|
sql.push_equal_sign();
|
||||||
sql.push_value(pragma_value)?;
|
sql.push_value(pragma_value)?;
|
||||||
self.execute(&sql, NO_PARAMS)?;
|
self.execute_batch(&sql)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a new value to `pragma_name` and return the updated value.
|
/// Set a new value to `pragma_name` and return the updated value.
|
||||||
|
@ -12,7 +12,7 @@ use std::sync::Arc;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RawStatement {
|
pub struct RawStatement {
|
||||||
ptr: *mut ffi::sqlite3_stmt,
|
ptr: *mut ffi::sqlite3_stmt,
|
||||||
tail: bool,
|
tail: usize,
|
||||||
// Cached indices of named parameters, computed on the fly.
|
// Cached indices of named parameters, computed on the fly.
|
||||||
cache: crate::util::ParamIndexCache,
|
cache: crate::util::ParamIndexCache,
|
||||||
// Cached SQL (trimmed) that we use as the key when we're in the statement
|
// Cached SQL (trimmed) that we use as the key when we're in the statement
|
||||||
@ -29,7 +29,7 @@ pub struct RawStatement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RawStatement {
|
impl RawStatement {
|
||||||
pub unsafe fn new(stmt: *mut ffi::sqlite3_stmt, tail: bool) -> RawStatement {
|
pub unsafe fn new(stmt: *mut ffi::sqlite3_stmt, tail: usize) -> RawStatement {
|
||||||
RawStatement {
|
RawStatement {
|
||||||
ptr: stmt,
|
ptr: stmt,
|
||||||
tail,
|
tail,
|
||||||
@ -170,6 +170,10 @@ impl RawStatement {
|
|||||||
|
|
||||||
#[cfg(feature = "extra_check")]
|
#[cfg(feature = "extra_check")]
|
||||||
pub fn has_tail(&self) -> bool {
|
pub fn has_tail(&self) -> bool {
|
||||||
|
self.tail != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tail(&self) -> usize {
|
||||||
self.tail
|
self.tail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -622,7 +622,7 @@ impl Statement<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn finalize_(&mut self) -> Result<()> {
|
fn finalize_(&mut self) -> Result<()> {
|
||||||
let mut stmt = unsafe { RawStatement::new(ptr::null_mut(), false) };
|
let mut stmt = unsafe { RawStatement::new(ptr::null_mut(), 0) };
|
||||||
mem::swap(&mut stmt, &mut self.stmt);
|
mem::swap(&mut stmt, &mut self.stmt);
|
||||||
self.conn.decode_result(stmt.finalize())
|
self.conn.decode_result(stmt.finalize())
|
||||||
}
|
}
|
||||||
@ -707,7 +707,7 @@ impl Statement<'_> {
|
|||||||
/// connection has closed is illegal, but `RawStatement` does not enforce
|
/// connection has closed is illegal, but `RawStatement` does not enforce
|
||||||
/// this, as it loses our protective `'conn` lifetime bound.
|
/// this, as it loses our protective `'conn` lifetime bound.
|
||||||
pub(crate) unsafe fn into_raw(mut self) -> RawStatement {
|
pub(crate) unsafe fn into_raw(mut self) -> RawStatement {
|
||||||
let mut stmt = RawStatement::new(ptr::null_mut(), false);
|
let mut stmt = RawStatement::new(ptr::null_mut(), 0);
|
||||||
mem::swap(&mut stmt, &mut self.stmt);
|
mem::swap(&mut stmt, &mut self.stmt);
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{Connection, Result, NO_PARAMS};
|
use crate::{Connection, Result};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
/// Options for transaction behavior. See [BEGIN
|
/// Options for transaction behavior. See [BEGIN
|
||||||
@ -120,7 +120,7 @@ impl Transaction<'_> {
|
|||||||
TransactionBehavior::Immediate => "BEGIN IMMEDIATE",
|
TransactionBehavior::Immediate => "BEGIN IMMEDIATE",
|
||||||
TransactionBehavior::Exclusive => "BEGIN EXCLUSIVE",
|
TransactionBehavior::Exclusive => "BEGIN EXCLUSIVE",
|
||||||
};
|
};
|
||||||
conn.execute(query, NO_PARAMS).map(move |_| Transaction {
|
conn.execute_batch(query).map(move |_| Transaction {
|
||||||
conn,
|
conn,
|
||||||
drop_behavior: DropBehavior::Rollback,
|
drop_behavior: DropBehavior::Rollback,
|
||||||
})
|
})
|
||||||
@ -180,7 +180,7 @@ impl Transaction<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn commit_(&mut self) -> Result<()> {
|
fn commit_(&mut self) -> Result<()> {
|
||||||
self.conn.execute("COMMIT", NO_PARAMS)?;
|
self.conn.execute_batch("COMMIT")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +190,7 @@ impl Transaction<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rollback_(&mut self) -> Result<()> {
|
fn rollback_(&mut self) -> Result<()> {
|
||||||
self.conn.execute("ROLLBACK", NO_PARAMS)?;
|
self.conn.execute_batch("ROLLBACK")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +238,7 @@ impl Savepoint<'_> {
|
|||||||
name: T,
|
name: T,
|
||||||
) -> Result<Savepoint<'_>> {
|
) -> Result<Savepoint<'_>> {
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
conn.execute(&format!("SAVEPOINT {}", name), NO_PARAMS)
|
conn.execute_batch(&format!("SAVEPOINT {}", name))
|
||||||
.map(|_| Savepoint {
|
.map(|_| Savepoint {
|
||||||
conn,
|
conn,
|
||||||
name,
|
name,
|
||||||
@ -291,8 +291,7 @@ impl Savepoint<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn commit_(&mut self) -> Result<()> {
|
fn commit_(&mut self) -> Result<()> {
|
||||||
self.conn
|
self.conn.execute_batch(&format!("RELEASE {}", self.name))?;
|
||||||
.execute(&format!("RELEASE {}", self.name), NO_PARAMS)?;
|
|
||||||
self.committed = true;
|
self.committed = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -305,8 +304,7 @@ impl Savepoint<'_> {
|
|||||||
/// rolled back, and can be rolled back again or committed.
|
/// rolled back, and can be rolled back again or committed.
|
||||||
pub fn rollback(&mut self) -> Result<()> {
|
pub fn rollback(&mut self) -> Result<()> {
|
||||||
self.conn
|
self.conn
|
||||||
.execute(&format!("ROLLBACK TO {}", self.name), NO_PARAMS)?;
|
.execute_batch(&format!("ROLLBACK TO {}", self.name))
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the savepoint, committing or rolling back according to the
|
/// Consumes the savepoint, committing or rolling back according to the
|
||||||
|
Loading…
Reference in New Issue
Block a user