marine_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//! ```ignore
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//! ```ignore
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//! ```ignore
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//! ```ignore
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#![allow(unused_unsafe)]
105
106use sqlite3_connector as ffi;
107
108use std::{error, fmt};
109
110macro_rules! error(
111 ($connection:expr, $code:expr) => (
112 match crate::last_error($connection) {
113 Some(error) => return Err(error),
114 _ => return Err(crate::Error {
115 code: Some($code as isize),
116 message: None,
117 }),
118 }
119 );
120);
121
122macro_rules! ok_descr(
123 ($connection:expr, $result:expr) => (
124 match $result.ret_code {
125 crate::ffi::SQLITE_OK => {}
126 code => error!($connection, code),
127 }
128 );
129 ($result:expr) => (
130 match $result.ret_code {
131 ::ffi::SQLITE_OK => {}
132 code => return Err(::Error {
133 code: Some(code as isize),
134 message: None,
135 }),
136 }
137 );
138);
139
140macro_rules! ok_raw(
141 ($connection:expr, $result:expr) => (
142 match $result {
143 crate::ffi::SQLITE_OK => {}
144 code => error!($connection, code),
145 }
146 );
147 ($result:expr) => (
148 match $result {
149 ::ffi::SQLITE_OK => {}
150 code => return Err(::Error {
151 code: Some(code as isize),
152 message: None,
153 }),
154 }
155 );
156);
157
158/// An error.
159#[derive(Debug)]
160pub struct Error {
161 /// The error code.
162 pub code: Option<isize>,
163 /// The error message.
164 pub message: Option<String>,
165}
166
167/// A result.
168pub type Result<T> = std::result::Result<T, Error>;
169
170/// A data type.
171#[derive(Clone, Copy, Debug, Eq, PartialEq)]
172pub enum Type {
173 /// The binary type.
174 Binary,
175 /// The floating-point type.
176 Float,
177 /// The integer type.
178 Integer,
179 /// The string type.
180 String,
181 /// The null type.
182 Null,
183}
184
185/// A typed value.
186#[derive(Clone, Debug, PartialEq)]
187pub enum Value {
188 /// Binary data.
189 Binary(Vec<u8>),
190 /// A floating-point number.
191 Float(f64),
192 /// An integer number.
193 Integer(i64),
194 /// A string.
195 String(String),
196 /// A null value.
197 Null,
198}
199
200impl fmt::Display for Error {
201 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
202 match (self.code, &self.message) {
203 (Some(code), &Some(ref message)) => write!(formatter, "{} (code {})", message, code),
204 (Some(code), _) => write!(formatter, "an SQLite error (code {})", code),
205 (_, &Some(ref message)) => message.fmt(formatter),
206 _ => write!(formatter, "an SQLite error"),
207 }
208 }
209}
210
211impl error::Error for Error {
212 fn description(&self) -> &str {
213 match self.message {
214 Some(ref message) => message,
215 _ => "an SQLite error",
216 }
217 }
218}
219
220impl Value {
221 /// Return the binary data if the value is `Binary`.
222 #[inline]
223 pub fn as_binary(&self) -> Option<&[u8]> {
224 if let &Value::Binary(ref value) = self {
225 return Some(value);
226 }
227 None
228 }
229
230 /// Return the floating-point number if the value is `Float`.
231 #[inline]
232 pub fn as_float(&self) -> Option<f64> {
233 if let &Value::Float(value) = self {
234 return Some(value);
235 }
236 None
237 }
238
239 /// Return the integer number if the value is `Integer`.
240 #[inline]
241 pub fn as_integer(&self) -> Option<i64> {
242 if let &Value::Integer(value) = self {
243 return Some(value);
244 }
245 None
246 }
247
248 /// Return the string if the value is `String`.
249 #[inline]
250 pub fn as_string(&self) -> Option<&str> {
251 if let &Value::String(ref value) = self {
252 return Some(value);
253 }
254 None
255 }
256
257 /// Return the type.
258 pub fn kind(&self) -> Type {
259 match self {
260 &Value::Binary(_) => Type::Binary,
261 &Value::Float(_) => Type::Float,
262 &Value::Integer(_) => Type::Integer,
263 &Value::String(_) => Type::String,
264 &Value::Null => Type::Null,
265 }
266 }
267}
268
269mod connection;
270mod cursor;
271mod sqlite3_connector;
272mod statement;
273
274pub use connection::Connection;
275pub use connection::OpenFlags;
276pub use cursor::Cursor;
277pub use sqlite3_connector::*;
278pub use statement::{Bindable, Readable, State, Statement};
279
280/// Open a read-write connection to a new or existing database.
281#[inline]
282pub fn open<T: AsRef<std::path::Path>>(path: T) -> Result<Connection> {
283 Connection::open(path)
284}
285
286/// Return the version number of SQLite.
287///
288/// For instance, the version `3.8.11.1` corresponds to the integer `3008011`.
289#[inline]
290pub fn version() -> usize {
291 unsafe { ffi::sqlite3_libversion_number() as usize }
292}
293
294fn last_error(raw: ffi::Sqlite3DbHandle) -> Option<Error> {
295 unsafe {
296 let code = ffi::sqlite3_errcode(raw);
297 if code == ffi::SQLITE_OK {
298 return None;
299 }
300 let message = ffi::sqlite3_errmsg(raw);
301 Some(Error {
302 code: Some(code as isize),
303 message: Some(message),
304 })
305 }
306}
307
308/// From the SQLite docs:
309///
310/// The sqlite3_soft_heap_limit64() interface sets and/or queries the soft limit on the amount of
311/// heap memory that may be allocated by SQLite. SQLite strives to keep heap memory utilization
312/// below the soft heap limit by reducing the number of pages held in the page cache as heap memory
313/// usages approaches the limit. The soft heap limit is "soft" because even though SQLite strives
314/// to stay below the limit, it will exceed the limit rather than generate an SQLITE_NOMEM error.
315/// In other words, the soft heap limit is advisory only.
316pub fn soft_soft_heap_limit64(limit: i64) -> i64 {
317 unsafe { ffi::sqlite3_soft_heap_limit64(limit) }
318}
319
320/// From the SQLite docs:
321///
322/// This interface sets a hard upper bound of N bytes on the amount of memory that will be
323/// allocated. The set_hard_heap_limit64 interface is similar to soft_heap_limit64
324/// except that memory allocations will fail when the hard heap limit is reached.
325pub fn set_hard_heap_limit64(limit: i64) -> i64 {
326 unsafe { ffi::sqlite3_hard_heap_limit64(limit) }
327}