Skip to content
This repository was archived by the owner on Jul 25, 2020. It is now read-only.

Fix various mutability problems. #104

Merged
merged 1 commit into from
Jul 30, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use types::*;
/// The database cursor.
pub struct Cursor<'db> {
stmt: *mut stmt,
_dbh: &'db *mut dbh
_dbh: &'db *mut dbh // make this non-`Send`able
}

pub fn cursor_with_statement<'db>(stmt: *mut stmt, dbh: &'db *mut dbh) -> Cursor<'db> {
Expand All @@ -65,30 +65,30 @@ impl<'db> Cursor<'db> {

/// Resets a prepared SQL statement, but does not reset its bindings.
/// See http://www.sqlite.org/c3ref/reset.html
pub fn reset(&self) -> ResultCode {
pub fn reset(&mut self) -> ResultCode {
unsafe {
sqlite3_reset(self.stmt)
}
}

/// Resets all bindings on a prepared SQL statement.
/// See http://www.sqlite.org/c3ref/clear_bindings.html
pub fn clear_bindings(&self) -> ResultCode {
pub fn clear_bindings(&mut self) -> ResultCode {
unsafe {
sqlite3_clear_bindings(self.stmt)
}
}

/// Evaluates a prepared SQL statement one ore more times.
/// See http://www.sqlite.org/c3ref/step.html
pub fn step(&self) -> ResultCode {
pub fn step(&mut self) -> ResultCode {
unsafe {
sqlite3_step(self.stmt)
}
}

///
pub fn step_row(&self) -> SqliteResult<Option<RowMap>> {
pub fn step_row(&mut self) -> SqliteResult<Option<RowMap>> {
let is_row: ResultCode = self.step();
if is_row == SQLITE_ROW {
let column_cnt = self.get_column_count();
Expand Down Expand Up @@ -121,7 +121,7 @@ impl<'db> Cursor<'db> {

///
/// See http://www.sqlite.org/c3ref/column_blob.html
pub fn get_blob<'a>(&'a self, i: int) -> Option<&'a [u8]> {
pub fn get_blob<'a>(&'a mut self, i: int) -> Option<&'a [u8]> {
let ptr = unsafe {sqlite3_column_blob(self.stmt, i as c_int)};
let len = unsafe {sqlite3_column_bytes(self.stmt, i as c_int)} as uint;
if ptr.is_null() {
Expand All @@ -134,31 +134,31 @@ impl<'db> Cursor<'db> {

///
/// See http://www.sqlite.org/c3ref/column_blob.html
pub fn get_int(&self, i: int) -> int {
pub fn get_int(&mut self, i: int) -> int {
unsafe {
return sqlite3_column_int(self.stmt, i as c_int) as int;
}
}

///
/// See http://www.sqlite.org/c3ref/column_blob.html
pub fn get_i64(&self, i: int) -> i64 {
pub fn get_i64(&mut self, i: int) -> i64 {
unsafe {
return sqlite3_column_int64(self.stmt, i as c_int) as i64;
}
}

///
/// See http://www.sqlite.org/c3ref/column_blob.html
pub fn get_f64(&self, i: int) -> f64 {
pub fn get_f64(&mut self, i: int) -> f64 {
unsafe {
return sqlite3_column_double(self.stmt, i as c_int);
}
}

///
/// See http://www.sqlite.org/c3ref/column_blob.html
pub fn get_text<'a>(&'a self, i: int) -> Option<&'a str> {
pub fn get_text<'a>(&'a mut self, i: int) -> Option<&'a str> {
let ptr = unsafe {sqlite3_column_text(self.stmt, i as c_int)};
let len = unsafe {sqlite3_column_bytes(self.stmt, i as c_int)} as uint;
if ptr.is_null() {
Expand Down Expand Up @@ -233,7 +233,7 @@ impl<'db> Cursor<'db> {
}

///
pub fn bind_params(&self, values: &[BindArg]) -> ResultCode {
pub fn bind_params(&mut self, values: &[BindArg]) -> ResultCode {
// SQL parameter index (starting from 1).
let mut i = 1i;
for v in values.iter() {
Expand All @@ -248,7 +248,7 @@ impl<'db> Cursor<'db> {

///
/// See http://www.sqlite.org/c3ref/bind_blob.html
pub fn bind_param(&self, i: int, value: &BindArg) -> ResultCode {
pub fn bind_param(&mut self, i: int, value: &BindArg) -> ResultCode {

debug!("`Cursor.bind_param()`: stmt={:?}", self.stmt);

Expand Down
7 changes: 5 additions & 2 deletions src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,20 @@ use ffi::*;
use libc::c_int;
use std::ptr;
use std::string;
use std::kinds::marker;
use types::*;

/// The database connection.
pub struct Database {
dbh: *mut dbh,
_marker: marker::NoSend // make this non-`Send`able
}

pub fn database_with_handle(dbh: *mut dbh) -> Database {
Database { dbh: dbh }
Database { dbh: dbh, _marker: marker::NoSend }
}

#[unsafe_destructor]
impl Drop for Database {
/// Closes the database connection.
/// See http://www.sqlite.org/c3ref/close.html
Expand Down Expand Up @@ -115,7 +118,7 @@ impl Database {

/// Sets a busy timeout.
/// See http://www.sqlite.org/c3ref/busy_timeout.html
pub fn set_busy_timeout(&self, ms: int) -> ResultCode {
pub fn set_busy_timeout(&mut self, ms: int) -> ResultCode {
unsafe {
sqlite3_busy_timeout(self.dbh, ms as c_int)
}
Expand Down
62 changes: 47 additions & 15 deletions src/sqlite3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ mod tests {
let database = checked_open();

checked_exec(&database, "BEGIN; CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT); COMMIT;");
let sth = checked_prepare(&database, "INSERT OR IGNORE INTO test (id) VALUES (1)");
let mut sth = checked_prepare(&database, "INSERT OR IGNORE INTO test (id) VALUES (1)");
let res = sth.step();
debug!("test `prepare_insert_stmt`: res={:?}", res);
}
Expand All @@ -153,7 +153,7 @@ mod tests {
COMMIT;"
);

let sth = checked_prepare(&database, "SELECT id FROM test WHERE id = 1;");
let mut sth = checked_prepare(&database, "SELECT id FROM test WHERE id = 1;");
assert!(sth.step() == SQLITE_ROW);
assert!(sth.get_int(0) == 1);
assert!(sth.step() == SQLITE_DONE);
Expand All @@ -170,7 +170,7 @@ mod tests {
COMMIT;"
);

let sth = checked_prepare(&database, "SELECT v FROM test WHERE id = 1;");
let mut sth = checked_prepare(&database, "SELECT v FROM test WHERE id = 1;");
assert!(sth.step() == SQLITE_ROW);
assert!(sth.get_blob(0) == Some([0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff].as_slice()));
assert!(sth.step() == SQLITE_DONE);
Expand All @@ -187,7 +187,7 @@ mod tests {
INSERT OR IGNORE INTO test (id) VALUES(3);
INSERT OR IGNORE INTO test (id) VALUES(4);"
);
let sth = checked_prepare(&database, "SELECT id FROM test WHERE id > ? AND id < ?");
let mut sth = checked_prepare(&database, "SELECT id FROM test WHERE id > ? AND id < ?");
assert!(sth.bind_param(1, &Integer(2)) == SQLITE_OK);
assert!(sth.bind_param(2, &Integer(4)) == SQLITE_OK);

Expand All @@ -205,7 +205,7 @@ mod tests {
"INSERT OR IGNORE INTO test (id) VALUES(0);
INSERT OR IGNORE INTO test (id) VALUES(1234567890123456);"
);
let sth = checked_prepare(&database, "SELECT id FROM test WHERE id > ?");
let mut sth = checked_prepare(&database, "SELECT id FROM test WHERE id > ?");
assert!(sth.bind_param(1, &Integer64(1234567890120000)) == SQLITE_OK);

assert!(sth.step() == SQLITE_ROW);
Expand All @@ -218,7 +218,7 @@ mod tests {

checked_exec(&database, "BEGIN; CREATE TABLE IF NOT EXISTS test (name text); COMMIT;");

let sth = checked_prepare(&database, "INSERT INTO test (name) VALUES (?)");
let mut sth = checked_prepare(&database, "INSERT INTO test (name) VALUES (?)");

assert!(sth.bind_param(1, &Text("test".to_string())) == SQLITE_OK);
}
Expand All @@ -229,7 +229,7 @@ mod tests {

checked_exec(&database, "BEGIN; CREATE TABLE IF NOT EXISTS test (name text, id integer); COMMIT;");

let sth = checked_prepare(&database, "INSERT INTO TEST (name, id) values (?, ?)");
let mut sth = checked_prepare(&database, "INSERT INTO TEST (name, id) values (?, ?)");
assert!(sth.bind_params(&[Integer(12345), Text("test".to_string())]) == SQLITE_OK);
}

Expand All @@ -239,16 +239,47 @@ mod tests {

checked_exec(&database, "BEGIN; CREATE TABLE IF NOT EXISTS test (id int, name text); COMMIT;");

let sth = checked_prepare(&database, "INSERT INTO test (name, id) VALUES (?, ?)");
let mut sth = checked_prepare(&database, "INSERT INTO test (name, id) VALUES (?, ?)");

assert!(sth.bind_param(1, &StaticText("test")) == SQLITE_OK);
assert!(sth.bind_param(2, &Integer(100)) == SQLITE_OK);
assert_eq!(sth.step(), SQLITE_DONE);

let st2 = checked_prepare(&database, "SELECT * FROM test");
let mut st2 = checked_prepare(&database, "SELECT * FROM test");
assert_eq!(st2.step(), SQLITE_ROW);
assert_eq!(st2.get_int(0), 100);
assert_eq!(st2.get_text(1), "test".to_string());
assert_eq!(st2.get_text(1), Some("test".as_slice()));
}

#[test]
fn prepared_stmt_bind_static_text_interleaved() {
let database = checked_open();

checked_exec(&database, "BEGIN; CREATE TABLE IF NOT EXISTS test (id int, name text); COMMIT;");

let mut sth = checked_prepare(&database, "INSERT INTO test (name, id) VALUES (?, ?)");
let mut st2 = checked_prepare(&database, "SELECT * FROM test");

assert_eq!(st2.step(), SQLITE_DONE);

assert_eq!(sth.bind_param(1, &StaticText("test")), SQLITE_OK);
assert_eq!(sth.bind_param(2, &Integer(100)), SQLITE_OK);
assert_eq!(sth.step(), SQLITE_DONE);

// this is perfectly safe.
assert_eq!(st2.reset(), SQLITE_OK);
assert_eq!(st2.step(), SQLITE_ROW);
assert_eq!(st2.get_int(0), 100);
assert_eq!(st2.get_text(1), Some("test".as_slice()));
assert_eq!(st2.step(), SQLITE_DONE);

// notes:
//
// while it is safe to make an update to the table *while* still reading from it,
// the update may or may not visible from the reading cursor depending on the query
// (e.g. `ORDER BY` on the unindexed table makes the cursor read every row in advance
// and the further changes won't be visible) and the result wildly varies.
// it is best not to rely on such behaviors.
}

#[test]
Expand All @@ -261,7 +292,7 @@ mod tests {
INSERT OR IGNORE INTO test (id, v) VALUES(1, 'leeeee');
COMMIT;"
);
let sth = checked_prepare(&database, "SELECT * FROM test");
let mut sth = checked_prepare(&database, "SELECT * FROM test");
assert!(sth.step() == SQLITE_ROW);
assert!(sth.get_column_names() == vec!("id".to_string(), "v".to_string()));
}
Expand Down Expand Up @@ -291,7 +322,8 @@ mod tests {
COMMIT;"
);
let sth = checked_prepare(&database, "SELECT * FROM test WHERE v=:Name");
assert!(sth.get_bind_index(":Name") == 1);
assert_eq!(sth.get_bind_index(":Name"), 1);
assert_eq!(sth.get_bind_index(":Bogus"), 0);
}

#[test]
Expand Down Expand Up @@ -322,7 +354,7 @@ mod tests {
COMMIT;
"
);
let sth = checked_prepare(&database, "SELECT * FROM test WHERE id=2");
let mut sth = checked_prepare(&database, "SELECT * FROM test WHERE id=2");
let r = sth.step_row();
let possible_row = r.unwrap();
match possible_row {
Expand Down Expand Up @@ -354,14 +386,14 @@ mod tests {
#[test]
fn get_text_without_step() {
let db = checked_open();
let c = checked_prepare(&db, "select 1 + 1");
let mut c = checked_prepare(&db, "select 1 + 1");
assert_eq!(c.get_text(0), None);
}

#[test]
fn get_text_on_bogus_col() {
let db = checked_open();
let c = checked_prepare(&db, "select 1 + 1");
let mut c = checked_prepare(&db, "select 1 + 1");
c.step();
assert_eq!(c.get_text(1), None);
}
Expand Down