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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
#![allow(non_camel_case_types)] #[cfg(test)] extern crate temporary; extern crate libc; use libc::{c_char, c_double, c_int, c_longlong, c_uchar, c_ulonglong, c_void}; #[repr(C)] pub struct sqlite3; #[repr(C)] pub struct sqlite3_stmt; pub type sqlite_int64 = c_longlong; pub type sqlite_uint64 = c_ulonglong; pub type sqlite3_int64 = sqlite_int64; pub type sqlite3_uint64 = sqlite_uint64; pub const SQLITE_OK: c_int = 0; pub const SQLITE_ERROR: c_int = 1; pub const SQLITE_INTERNAL: c_int = 2; pub const SQLITE_PERM: c_int = 3; pub const SQLITE_ABORT: c_int = 4; pub const SQLITE_BUSY: c_int = 5; pub const SQLITE_LOCKED: c_int = 6; pub const SQLITE_NOMEM: c_int = 7; pub const SQLITE_READONLY: c_int = 8; pub const SQLITE_INTERRUPT: c_int = 9; pub const SQLITE_IOERR: c_int = 10; pub const SQLITE_CORRUPT: c_int = 11; pub const SQLITE_NOTFOUND: c_int = 12; pub const SQLITE_FULL: c_int = 13; pub const SQLITE_CANTOPEN: c_int = 14; pub const SQLITE_PROTOCOL: c_int = 15; pub const SQLITE_EMPTY: c_int = 16; pub const SQLITE_SCHEMA: c_int = 17; pub const SQLITE_TOOBIG: c_int = 18; pub const SQLITE_CONSTRAINT: c_int = 19; pub const SQLITE_MISMATCH: c_int = 20; pub const SQLITE_MISUSE: c_int = 21; pub const SQLITE_NOLFS: c_int = 22; pub const SQLITE_AUTH: c_int = 23; pub const SQLITE_FORMAT: c_int = 24; pub const SQLITE_RANGE: c_int = 25; pub const SQLITE_NOTADB: c_int = 26; pub const SQLITE_NOTICE: c_int = 27; pub const SQLITE_WARNING: c_int = 28; pub const SQLITE_ROW: c_int = 100; pub const SQLITE_DONE: c_int = 101; pub type sqlite3_exec_callback = extern fn(*mut c_void, c_int, *mut *mut c_char, *mut *mut c_char) -> c_int; pub type sqlite3_bind_callback = extern fn(*mut c_void); extern "C" { pub fn sqlite3_bind_double(stmt: *mut sqlite3_stmt, i: c_int, value: c_double) -> c_int; pub fn sqlite3_bind_int(stmt: *mut sqlite3_stmt, i: c_int, value: c_int) -> c_int; pub fn sqlite3_bind_int64(stmt: *mut sqlite3_stmt, i: c_int, value: sqlite3_int64) -> c_int; pub fn sqlite3_bind_text(stmt: *mut sqlite3_stmt, i: c_int, data: *const c_char, n: c_int, del: Option<sqlite3_bind_callback>) -> c_int; pub fn sqlite3_close(db: *mut sqlite3) -> c_int; pub fn sqlite3_column_double(stmt: *mut sqlite3_stmt, i: c_int) -> c_double; pub fn sqlite3_column_int(stmt: *mut sqlite3_stmt, i: c_int) -> c_int; pub fn sqlite3_column_int64(stmt: *mut sqlite3_stmt, i: c_int) -> sqlite3_int64; pub fn sqlite3_column_text(stmt: *mut sqlite3_stmt, i: c_int) -> *const c_uchar; pub fn sqlite3_errmsg(db: *mut sqlite3) -> *const c_char; pub fn sqlite3_exec(db: *mut sqlite3, sql: *const c_char, callback: Option<sqlite3_exec_callback>, arg: *mut c_void, errmsg: *mut *mut c_char) -> c_int; pub fn sqlite3_finalize(stmt: *mut sqlite3_stmt) -> c_int; pub fn sqlite3_free(p: *mut c_void); pub fn sqlite3_malloc(n: c_int) -> *mut c_void; pub fn sqlite3_open(filename: *const c_char, db: *mut *mut sqlite3) -> c_int; pub fn sqlite3_prepare(db: *mut sqlite3, sql: *const c_char, n: c_int, stmt: *mut *mut sqlite3_stmt, tail: *mut *const c_char) -> c_int; pub fn sqlite3_reset(stmt: *mut sqlite3_stmt) -> c_int; pub fn sqlite3_step(stmt: *mut sqlite3_stmt) -> c_int; } #[cfg(test)] mod tests { use std::ffi::{CStr, CString}; use std::ops::Deref; use temporary::Directory; macro_rules! ok( ($result:expr) => ($result.unwrap()); ); macro_rules! success( ($result:expr) => (assert!($result == ::SQLITE_OK)); ); macro_rules! c_str( ($pointer:expr) => (CStr::from_ptr($pointer as *const _)); ); macro_rules! c_string( ($string:expr) => (ok!(CString::new($string))); ); #[test] fn workflow() { use libc::{c_char, c_int, c_void}; open(|database| unsafe { success!(::sqlite3_exec(database, c_string!( "CREATE TABLE `users` (id INTEGER, name VARCHAR(255), age REAL);" ).as_ptr(), None, 0 as *mut _, 0 as *mut _)); { let mut statement = 0 as *mut _; let mut tail = 0 as *const _; success!(::sqlite3_prepare(database, c_string!( "INSERT INTO `users` (id, name, age) VALUES (?, ?, ?);" ).as_ptr(), -1, &mut statement, &mut tail)); let name = c_string!("Alice"); success!(::sqlite3_bind_int(statement, 1, 1)); success!(::sqlite3_bind_text(statement, 2, name.as_ptr(), -1, None)); success!(::sqlite3_bind_double(statement, 3, 20.99)); assert!(::sqlite3_step(statement) == ::SQLITE_DONE); success!(::sqlite3_finalize(statement)); } { let mut done = false; success!(::sqlite3_exec(database, c_string!( "SELECT * FROM `users`;" ).as_ptr(), Some(list), &mut done as *mut _ as *mut _, 0 as *mut _)); assert!(done); } { let mut statement = 0 as *mut _; let mut tail = 0 as *const _; success!(::sqlite3_prepare(database, c_string!( "SELECT * FROM `users`;" ).as_ptr(), -1, &mut statement, &mut tail)); assert!(::sqlite3_step(statement) == ::SQLITE_ROW); assert!(::sqlite3_column_int(statement, 0) == 1); assert!(c_str!(::sqlite3_column_text(statement, 1)) == c_string!("Alice").deref()); assert!(::sqlite3_column_double(statement, 2) == 20.99); assert!(::sqlite3_step(statement) == ::SQLITE_DONE); success!(::sqlite3_finalize(statement)); } }); extern fn list(done: *mut c_void, count: c_int, values: *mut *mut c_char, _: *mut *mut c_char) -> c_int { unsafe { assert!(count == 3); assert!(c_str!(*values) == c_string!("1").deref()); assert!(c_str!(*values.offset(1)) == c_string!("Alice").deref()); assert!(c_str!(*values.offset(2)) == c_string!("20.99").deref()); *(done as *mut bool) = true; } 0 } } fn open<F>(mut code: F) where F: FnMut(*mut ::sqlite3) { let (path, _directory) = setup(); let mut database = 0 as *mut _; unsafe { success!(::sqlite3_open(path.as_ptr(), &mut database)); code(database); success!(::sqlite3_close(database)); } } fn setup() -> (CString, Directory) { let directory = ok!(Directory::new("sqlite-sys")); let path = directory.path().join("database.sqlite3"); let path = c_string!(ok!(path.to_str())); (path, directory) } }