sqlite3/
lib.rs

1//! Interface to [SQLite][1].
2//!
3//! ## Example
4//!
5//! Open a connection, create a table, and insert some rows:
6//!
7//! ```
8//! let connection = sqlite::open(":memory:").unwrap();
9//!
10//! connection
11//!     .execute(
12//!         "
13//!         CREATE TABLE users (name TEXT, age INTEGER);
14//!         INSERT INTO users (name, age) VALUES ('Alice', 42);
15//!         INSERT INTO users (name, age) VALUES ('Bob', 69);
16//!         ",
17//!     )
18//!     .unwrap();
19//! ```
20//!
21//! Select some rows and process them one by one as plain text:
22//!
23//! ```
24//! # let connection = sqlite::open(":memory:").unwrap();
25//! # connection
26//! #     .execute(
27//! #         "
28//! #         CREATE TABLE users (name TEXT, age INTEGER);
29//! #         INSERT INTO users (name, age) VALUES ('Alice', 42);
30//! #         INSERT INTO users (name, age) VALUES ('Bob', 69);
31//! #         ",
32//! #     )
33//! #     .unwrap();
34//! connection
35//!     .iterate("SELECT * FROM users WHERE age > 50", |pairs| {
36//!         for &(column, value) in pairs.iter() {
37//!             println!("{} = {}", column, value.unwrap());
38//!         }
39//!         true
40//!     })
41//!     .unwrap();
42//! ```
43//!
44//! The same query using a prepared statement, which is much more efficient than
45//! the previous technique:
46//!
47//! ```
48//! use sqlite::State;
49//! # let connection = sqlite::open(":memory:").unwrap();
50//! # connection
51//! #     .execute(
52//! #         "
53//! #         CREATE TABLE users (name TEXT, age INTEGER);
54//! #         INSERT INTO users (name, age) VALUES ('Alice', 42);
55//! #         INSERT INTO users (name, age) VALUES ('Bob', 69);
56//! #         ",
57//! #     )
58//! #     .unwrap();
59//!
60//! let mut statement = connection
61//!     .prepare("SELECT * FROM users WHERE age > ?")
62//!     .unwrap();
63//!
64//! statement.bind(1, 50).unwrap();
65//!
66//! while let State::Row = statement.next().unwrap() {
67//!     println!("name = {}", statement.read::<String>(0).unwrap());
68//!     println!("age = {}", statement.read::<i64>(1).unwrap());
69//! }
70//! ```
71//!
72//! The same query using a cursor, which is a wrapper around a prepared
73//! statement providing the concept of row and featuring all-at-once binding:
74//!
75//! ```
76//! use sqlite::Value;
77//! # let connection = sqlite::open(":memory:").unwrap();
78//! # connection
79//! #     .execute(
80//! #         "
81//! #         CREATE TABLE users (name TEXT, age INTEGER);
82//! #         INSERT INTO users (name, age) VALUES ('Alice', 42);
83//! #         INSERT INTO users (name, age) VALUES ('Bob', 69);
84//! #         ",
85//! #     )
86//! #     .unwrap();
87//!
88//! let mut cursor = connection
89//!     .prepare("SELECT * FROM users WHERE age > ?")
90//!     .unwrap()
91//!     .cursor();
92//!
93//! cursor.bind(&[Value::Integer(50)]).unwrap();
94//!
95//! while let Some(row) = cursor.next().unwrap() {
96//!     println!("name = {}", row[0].as_string().unwrap());
97//!     println!("age = {}", row[1].as_integer().unwrap());
98//! }
99//! ```
100//!
101//! [1]: https://www.sqlite.org
102
103extern crate libc;
104extern crate sqlite3_sys as ffi;
105
106use std::{error, fmt};
107
108macro_rules! raise(
109    ($message:expr) => (
110        return Err(::Error {
111            code: None,
112            message: Some($message.to_string()),
113        })
114    );
115);
116
117macro_rules! error(
118    ($connection:expr, $code:expr) => (
119        match ::last_error($connection) {
120            Some(error) => return Err(error),
121            _ => return Err(::Error {
122                code: Some($code as isize),
123                message: None,
124            }),
125        }
126    );
127);
128
129macro_rules! ok(
130    ($connection:expr, $result:expr) => (
131        match $result {
132            ::ffi::SQLITE_OK => {}
133            code => error!($connection, code),
134        }
135    );
136    ($result:expr) => (
137        match $result {
138            ::ffi::SQLITE_OK => {}
139            code => return Err(::Error {
140                code: Some(code as isize),
141                message: None,
142            }),
143        }
144    );
145);
146
147macro_rules! c_str_to_str(
148    ($string:expr) => (::std::str::from_utf8(::std::ffi::CStr::from_ptr($string).to_bytes()));
149);
150
151macro_rules! c_str_to_string(
152    ($string:expr) => (
153        String::from_utf8_lossy(::std::ffi::CStr::from_ptr($string as *const _).to_bytes())
154               .into_owned()
155    );
156);
157
158macro_rules! path_to_cstr(
159    ($path:expr) => (
160        match $path.to_str() {
161            Some(path) => {
162                match ::std::ffi::CString::new(path) {
163                    Ok(string) => string,
164                    _ => raise!("failed to process a path"),
165                }
166            }
167            _ => raise!("failed to process a path"),
168        }
169    );
170);
171
172macro_rules! str_to_cstr(
173    ($string:expr) => (
174        match ::std::ffi::CString::new($string) {
175            Ok(string) => string,
176            _ => raise!("failed to process a string"),
177        }
178    );
179);
180
181/// An error.
182#[derive(Debug)]
183pub struct Error {
184    /// The error code.
185    pub code: Option<isize>,
186    /// The error message.
187    pub message: Option<String>,
188}
189
190/// A result.
191pub type Result<T> = std::result::Result<T, Error>;
192
193/// A data type.
194#[derive(Clone, Copy, Debug, Eq, PartialEq)]
195pub enum Type {
196    /// The binary type.
197    Binary,
198    /// The floating-point type.
199    Float,
200    /// The integer type.
201    Integer,
202    /// The string type.
203    String,
204    /// The null type.
205    Null,
206}
207
208/// A typed value.
209#[derive(Clone, Debug, PartialEq)]
210pub enum Value {
211    /// Binary data.
212    Binary(Vec<u8>),
213    /// A floating-point number.
214    Float(f64),
215    /// An integer number.
216    Integer(i64),
217    /// A string.
218    String(String),
219    /// A null value.
220    Null,
221}
222
223impl fmt::Display for Error {
224    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
225        match (self.code, &self.message) {
226            (Some(code), &Some(ref message)) => write!(formatter, "{} (code {})", message, code),
227            (Some(code), _) => write!(formatter, "an SQLite error (code {})", code),
228            (_, &Some(ref message)) => message.fmt(formatter),
229            _ => write!(formatter, "an SQLite error"),
230        }
231    }
232}
233
234impl error::Error for Error {
235    fn description(&self) -> &str {
236        match self.message {
237            Some(ref message) => message,
238            _ => "an SQLite error",
239        }
240    }
241}
242
243impl Value {
244    /// Return the binary data if the value is `Binary`.
245    #[inline]
246    pub fn as_binary(&self) -> Option<&[u8]> {
247        if let &Value::Binary(ref value) = self {
248            return Some(value);
249        }
250        None
251    }
252
253    /// Return the floating-point number if the value is `Float`.
254    #[inline]
255    pub fn as_float(&self) -> Option<f64> {
256        if let &Value::Float(value) = self {
257            return Some(value);
258        }
259        None
260    }
261
262    /// Return the integer number if the value is `Integer`.
263    #[inline]
264    pub fn as_integer(&self) -> Option<i64> {
265        if let &Value::Integer(value) = self {
266            return Some(value);
267        }
268        None
269    }
270
271    /// Return the string if the value is `String`.
272    #[inline]
273    pub fn as_string(&self) -> Option<&str> {
274        if let &Value::String(ref value) = self {
275            return Some(value);
276        }
277        None
278    }
279
280    /// Return the type.
281    pub fn kind(&self) -> Type {
282        match self {
283            &Value::Binary(_) => Type::Binary,
284            &Value::Float(_) => Type::Float,
285            &Value::Integer(_) => Type::Integer,
286            &Value::String(_) => Type::String,
287            &Value::Null => Type::Null,
288        }
289    }
290}
291
292mod connection;
293mod cursor;
294mod statement;
295
296pub use connection::Connection;
297pub use cursor::Cursor;
298pub use statement::{Bindable, Readable, State, Statement};
299
300/// Open a connection to a new or existing database.
301#[inline]
302pub fn open<T: AsRef<std::path::Path>>(path: T) -> Result<Connection> {
303    Connection::open(path)
304}
305
306/// Return the version number of SQLite.
307///
308/// For instance, the version `3.8.11.1` corresponds to the integer `3008011`.
309#[inline]
310pub fn version() -> usize {
311    unsafe { ffi::sqlite3_libversion_number() as usize }
312}
313
314fn last_error(raw: *mut ffi::sqlite3) -> Option<Error> {
315    unsafe {
316        let code = ffi::sqlite3_errcode(raw);
317        if code == ffi::SQLITE_OK {
318            return None;
319        }
320        let message = ffi::sqlite3_errmsg(raw);
321        if message.is_null() {
322            return None;
323        }
324        Some(Error {
325            code: Some(code as isize),
326            message: Some(c_str_to_string!(message)),
327        })
328    }
329}