2013-08-04 02:17:32 +00:00
|
|
|
use std::cell::Cell;
|
2013-08-17 22:09:26 +00:00
|
|
|
use std::c_str::{ToCStr, CString};
|
2013-07-25 07:10:18 +00:00
|
|
|
use std::str;
|
|
|
|
use std::ptr;
|
2013-08-04 02:17:32 +00:00
|
|
|
use std::libc::{c_void, c_char, c_int};
|
|
|
|
use std::iterator::RandomAccessIterator;
|
2013-08-04 05:21:16 +00:00
|
|
|
use std::vec;
|
2013-07-25 07:10:18 +00:00
|
|
|
|
|
|
|
mod ffi {
|
2013-08-04 02:17:32 +00:00
|
|
|
use std::libc::{c_char, c_int, c_uchar, c_uint, c_void};
|
2013-07-25 07:10:18 +00:00
|
|
|
|
|
|
|
pub type PGconn = c_void;
|
|
|
|
pub type PGresult = c_void;
|
2013-08-04 02:17:32 +00:00
|
|
|
pub type Oid = c_uint;
|
|
|
|
|
|
|
|
pub static CONNECTION_OK: c_int = 0;
|
|
|
|
|
|
|
|
pub static PGRES_EMPTY_QUERY: c_int = 0;
|
|
|
|
pub static PGRES_COMMAND_OK: c_int = 1;
|
|
|
|
pub static PGRES_TUPLES_OK: c_int = 2;
|
|
|
|
|
|
|
|
pub static TEXT_FORMAT: c_int = 0;
|
|
|
|
|
|
|
|
// FIXME when FFI gets fixed
|
|
|
|
type PQnoticeProcessor = *c_uchar /*extern "C" fn(*c_void, *c_char)*/;
|
2013-07-25 07:10:18 +00:00
|
|
|
|
|
|
|
#[link_args = "-lpq"]
|
|
|
|
extern "C" {
|
|
|
|
fn PQconnectdb(conninfo: *c_char) -> *PGconn;
|
2013-08-04 02:17:32 +00:00
|
|
|
fn PQsetNoticeProcessor(conn: *PGconn, proc: PQnoticeProcessor,
|
|
|
|
arg: *c_void) -> PQnoticeProcessor;
|
2013-07-25 07:10:18 +00:00
|
|
|
fn PQfinish(conn: *PGconn);
|
2013-08-04 02:17:32 +00:00
|
|
|
fn PQstatus(conn: *PGconn) -> c_int;
|
2013-07-25 07:10:18 +00:00
|
|
|
fn PQerrorMessage(conn: *PGconn) -> *c_char;
|
2013-08-04 02:17:32 +00:00
|
|
|
fn PQexec(conn: *PGconn, query: *c_char) -> *PGresult;
|
|
|
|
fn PQresultStatus(result: *PGresult) -> c_int;
|
|
|
|
fn PQresultErrorMessage(result: *PGresult) -> *c_char;
|
|
|
|
fn PQclear(result: *PGresult);
|
|
|
|
fn PQprepare(conn: *PGconn, stmtName: *c_char, query: *c_char,
|
|
|
|
nParams: c_int, paramTypes: *Oid) -> *PGresult;
|
2013-08-04 05:21:16 +00:00
|
|
|
fn PQdescribePrepared(conn: *PGconn, stmtName: *c_char) -> *PGresult;
|
2013-08-04 02:17:32 +00:00
|
|
|
fn PQexecPrepared(conn: *PGconn, stmtName: *c_char, nParams: c_int,
|
|
|
|
paramValues: **c_char, paramLengths: *c_int,
|
|
|
|
paramFormats: *c_int, resultFormat: c_int)
|
2013-08-18 03:42:40 +00:00
|
|
|
-> *PGresult;
|
2013-08-04 02:17:32 +00:00
|
|
|
fn PQntuples(result: *PGresult) -> c_int;
|
|
|
|
fn PQnfields(result: *PGresult) -> c_int;
|
2013-08-04 05:21:16 +00:00
|
|
|
fn PQnparams(result: *PGresult) -> c_int;
|
2013-08-04 02:17:32 +00:00
|
|
|
fn PQcmdTuples(result: *PGresult) -> *c_char;
|
2013-08-05 00:48:48 +00:00
|
|
|
fn PQgetisnull(result: *PGresult, row_number: c_int, col_number: c_int)
|
2013-08-18 03:42:40 +00:00
|
|
|
-> c_int;
|
2013-08-04 02:17:32 +00:00
|
|
|
fn PQgetvalue(result: *PGresult, row_number: c_int, col_number: c_int)
|
2013-08-18 03:42:40 +00:00
|
|
|
-> *c_char;
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 03:30:31 +00:00
|
|
|
pub struct PostgresConnection {
|
2013-08-04 02:17:32 +00:00
|
|
|
priv conn: *ffi::PGconn,
|
|
|
|
priv next_stmt_id: Cell<uint>,
|
|
|
|
}
|
|
|
|
|
2013-08-18 03:30:31 +00:00
|
|
|
extern "C" fn notice_handler(_arg: *c_void, message: *c_char) {
|
|
|
|
let message = unsafe { str::raw::from_c_str(message) };
|
|
|
|
if message.starts_with("DEBUG") {
|
|
|
|
debug!("%s", message);
|
|
|
|
} else if message.starts_with("NOTICE") ||
|
|
|
|
message.starts_with("INFO") ||
|
|
|
|
message.starts_with("LOG") {
|
|
|
|
info!("%s", message);
|
|
|
|
} else if message.starts_with("WARNING") {
|
|
|
|
warn!("%s", message);
|
2013-08-04 02:17:32 +00:00
|
|
|
} else {
|
2013-08-18 03:30:31 +00:00
|
|
|
error!("%s", message);
|
2013-08-04 02:17:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[unsafe_destructor]
|
2013-08-18 03:30:31 +00:00
|
|
|
impl Drop for PostgresConnection {
|
2013-08-04 02:17:32 +00:00
|
|
|
fn drop(&self) {
|
|
|
|
unsafe { ffi::PQfinish(self.conn) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 03:30:31 +00:00
|
|
|
impl PostgresConnection {
|
2013-08-18 03:42:40 +00:00
|
|
|
fn status(&self) -> c_int {
|
|
|
|
unsafe { ffi::PQstatus(self.conn) }
|
|
|
|
}
|
|
|
|
|
2013-08-04 02:17:32 +00:00
|
|
|
fn get_error(&self) -> ~str {
|
|
|
|
unsafe { str::raw::from_c_str(ffi::PQerrorMessage(self.conn)) }
|
|
|
|
}
|
2013-08-18 03:42:40 +00:00
|
|
|
|
|
|
|
fn set_notice_processor(&mut self,
|
|
|
|
handler: *u8 /* extern "C" fn(*c_void, *c_char) */,
|
|
|
|
arg: *c_void) {
|
|
|
|
unsafe { ffi::PQsetNoticeProcessor(self.conn, handler, arg); }
|
|
|
|
}
|
2013-08-04 02:17:32 +00:00
|
|
|
}
|
2013-07-25 07:10:18 +00:00
|
|
|
|
2013-08-18 03:30:31 +00:00
|
|
|
impl PostgresConnection {
|
2013-08-04 02:17:32 +00:00
|
|
|
pub fn new(uri: &str) -> Result<~PostgresConnection, ~str> {
|
2013-08-18 03:42:40 +00:00
|
|
|
let mut conn = ~PostgresConnection {
|
|
|
|
conn: do uri.with_c_str |c_uri| {
|
|
|
|
unsafe { ffi::PQconnectdb(c_uri) }
|
|
|
|
},
|
|
|
|
next_stmt_id: Cell::new(0)
|
|
|
|
};
|
|
|
|
|
|
|
|
conn.set_notice_processor(notice_handler, ptr::null());
|
|
|
|
|
|
|
|
match conn.status() {
|
|
|
|
ffi::CONNECTION_OK => Ok(conn),
|
|
|
|
_ => Err(conn.get_error())
|
2013-08-04 02:17:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn prepare<'a>(&'a self, query: &str)
|
2013-08-18 03:42:40 +00:00
|
|
|
-> Result<~PostgresStatement<'a>, ~str> {
|
2013-08-04 02:17:32 +00:00
|
|
|
let id = self.next_stmt_id.take();
|
|
|
|
let name = fmt!("__libpostgres_stmt_%u", id);
|
|
|
|
self.next_stmt_id.put_back(id + 1);
|
|
|
|
|
2013-08-04 05:21:16 +00:00
|
|
|
let mut res = unsafe {
|
2013-08-17 22:09:26 +00:00
|
|
|
let raw_res = do query.with_c_str |c_query| {
|
|
|
|
do name.with_c_str |c_name| {
|
2013-08-04 02:17:32 +00:00
|
|
|
ffi::PQprepare(self.conn, c_name, c_query,
|
|
|
|
0, ptr::null())
|
|
|
|
}
|
|
|
|
};
|
|
|
|
PostgresResult {result: raw_res}
|
|
|
|
};
|
|
|
|
|
2013-08-04 05:21:16 +00:00
|
|
|
if res.status() != ffi::PGRES_COMMAND_OK {
|
|
|
|
return Err(res.error());
|
2013-08-04 02:17:32 +00:00
|
|
|
}
|
2013-08-04 05:21:16 +00:00
|
|
|
|
|
|
|
res = unsafe {
|
2013-08-17 22:09:26 +00:00
|
|
|
let raw_res = do name.with_c_str |c_name| {
|
2013-08-04 05:21:16 +00:00
|
|
|
ffi::PQdescribePrepared(self.conn, c_name)
|
|
|
|
};
|
|
|
|
PostgresResult {result: raw_res}
|
|
|
|
};
|
|
|
|
|
|
|
|
if res.status() != ffi::PGRES_COMMAND_OK {
|
|
|
|
return Err(res.error());
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(~PostgresStatement {conn: self, name: name,
|
|
|
|
num_params: res.num_params()})
|
2013-08-04 02:17:32 +00:00
|
|
|
}
|
|
|
|
|
2013-08-18 03:42:40 +00:00
|
|
|
pub fn update(&self, query: &str, params: &[&ToSql])
|
|
|
|
-> Result<uint, ~str> {
|
2013-08-04 02:17:32 +00:00
|
|
|
do self.prepare(query).chain |stmt| {
|
2013-08-04 05:21:16 +00:00
|
|
|
stmt.update(params)
|
2013-08-04 02:17:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 02:09:56 +00:00
|
|
|
pub fn query(&self, query: &str, params: &[&ToSql])
|
2013-08-18 03:42:40 +00:00
|
|
|
-> Result<~PostgresResult, ~str> {
|
2013-08-04 02:17:32 +00:00
|
|
|
do self.prepare(query).chain |stmt| {
|
2013-08-04 05:21:16 +00:00
|
|
|
stmt.query(params)
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-04 05:21:16 +00:00
|
|
|
|
|
|
|
pub fn in_transaction<T>(&self,
|
|
|
|
blk: &fn(&PostgresConnection) -> Result<T, ~str>)
|
2013-08-18 03:42:40 +00:00
|
|
|
-> Result<T, ~str> {
|
2013-08-04 05:21:16 +00:00
|
|
|
match self.update("BEGIN", []) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(err) => return Err(err)
|
|
|
|
};
|
|
|
|
|
|
|
|
// If the task fails in blk, the transaction will roll back when the
|
|
|
|
// connection closes
|
|
|
|
let ret = blk(self);
|
|
|
|
|
|
|
|
// TODO What to do about errors here?
|
|
|
|
if ret.is_ok() {
|
|
|
|
self.update("COMMIT", []);
|
|
|
|
} else {
|
2013-08-04 06:52:14 +00:00
|
|
|
self.update("ROLLBACK", []);
|
2013-08-04 05:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret
|
|
|
|
}
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
|
|
|
|
2013-08-04 02:17:32 +00:00
|
|
|
pub struct PostgresStatement<'self> {
|
2013-08-18 03:30:31 +00:00
|
|
|
priv conn: &'self PostgresConnection,
|
2013-08-04 05:21:16 +00:00
|
|
|
priv name: ~str,
|
|
|
|
priv num_params: uint
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
|
|
|
|
2013-08-04 02:17:32 +00:00
|
|
|
#[unsafe_destructor]
|
|
|
|
impl<'self> Drop for PostgresStatement<'self> {
|
2013-07-25 07:10:18 +00:00
|
|
|
fn drop(&self) {
|
2013-08-04 02:17:32 +00:00
|
|
|
// We can't do self.conn.update(...) since that will create a statement
|
|
|
|
let query = fmt!("DEALLOCATE %s", self.name);
|
2013-07-25 07:10:18 +00:00
|
|
|
unsafe {
|
2013-08-17 22:09:26 +00:00
|
|
|
do query.with_c_str |c_query| {
|
2013-08-04 02:17:32 +00:00
|
|
|
ffi::PQclear(ffi::PQexec(self.conn.conn, c_query));
|
|
|
|
}
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-04 02:17:32 +00:00
|
|
|
impl<'self> PostgresStatement<'self> {
|
2013-08-18 02:09:56 +00:00
|
|
|
fn exec(&self, params: &[&ToSql]) -> Result<~PostgresResult, ~str> {
|
2013-08-04 05:21:16 +00:00
|
|
|
if params.len() != self.num_params {
|
|
|
|
return Err(~"Incorrect number of parameters");
|
|
|
|
}
|
|
|
|
|
2013-08-04 02:17:32 +00:00
|
|
|
let res = unsafe {
|
2013-08-17 22:09:26 +00:00
|
|
|
let raw_res = do self.name.with_c_str |c_name| {
|
2013-08-18 02:09:56 +00:00
|
|
|
let str_params: ~[Option<~str>] = do params.map |param| {
|
|
|
|
param.to_sql()
|
|
|
|
};
|
|
|
|
do with_c_str_array(str_params) |c_params| {
|
2013-08-04 05:21:16 +00:00
|
|
|
ffi::PQexecPrepared(self.conn.conn, c_name,
|
|
|
|
self.num_params as c_int,
|
|
|
|
c_params, ptr::null(), ptr::null(),
|
|
|
|
ffi::TEXT_FORMAT)
|
|
|
|
}
|
2013-08-04 02:17:32 +00:00
|
|
|
};
|
|
|
|
~PostgresResult{result: raw_res}
|
|
|
|
};
|
|
|
|
|
|
|
|
match res.status() {
|
|
|
|
ffi::PGRES_EMPTY_QUERY |
|
|
|
|
ffi::PGRES_COMMAND_OK |
|
|
|
|
ffi::PGRES_TUPLES_OK => Ok(res),
|
|
|
|
_ => Err(res.error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 02:09:56 +00:00
|
|
|
pub fn update(&self, params: &[&ToSql]) -> Result<uint, ~str> {
|
2013-08-04 05:21:16 +00:00
|
|
|
do self.exec(params).chain |res| {
|
2013-08-04 02:17:32 +00:00
|
|
|
Ok(res.affected_rows())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 02:09:56 +00:00
|
|
|
pub fn query(&self, params: &[&ToSql]) -> Result<~PostgresResult, ~str> {
|
2013-08-04 05:21:16 +00:00
|
|
|
do self.exec(params).chain |res| {
|
2013-08-04 02:17:32 +00:00
|
|
|
Ok(res)
|
|
|
|
}
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 02:09:56 +00:00
|
|
|
fn with_c_str_array<T>(array: &[Option<~str>], blk: &fn(**c_char) -> T) -> T {
|
2013-08-17 22:09:26 +00:00
|
|
|
let mut cstrs: ~[CString] = ~[];
|
|
|
|
let mut c_array: ~[*c_char] = ~[];
|
2013-08-05 00:48:48 +00:00
|
|
|
for s in array.iter() {
|
2013-08-18 02:09:56 +00:00
|
|
|
match *s {
|
|
|
|
None => {
|
|
|
|
c_array.push(ptr::null())
|
|
|
|
}
|
|
|
|
Some(ref s) => {
|
|
|
|
cstrs.push(s.to_c_str());
|
|
|
|
do cstrs.last().with_ref |c_str| {
|
|
|
|
c_array.push(c_str);
|
|
|
|
}
|
|
|
|
}
|
2013-08-05 00:48:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
blk(vec::raw::to_ptr(c_array))
|
|
|
|
}
|
|
|
|
|
2013-08-04 02:17:32 +00:00
|
|
|
pub struct PostgresResult {
|
|
|
|
priv result: *ffi::PGresult
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
|
|
|
|
2013-08-04 02:17:32 +00:00
|
|
|
impl Drop for PostgresResult {
|
2013-07-25 07:10:18 +00:00
|
|
|
fn drop(&self) {
|
2013-08-04 02:17:32 +00:00
|
|
|
unsafe { ffi::PQclear(self.result) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PostgresResult {
|
|
|
|
fn status(&self) -> c_int {
|
|
|
|
unsafe { ffi::PQresultStatus(self.result) }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn error(&self) -> ~str {
|
|
|
|
unsafe { str::raw::from_c_str(ffi::PQresultErrorMessage(self.result)) }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn affected_rows(&self) -> uint {
|
|
|
|
let s = unsafe {
|
|
|
|
str::raw::from_c_str(ffi::PQcmdTuples(self.result))
|
|
|
|
};
|
|
|
|
|
|
|
|
match FromStr::from_str(s) {
|
|
|
|
Some(updates) => updates,
|
|
|
|
None => 0
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-04 05:21:16 +00:00
|
|
|
|
|
|
|
fn num_params(&self) -> uint {
|
|
|
|
unsafe { ffi::PQnparams(self.result) as uint }
|
|
|
|
}
|
2013-08-05 00:48:48 +00:00
|
|
|
|
2013-08-17 22:09:26 +00:00
|
|
|
fn get_value(&self, row: uint, col: uint) -> Option<~str> {
|
2013-08-05 00:48:48 +00:00
|
|
|
unsafe {
|
2013-08-17 22:09:26 +00:00
|
|
|
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
|
|
|
|
}
|
2013-08-05 00:48:48 +00:00
|
|
|
}
|
|
|
|
}
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
|
|
|
|
2013-08-04 02:17:32 +00:00
|
|
|
impl Container for PostgresResult {
|
|
|
|
fn len(&self) -> uint {
|
|
|
|
unsafe { ffi::PQntuples(self.result) as uint }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PostgresResult {
|
|
|
|
pub fn iter<'a>(&'a self) -> PostgresResultIterator<'a> {
|
|
|
|
PostgresResultIterator {result: self, next_row: 0}
|
|
|
|
}
|
2013-08-04 05:21:16 +00:00
|
|
|
|
|
|
|
pub fn get<'a>(&'a self, idx: uint) -> PostgresRow<'a> {
|
|
|
|
if idx >= self.len() {
|
|
|
|
fail!("Out of bounds access");
|
|
|
|
}
|
|
|
|
|
2013-08-17 22:09:26 +00:00
|
|
|
self.iter().idx(idx).unwrap()
|
2013-08-04 05:21:16 +00:00
|
|
|
}
|
2013-08-04 02:17:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct PostgresResultIterator<'self> {
|
|
|
|
priv result: &'self PostgresResult,
|
|
|
|
priv next_row: uint
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'self> Iterator<PostgresRow<'self>> for PostgresResultIterator<'self> {
|
|
|
|
fn next(&mut self) -> Option<PostgresRow<'self>> {
|
|
|
|
if self.result.len() == self.next_row {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
let row = self.next_row;
|
|
|
|
self.next_row += 1;
|
|
|
|
Some(PostgresRow {result: self.result, row: row})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn size_hint(&self) -> (uint, Option<uint>) {
|
|
|
|
let rem = self.result.len() - self.next_row;
|
|
|
|
(rem, Some(rem))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'self> RandomAccessIterator<PostgresRow<'self>> for
|
|
|
|
PostgresResultIterator<'self> {
|
|
|
|
fn indexable(&self) -> uint {
|
|
|
|
self.result.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn idx(&self, idx: uint) -> Option<PostgresRow<'self>> {
|
|
|
|
if idx < self.indexable() {
|
|
|
|
Some(PostgresRow {result: self.result, row: idx})
|
|
|
|
} else {
|
|
|
|
None
|
2013-07-25 07:10:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-04 02:17:32 +00:00
|
|
|
pub struct PostgresRow<'self> {
|
|
|
|
priv result: &'self PostgresResult,
|
2013-07-25 07:10:18 +00:00
|
|
|
priv row: uint
|
|
|
|
}
|
2013-08-04 02:17:32 +00:00
|
|
|
|
|
|
|
impl<'self> Container for PostgresRow<'self> {
|
|
|
|
fn len(&self) -> uint {
|
|
|
|
unsafe { ffi::PQnfields(self.result.result) as uint }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-05 00:48:48 +00:00
|
|
|
impl<'self, T: FromSql> Index<uint, T> for PostgresRow<'self> {
|
|
|
|
fn index(&self, idx: &uint) -> T {
|
2013-08-04 05:21:16 +00:00
|
|
|
self.get(*idx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'self> PostgresRow<'self> {
|
2013-08-17 22:09:26 +00:00
|
|
|
fn get_value(&self, col: uint) -> Option<~str> {
|
2013-08-05 00:48:48 +00:00
|
|
|
self.result.get_value(self.row, col)
|
2013-08-04 02:17:32 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-04 05:21:16 +00:00
|
|
|
|
2013-08-05 00:48:48 +00:00
|
|
|
impl<'self> PostgresRow<'self> {
|
|
|
|
pub fn get<T: FromSql>(&self, idx: uint) -> T {
|
|
|
|
if idx >= self.len() {
|
|
|
|
fail!("Out of bounds access");
|
2013-08-04 05:21:16 +00:00
|
|
|
}
|
2013-08-05 00:48:48 +00:00
|
|
|
FromSql::from_sql(self, idx)
|
2013-08-04 05:21:16 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-05 00:48:48 +00:00
|
|
|
|
|
|
|
pub trait FromSql {
|
|
|
|
fn from_sql(row: &PostgresRow, idx: uint) -> Self;
|
|
|
|
}
|
|
|
|
|
2013-08-17 22:09:26 +00:00
|
|
|
macro_rules! from_opt_impl(
|
2013-08-05 00:48:48 +00:00
|
|
|
($t:ty) => (
|
|
|
|
impl FromSql for $t {
|
|
|
|
fn from_sql(row: &PostgresRow, idx: uint) -> $t {
|
2013-08-17 22:09:26 +00:00
|
|
|
FromSql::from_sql::<Option<$t>>(row, idx).unwrap()
|
2013-08-05 00:48:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2013-08-17 22:09:26 +00:00
|
|
|
macro_rules! from_str_opt_impl(
|
2013-08-05 00:48:48 +00:00
|
|
|
($t:ty) => (
|
|
|
|
impl FromSql for Option<$t> {
|
|
|
|
fn from_sql(row: &PostgresRow, idx: uint) -> Option<$t> {
|
2013-08-17 22:09:26 +00:00
|
|
|
do row.get_value(idx).chain |s| {
|
|
|
|
Some(FromStr::from_str(s).unwrap())
|
2013-08-05 00:48:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2013-08-17 22:09:26 +00:00
|
|
|
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)
|
2013-08-18 02:09:56 +00:00
|
|
|
|
|
|
|
pub trait ToSql {
|
|
|
|
fn to_sql(&self) -> Option<~str>;
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! to_str_impl(
|
|
|
|
($t:ty) => (
|
|
|
|
impl ToSql for $t {
|
|
|
|
fn to_sql(&self) -> Option<~str> {
|
|
|
|
Some(self.to_str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
macro_rules! to_str_opt_impl(
|
|
|
|
($t:ty) => (
|
|
|
|
impl ToSql for Option<$t> {
|
|
|
|
fn to_sql(&self) -> Option<~str> {
|
|
|
|
match *self {
|
|
|
|
Some(ref val) => Some(val.to_sql().unwrap()),
|
|
|
|
None => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
to_str_impl!(int)
|
|
|
|
to_str_opt_impl!(int)
|
|
|
|
to_str_impl!(i8)
|
|
|
|
to_str_opt_impl!(i8)
|
|
|
|
to_str_impl!(i16)
|
|
|
|
to_str_opt_impl!(i16)
|
|
|
|
to_str_impl!(i32)
|
|
|
|
to_str_opt_impl!(i32)
|
|
|
|
to_str_impl!(i64)
|
|
|
|
to_str_opt_impl!(i64)
|
|
|
|
to_str_impl!(uint)
|
|
|
|
to_str_opt_impl!(uint)
|
|
|
|
to_str_impl!(u8)
|
|
|
|
to_str_opt_impl!(u8)
|
|
|
|
to_str_impl!(u16)
|
|
|
|
to_str_opt_impl!(u16)
|
|
|
|
to_str_impl!(u32)
|
|
|
|
to_str_opt_impl!(u32)
|
|
|
|
to_str_impl!(u64)
|
|
|
|
to_str_opt_impl!(u64)
|
|
|
|
to_str_impl!(float)
|
|
|
|
to_str_opt_impl!(float)
|
|
|
|
to_str_impl!(f32)
|
|
|
|
to_str_opt_impl!(f32)
|
|
|
|
to_str_impl!(f64)
|
|
|
|
to_str_opt_impl!(f64)
|
|
|
|
|
|
|
|
impl<'self> ToSql for &'self str {
|
|
|
|
fn to_sql(&self) -> Option<~str> {
|
|
|
|
Some(self.to_str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 02:42:12 +00:00
|
|
|
impl ToSql for ~str {
|
|
|
|
fn to_sql(&self) -> Option<~str> {
|
|
|
|
Some(self.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-18 02:09:56 +00:00
|
|
|
impl ToSql for Option<~str> {
|
|
|
|
fn to_sql(&self) -> Option<~str> {
|
|
|
|
self.clone()
|
|
|
|
}
|
|
|
|
}
|