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}