forked from rust-postgres/rust-postgres
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlib.rs
More file actions
155 lines (130 loc) · 4.17 KB
/
Copy pathlib.rs
File metadata and controls
155 lines (130 loc) · 4.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
extern mod sql;
use std::libc::c_int;
use std::ptr;
use std::str;
mod ffi {
use std::libc::{c_char, c_int, c_void};
pub type sqlite3 = c_void;
pub type sqlite3_stmt = c_void;
pub static SQLITE_OK: c_int = 0;
pub static SQLITE_ROW: c_int = 100;
pub static SQLITE_DONE: c_int = 101;
#[link_args = "-lsqlite3"]
extern "C" {
fn sqlite3_open(filename: *c_char, ppDb: *mut *sqlite3) -> c_int;
fn sqlite3_close(db: *sqlite3) -> c_int;
fn sqlite3_errmsg(db: *sqlite3) -> *c_char;
fn sqlite3_changes(db: *sqlite3) -> c_int;
fn sqlite3_prepare_v2(db: *sqlite3, zSql: *c_char, nByte: c_int,
ppStmt: *mut *sqlite3_stmt, pzTail: *mut *c_char)
-> c_int;
fn sqlite3_reset(pStmt: *sqlite3_stmt) -> c_int;
fn sqlite3_step(pStmt: *sqlite3_stmt) -> c_int;
fn sqlite3_column_count(pStmt: *sqlite3_stmt) -> c_int;
fn sqlite3_column_text(pStmt: *sqlite3_stmt, iCol: c_int) -> *c_char;
fn sqlite3_finalize(pStmt: *sqlite3_stmt) -> c_int;
}
}
pub fn open(filename: &str) -> Result<~Connection, ~str> {
let mut conn = ~Connection {conn: ptr::null()};
let ret = do filename.as_c_str |c_filename| {
unsafe { ffi::sqlite3_open(c_filename, &mut conn.conn) }
};
match ret {
ffi::SQLITE_OK => Ok(conn),
_ => Err(conn.get_error())
}
}
pub struct Connection {
priv conn: *ffi::sqlite3
}
impl Drop for Connection {
fn drop(&self) {
let ret = unsafe { ffi::sqlite3_close(self.conn) };
assert!(ret == ffi::SQLITE_OK);
}
}
impl Connection {
fn get_error(&self) -> ~str {
unsafe {
str::raw::from_c_str(ffi::sqlite3_errmsg(self.conn))
}
}
}
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| {
unsafe {
ffi::sqlite3_prepare_v2(self.conn, c_query, -1, &mut stmt.stmt,
ptr::mut_null())
}
};
match ret {
ffi::SQLITE_OK => Ok(stmt),
_ => Err(self.get_error())
}
}
}
pub struct PreparedStatement<'self> {
priv conn: &'self Connection,
priv stmt: *ffi::sqlite3_stmt
}
#[unsafe_destructor]
impl<'self> Drop for PreparedStatement<'self> {
fn drop(&self) {
unsafe { ffi::sqlite3_finalize(self.stmt); }
}
}
impl<'self> PreparedStatement<'self> {
pub fn update(&self) -> Result<uint, ~str> {
unsafe { ffi::sqlite3_reset(self.stmt); }
let ret = unsafe { ffi::sqlite3_step(self.stmt) };
match ret {
// TODO: Should we consider a query that returned rows an error?
ffi::SQLITE_DONE | ffi::SQLITE_ROW =>
Ok(unsafe { ffi::sqlite3_changes(self.conn.conn) } as uint),
_ => Err(self.conn.get_error())
}
}
pub fn query<'a>(&'a self) -> Result<ResultIterator<'a>, ~str> {
unsafe { ffi::sqlite3_reset(self.stmt); }
Ok(ResultIterator {stmt: self})
}
}
pub struct ResultIterator<'self> {
priv stmt: &'self PreparedStatement<'self>
}
impl<'self> Iterator<Row<'self>> for ResultIterator<'self> {
fn next(&mut self) -> Option<Row<'self>> {
let ret = unsafe { ffi::sqlite3_step(self.stmt.stmt) };
match ret {
ffi::SQLITE_ROW => Some(Row {stmt: self.stmt}),
// TODO: Ignoring errors for now
_ => None
}
}
}
pub struct Row<'self> {
priv stmt: &'self PreparedStatement<'self>
}
impl<'self> Container for Row<'self> {
fn len(&self) -> uint {
unsafe { ffi::sqlite3_column_count(self.stmt.stmt) as uint }
}
fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'self> Row<'self> {
pub fn get<T: FromStr>(&self, idx: uint) -> Option<T> {
let raw = unsafe {
ffi::sqlite3_column_text(self.stmt.stmt, idx as c_int)
};
if ptr::is_null(raw) {
return None;
}
FromStr::from_str(unsafe { str::raw::from_c_str(raw) })
}
}