Add methods to access the session transaction isolation level
Closes #115
This commit is contained in:
parent
4a0067af6f
commit
8b43f0e3cf
72
src/lib.rs
72
src/lib.rs
@ -59,6 +59,7 @@ use debug_builders::DebugStruct;
|
||||
use openssl::crypto::hash::{self, Hasher};
|
||||
use openssl::ssl::{SslContext, MaybeSslStream};
|
||||
use serialize::hex::ToHex;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::{ToOwned, Cow};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::{VecDeque, HashMap};
|
||||
@ -399,6 +400,60 @@ pub fn cancel_query<T>(params: T, ssl: &SslMode, data: CancelData)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// An enumeration of transaction isolation levels.
|
||||
///
|
||||
/// See the (Postgres documentation)[http://www.postgresql.org/docs/9.4/static/transaction-iso.html]
|
||||
/// for full details on the semantics of each level.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum IsolationLevel {
|
||||
/// The "read uncommitted" level.
|
||||
///
|
||||
/// In current versions of Postgres, this behaves identically to
|
||||
/// `ReadCommitted`.
|
||||
ReadUncommitted,
|
||||
/// The "read committed" level.
|
||||
///
|
||||
/// This is the default isolation level in Postgres.
|
||||
ReadCommitted,
|
||||
/// The "repeatable read" level.
|
||||
RepeatableRead,
|
||||
/// The "serializable" level.
|
||||
Serializable,
|
||||
}
|
||||
|
||||
impl IsolationLevel {
|
||||
fn to_set_query(&self) -> &'static str {
|
||||
match *self {
|
||||
IsolationLevel::ReadUncommitted => {
|
||||
"SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"
|
||||
}
|
||||
IsolationLevel::ReadCommitted => {
|
||||
"SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED"
|
||||
}
|
||||
IsolationLevel::RepeatableRead => {
|
||||
"SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ"
|
||||
}
|
||||
IsolationLevel::Serializable => {
|
||||
"SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(raw: &str) -> Result<IsolationLevel> {
|
||||
if raw.eq_ignore_ascii_case("READ UNCOMMITTED") {
|
||||
Ok(IsolationLevel::ReadUncommitted)
|
||||
} else if raw.eq_ignore_ascii_case("READ COMMITTED") {
|
||||
Ok(IsolationLevel::ReadCommitted)
|
||||
} else if raw.eq_ignore_ascii_case("REPEATABLE READ") {
|
||||
Ok(IsolationLevel::RepeatableRead)
|
||||
} else if raw.eq_ignore_ascii_case("SERIALIZABLE") {
|
||||
Ok(IsolationLevel::Serializable)
|
||||
} else {
|
||||
Err(Error::BadResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct CachedStatement {
|
||||
name: String,
|
||||
@ -1062,6 +1117,23 @@ impl Connection {
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the isolation level which will be used for future transactions.
|
||||
///
|
||||
/// ## Note
|
||||
///
|
||||
/// This will not change the behavior of an active transaction.
|
||||
pub fn set_transaction_isolation(&self, level: IsolationLevel) -> Result<()> {
|
||||
self.batch_execute(level.to_set_query())
|
||||
}
|
||||
|
||||
/// Returns the isolation level which will be used for future transactions.
|
||||
pub fn get_transaction_isolation(&self) -> Result<IsolationLevel> {
|
||||
let mut conn = self.conn.borrow_mut();
|
||||
check_desync!(conn);
|
||||
let result = try!(conn.quick_query("SHOW TRANSACTION ISOLATION LEVEL"));
|
||||
IsolationLevel::parse(result[0][0].as_ref().unwrap())
|
||||
}
|
||||
|
||||
/// A convenience function for queries that are only run once.
|
||||
///
|
||||
/// If an error is returned, it could have come from either the preparation
|
||||
|
@ -18,6 +18,7 @@ use postgres::{HandleNotice,
|
||||
ConnectError,
|
||||
DbError,
|
||||
IntoConnectParams,
|
||||
IsolationLevel,
|
||||
VecStreamIterator};
|
||||
use postgres::SqlState::{SyntaxError,
|
||||
QueryCanceled,
|
||||
@ -944,3 +945,17 @@ fn url_encoded_password() {
|
||||
assert_eq!("username{|", ¶ms.user.as_ref().unwrap().user[..]);
|
||||
assert_eq!("password{|", ¶ms.user.as_ref().unwrap().password.as_ref().unwrap()[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transaction_isolation_level() {
|
||||
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
|
||||
assert_eq!(IsolationLevel::ReadCommitted, or_panic!(conn.get_transaction_isolation()));
|
||||
or_panic!(conn.set_transaction_isolation(IsolationLevel::ReadUncommitted));
|
||||
assert_eq!(IsolationLevel::ReadUncommitted, or_panic!(conn.get_transaction_isolation()));
|
||||
or_panic!(conn.set_transaction_isolation(IsolationLevel::RepeatableRead));
|
||||
assert_eq!(IsolationLevel::RepeatableRead, or_panic!(conn.get_transaction_isolation()));
|
||||
or_panic!(conn.set_transaction_isolation(IsolationLevel::Serializable));
|
||||
assert_eq!(IsolationLevel::Serializable, or_panic!(conn.get_transaction_isolation()));
|
||||
or_panic!(conn.set_transaction_isolation(IsolationLevel::ReadCommitted));
|
||||
assert_eq!(IsolationLevel::ReadCommitted, or_panic!(conn.get_transaction_isolation()));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user