fce_sqlite_connector/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 VALUES ('Alice', 42);
15//! INSERT INTO users 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 VALUES ('Alice', 42);
30//! # INSERT INTO users 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 VALUES ('Alice', 42);
55//! # INSERT INTO users 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 VALUES ('Alice', 42);
83//! # INSERT INTO users 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
103#![allow(dead_code)]
104
105use sqlite3_connector as ffi;
106
107use std::{error, fmt};
108
109macro_rules! error(
110 ($connection:expr, $code:expr) => (
111 match ::last_error($connection) {
112 Some(error) => return Err(error),
113 _ => return Err(::Error {
114 code: Some($code as isize),
115 message: None,
116 }),
117 }
118 );
119);
120
121macro_rules! ok_descr(
122 ($connection:expr, $result:expr) => (
123 match $result.ret_code {
124 ::ffi::SQLITE_OK => {}
125 code => error!($connection, code),
126 }
127 );
128 ($result:expr) => (
129 match $result.ret_code {
130 ::ffi::SQLITE_OK => {}
131 code => return Err(::Error {
132 code: Some(code as isize),
133 message: None,
134 }),
135 }
136 );
137);
138
139macro_rules! ok_raw(
140 ($connection:expr, $result:expr) => (
141 match $result {
142 ::ffi::SQLITE_OK => {}
143 code => error!($connection, code),
144 }
145 );
146 ($result:expr) => (
147 match $result {
148 ::ffi::SQLITE_OK => {}
149 code => return Err(::Error {
150 code: Some(code as isize),
151 message: None,
152 }),
153 }
154 );
155);
156
157/// An error.
158#[derive(Debug)]
159pub struct Error {
160 /// The error code.
161 pub code: Option<isize>,
162 /// The error message.
163 pub message: Option<String>,
164}
165
166/// A result.
167pub type Result<T> = std::result::Result<T, Error>;
168
169/// A data type.
170#[derive(Clone, Copy, Debug, Eq, PartialEq)]
171pub enum Type {
172 /// The binary type.
173 Binary,
174 /// The floating-point type.
175 Float,
176 /// The integer type.
177 Integer,
178 /// The string type.
179 String,
180 /// The null type.
181 Null,
182}
183
184/// A typed value.
185#[derive(Clone, Debug, PartialEq)]
186pub enum Value {
187 /// Binary data.
188 Binary(Vec<u8>),
189 /// A floating-point number.
190 Float(f64),
191 /// An integer number.
192 Integer(i64),
193 /// A string.
194 String(String),
195 /// A null value.
196 Null,
197}
198
199impl fmt::Display for Error {
200 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
201 match (self.code, &self.message) {
202 (Some(code), &Some(ref message)) => write!(formatter, "{} (code {})", message, code),
203 (Some(code), _) => write!(formatter, "an SQLite error (code {})", code),
204 (_, &Some(ref message)) => message.fmt(formatter),
205 _ => write!(formatter, "an SQLite error"),
206 }
207 }
208}
209
210impl error::Error for Error {
211 fn description(&self) -> &str {
212 match self.message {
213 Some(ref message) => message,
214 _ => "an SQLite error",
215 }
216 }
217}
218
219impl Value {
220 /// Return the binary data if the value is `Binary`.
221 #[inline]
222 pub fn as_binary(&self) -> Option<&[u8]> {
223 if let &Value::Binary(ref value) = self {
224 return Some(value);
225 }
226 None
227 }
228
229 /// Return the floating-point number if the value is `Float`.
230 #[inline]
231 pub fn as_float(&self) -> Option<f64> {
232 if let &Value::Float(value) = self {
233 return Some(value);
234 }
235 None
236 }
237
238 /// Return the integer number if the value is `Integer`.
239 #[inline]
240 pub fn as_integer(&self) -> Option<i64> {
241 if let &Value::Integer(value) = self {
242 return Some(value);
243 }
244 None
245 }
246
247 /// Return the string if the value is `String`.
248 #[inline]
249 pub fn as_string(&self) -> Option<&str> {
250 if let &Value::String(ref value) = self {
251 return Some(value);
252 }
253 None
254 }
255
256 /// Return the type.
257 pub fn kind(&self) -> Type {
258 match self {
259 &Value::Binary(_) => Type::Binary,
260 &Value::Float(_) => Type::Float,
261 &Value::Integer(_) => Type::Integer,
262 &Value::String(_) => Type::String,
263 &Value::Null => Type::Null,
264 }
265 }
266}
267
268mod connection;
269mod cursor;
270mod sqlite3_connector;
271mod statement;
272
273pub use connection::Connection;
274pub use connection::OpenFlags;
275pub use cursor::Cursor;
276pub use statement::{Bindable, Readable, State, Statement};
277pub use sqlite3_connector::*;
278
279/// Open a read-write connection to a new or existing database.
280#[inline]
281pub fn open<T: AsRef<std::path::Path>>(path: T) -> Result<Connection> {
282 Connection::open(path)
283}
284
285/// Return the version number of SQLite.
286///
287/// For instance, the version `3.8.11.1` corresponds to the integer `3008011`.
288#[inline]
289pub fn version() -> usize {
290 unsafe { ffi::sqlite3_libversion_number() as usize }
291}
292
293fn last_error(raw: ffi::Sqlite3DbHandle) -> Option<Error> {
294 unsafe {
295 let code = ffi::sqlite3_errcode(raw);
296 if code == ffi::SQLITE_OK {
297 return None;
298 }
299 let message = ffi::sqlite3_errmsg(raw);
300 Some(Error {
301 code: Some(code as isize),
302 message: Some(message),
303 })
304 }
305}