mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
Merge pull request #97 from jgallagher/remove-sqlite-prefix
Remove unnecessary prefixes on many types.
This commit is contained in:
commit
b177502404
@ -11,3 +11,4 @@ rusqlite contributors (sorted alphabetically)
|
|||||||
* [krdln](https://github.com/krdln)
|
* [krdln](https://github.com/krdln)
|
||||||
* [Ben Striegel](https://github.com/bstrie)
|
* [Ben Striegel](https://github.com/bstrie)
|
||||||
* [Andrew Straw](https://github.com/astraw)
|
* [Andrew Straw](https://github.com/astraw)
|
||||||
|
* [Ronald Kinard](https://github.com/Furyhunter)
|
||||||
|
16
Changelog.md
16
Changelog.md
@ -1,5 +1,21 @@
|
|||||||
# Version UPCOMING (TBD)
|
# Version UPCOMING (TBD)
|
||||||
|
|
||||||
|
* BREAKING CHANGE: `SqliteTransactionDeferred`, `SqliteTransactionImmediate`, and
|
||||||
|
`SqliteTransactionExclusive` are no longer exported. Instead, use
|
||||||
|
`TransactionBehavior::Deferred`, `TransactionBehavior::Immediate`, and
|
||||||
|
`TransactionBehavior::Exclusive`.
|
||||||
|
* Removed `Sqlite` prefix on many types:
|
||||||
|
* `SqliteConnection` is now `Connection`
|
||||||
|
* `SqliteError` is now `Error`
|
||||||
|
* `SqliteResult` is now `Result`
|
||||||
|
* `SqliteStatement` is now `Statement`
|
||||||
|
* `SqliteRows` is now `Rows`
|
||||||
|
* `SqliteRow` is now `Row`
|
||||||
|
* `SqliteOpenFlags` is now `OpenFlags`
|
||||||
|
* `SqliteTransaction` is now `Transaction`.
|
||||||
|
* `SqliteTransactionBehavior` is now `TransactionBehavior`.
|
||||||
|
* `SqliteLoadExtensionGuard` is now `LoadExtensionGuard`.
|
||||||
|
The old, prefixed names are still exported but are deprecated.
|
||||||
* Adds a variety of `..._named` methods for executing queries using named placeholder parameters.
|
* 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
|
||||||
|
12
README.md
12
README.md
@ -11,7 +11,7 @@ extern crate rusqlite;
|
|||||||
extern crate time;
|
extern crate time;
|
||||||
|
|
||||||
use time::Timespec;
|
use time::Timespec;
|
||||||
use rusqlite::SqliteConnection;
|
use rusqlite::Connection;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Person {
|
struct Person {
|
||||||
@ -22,7 +22,7 @@ struct Person {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let conn = SqliteConnection::open_in_memory().unwrap();
|
let conn = Connection::open_in_memory().unwrap();
|
||||||
|
|
||||||
conn.execute("CREATE TABLE person (
|
conn.execute("CREATE TABLE person (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
@ -56,7 +56,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Design of SqliteRows and SqliteRow
|
### Design of Rows and Row
|
||||||
|
|
||||||
To retrieve the result rows from a query, SQLite requires you to call
|
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
|
[sqlite3_step()](https://www.sqlite.org/c3ref/step.html) on a prepared statement. You can only
|
||||||
@ -67,12 +67,12 @@ satisfy the [Iterator](http://doc.rust-lang.org/std/iter/trait.Iterator.html) tr
|
|||||||
you cannot (as easily) loop over the rows, or use many of the helpful Iterator methods like `map`
|
you cannot (as easily) loop over the rows, or use many of the helpful Iterator methods like `map`
|
||||||
and `filter`.
|
and `filter`.
|
||||||
|
|
||||||
Instead, Rusqlite's `SqliteRows` handle does conform to `Iterator`. It ensures safety by
|
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
|
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:
|
will panic if you do so. A specific example that will panic:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn bad_function_will_panic(conn: &SqliteConnection) -> SqliteResult<i64> {
|
fn bad_function_will_panic(conn: &Connection) -> Result<i64> {
|
||||||
let mut stmt = try!(conn.prepare("SELECT id FROM my_table"));
|
let mut stmt = try!(conn.prepare("SELECT id FROM my_table"));
|
||||||
let mut rows = try!(stmt.query(&[]));
|
let mut rows = try!(stmt.query(&[]));
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ fn bad_function_will_panic(conn: &SqliteConnection) -> SqliteResult<i64> {
|
|||||||
```
|
```
|
||||||
|
|
||||||
There are other, less obvious things that may result in a panic as well, such as calling
|
There are other, less obvious things that may result in a panic as well, such as calling
|
||||||
`collect()` on a `SqliteRows` and then trying to use the collected rows.
|
`collect()` on a `Rows` and then trying to use the collected rows.
|
||||||
|
|
||||||
Strongly consider using the method `query_map()` instead, if you can.
|
Strongly consider using the method `query_map()` instead, if you can.
|
||||||
`query_map()` returns an iterator over rows-mapped-to-some-type. This
|
`query_map()` returns an iterator over rows-mapped-to-some-type. This
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Online SQLite backup API.
|
//! Online SQLite backup API.
|
||||||
//!
|
//!
|
||||||
//! To create a `Backup`, you must have two distinct `SqliteConnection`s - one
|
//! To create a `Backup`, you must have two distinct `Connection`s - one
|
||||||
//! for the source (which can be used while the backup is running) and one for
|
//! for the source (which can be used while the backup is running) and one for
|
||||||
//! the destination (which cannot). A `Backup` handle exposes three methods:
|
//! the destination (which cannot). A `Backup` handle exposes three methods:
|
||||||
//! `step` will attempt to back up a specified number of pages, `progress` gets
|
//! `step` will attempt to back up a specified number of pages, `progress` gets
|
||||||
@ -14,13 +14,13 @@
|
|||||||
//! documentation](https://www.sqlite.org/backup.html).
|
//! documentation](https://www.sqlite.org/backup.html).
|
||||||
//!
|
//!
|
||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! # use rusqlite::{backup, SqliteConnection, SqliteResult};
|
//! # use rusqlite::{backup, Connection, Result};
|
||||||
//! # use std::path::Path;
|
//! # use std::path::Path;
|
||||||
//! # use std::time;
|
//! # use std::time;
|
||||||
//!
|
//!
|
||||||
//! fn backupDb<P: AsRef<Path>>(src: &SqliteConnection, dst: P, progress: fn(backup::Progress))
|
//! fn backupDb<P: AsRef<Path>>(src: &Connection, dst: P, progress: fn(backup::Progress))
|
||||||
//! -> SqliteResult<()> {
|
//! -> Result<()> {
|
||||||
//! let mut dst = try!(SqliteConnection::open(dst));
|
//! let mut dst = try!(Connection::open(dst));
|
||||||
//! let backup = try!(backup::Backup::new(src, &mut dst));
|
//! let backup = try!(backup::Backup::new(src, &mut dst));
|
||||||
//! backup.run_to_completion(5, time::Duration::from_millis(250), Some(progress))
|
//! backup.run_to_completion(5, time::Duration::from_millis(250), Some(progress))
|
||||||
//! }
|
//! }
|
||||||
@ -36,9 +36,9 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use ffi;
|
use ffi;
|
||||||
|
|
||||||
use {DatabaseName, SqliteConnection, SqliteError, SqliteResult};
|
use {DatabaseName, Connection, Error, Result};
|
||||||
|
|
||||||
impl SqliteConnection {
|
impl Connection {
|
||||||
/// Back up the `name` database to the given destination path.
|
/// Back up the `name` database to the given destination path.
|
||||||
/// If `progress` is not `None`, it will be called periodically
|
/// If `progress` is not `None`, it will be called periodically
|
||||||
/// until the backup completes.
|
/// until the backup completes.
|
||||||
@ -55,9 +55,9 @@ impl SqliteConnection {
|
|||||||
name: DatabaseName,
|
name: DatabaseName,
|
||||||
dst_path: P,
|
dst_path: P,
|
||||||
progress: Option<fn(Progress)>)
|
progress: Option<fn(Progress)>)
|
||||||
-> SqliteResult<()> {
|
-> Result<()> {
|
||||||
use self::StepResult::{More, Done, Busy, Locked};
|
use self::StepResult::{More, Done, Busy, Locked};
|
||||||
let mut dst = try!(SqliteConnection::open(dst_path));
|
let mut dst = try!(Connection::open(dst_path));
|
||||||
let backup = try!(Backup::new_with_names(self, name, &mut dst, DatabaseName::Main));
|
let backup = try!(Backup::new_with_names(self, name, &mut dst, DatabaseName::Main));
|
||||||
|
|
||||||
let mut r = More;
|
let mut r = More;
|
||||||
@ -70,8 +70,8 @@ impl SqliteConnection {
|
|||||||
|
|
||||||
match r {
|
match r {
|
||||||
Done => Ok(()),
|
Done => Ok(()),
|
||||||
Busy => Err(SqliteError::from_handle(ptr::null_mut(), ffi::SQLITE_BUSY)),
|
Busy => Err(Error::from_handle(ptr::null_mut(), ffi::SQLITE_BUSY)),
|
||||||
Locked => Err(SqliteError::from_handle(ptr::null_mut(), ffi::SQLITE_LOCKED)),
|
Locked => Err(Error::from_handle(ptr::null_mut(), ffi::SQLITE_LOCKED)),
|
||||||
More => unreachable!(),
|
More => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,9 +92,9 @@ impl SqliteConnection {
|
|||||||
name: DatabaseName,
|
name: DatabaseName,
|
||||||
src_path: P,
|
src_path: P,
|
||||||
progress: Option<fn(Progress)>)
|
progress: Option<fn(Progress)>)
|
||||||
-> SqliteResult<()> {
|
-> Result<()> {
|
||||||
use self::StepResult::{More, Done, Busy, Locked};
|
use self::StepResult::{More, Done, Busy, Locked};
|
||||||
let src = try!(SqliteConnection::open(src_path));
|
let src = try!(Connection::open(src_path));
|
||||||
let restore = try!(Backup::new_with_names(&src, DatabaseName::Main, self, name));
|
let restore = try!(Backup::new_with_names(&src, DatabaseName::Main, self, name));
|
||||||
|
|
||||||
let mut r = More;
|
let mut r = More;
|
||||||
@ -115,8 +115,8 @@ impl SqliteConnection {
|
|||||||
|
|
||||||
match r {
|
match r {
|
||||||
Done => Ok(()),
|
Done => Ok(()),
|
||||||
Busy => Err(SqliteError::from_handle(ptr::null_mut(), ffi::SQLITE_BUSY)),
|
Busy => Err(Error::from_handle(ptr::null_mut(), ffi::SQLITE_BUSY)),
|
||||||
Locked => Err(SqliteError::from_handle(ptr::null_mut(), ffi::SQLITE_LOCKED)),
|
Locked => Err(Error::from_handle(ptr::null_mut(), ffi::SQLITE_LOCKED)),
|
||||||
More => unreachable!(),
|
More => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,9 +170,9 @@ impl<'a, 'b> Backup<'a, 'b> {
|
|||||||
///
|
///
|
||||||
/// Will return `Err` if the underlying `sqlite3_backup_init` call returns
|
/// Will return `Err` if the underlying `sqlite3_backup_init` call returns
|
||||||
/// `NULL`.
|
/// `NULL`.
|
||||||
pub fn new(from: &'a SqliteConnection,
|
pub fn new(from: &'a Connection,
|
||||||
to: &'b mut SqliteConnection)
|
to: &'b mut Connection)
|
||||||
-> SqliteResult<Backup<'a, 'b>> {
|
-> Result<Backup<'a, 'b>> {
|
||||||
Backup::new_with_names(from, DatabaseName::Main, to, DatabaseName::Main)
|
Backup::new_with_names(from, DatabaseName::Main, to, DatabaseName::Main)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,11 +185,11 @@ impl<'a, 'b> Backup<'a, 'b> {
|
|||||||
///
|
///
|
||||||
/// Will return `Err` if the underlying `sqlite3_backup_init` call returns
|
/// Will return `Err` if the underlying `sqlite3_backup_init` call returns
|
||||||
/// `NULL`.
|
/// `NULL`.
|
||||||
pub fn new_with_names(from: &'a SqliteConnection,
|
pub fn new_with_names(from: &'a Connection,
|
||||||
from_name: DatabaseName,
|
from_name: DatabaseName,
|
||||||
to: &'b mut SqliteConnection,
|
to: &'b mut Connection,
|
||||||
to_name: DatabaseName)
|
to_name: DatabaseName)
|
||||||
-> SqliteResult<Backup<'a, 'b>> {
|
-> Result<Backup<'a, 'b>> {
|
||||||
let to_name = try!(to_name.to_cstring());
|
let to_name = try!(to_name.to_cstring());
|
||||||
let from_name = try!(from_name.to_cstring());
|
let from_name = try!(from_name.to_cstring());
|
||||||
|
|
||||||
@ -201,7 +201,7 @@ impl<'a, 'b> Backup<'a, 'b> {
|
|||||||
from.db.borrow_mut().db,
|
from.db.borrow_mut().db,
|
||||||
from_name.as_ptr());
|
from_name.as_ptr());
|
||||||
if b.is_null() {
|
if b.is_null() {
|
||||||
return Err(SqliteError::from_handle(to_db, ffi::sqlite3_errcode(to_db)));
|
return Err(Error::from_handle(to_db, ffi::sqlite3_errcode(to_db)));
|
||||||
}
|
}
|
||||||
b
|
b
|
||||||
};
|
};
|
||||||
@ -235,7 +235,7 @@ impl<'a, 'b> Backup<'a, 'b> {
|
|||||||
/// an error code other than `DONE`, `OK`, `BUSY`, or `LOCKED`. `BUSY` and
|
/// an error code other than `DONE`, `OK`, `BUSY`, or `LOCKED`. `BUSY` and
|
||||||
/// `LOCKED` are transient errors and are therefore returned as possible
|
/// `LOCKED` are transient errors and are therefore returned as possible
|
||||||
/// `Ok` values.
|
/// `Ok` values.
|
||||||
pub fn step(&self, num_pages: c_int) -> SqliteResult<StepResult> {
|
pub fn step(&self, num_pages: c_int) -> Result<StepResult> {
|
||||||
use self::StepResult::{Done, More, Busy, Locked};
|
use self::StepResult::{Done, More, Busy, Locked};
|
||||||
|
|
||||||
let rc = unsafe { ffi::sqlite3_backup_step(self.b, num_pages) };
|
let rc = unsafe { ffi::sqlite3_backup_step(self.b, num_pages) };
|
||||||
@ -245,7 +245,7 @@ impl<'a, 'b> Backup<'a, 'b> {
|
|||||||
ffi::SQLITE_BUSY => Ok(Busy),
|
ffi::SQLITE_BUSY => Ok(Busy),
|
||||||
ffi::SQLITE_LOCKED => Ok(Locked),
|
ffi::SQLITE_LOCKED => Ok(Locked),
|
||||||
rc => {
|
rc => {
|
||||||
Err(SqliteError {
|
Err(Error {
|
||||||
code: rc,
|
code: rc,
|
||||||
message: ffi::code_to_str(rc).into(),
|
message: ffi::code_to_str(rc).into(),
|
||||||
})
|
})
|
||||||
@ -272,7 +272,7 @@ impl<'a, 'b> Backup<'a, 'b> {
|
|||||||
pages_per_step: c_int,
|
pages_per_step: c_int,
|
||||||
pause_between_pages: Duration,
|
pause_between_pages: Duration,
|
||||||
progress: Option<fn(Progress)>)
|
progress: Option<fn(Progress)>)
|
||||||
-> SqliteResult<()> {
|
-> Result<()> {
|
||||||
use self::StepResult::{Done, More, Busy, Locked};
|
use self::StepResult::{Done, More, Busy, Locked};
|
||||||
|
|
||||||
assert!(pages_per_step > 0, "pages_per_step must be positive");
|
assert!(pages_per_step > 0, "pages_per_step must be positive");
|
||||||
@ -298,21 +298,21 @@ impl<'a, 'b> Drop for Backup<'a, 'b> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use {SqliteConnection, DatabaseName};
|
use {Connection, DatabaseName};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use super::Backup;
|
use super::Backup;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn test_backup() {
|
fn test_backup() {
|
||||||
let src = SqliteConnection::open_in_memory().unwrap();
|
let src = Connection::open_in_memory().unwrap();
|
||||||
let sql = "BEGIN;
|
let sql = "BEGIN;
|
||||||
CREATE TABLE foo(x INTEGER);
|
CREATE TABLE foo(x INTEGER);
|
||||||
INSERT INTO foo VALUES(42);
|
INSERT INTO foo VALUES(42);
|
||||||
END;";
|
END;";
|
||||||
src.execute_batch(sql).unwrap();
|
src.execute_batch(sql).unwrap();
|
||||||
|
|
||||||
let mut dst = SqliteConnection::open_in_memory().unwrap();
|
let mut dst = Connection::open_in_memory().unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let backup = Backup::new(&src, &mut dst).unwrap();
|
let backup = Backup::new(&src, &mut dst).unwrap();
|
||||||
@ -336,14 +336,14 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn test_backup_temp() {
|
fn test_backup_temp() {
|
||||||
let src = SqliteConnection::open_in_memory().unwrap();
|
let src = Connection::open_in_memory().unwrap();
|
||||||
let sql = "BEGIN;
|
let sql = "BEGIN;
|
||||||
CREATE TEMPORARY TABLE foo(x INTEGER);
|
CREATE TEMPORARY TABLE foo(x INTEGER);
|
||||||
INSERT INTO foo VALUES(42);
|
INSERT INTO foo VALUES(42);
|
||||||
END;";
|
END;";
|
||||||
src.execute_batch(sql).unwrap();
|
src.execute_batch(sql).unwrap();
|
||||||
|
|
||||||
let mut dst = SqliteConnection::open_in_memory().unwrap();
|
let mut dst = Connection::open_in_memory().unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let backup = Backup::new_with_names(&src,
|
let backup = Backup::new_with_names(&src,
|
||||||
@ -375,7 +375,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn test_backup_attached() {
|
fn test_backup_attached() {
|
||||||
let src = SqliteConnection::open_in_memory().unwrap();
|
let src = Connection::open_in_memory().unwrap();
|
||||||
let sql = "ATTACH DATABASE ':memory:' AS my_attached;
|
let sql = "ATTACH DATABASE ':memory:' AS my_attached;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
CREATE TABLE my_attached.foo(x INTEGER);
|
CREATE TABLE my_attached.foo(x INTEGER);
|
||||||
@ -383,7 +383,7 @@ mod test {
|
|||||||
END;";
|
END;";
|
||||||
src.execute_batch(sql).unwrap();
|
src.execute_batch(sql).unwrap();
|
||||||
|
|
||||||
let mut dst = SqliteConnection::open_in_memory().unwrap();
|
let mut dst = Connection::open_in_memory().unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let backup = Backup::new_with_names(&src,
|
let backup = Backup::new_with_names(&src,
|
||||||
|
@ -12,11 +12,11 @@
|
|||||||
//! extern crate rusqlite;
|
//! extern crate rusqlite;
|
||||||
//! extern crate regex;
|
//! extern crate regex;
|
||||||
//!
|
//!
|
||||||
//! use rusqlite::{SqliteConnection, SqliteError, SqliteResult};
|
//! use rusqlite::{Connection, Error, Result};
|
||||||
//! use std::collections::HashMap;
|
//! use std::collections::HashMap;
|
||||||
//! use regex::Regex;
|
//! use regex::Regex;
|
||||||
//!
|
//!
|
||||||
//! fn add_regexp_function(db: &SqliteConnection) -> SqliteResult<()> {
|
//! fn add_regexp_function(db: &Connection) -> Result<()> {
|
||||||
//! let mut cached_regexes = HashMap::new();
|
//! let mut cached_regexes = HashMap::new();
|
||||||
//! db.create_scalar_function("regexp", 2, true, move |ctx| {
|
//! db.create_scalar_function("regexp", 2, true, move |ctx| {
|
||||||
//! let regex_s = try!(ctx.get::<String>(0));
|
//! let regex_s = try!(ctx.get::<String>(0));
|
||||||
@ -26,7 +26,7 @@
|
|||||||
//! match entry {
|
//! match entry {
|
||||||
//! Occupied(occ) => occ.into_mut(),
|
//! Occupied(occ) => occ.into_mut(),
|
||||||
//! Vacant(vac) => {
|
//! Vacant(vac) => {
|
||||||
//! let r = try!(Regex::new(®ex_s).map_err(|e| SqliteError {
|
//! let r = try!(Regex::new(®ex_s).map_err(|e| Error {
|
||||||
//! code: libsqlite3_sys::SQLITE_ERROR,
|
//! code: libsqlite3_sys::SQLITE_ERROR,
|
||||||
//! message: format!("Invalid regular expression: {}", e),
|
//! message: format!("Invalid regular expression: {}", e),
|
||||||
//! }));
|
//! }));
|
||||||
@ -41,7 +41,7 @@
|
|||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let db = SqliteConnection::open_in_memory().unwrap();
|
//! let db = Connection::open_in_memory().unwrap();
|
||||||
//! add_regexp_function(&db).unwrap();
|
//! add_regexp_function(&db).unwrap();
|
||||||
//!
|
//!
|
||||||
//! let is_match = db.query_row("SELECT regexp('[aeiou]*', 'aaaaeeeiii')", &[],
|
//! let is_match = db.query_row("SELECT regexp('[aeiou]*', 'aaaaeeeiii')", &[],
|
||||||
@ -65,7 +65,7 @@ pub use ffi::sqlite3_value_numeric_type;
|
|||||||
|
|
||||||
use types::Null;
|
use types::Null;
|
||||||
|
|
||||||
use {SqliteResult, SqliteError, SqliteConnection, str_to_cstring, InnerSqliteConnection};
|
use {Result, Error, Connection, str_to_cstring, InnerConnection};
|
||||||
|
|
||||||
/// A trait for types that can be converted into the result of an SQL function.
|
/// A trait for types that can be converted into the result of an SQL function.
|
||||||
pub trait ToResult {
|
pub trait ToResult {
|
||||||
@ -165,7 +165,7 @@ impl ToResult for Null {
|
|||||||
|
|
||||||
/// A trait for types that can be created from a SQLite function parameter value.
|
/// A trait for types that can be created from a SQLite function parameter value.
|
||||||
pub trait FromValue: Sized {
|
pub trait FromValue: Sized {
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Self>;
|
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<Self>;
|
||||||
|
|
||||||
/// FromValue types can implement this method and use sqlite3_value_type to check that
|
/// FromValue types can implement this method and use sqlite3_value_type to check that
|
||||||
/// the type reported by SQLite matches a type suitable for Self. This method is used
|
/// the type reported by SQLite matches a type suitable for Self. This method is used
|
||||||
@ -180,7 +180,7 @@ pub trait FromValue: Sized {
|
|||||||
macro_rules! raw_from_impl(
|
macro_rules! raw_from_impl(
|
||||||
($t:ty, $f:ident, $c:expr) => (
|
($t:ty, $f:ident, $c:expr) => (
|
||||||
impl FromValue for $t {
|
impl FromValue for $t {
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<$t> {
|
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<$t> {
|
||||||
Ok(ffi::$f(v))
|
Ok(ffi::$f(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ raw_from_impl!(c_int, sqlite3_value_int, ffi::SQLITE_INTEGER);
|
|||||||
raw_from_impl!(i64, sqlite3_value_int64, ffi::SQLITE_INTEGER);
|
raw_from_impl!(i64, sqlite3_value_int64, ffi::SQLITE_INTEGER);
|
||||||
|
|
||||||
impl FromValue for bool {
|
impl FromValue for bool {
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<bool> {
|
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<bool> {
|
||||||
match ffi::sqlite3_value_int(v) {
|
match ffi::sqlite3_value_int(v) {
|
||||||
0 => Ok(false),
|
0 => Ok(false),
|
||||||
_ => Ok(true),
|
_ => Ok(true),
|
||||||
@ -208,7 +208,7 @@ impl FromValue for bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue for c_double {
|
impl FromValue for c_double {
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<c_double> {
|
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<c_double> {
|
||||||
Ok(ffi::sqlite3_value_double(v))
|
Ok(ffi::sqlite3_value_double(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ impl FromValue for c_double {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue for String {
|
impl FromValue for String {
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<String> {
|
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<String> {
|
||||||
let c_text = ffi::sqlite3_value_text(v);
|
let c_text = ffi::sqlite3_value_text(v);
|
||||||
if c_text.is_null() {
|
if c_text.is_null() {
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
@ -228,7 +228,7 @@ impl FromValue for String {
|
|||||||
let utf8_str = str::from_utf8(c_slice);
|
let utf8_str = str::from_utf8(c_slice);
|
||||||
utf8_str.map(|s| s.to_string())
|
utf8_str.map(|s| s.to_string())
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
SqliteError {
|
Error {
|
||||||
code: 0,
|
code: 0,
|
||||||
message: e.to_string(),
|
message: e.to_string(),
|
||||||
}
|
}
|
||||||
@ -242,7 +242,7 @@ impl FromValue for String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue for Vec<u8> {
|
impl FromValue for Vec<u8> {
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Vec<u8>> {
|
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<Vec<u8>> {
|
||||||
use std::slice::from_raw_parts;
|
use std::slice::from_raw_parts;
|
||||||
let c_blob = ffi::sqlite3_value_blob(v);
|
let c_blob = ffi::sqlite3_value_blob(v);
|
||||||
let len = ffi::sqlite3_value_bytes(v);
|
let len = ffi::sqlite3_value_bytes(v);
|
||||||
@ -260,7 +260,7 @@ impl FromValue for Vec<u8> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FromValue> FromValue for Option<T> {
|
impl<T: FromValue> FromValue for Option<T> {
|
||||||
unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Option<T>> {
|
unsafe fn parameter_value(v: *mut sqlite3_value) -> Result<Option<T>> {
|
||||||
if sqlite3_value_type(v) == ffi::SQLITE_NULL {
|
if sqlite3_value_type(v) == ffi::SQLITE_NULL {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
@ -296,13 +296,13 @@ impl<'a> Context<'a> {
|
|||||||
/// Will panic if `idx` is greater than or equal to `self.len()`.
|
/// Will panic if `idx` is greater than or equal to `self.len()`.
|
||||||
///
|
///
|
||||||
/// Will return Err if the underlying SQLite type cannot be converted to a `T`.
|
/// Will return Err if the underlying SQLite type cannot be converted to a `T`.
|
||||||
pub fn get<T: FromValue>(&self, idx: usize) -> SqliteResult<T> {
|
pub fn get<T: FromValue>(&self, idx: usize) -> Result<T> {
|
||||||
let arg = self.args[idx];
|
let arg = self.args[idx];
|
||||||
unsafe {
|
unsafe {
|
||||||
if T::parameter_has_valid_sqlite_type(arg) {
|
if T::parameter_has_valid_sqlite_type(arg) {
|
||||||
T::parameter_value(arg)
|
T::parameter_value(arg)
|
||||||
} else {
|
} else {
|
||||||
Err(SqliteError {
|
Err(Error {
|
||||||
code: ffi::SQLITE_MISMATCH,
|
code: ffi::SQLITE_MISMATCH,
|
||||||
message: "Invalid value type".to_string(),
|
message: "Invalid value type".to_string(),
|
||||||
})
|
})
|
||||||
@ -341,7 +341,7 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SqliteConnection {
|
impl Connection {
|
||||||
/// Attach a user-defined scalar function to this database connection.
|
/// Attach a user-defined scalar function to this database connection.
|
||||||
///
|
///
|
||||||
/// `fn_name` is the name the function will be accessible from SQL.
|
/// `fn_name` is the name the function will be accessible from SQL.
|
||||||
@ -355,9 +355,9 @@ impl SqliteConnection {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use rusqlite::{SqliteConnection, SqliteResult};
|
/// # use rusqlite::{Connection, Result};
|
||||||
/// # type c_double = f64;
|
/// # type c_double = f64;
|
||||||
/// fn scalar_function_example(db: SqliteConnection) -> SqliteResult<()> {
|
/// fn scalar_function_example(db: Connection) -> Result<()> {
|
||||||
/// try!(db.create_scalar_function("halve", 1, true, |ctx| {
|
/// try!(db.create_scalar_function("halve", 1, true, |ctx| {
|
||||||
/// let value = try!(ctx.get::<c_double>(0));
|
/// let value = try!(ctx.get::<c_double>(0));
|
||||||
/// Ok(value / 2f64)
|
/// Ok(value / 2f64)
|
||||||
@ -377,8 +377,8 @@ impl SqliteConnection {
|
|||||||
n_arg: c_int,
|
n_arg: c_int,
|
||||||
deterministic: bool,
|
deterministic: bool,
|
||||||
x_func: F)
|
x_func: F)
|
||||||
-> SqliteResult<()>
|
-> Result<()>
|
||||||
where F: FnMut(&Context) -> SqliteResult<T>,
|
where F: FnMut(&Context) -> Result<T>,
|
||||||
T: ToResult
|
T: ToResult
|
||||||
{
|
{
|
||||||
self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func)
|
self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func)
|
||||||
@ -392,25 +392,25 @@ impl SqliteConnection {
|
|||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return Err if the function could not be removed.
|
/// Will return Err if the function could not be removed.
|
||||||
pub fn remove_function(&self, fn_name: &str, n_arg: c_int) -> SqliteResult<()> {
|
pub fn remove_function(&self, fn_name: &str, n_arg: c_int) -> Result<()> {
|
||||||
self.db.borrow_mut().remove_function(fn_name, n_arg)
|
self.db.borrow_mut().remove_function(fn_name, n_arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerSqliteConnection {
|
impl InnerConnection {
|
||||||
fn create_scalar_function<F, T>(&mut self,
|
fn create_scalar_function<F, T>(&mut self,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
n_arg: c_int,
|
n_arg: c_int,
|
||||||
deterministic: bool,
|
deterministic: bool,
|
||||||
x_func: F)
|
x_func: F)
|
||||||
-> SqliteResult<()>
|
-> Result<()>
|
||||||
where F: FnMut(&Context) -> SqliteResult<T>,
|
where F: FnMut(&Context) -> Result<T>,
|
||||||
T: ToResult
|
T: ToResult
|
||||||
{
|
{
|
||||||
extern "C" fn call_boxed_closure<F, T>(ctx: *mut sqlite3_context,
|
extern "C" fn call_boxed_closure<F, T>(ctx: *mut sqlite3_context,
|
||||||
argc: c_int,
|
argc: c_int,
|
||||||
argv: *mut *mut sqlite3_value)
|
argv: *mut *mut sqlite3_value)
|
||||||
where F: FnMut(&Context) -> SqliteResult<T>,
|
where F: FnMut(&Context) -> Result<T>,
|
||||||
T: ToResult
|
T: ToResult
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -452,7 +452,7 @@ impl InnerSqliteConnection {
|
|||||||
self.decode_result(r)
|
self.decode_result(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_function(&mut self, fn_name: &str, n_arg: c_int) -> SqliteResult<()> {
|
fn remove_function(&mut self, fn_name: &str, n_arg: c_int) -> Result<()> {
|
||||||
let c_name = try!(str_to_cstring(fn_name));
|
let c_name = try!(str_to_cstring(fn_name));
|
||||||
let r = unsafe {
|
let r = unsafe {
|
||||||
ffi::sqlite3_create_function_v2(self.db(),
|
ffi::sqlite3_create_function_v2(self.db(),
|
||||||
@ -477,11 +477,11 @@ mod test {
|
|||||||
use libc::c_double;
|
use libc::c_double;
|
||||||
use self::regex::Regex;
|
use self::regex::Regex;
|
||||||
|
|
||||||
use {SqliteConnection, SqliteError, SqliteResult};
|
use {Connection, Error, Result};
|
||||||
use ffi;
|
use ffi;
|
||||||
use functions::Context;
|
use functions::Context;
|
||||||
|
|
||||||
fn half(ctx: &Context) -> SqliteResult<c_double> {
|
fn half(ctx: &Context) -> Result<c_double> {
|
||||||
assert!(ctx.len() == 1, "called with unexpected number of arguments");
|
assert!(ctx.len() == 1, "called with unexpected number of arguments");
|
||||||
let value = try!(ctx.get::<c_double>(0));
|
let value = try!(ctx.get::<c_double>(0));
|
||||||
Ok(value / 2f64)
|
Ok(value / 2f64)
|
||||||
@ -489,7 +489,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_function_half() {
|
fn test_function_half() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
db.create_scalar_function("half", 1, true, half).unwrap();
|
db.create_scalar_function("half", 1, true, half).unwrap();
|
||||||
let result = db.query_row("SELECT half(6)", &[], |r| r.get::<f64>(0));
|
let result = db.query_row("SELECT half(6)", &[], |r| r.get::<f64>(0));
|
||||||
|
|
||||||
@ -498,7 +498,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_remove_function() {
|
fn test_remove_function() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
db.create_scalar_function("half", 1, true, half).unwrap();
|
db.create_scalar_function("half", 1, true, half).unwrap();
|
||||||
let result = db.query_row("SELECT half(6)", &[], |r| r.get::<f64>(0));
|
let result = db.query_row("SELECT half(6)", &[], |r| r.get::<f64>(0));
|
||||||
assert_eq!(3f64, result.unwrap());
|
assert_eq!(3f64, result.unwrap());
|
||||||
@ -511,7 +511,7 @@ mod test {
|
|||||||
// This implementation of a regexp scalar function uses SQLite's auxilliary data
|
// This implementation of a regexp scalar function uses SQLite's auxilliary data
|
||||||
// (https://www.sqlite.org/c3ref/get_auxdata.html) to avoid recompiling the regular
|
// (https://www.sqlite.org/c3ref/get_auxdata.html) to avoid recompiling the regular
|
||||||
// expression multiple times within one query.
|
// expression multiple times within one query.
|
||||||
fn regexp_with_auxilliary(ctx: &Context) -> SqliteResult<bool> {
|
fn regexp_with_auxilliary(ctx: &Context) -> Result<bool> {
|
||||||
assert!(ctx.len() == 2, "called with unexpected number of arguments");
|
assert!(ctx.len() == 2, "called with unexpected number of arguments");
|
||||||
|
|
||||||
let saved_re: Option<&Regex> = unsafe { ctx.get_aux(0) };
|
let saved_re: Option<&Regex> = unsafe { ctx.get_aux(0) };
|
||||||
@ -519,7 +519,7 @@ mod test {
|
|||||||
None => {
|
None => {
|
||||||
let s = try!(ctx.get::<String>(0));
|
let s = try!(ctx.get::<String>(0));
|
||||||
let r = try!(Regex::new(&s).map_err(|e| {
|
let r = try!(Regex::new(&s).map_err(|e| {
|
||||||
SqliteError {
|
Error {
|
||||||
code: ffi::SQLITE_ERROR,
|
code: ffi::SQLITE_ERROR,
|
||||||
message: format!("Invalid regular expression: {}", e),
|
message: format!("Invalid regular expression: {}", e),
|
||||||
}
|
}
|
||||||
@ -546,7 +546,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn test_function_regexp_with_auxilliary() {
|
fn test_function_regexp_with_auxilliary() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
db.execute_batch("BEGIN;
|
db.execute_batch("BEGIN;
|
||||||
CREATE TABLE foo (x string);
|
CREATE TABLE foo (x string);
|
||||||
INSERT INTO foo VALUES ('lisa');
|
INSERT INTO foo VALUES ('lisa');
|
||||||
@ -571,7 +571,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
fn test_function_regexp_with_hashmap_cache() {
|
fn test_function_regexp_with_hashmap_cache() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
db.execute_batch("BEGIN;
|
db.execute_batch("BEGIN;
|
||||||
CREATE TABLE foo (x string);
|
CREATE TABLE foo (x string);
|
||||||
INSERT INTO foo VALUES ('lisa');
|
INSERT INTO foo VALUES ('lisa');
|
||||||
@ -593,7 +593,7 @@ mod test {
|
|||||||
match entry {
|
match entry {
|
||||||
Occupied(occ) => occ.into_mut(),
|
Occupied(occ) => occ.into_mut(),
|
||||||
Vacant(vac) => {
|
Vacant(vac) => {
|
||||||
let r = try!(Regex::new(®ex_s).map_err(|e| SqliteError {
|
let r = try!(Regex::new(®ex_s).map_err(|e| Error {
|
||||||
code: ffi::SQLITE_ERROR,
|
code: ffi::SQLITE_ERROR,
|
||||||
message: format!("Invalid regular expression: {}", e),
|
message: format!("Invalid regular expression: {}", e),
|
||||||
}));
|
}));
|
||||||
@ -621,7 +621,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_varargs_function() {
|
fn test_varargs_function() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
db.create_scalar_function("my_concat", -1, true, |ctx| {
|
db.create_scalar_function("my_concat", -1, true, |ctx| {
|
||||||
let mut ret = String::new();
|
let mut ret = String::new();
|
||||||
|
|
||||||
|
406
src/lib.rs
406
src/lib.rs
File diff suppressed because it is too large
Load Diff
@ -1,32 +1,35 @@
|
|||||||
use {SqliteResult, SqliteConnection};
|
use {Result, Connection};
|
||||||
|
|
||||||
|
/// Old name for `LoadExtensionGuard`. `SqliteLoadExtensionGuard` is deprecated.
|
||||||
|
pub type SqliteLoadExtensionGuard<'conn> = LoadExtensionGuard<'conn>;
|
||||||
|
|
||||||
/// RAII guard temporarily enabling SQLite extensions to be loaded.
|
/// RAII guard temporarily enabling SQLite extensions to be loaded.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{SqliteConnection, SqliteResult, SqliteLoadExtensionGuard};
|
/// # use rusqlite::{Connection, Result, LoadExtensionGuard};
|
||||||
/// # use std::path::{Path};
|
/// # use std::path::{Path};
|
||||||
/// fn load_my_extension(conn: &SqliteConnection) -> SqliteResult<()> {
|
/// fn load_my_extension(conn: &Connection) -> Result<()> {
|
||||||
/// let _guard = try!(SqliteLoadExtensionGuard::new(conn));
|
/// let _guard = try!(LoadExtensionGuard::new(conn));
|
||||||
///
|
///
|
||||||
/// conn.load_extension(Path::new("my_sqlite_extension"), None)
|
/// conn.load_extension(Path::new("my_sqlite_extension"), None)
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct SqliteLoadExtensionGuard<'conn> {
|
pub struct LoadExtensionGuard<'conn> {
|
||||||
conn: &'conn SqliteConnection,
|
conn: &'conn Connection,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'conn> SqliteLoadExtensionGuard<'conn> {
|
impl<'conn> LoadExtensionGuard<'conn> {
|
||||||
/// Attempt to enable loading extensions. Loading extensions will be disabled when this
|
/// Attempt to enable loading extensions. Loading extensions will be disabled when this
|
||||||
/// guard goes out of scope. Cannot be meaningfully nested.
|
/// guard goes out of scope. Cannot be meaningfully nested.
|
||||||
pub fn new(conn: &SqliteConnection) -> SqliteResult<SqliteLoadExtensionGuard> {
|
pub fn new(conn: &Connection) -> Result<LoadExtensionGuard> {
|
||||||
conn.load_extension_enable().map(|_| SqliteLoadExtensionGuard { conn: conn })
|
conn.load_extension_enable().map(|_| LoadExtensionGuard { conn: conn })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_must_use)]
|
#[allow(unused_must_use)]
|
||||||
impl<'conn> Drop for SqliteLoadExtensionGuard<'conn> {
|
impl<'conn> Drop for LoadExtensionGuard<'conn> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.conn.load_extension_disable();
|
self.conn.load_extension_disable();
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,10 @@ use libc::c_int;
|
|||||||
|
|
||||||
use super::ffi;
|
use super::ffi;
|
||||||
|
|
||||||
use {SqliteResult, SqliteError, SqliteConnection, SqliteStatement, SqliteRows, SqliteRow,
|
use {Result, Error, Connection, Statement, Rows, Row, str_to_cstring};
|
||||||
str_to_cstring};
|
|
||||||
use types::ToSql;
|
use types::ToSql;
|
||||||
|
|
||||||
impl SqliteConnection {
|
impl Connection {
|
||||||
/// Convenience method to prepare and execute a single SQL statement with named parameter(s).
|
/// 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
|
/// On success, returns the number of rows that were changed or inserted or deleted (via
|
||||||
@ -15,8 +14,8 @@ impl SqliteConnection {
|
|||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{SqliteConnection, SqliteResult};
|
/// # use rusqlite::{Connection, Result};
|
||||||
/// fn insert(conn: &SqliteConnection) -> SqliteResult<i32> {
|
/// fn insert(conn: &Connection) -> Result<i32> {
|
||||||
/// conn.execute_named("INSERT INTO test (name) VALUES (:name)", &[(":name", &"one")])
|
/// conn.execute_named("INSERT INTO test (name) VALUES (:name)", &[(":name", &"one")])
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
@ -25,7 +24,7 @@ impl SqliteConnection {
|
|||||||
///
|
///
|
||||||
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
/// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
|
||||||
/// underlying SQLite call fails.
|
/// underlying SQLite call fails.
|
||||||
pub fn execute_named(&self, sql: &str, params: &[(&str, &ToSql)]) -> SqliteResult<c_int> {
|
pub fn execute_named(&self, sql: &str, params: &[(&str, &ToSql)]) -> Result<c_int> {
|
||||||
self.prepare(sql).and_then(|mut stmt| stmt.execute_named(params))
|
self.prepare(sql).and_then(|mut stmt| stmt.execute_named(params))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,8 +41,8 @@ impl SqliteConnection {
|
|||||||
sql: &str,
|
sql: &str,
|
||||||
params: &[(&str, &ToSql)],
|
params: &[(&str, &ToSql)],
|
||||||
f: F)
|
f: F)
|
||||||
-> SqliteResult<T>
|
-> Result<T>
|
||||||
where F: FnOnce(SqliteRow) -> T
|
where F: FnOnce(Row) -> T
|
||||||
{
|
{
|
||||||
let mut stmt = try!(self.prepare(sql));
|
let mut stmt = try!(self.prepare(sql));
|
||||||
let mut rows = try!(stmt.query_named(params));
|
let mut rows = try!(stmt.query_named(params));
|
||||||
@ -52,14 +51,14 @@ impl SqliteConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'conn> SqliteStatement<'conn> {
|
impl<'conn> Statement<'conn> {
|
||||||
/// Return the index of an SQL parameter given its name.
|
/// Return the index of an SQL parameter given its name.
|
||||||
///
|
///
|
||||||
/// # Failure
|
/// # Failure
|
||||||
///
|
///
|
||||||
/// Will return Err if `name` is invalid. Will return Ok(None) if the name
|
/// Will return Err if `name` is invalid. Will return Ok(None) if the name
|
||||||
/// is valid but not a bound parameter of this statement.
|
/// is valid but not a bound parameter of this statement.
|
||||||
pub fn parameter_index(&self, name: &str) -> SqliteResult<Option<i32>> {
|
pub fn parameter_index(&self, name: &str) -> Result<Option<i32>> {
|
||||||
let c_name = try!(str_to_cstring(name));
|
let c_name = try!(str_to_cstring(name));
|
||||||
let c_index = unsafe { ffi::sqlite3_bind_parameter_index(self.stmt, c_name.as_ptr()) };
|
let c_index = unsafe { ffi::sqlite3_bind_parameter_index(self.stmt, c_name.as_ptr()) };
|
||||||
Ok(match c_index {
|
Ok(match c_index {
|
||||||
@ -79,8 +78,8 @@ impl<'conn> SqliteStatement<'conn> {
|
|||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{SqliteConnection, SqliteResult};
|
/// # use rusqlite::{Connection, Result};
|
||||||
/// fn insert(conn: &SqliteConnection) -> SqliteResult<i32> {
|
/// fn insert(conn: &Connection) -> Result<i32> {
|
||||||
/// let mut stmt = try!(conn.prepare("INSERT INTO test (name) VALUES (:name)"));
|
/// let mut stmt = try!(conn.prepare("INSERT INTO test (name) VALUES (:name)"));
|
||||||
/// stmt.execute_named(&[(":name", &"one")])
|
/// stmt.execute_named(&[(":name", &"one")])
|
||||||
/// }
|
/// }
|
||||||
@ -90,7 +89,7 @@ impl<'conn> SqliteStatement<'conn> {
|
|||||||
///
|
///
|
||||||
/// Will return `Err` if binding parameters fails, the executed statement returns rows (in
|
/// 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.
|
/// 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> {
|
pub fn execute_named(&mut self, params: &[(&str, &ToSql)]) -> Result<c_int> {
|
||||||
try!(self.bind_parameters_named(params));
|
try!(self.bind_parameters_named(params));
|
||||||
unsafe {
|
unsafe {
|
||||||
self.execute_()
|
self.execute_()
|
||||||
@ -105,8 +104,8 @@ impl<'conn> SqliteStatement<'conn> {
|
|||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{SqliteConnection, SqliteResult, SqliteRows};
|
/// # use rusqlite::{Connection, Result, Rows};
|
||||||
/// fn query(conn: &SqliteConnection) -> SqliteResult<()> {
|
/// fn query(conn: &Connection) -> Result<()> {
|
||||||
/// let mut stmt = try!(conn.prepare("SELECT * FROM test where name = :name"));
|
/// let mut stmt = try!(conn.prepare("SELECT * FROM test where name = :name"));
|
||||||
/// let mut rows = try!(stmt.query_named(&[(":name", &"one")]));
|
/// let mut rows = try!(stmt.query_named(&[(":name", &"one")]));
|
||||||
/// for row in rows {
|
/// for row in rows {
|
||||||
@ -121,20 +120,20 @@ impl<'conn> SqliteStatement<'conn> {
|
|||||||
/// Will return `Err` if binding parameters fails.
|
/// Will return `Err` if binding parameters fails.
|
||||||
pub fn query_named<'a>(&'a mut self,
|
pub fn query_named<'a>(&'a mut self,
|
||||||
params: &[(&str, &ToSql)])
|
params: &[(&str, &ToSql)])
|
||||||
-> SqliteResult<SqliteRows<'a>> {
|
-> Result<Rows<'a>> {
|
||||||
self.reset_if_needed();
|
self.reset_if_needed();
|
||||||
try!(self.bind_parameters_named(params));
|
try!(self.bind_parameters_named(params));
|
||||||
|
|
||||||
self.needs_reset = true;
|
self.needs_reset = true;
|
||||||
Ok(SqliteRows::new(self))
|
Ok(Rows::new(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind_parameters_named(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<()> {
|
fn bind_parameters_named(&mut self, params: &[(&str, &ToSql)]) -> Result<()> {
|
||||||
for &(name, value) in params {
|
for &(name, value) in params {
|
||||||
if let Some(i) = try!(self.parameter_index(name)) {
|
if let Some(i) = try!(self.parameter_index(name)) {
|
||||||
try!(self.conn.decode_result(unsafe { value.bind_parameter(self.stmt, i) }));
|
try!(self.conn.decode_result(unsafe { value.bind_parameter(self.stmt, i) }));
|
||||||
} else {
|
} else {
|
||||||
return Err(SqliteError {
|
return Err(Error {
|
||||||
code: ffi::SQLITE_MISUSE,
|
code: ffi::SQLITE_MISUSE,
|
||||||
message: format!("Invalid parameter name: {}", name),
|
message: format!("Invalid parameter name: {}", name),
|
||||||
});
|
});
|
||||||
@ -146,11 +145,11 @@ impl<'conn> SqliteStatement<'conn> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use SqliteConnection;
|
use Connection;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_execute_named() {
|
fn test_execute_named() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap();
|
db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap();
|
||||||
|
|
||||||
assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)]).unwrap(),
|
assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)]).unwrap(),
|
||||||
@ -167,7 +166,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_stmt_execute_named() {
|
fn test_stmt_execute_named() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
|
let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
|
||||||
INTEGER)";
|
INTEGER)";
|
||||||
db.execute_batch(sql).unwrap();
|
db.execute_batch(sql).unwrap();
|
||||||
@ -184,7 +183,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_query_named() {
|
fn test_query_named() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
|
let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
|
||||||
INTEGER)";
|
INTEGER)";
|
||||||
db.execute_batch(sql).unwrap();
|
db.execute_batch(sql).unwrap();
|
||||||
@ -195,7 +194,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unbound_parameters_are_null() {
|
fn test_unbound_parameters_are_null() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
let sql = "CREATE TABLE test (x TEXT, y TEXT)";
|
let sql = "CREATE TABLE test (x TEXT, y TEXT)";
|
||||||
db.execute_batch(sql).unwrap();
|
db.execute_batch(sql).unwrap();
|
||||||
|
|
||||||
@ -209,7 +208,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unbound_parameters_are_reused() {
|
fn test_unbound_parameters_are_reused() {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
let sql = "CREATE TABLE test (x TEXT, y TEXT)";
|
let sql = "CREATE TABLE test (x TEXT, y TEXT)";
|
||||||
db.execute_batch(sql).unwrap();
|
db.execute_batch(sql).unwrap();
|
||||||
|
|
||||||
|
14
src/trace.rs
14
src/trace.rs
@ -8,7 +8,7 @@ use std::str;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use super::ffi;
|
use super::ffi;
|
||||||
use {SqliteError, SqliteResult, SqliteConnection};
|
use {Error, Result, Connection};
|
||||||
|
|
||||||
/// Set up the process-wide SQLite error logging callback.
|
/// Set up the process-wide SQLite error logging callback.
|
||||||
/// This function is marked unsafe for two reasons:
|
/// This function is marked unsafe for two reasons:
|
||||||
@ -21,7 +21,7 @@ use {SqliteError, SqliteResult, SqliteConnection};
|
|||||||
/// * It must be threadsafe if SQLite is used in a multithreaded way.
|
/// * It must be threadsafe if SQLite is used in a multithreaded way.
|
||||||
///
|
///
|
||||||
/// cf [The Error And Warning Log](http://sqlite.org/errlog.html).
|
/// cf [The Error And Warning Log](http://sqlite.org/errlog.html).
|
||||||
pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> SqliteResult<()> {
|
pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> Result<()> {
|
||||||
extern "C" fn log_callback(p_arg: *mut c_void, err: c_int, msg: *const c_char) {
|
extern "C" fn log_callback(p_arg: *mut c_void, err: c_int, msg: *const c_char) {
|
||||||
let c_slice = unsafe { CStr::from_ptr(msg).to_bytes() };
|
let c_slice = unsafe { CStr::from_ptr(msg).to_bytes() };
|
||||||
let callback: fn(c_int, &str) = unsafe { mem::transmute(p_arg) };
|
let callback: fn(c_int, &str) = unsafe { mem::transmute(p_arg) };
|
||||||
@ -43,7 +43,7 @@ pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> SqliteResult<()>
|
|||||||
};
|
};
|
||||||
|
|
||||||
if rc != ffi::SQLITE_OK {
|
if rc != ffi::SQLITE_OK {
|
||||||
return Err(SqliteError {
|
return Err(Error {
|
||||||
code: rc,
|
code: rc,
|
||||||
message: "sqlite3_config(SQLITE_CONFIG_LOG, ...)".to_string(),
|
message: "sqlite3_config(SQLITE_CONFIG_LOG, ...)".to_string(),
|
||||||
});
|
});
|
||||||
@ -60,7 +60,7 @@ pub fn log(err_code: c_int, msg: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SqliteConnection {
|
impl Connection {
|
||||||
/// Register or clear a callback function that can be used for tracing the execution of SQL statements.
|
/// Register or clear a callback function that can be used for tracing the execution of SQL statements.
|
||||||
///
|
///
|
||||||
/// Prepared statement placeholders are replaced/logged with their assigned values.
|
/// Prepared statement placeholders are replaced/logged with their assigned values.
|
||||||
@ -120,7 +120,7 @@ mod test {
|
|||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use SqliteConnection;
|
use Connection;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_trace() {
|
fn test_trace() {
|
||||||
@ -132,7 +132,7 @@ mod test {
|
|||||||
traced_stmts.push(s.to_owned());
|
traced_stmts.push(s.to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut db = SqliteConnection::open_in_memory().unwrap();
|
let mut db = Connection::open_in_memory().unwrap();
|
||||||
db.trace(Some(tracer));
|
db.trace(Some(tracer));
|
||||||
{
|
{
|
||||||
let _ = db.query_row("SELECT ?", &[&1i32], |_| {});
|
let _ = db.query_row("SELECT ?", &[&1i32], |_| {});
|
||||||
@ -160,7 +160,7 @@ mod test {
|
|||||||
profiled.push((s.to_owned(), d));
|
profiled.push((s.to_owned(), d));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut db = SqliteConnection::open_in_memory().unwrap();
|
let mut db = Connection::open_in_memory().unwrap();
|
||||||
db.profile(Some(profiler));
|
db.profile(Some(profiler));
|
||||||
db.execute_batch("PRAGMA application_id = 1").unwrap();
|
db.execute_batch("PRAGMA application_id = 1").unwrap();
|
||||||
db.profile(None);
|
db.profile(None);
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
use {SqliteResult, SqliteConnection};
|
use {Result, Connection};
|
||||||
|
|
||||||
pub use SqliteTransactionBehavior::{SqliteTransactionDeferred, SqliteTransactionImmediate,
|
/// Old name for `TransactionBehavior`. `SqliteTransactionBehavior` is deprecated.
|
||||||
SqliteTransactionExclusive};
|
pub type SqliteTransactionBehavior = TransactionBehavior;
|
||||||
|
|
||||||
/// Options for transaction behavior. See [BEGIN
|
/// Options for transaction behavior. See [BEGIN
|
||||||
/// TRANSACTION](http://www.sqlite.org/lang_transaction.html) for details.
|
/// TRANSACTION](http://www.sqlite.org/lang_transaction.html) for details.
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub enum SqliteTransactionBehavior {
|
pub enum TransactionBehavior {
|
||||||
SqliteTransactionDeferred,
|
Deferred,
|
||||||
SqliteTransactionImmediate,
|
Immediate,
|
||||||
SqliteTransactionExclusive,
|
Exclusive,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Old name for `Transaction`. `SqliteTransaction` is deprecated.
|
||||||
|
pub type SqliteTransaction<'conn> = Transaction<'conn>;
|
||||||
|
|
||||||
|
///
|
||||||
/// Represents a transaction on a database connection.
|
/// Represents a transaction on a database connection.
|
||||||
///
|
///
|
||||||
/// ## Note
|
/// ## Note
|
||||||
@ -22,10 +26,10 @@ pub enum SqliteTransactionBehavior {
|
|||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{SqliteConnection, SqliteResult};
|
/// # use rusqlite::{Connection, Result};
|
||||||
/// # fn do_queries_part_1(conn: &SqliteConnection) -> SqliteResult<()> { Ok(()) }
|
/// # fn do_queries_part_1(conn: &Connection) -> Result<()> { Ok(()) }
|
||||||
/// # fn do_queries_part_2(conn: &SqliteConnection) -> SqliteResult<()> { Ok(()) }
|
/// # fn do_queries_part_2(conn: &Connection) -> Result<()> { Ok(()) }
|
||||||
/// fn perform_queries(conn: &SqliteConnection) -> SqliteResult<()> {
|
/// fn perform_queries(conn: &Connection) -> Result<()> {
|
||||||
/// let tx = try!(conn.transaction());
|
/// let tx = try!(conn.transaction());
|
||||||
///
|
///
|
||||||
/// try!(do_queries_part_1(conn)); // tx causes rollback if this fails
|
/// try!(do_queries_part_1(conn)); // tx causes rollback if this fails
|
||||||
@ -34,25 +38,25 @@ pub enum SqliteTransactionBehavior {
|
|||||||
/// tx.commit()
|
/// tx.commit()
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct SqliteTransaction<'conn> {
|
pub struct Transaction<'conn> {
|
||||||
conn: &'conn SqliteConnection,
|
conn: &'conn Connection,
|
||||||
depth: u32,
|
depth: u32,
|
||||||
commit: bool,
|
commit: bool,
|
||||||
finished: bool,
|
finished: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'conn> SqliteTransaction<'conn> {
|
impl<'conn> Transaction<'conn> {
|
||||||
/// Begin a new transaction. Cannot be nested; see `savepoint` for nested transactions.
|
/// Begin a new transaction. Cannot be nested; see `savepoint` for nested transactions.
|
||||||
pub fn new(conn: &SqliteConnection,
|
pub fn new(conn: &Connection,
|
||||||
behavior: SqliteTransactionBehavior)
|
behavior: TransactionBehavior)
|
||||||
-> SqliteResult<SqliteTransaction> {
|
-> Result<Transaction> {
|
||||||
let query = match behavior {
|
let query = match behavior {
|
||||||
SqliteTransactionDeferred => "BEGIN DEFERRED",
|
TransactionBehavior::Deferred => "BEGIN DEFERRED",
|
||||||
SqliteTransactionImmediate => "BEGIN IMMEDIATE",
|
TransactionBehavior::Immediate => "BEGIN IMMEDIATE",
|
||||||
SqliteTransactionExclusive => "BEGIN EXCLUSIVE",
|
TransactionBehavior::Exclusive => "BEGIN EXCLUSIVE",
|
||||||
};
|
};
|
||||||
conn.execute_batch(query).map(|_| {
|
conn.execute_batch(query).map(|_| {
|
||||||
SqliteTransaction {
|
Transaction {
|
||||||
conn: conn,
|
conn: conn,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
commit: false,
|
commit: false,
|
||||||
@ -71,9 +75,9 @@ impl<'conn> SqliteTransaction<'conn> {
|
|||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use rusqlite::{SqliteConnection, SqliteResult};
|
/// # use rusqlite::{Connection, Result};
|
||||||
/// # fn perform_queries_part_1_succeeds(conn: &SqliteConnection) -> bool { true }
|
/// # fn perform_queries_part_1_succeeds(conn: &Connection) -> bool { true }
|
||||||
/// fn perform_queries(conn: &SqliteConnection) -> SqliteResult<()> {
|
/// fn perform_queries(conn: &Connection) -> Result<()> {
|
||||||
/// let tx = try!(conn.transaction());
|
/// let tx = try!(conn.transaction());
|
||||||
///
|
///
|
||||||
/// {
|
/// {
|
||||||
@ -87,9 +91,9 @@ impl<'conn> SqliteTransaction<'conn> {
|
|||||||
/// tx.commit()
|
/// tx.commit()
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn savepoint<'a>(&'a self) -> SqliteResult<SqliteTransaction<'a>> {
|
pub fn savepoint<'a>(&'a self) -> Result<Transaction<'a>> {
|
||||||
self.conn.execute_batch("SAVEPOINT sp").map(|_| {
|
self.conn.execute_batch("SAVEPOINT sp").map(|_| {
|
||||||
SqliteTransaction {
|
Transaction {
|
||||||
conn: self.conn,
|
conn: self.conn,
|
||||||
depth: self.depth + 1,
|
depth: self.depth + 1,
|
||||||
commit: false,
|
commit: false,
|
||||||
@ -119,11 +123,11 @@ impl<'conn> SqliteTransaction<'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience method which consumes and commits a transaction.
|
/// A convenience method which consumes and commits a transaction.
|
||||||
pub fn commit(mut self) -> SqliteResult<()> {
|
pub fn commit(mut self) -> Result<()> {
|
||||||
self.commit_()
|
self.commit_()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit_(&mut self) -> SqliteResult<()> {
|
fn commit_(&mut self) -> Result<()> {
|
||||||
self.finished = true;
|
self.finished = true;
|
||||||
self.conn.execute_batch(if self.depth == 0 {
|
self.conn.execute_batch(if self.depth == 0 {
|
||||||
"COMMIT"
|
"COMMIT"
|
||||||
@ -133,11 +137,11 @@ impl<'conn> SqliteTransaction<'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience method which consumes and rolls back a transaction.
|
/// A convenience method which consumes and rolls back a transaction.
|
||||||
pub fn rollback(mut self) -> SqliteResult<()> {
|
pub fn rollback(mut self) -> Result<()> {
|
||||||
self.rollback_()
|
self.rollback_()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rollback_(&mut self) -> SqliteResult<()> {
|
fn rollback_(&mut self) -> Result<()> {
|
||||||
self.finished = true;
|
self.finished = true;
|
||||||
self.conn.execute_batch(if self.depth == 0 {
|
self.conn.execute_batch(if self.depth == 0 {
|
||||||
"ROLLBACK"
|
"ROLLBACK"
|
||||||
@ -151,11 +155,11 @@ impl<'conn> SqliteTransaction<'conn> {
|
|||||||
///
|
///
|
||||||
/// Functionally equivalent to the `Drop` implementation, but allows callers to see any
|
/// Functionally equivalent to the `Drop` implementation, but allows callers to see any
|
||||||
/// errors that occur.
|
/// errors that occur.
|
||||||
pub fn finish(mut self) -> SqliteResult<()> {
|
pub fn finish(mut self) -> Result<()> {
|
||||||
self.finish_()
|
self.finish_()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_(&mut self) -> SqliteResult<()> {
|
fn finish_(&mut self) -> Result<()> {
|
||||||
match (self.finished, self.commit) {
|
match (self.finished, self.commit) {
|
||||||
(true, _) => Ok(()),
|
(true, _) => Ok(()),
|
||||||
(false, true) => self.commit_(),
|
(false, true) => self.commit_(),
|
||||||
@ -165,7 +169,7 @@ impl<'conn> SqliteTransaction<'conn> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_must_use)]
|
#[allow(unused_must_use)]
|
||||||
impl<'conn> Drop for SqliteTransaction<'conn> {
|
impl<'conn> Drop for Transaction<'conn> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.finish_();
|
self.finish_();
|
||||||
}
|
}
|
||||||
@ -173,10 +177,10 @@ impl<'conn> Drop for SqliteTransaction<'conn> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use SqliteConnection;
|
use Connection;
|
||||||
|
|
||||||
fn checked_memory_handle() -> SqliteConnection {
|
fn checked_memory_handle() -> Connection {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
db.execute_batch("CREATE TABLE foo (x INTEGER)").unwrap();
|
db.execute_batch("CREATE TABLE foo (x INTEGER)").unwrap();
|
||||||
db
|
db
|
||||||
}
|
}
|
||||||
|
36
src/types.rs
36
src/types.rs
@ -26,7 +26,7 @@
|
|||||||
//! extern crate libc;
|
//! extern crate libc;
|
||||||
//!
|
//!
|
||||||
//! use rusqlite::types::{FromSql, ToSql, sqlite3_stmt};
|
//! use rusqlite::types::{FromSql, ToSql, sqlite3_stmt};
|
||||||
//! use rusqlite::{SqliteResult};
|
//! use rusqlite::{Result};
|
||||||
//! use libc::c_int;
|
//! use libc::c_int;
|
||||||
//! use time;
|
//! use time;
|
||||||
//!
|
//!
|
||||||
@ -34,7 +34,7 @@
|
|||||||
//!
|
//!
|
||||||
//! impl FromSql for TimespecSql {
|
//! impl FromSql for TimespecSql {
|
||||||
//! unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int)
|
//! unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int)
|
||||||
//! -> SqliteResult<TimespecSql> {
|
//! -> Result<TimespecSql> {
|
||||||
//! let as_f64_result = FromSql::column_result(stmt, col);
|
//! let as_f64_result = FromSql::column_result(stmt, col);
|
||||||
//! as_f64_result.map(|as_f64: f64| {
|
//! as_f64_result.map(|as_f64: f64| {
|
||||||
//! TimespecSql(time::Timespec{ sec: as_f64.trunc() as i64,
|
//! TimespecSql(time::Timespec{ sec: as_f64.trunc() as i64,
|
||||||
@ -59,7 +59,7 @@ use std::ffi::CStr;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::str;
|
use std::str;
|
||||||
use super::ffi;
|
use super::ffi;
|
||||||
use super::{SqliteResult, SqliteError, str_to_cstring};
|
use super::{Result, Error, str_to_cstring};
|
||||||
|
|
||||||
pub use ffi::sqlite3_stmt;
|
pub use ffi::sqlite3_stmt;
|
||||||
pub use ffi::sqlite3_column_type;
|
pub use ffi::sqlite3_column_type;
|
||||||
@ -75,11 +75,11 @@ pub trait ToSql {
|
|||||||
|
|
||||||
/// A trait for types that can be created from a SQLite value.
|
/// A trait for types that can be created from a SQLite value.
|
||||||
pub trait FromSql: Sized {
|
pub trait FromSql: Sized {
|
||||||
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> SqliteResult<Self>;
|
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<Self>;
|
||||||
|
|
||||||
/// FromSql types can implement this method and use sqlite3_column_type to check that
|
/// FromSql types can implement this method and use sqlite3_column_type to check that
|
||||||
/// the type reported by SQLite matches a type suitable for Self. This method is used
|
/// the type reported by SQLite matches a type suitable for Self. This method is used
|
||||||
/// by `SqliteRow::get_checked` to confirm that the column contains a valid type before
|
/// by `Row::get_checked` to confirm that the column contains a valid type before
|
||||||
/// attempting to retrieve the value.
|
/// attempting to retrieve the value.
|
||||||
unsafe fn column_has_valid_sqlite_type(_: *mut sqlite3_stmt, _: c_int) -> bool {
|
unsafe fn column_has_valid_sqlite_type(_: *mut sqlite3_stmt, _: c_int) -> bool {
|
||||||
true
|
true
|
||||||
@ -176,12 +176,12 @@ impl<T: ToSql> ToSql for Option<T> {
|
|||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # extern crate libc;
|
/// # extern crate libc;
|
||||||
/// # extern crate rusqlite;
|
/// # extern crate rusqlite;
|
||||||
/// # use rusqlite::{SqliteConnection, SqliteResult};
|
/// # use rusqlite::{Connection, Result};
|
||||||
/// # use rusqlite::types::{Null};
|
/// # use rusqlite::types::{Null};
|
||||||
/// # use libc::{c_int};
|
/// # use libc::{c_int};
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// }
|
/// }
|
||||||
/// fn insert_null(conn: &SqliteConnection) -> SqliteResult<c_int> {
|
/// fn insert_null(conn: &Connection) -> Result<c_int> {
|
||||||
/// conn.execute("INSERT INTO people (name) VALUES (?)", &[&Null])
|
/// conn.execute("INSERT INTO people (name) VALUES (?)", &[&Null])
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
@ -197,7 +197,7 @@ impl ToSql for Null {
|
|||||||
macro_rules! raw_from_impl(
|
macro_rules! raw_from_impl(
|
||||||
($t:ty, $f:ident, $c:expr) => (
|
($t:ty, $f:ident, $c:expr) => (
|
||||||
impl FromSql for $t {
|
impl FromSql for $t {
|
||||||
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> SqliteResult<$t> {
|
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<$t> {
|
||||||
Ok(ffi::$f(stmt, col))
|
Ok(ffi::$f(stmt, col))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ raw_from_impl!(i64, sqlite3_column_int64, ffi::SQLITE_INTEGER);
|
|||||||
raw_from_impl!(c_double, sqlite3_column_double, ffi::SQLITE_FLOAT);
|
raw_from_impl!(c_double, sqlite3_column_double, ffi::SQLITE_FLOAT);
|
||||||
|
|
||||||
impl FromSql for bool {
|
impl FromSql for bool {
|
||||||
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> SqliteResult<bool> {
|
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<bool> {
|
||||||
match ffi::sqlite3_column_int(stmt, col) {
|
match ffi::sqlite3_column_int(stmt, col) {
|
||||||
0 => Ok(false),
|
0 => Ok(false),
|
||||||
_ => Ok(true),
|
_ => Ok(true),
|
||||||
@ -226,7 +226,7 @@ impl FromSql for bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for String {
|
impl FromSql for String {
|
||||||
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> SqliteResult<String> {
|
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<String> {
|
||||||
let c_text = ffi::sqlite3_column_text(stmt, col);
|
let c_text = ffi::sqlite3_column_text(stmt, col);
|
||||||
if c_text.is_null() {
|
if c_text.is_null() {
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
@ -235,7 +235,7 @@ impl FromSql for String {
|
|||||||
let utf8_str = str::from_utf8(c_slice);
|
let utf8_str = str::from_utf8(c_slice);
|
||||||
utf8_str.map(|s| s.to_string())
|
utf8_str.map(|s| s.to_string())
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
SqliteError {
|
Error {
|
||||||
code: 0,
|
code: 0,
|
||||||
message: e.to_string(),
|
message: e.to_string(),
|
||||||
}
|
}
|
||||||
@ -249,7 +249,7 @@ impl FromSql for String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for Vec<u8> {
|
impl FromSql for Vec<u8> {
|
||||||
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> SqliteResult<Vec<u8>> {
|
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<Vec<u8>> {
|
||||||
use std::slice::from_raw_parts;
|
use std::slice::from_raw_parts;
|
||||||
let c_blob = ffi::sqlite3_column_blob(stmt, col);
|
let c_blob = ffi::sqlite3_column_blob(stmt, col);
|
||||||
let len = ffi::sqlite3_column_bytes(stmt, col);
|
let len = ffi::sqlite3_column_bytes(stmt, col);
|
||||||
@ -269,13 +269,13 @@ impl FromSql for Vec<u8> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for time::Timespec {
|
impl FromSql for time::Timespec {
|
||||||
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> SqliteResult<time::Timespec> {
|
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<time::Timespec> {
|
||||||
let col_str = FromSql::column_result(stmt, col);
|
let col_str = FromSql::column_result(stmt, col);
|
||||||
col_str.and_then(|txt: String| {
|
col_str.and_then(|txt: String| {
|
||||||
time::strptime(&txt, SQLITE_DATETIME_FMT)
|
time::strptime(&txt, SQLITE_DATETIME_FMT)
|
||||||
.map(|tm| tm.to_timespec())
|
.map(|tm| tm.to_timespec())
|
||||||
.map_err(|parse_error| {
|
.map_err(|parse_error| {
|
||||||
SqliteError {
|
Error {
|
||||||
code: ffi::SQLITE_MISMATCH,
|
code: ffi::SQLITE_MISMATCH,
|
||||||
message: format!("{}", parse_error),
|
message: format!("{}", parse_error),
|
||||||
}
|
}
|
||||||
@ -289,7 +289,7 @@ impl FromSql for time::Timespec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FromSql> FromSql for Option<T> {
|
impl<T: FromSql> FromSql for Option<T> {
|
||||||
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> SqliteResult<Option<T>> {
|
unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<Option<T>> {
|
||||||
if sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL {
|
if sqlite3_column_type(stmt, col) == ffi::SQLITE_NULL {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
@ -305,13 +305,13 @@ impl<T: FromSql> FromSql for Option<T> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use SqliteConnection;
|
use Connection;
|
||||||
use ffi;
|
use ffi;
|
||||||
use super::time;
|
use super::time;
|
||||||
use libc::{c_int, c_double};
|
use libc::{c_int, c_double};
|
||||||
|
|
||||||
fn checked_memory_handle() -> SqliteConnection {
|
fn checked_memory_handle() -> Connection {
|
||||||
let db = SqliteConnection::open_in_memory().unwrap();
|
let db = Connection::open_in_memory().unwrap();
|
||||||
db.execute_batch("CREATE TABLE foo (b BLOB, t TEXT, i INTEGER, f FLOAT, n)").unwrap();
|
db.execute_batch("CREATE TABLE foo (b BLOB, t TEXT, i INTEGER, f FLOAT, n)").unwrap();
|
||||||
db
|
db
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user