diff --git a/.gitignore b/.gitignore index ce200c7d..ce9b1046 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ *.so *.dummy -/postgres -/test* +check-* diff --git a/Makefile b/Makefile index b108e00d..09f393e9 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,17 @@ sqlite3.dummy: src/sqlite3/lib.rs sql.dummy $(RUSTC) $(RUSTFLAGS) --lib src/sqlite3/lib.rs -o $@ touch $@ +.PHONY: check +check: check-postgres check-sqlite3 + +check-postgres: postgres.dummy src/postgres/test.rs + $(RUSTC) $(RUSTFLAGS) --test src/postgres/test.rs -o $@ + ./$@ + +check-sqlite3: sqlite3.dummy src/sqlite3/test.rs + $(RUSTC) $(RUSTFLAGS) --test src/sqlite3/test.rs -o $@ + ./$@ + .PHONY: clean clean: - rm *.dummy *.so + rm *.dummy *.so check-* diff --git a/src/postgres/lib.rs b/src/postgres/lib.rs index 7e5f5bff..b2e4d863 100644 --- a/src/postgres/lib.rs +++ b/src/postgres/lib.rs @@ -1,4 +1,5 @@ use std::cell::Cell; +use std::c_str::{ToCStr, CString}; use std::str; use std::ptr; use std::libc::{c_void, c_char, c_int}; @@ -97,7 +98,7 @@ impl<'self> PostgresConnection<'self> { impl<'self> PostgresConnection<'self> { pub fn new(uri: &str) -> Result<~PostgresConnection, ~str> { unsafe { - let conn = ~PostgresConnection {conn: do uri.as_c_str |c_uri| { + let conn = ~PostgresConnection {conn: do uri.with_c_str |c_uri| { ffi::PQconnectdb(c_uri) }, next_stmt_id: Cell::new(0), notice_handler: log_notice_handler}; let arg: *PostgresConnection = &*conn; @@ -122,8 +123,8 @@ impl<'self> PostgresConnection<'self> { self.next_stmt_id.put_back(id + 1); let mut res = unsafe { - let raw_res = do query.as_c_str |c_query| { - do name.as_c_str |c_name| { + let raw_res = do query.with_c_str |c_query| { + do name.with_c_str |c_name| { ffi::PQprepare(self.conn, c_name, c_query, 0, ptr::null()) } @@ -136,7 +137,7 @@ impl<'self> PostgresConnection<'self> { } res = unsafe { - let raw_res = do name.as_c_str |c_name| { + let raw_res = do name.with_c_str |c_name| { ffi::PQdescribePrepared(self.conn, c_name) }; PostgresResult {result: raw_res} @@ -198,7 +199,7 @@ impl<'self> Drop for PostgresStatement<'self> { // We can't do self.conn.update(...) since that will create a statement let query = fmt!("DEALLOCATE %s", self.name); unsafe { - do query.as_c_str |c_query| { + do query.with_c_str |c_query| { ffi::PQclear(ffi::PQexec(self.conn.conn, c_query)); } } @@ -212,8 +213,8 @@ impl<'self> PostgresStatement<'self> { } let res = unsafe { - let raw_res = do self.name.as_c_str |c_name| { - do as_c_str_array(params) |c_params| { + let raw_res = do self.name.with_c_str |c_name| { + do with_c_str_array(params) |c_params| { ffi::PQexecPrepared(self.conn.conn, c_name, self.num_params as c_int, c_params, ptr::null(), ptr::null(), @@ -244,12 +245,13 @@ impl<'self> PostgresStatement<'self> { } } -fn as_c_str_array(array: &[~str], blk: &fn(**c_char) -> T) -> T { - let mut c_array: ~[*c_char] = vec::with_capacity(array.len() + 1); +fn with_c_str_array(array: &[~str], blk: &fn(**c_char) -> T) -> T { + let mut cstrs: ~[CString] = ~[]; + let mut c_array: ~[*c_char] = ~[]; for s in array.iter() { - // DANGER, WILL ROBINSON - do s.as_c_str |c_s| { - c_array.push(c_s); + cstrs.push(s.to_c_str()); + do cstrs.last().with_ref |c_str| { + c_array.push(c_str); } } c_array.push(ptr::null()); @@ -290,18 +292,17 @@ impl PostgresResult { unsafe { ffi::PQnparams(self.result) as uint } } - fn is_null(&self, row: uint, col: uint) -> bool { + fn get_value(&self, row: uint, col: uint) -> Option<~str> { unsafe { - ffi::PQgetisnull(self.result, row as c_int, col as c_int) == 1 - } - } - - fn get_value(&self, row: uint, col: uint) -> ~str { - unsafe { - let raw_s = ffi::PQgetvalue(self.result, - row as c_int, - col as c_int); - str::raw::from_c_str(raw_s) + match ffi::PQgetisnull(self.result, row as c_int, col as c_int) { + 0 => { + let raw_s = ffi::PQgetvalue(self.result, + row as c_int, + col as c_int); + Some(str::raw::from_c_str(raw_s)) + } + _ => None + } } } } @@ -322,7 +323,7 @@ impl PostgresResult { fail!("Out of bounds access"); } - self.iter().idx(idx).get() + self.iter().idx(idx).unwrap() } } @@ -381,11 +382,7 @@ impl<'self, T: FromSql> Index for PostgresRow<'self> { } impl<'self> PostgresRow<'self> { - fn is_null(&self, col: uint) -> bool { - self.result.is_null(self.row, col) - } - - fn get_value(&self, col: uint) -> ~str { + fn get_value(&self, col: uint) -> Option<~str> { self.result.get_value(self.row, col) } } @@ -403,55 +400,58 @@ pub trait FromSql { fn from_sql(row: &PostgresRow, idx: uint) -> Self; } -macro_rules! from_str_impl( +macro_rules! from_opt_impl( ($t:ty) => ( impl FromSql for $t { fn from_sql(row: &PostgresRow, idx: uint) -> $t { - if row.is_null(idx) { - fail!("Row is NULL"); - } - FromStr::from_str(row.get_value(idx)).get() + FromSql::from_sql::>(row, idx).unwrap() } } ) ) -macro_rules! option_impl( +macro_rules! from_str_opt_impl( ($t:ty) => ( impl FromSql for Option<$t> { fn from_sql(row: &PostgresRow, idx: uint) -> Option<$t> { - match row.is_null(idx) { - true => None, - false => Some(FromSql::from_sql(row, idx)) + do row.get_value(idx).chain |s| { + Some(FromStr::from_str(s).unwrap()) } } } ) ) -from_str_impl!(int) -option_impl!(int) -from_str_impl!(i8) -option_impl!(i8) -from_str_impl!(i16) -option_impl!(i16) -from_str_impl!(i32) -option_impl!(i32) -from_str_impl!(i64) -option_impl!(i64) -from_str_impl!(uint) -option_impl!(uint) -from_str_impl!(u8) -option_impl!(u8) -from_str_impl!(u16) -option_impl!(u16) -from_str_impl!(u32) -option_impl!(u32) -from_str_impl!(u64) -option_impl!(u64) -from_str_impl!(float) -option_impl!(float) -from_str_impl!(f32) -option_impl!(f32) -from_str_impl!(f64) -option_impl!(f64) +from_opt_impl!(int) +from_str_opt_impl!(int) +from_opt_impl!(i8) +from_str_opt_impl!(i8) +from_opt_impl!(i16) +from_str_opt_impl!(i16) +from_opt_impl!(i32) +from_str_opt_impl!(i32) +from_opt_impl!(i64) +from_str_opt_impl!(i64) +from_opt_impl!(uint) +from_str_opt_impl!(uint) +from_opt_impl!(u8) +from_str_opt_impl!(u8) +from_opt_impl!(u16) +from_str_opt_impl!(u16) +from_opt_impl!(u32) +from_str_opt_impl!(u32) +from_opt_impl!(u64) +from_str_opt_impl!(u64) +from_opt_impl!(float) +from_str_opt_impl!(float) +from_opt_impl!(f32) +from_str_opt_impl!(f32) +from_opt_impl!(f64) +from_str_opt_impl!(f64) + +impl FromSql for Option<~str> { + fn from_sql(row: &PostgresRow, idx: uint) -> Option<~str> { + row.get_value(idx) + } +} +from_opt_impl!(~str) diff --git a/src/sqlite3/lib.rs b/src/sqlite3/lib.rs index 2b068730..075db03f 100644 --- a/src/sqlite3/lib.rs +++ b/src/sqlite3/lib.rs @@ -1,3 +1,4 @@ +use std::c_str::ToCStr; use std::libc::c_int; use std::ptr; use std::str; @@ -45,7 +46,7 @@ mod ffi { pub fn open(filename: &str) -> Result<~Connection, ~str> { let mut conn = ~Connection {conn: ptr::null()}; - let ret = do filename.as_c_str |c_filename| { + let ret = do filename.with_c_str |c_filename| { unsafe { ffi::sqlite3_open(c_filename, &mut conn.conn) } }; @@ -95,7 +96,7 @@ impl Connection { pub fn prepare<'a>(&'a self, query: &str) -> Result<~PreparedStatement<'a>, ~str> { let mut stmt = ~PreparedStatement {conn: self, stmt: ptr::null()}; - let ret = do query.as_c_str |c_query| { + let ret = do query.with_c_str |c_query| { unsafe { ffi::sqlite3_prepare_v2(self.conn, c_query, -1, &mut stmt.stmt, ptr::mut_null()) @@ -166,7 +167,7 @@ impl<'self> PreparedStatement<'self> { fn bind_params(&self, params: &[@SqlType]) -> Result<(), ~str> { for (idx, param) in params.iter().enumerate() { let ret = match param.to_sql_str() { - Some(val) => do val.as_c_str |c_param| { + Some(val) => do val.with_c_str |c_param| { unsafe { ffi::sqlite3_bind_text(self.stmt, (idx+1) as c_int, c_param, -1, @@ -295,7 +296,7 @@ macro_rules! to_from_str_impl( } fn from_sql_str(sql_str: &Option<~str>) -> $t { - FromStr::from_str(*sql_str.get_ref()).get() + FromStr::from_str(*sql_str.get_ref()).unwrap() } } ) @@ -307,7 +308,7 @@ macro_rules! option_impl( fn to_sql_str(&self) -> Option<~str> { match *self { None => None, - Some(ref v) => Some(v.to_sql_str().get()) + Some(ref v) => Some(v.to_sql_str().unwrap()) } } diff --git a/src/sqlite3/test.rs b/src/sqlite3/test.rs index ffab6eae..c68d3f90 100644 --- a/src/sqlite3/test.rs +++ b/src/sqlite3/test.rs @@ -19,11 +19,9 @@ fn test_basic() { )")); chk!(conn.update("INSERT INTO foo (id) VALUES (101), (102)")); - do conn.query("SELECT id FROM foo") |it| { - for it.advance |row| { - printfln!("%u %d", row.len(), row[0]); - } - }; + assert_eq!(2, chk!(conn.query("SELECT COUNT(*) FROM foo", |it| { + it.next().unwrap()[0] + }))); } #[test] @@ -37,7 +35,7 @@ fn test_trans() { Err::<(), ~str>(~"") }; assert_eq!(0, chk!(conn.query("SELECT COUNT(*) FROM bar", |it| { - it.next().get()[0] + it.next().unwrap()[0] }))); do conn.in_transaction |conn| { @@ -46,7 +44,7 @@ fn test_trans() { }; assert_eq!(1, chk!(conn.query("SELECT COUNT(*) FROM bar", |it| { - it.next().get()[0] + it.next().unwrap()[0] }))); } @@ -60,7 +58,7 @@ fn test_params() { &[@100 as @SqlType, @101 as @SqlType])); assert_eq!(2, chk!(conn.query("SELECT COUNT(*) FROM foo", |it| { - it.next().get()[0] + it.next().unwrap()[0] }))); } @@ -76,10 +74,10 @@ fn test_null() { @101 as @SqlType, @Some(1) as @SqlType])); do conn.query("SELECT n FROM foo WHERE id = 100") |it| { - assert!(it.next().get().get::>(0).is_none()); + assert!(it.next().unwrap().get::>(0).is_none()); }; do conn.query("SELECT n FROM foo WHERE id = 101") |it| { - assert_eq!(Some(1), it.next().get()[0]) + assert_eq!(Some(1), it.next().unwrap()[0]) }; }