sqlite_ll/connection.rs
1use core::ffi::CStr;
2use core::ffi::{c_int, c_uint, c_void};
3use core::mem::MaybeUninit;
4use core::ops::BitOr;
5use core::ptr;
6use core::ptr::NonNull;
7
8#[cfg(feature = "std")]
9use std::path::Path;
10
11use crate::State;
12use crate::error::{Error, Result};
13use crate::owned::Owned;
14use crate::statement::Statement;
15use crate::utils::sqlite3_try;
16
17use sqlite3_sys as ffi;
18
19/// A collection of flags use to prepare a statement.
20pub struct Prepare(c_uint);
21
22impl Prepare {
23 /// No flags.
24 ///
25 /// This provides the default behavior when preparing a statement.
26 pub const EMPTY: Self = Self(0);
27
28 /// The PERSISTENT flag is a hint to the query planner that the prepared
29 /// statement will be retained for a long time and probably reused many
30 /// times. Without this flag, sqlite3_prepare_v3() and
31 /// sqlite3_prepare16_v3() assume that the prepared statement will be used
32 /// just once or at most a few times and then destroyed using
33 /// sqlite3_finalize() relatively soon. The current implementation acts on
34 /// this hint by avoiding the use of lookaside memory so as not to deplete
35 /// the limited store of lookaside memory. Future versions of SQLite may act
36 /// on this hint differently.
37 pub const PERSISTENT: Self = Self(ffi::SQLITE_PREPARE_PERSISTENT as c_uint);
38
39 /// The NORMALIZE flag is a no-op. This flag used to be required for any
40 /// prepared statement that wanted to use the sqlite3_normalized_sql()
41 /// interface. However, the sqlite3_normalized_sql() interface is now
42 /// available to all prepared statements, regardless of whether or not they
43 /// use this flag.
44 pub const NORMALIZE: Self = Self(ffi::SQLITE_PREPARE_NORMALIZE as c_uint);
45
46 /// The NO_VTAB flag causes the SQL compiler to return an error if the
47 /// statement uses any virtual tables.
48 pub const NO_VTAB: Self = Self(ffi::SQLITE_PREPARE_NO_VTAB as c_uint);
49}
50
51impl BitOr for Prepare {
52 type Output = Self;
53
54 fn bitor(self, rhs: Self) -> Self::Output {
55 Self(self.0 | rhs.0)
56 }
57}
58
59/// A sqlite database connection.
60///
61/// Connections are not thread-safe objects.
62///
63/// # Examples
64///
65/// Opening a connection to a filesystem path:
66///
67/// ```no_run
68/// use sqlite_ll::Connection;
69///
70/// let c = Connection::open("database.db")?;
71/// c.execute("CREATE TABLE test (id INTEGER);")?;
72/// # Ok::<_, sqlite_ll::Error>(())
73/// ```
74///
75/// Opening an in-memory database:
76///
77/// ```
78/// use sqlite_ll::Connection;
79///
80/// let c = Connection::memory()?;
81/// c.execute("CREATE TABLE test (id INTEGER);")?;
82/// # Ok::<_, sqlite_ll::Error>(())
83/// ```
84pub struct Connection {
85 raw: NonNull<ffi::sqlite3>,
86 busy_callback: Option<Owned>,
87}
88
89/// Connection is `Send`.
90unsafe impl Send for Connection {}
91
92impl Connection {
93 /// Open a read-write connection to a new or existing database.
94 #[cfg(feature = "std")]
95 pub fn open(path: impl AsRef<Path>) -> Result<Connection> {
96 OpenOptions::new().set_create().set_read_write().open(path)
97 }
98
99 /// Open an in-memory database.
100 pub fn memory() -> Result<Connection> {
101 OpenOptions::new().set_create().set_read_write().memory()
102 }
103
104 /// Execute a statement without processing the resulting rows if any.
105 #[inline]
106 pub fn execute(&self, stmt: impl AsRef<str>) -> Result<()> {
107 let stmt = stmt.as_ref();
108
109 unsafe {
110 let mut ptr = stmt.as_ptr().cast();
111 let mut len = stmt.len();
112
113 while len > 0 {
114 let mut raw = MaybeUninit::uninit();
115 let mut rest = MaybeUninit::uninit();
116
117 let l = i32::try_from(len).unwrap_or(i32::MAX);
118
119 let res = ffi::sqlite3_prepare_v3(
120 self.raw.as_ptr(),
121 ptr,
122 l,
123 0,
124 raw.as_mut_ptr(),
125 rest.as_mut_ptr(),
126 );
127
128 if res != ffi::SQLITE_OK {
129 return Err(Error::new(ffi::sqlite3_errcode(self.raw.as_ptr())));
130 }
131
132 let rest = rest.assume_init();
133
134 // If statement is null then it's simply empty, so we can safely
135 // skip it, otherwise iterate over all rows.
136 if let Some(raw) = NonNull::new(raw.assume_init()) {
137 let mut statement = Statement::from_raw(raw);
138 while let State::Row = statement.step()? {}
139 }
140
141 // Skip over empty statements.
142 let o = rest.offset_from_unsigned(ptr);
143 len -= o;
144 ptr = rest;
145 }
146
147 Ok(())
148 }
149 }
150
151 /// Build a prepared statement.
152 ///
153 /// This is the same as calling `prepare_with` with `Prepare::EMPTY`.
154 ///
155 /// The database connection will be kept open for the lifetime of this
156 /// statement.
157 ///
158 /// # Errors
159 ///
160 /// If the prepare call contains multiple statements, it will error. To
161 /// execute multiple statements, use [`execute`] instead.
162 ///
163 /// ```
164 /// use sqlite_ll::{Connection, Code};
165 ///
166 /// let c = Connection::memory()?;
167 ///
168 /// let e = c.prepare(
169 /// "
170 /// CREATE TABLE test (id INTEGER) /* test */;
171 /// INSERT INTO test (id) VALUES (1);
172 /// "
173 /// ).unwrap_err();
174 ///
175 /// assert_eq!(e.code(), Code::ERROR);
176 /// # Ok::<_, sqlite_ll::Error>(())
177 /// ```
178 ///
179 /// [`execute`]: Self::execute
180 ///
181 /// # Examples
182 ///
183 /// ```
184 /// use sqlite_ll::{Connection, State, Prepare};
185 ///
186 /// let c = Connection::memory()?;
187 /// c.execute("CREATE TABLE test (id INTEGER);")?;
188 ///
189 /// let mut insert_stmt = c.prepare("INSERT INTO test (id) VALUES (?);")?;
190 /// let mut query_stmt = c.prepare("SELECT id FROM test;")?;
191 ///
192 /// drop(c);
193 ///
194 /// insert_stmt.reset()?;
195 /// insert_stmt.bind(1, 42)?;
196 /// assert_eq!(insert_stmt.step()?, State::Done);
197 ///
198 /// query_stmt.reset()?;
199 ///
200 /// while let State::Row = query_stmt.step()? {
201 /// let id: i64 = query_stmt.read(0)?;
202 /// assert_eq!(id, 42);
203 /// }
204 /// # Ok::<_, sqlite_ll::Error>(())
205 /// ```
206 #[inline]
207 pub fn prepare(&self, stmt: impl AsRef<str>) -> Result<Statement> {
208 self.prepare_with(stmt, Prepare::EMPTY)
209 }
210
211 /// Build a prepared statement with custom flags.
212 ///
213 /// For long-running statements it is recommended that they have the
214 /// [`Prepare::PERSISTENT`] flag set.
215 ///
216 /// The database connection will be kept open for the lifetime of this
217 /// statement.
218 ///
219 /// # Errors
220 ///
221 /// If the prepare call contains multiple statements, it will error. To
222 /// execute multiple statements, use [`execute`] instead.
223 ///
224 /// ```
225 /// use sqlite_ll::{Connection, Code, Prepare};
226 ///
227 /// let c = Connection::memory()?;
228 ///
229 /// let e = c.prepare_with(
230 /// "
231 /// CREATE TABLE test (id INTEGER) /* test */;
232 /// INSERT INTO test (id) VALUES (1);
233 /// ",
234 /// Prepare::PERSISTENT
235 /// ).unwrap_err();
236 /// assert_eq!(e.code(), Code::ERROR);
237 /// # Ok::<_, sqlite_ll::Error>(())
238 /// ```
239 ///
240 /// [`execute`]: Self::execute
241 ///
242 /// # Examples
243 ///
244 /// ```
245 /// use sqlite_ll::{Connection, State, Prepare};
246 ///
247 /// let c = Connection::memory()?;
248 /// c.execute("CREATE TABLE test (id INTEGER);")?;
249 ///
250 /// let mut insert_stmt = c.prepare_with("INSERT INTO test (id) VALUES (?);", Prepare::PERSISTENT)?;
251 /// let mut query_stmt = c.prepare_with("SELECT id FROM test;", Prepare::PERSISTENT)?;
252 ///
253 /// drop(c);
254 ///
255 /// /* .. */
256 ///
257 /// insert_stmt.reset()?;
258 /// insert_stmt.bind(1, 42)?;
259 /// assert_eq!(insert_stmt.step()?, State::Done);
260 ///
261 /// query_stmt.reset()?;
262 ///
263 /// while let State::Row = query_stmt.step()? {
264 /// let id: i64 = query_stmt.read(0)?;
265 /// assert_eq!(id, 42);
266 /// }
267 /// # Ok::<_, sqlite_ll::Error>(())
268 /// ```
269 pub fn prepare_with(&self, stmt: impl AsRef<str>, flags: Prepare) -> Result<Statement> {
270 let stmt = stmt.as_ref();
271
272 unsafe {
273 let mut raw = MaybeUninit::uninit();
274 let mut rest = MaybeUninit::uninit();
275
276 let ptr = stmt.as_ptr().cast();
277 let len = i32::try_from(stmt.len()).unwrap_or(i32::MAX);
278
279 sqlite3_try! {
280 ffi::sqlite3_prepare_v3(
281 self.raw.as_ptr(),
282 ptr,
283 len,
284 flags.0,
285 raw.as_mut_ptr(),
286 rest.as_mut_ptr(),
287 )
288 };
289
290 let rest = rest.assume_init();
291
292 let o = rest.offset_from_unsigned(ptr);
293
294 if o != stmt.len() {
295 return Err(Error::new(ffi::SQLITE_ERROR));
296 }
297
298 let raw = ptr::NonNull::new_unchecked(raw.assume_init());
299 Ok(Statement::from_raw(raw))
300 }
301 }
302
303 /// Return the number of rows inserted, updated, or deleted by the most
304 /// recent INSERT, UPDATE, or DELETE statement.
305 #[inline]
306 pub fn change_count(&self) -> usize {
307 unsafe { ffi::sqlite3_changes(self.raw.as_ptr()) as usize }
308 }
309
310 /// Return the total number of rows inserted, updated, and deleted by all
311 /// INSERT, UPDATE, and DELETE statements since the connection was opened.
312 #[inline]
313 pub fn total_change_count(&self) -> usize {
314 unsafe { ffi::sqlite3_total_changes(self.raw.as_ptr()) as usize }
315 }
316
317 /// Set a callback for handling busy events.
318 ///
319 /// The callback is triggered when the database cannot perform an operation
320 /// due to processing of some other request. If the callback returns `true`,
321 /// the operation will be repeated.
322 pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()>
323 where
324 F: FnMut(usize) -> bool + Send + 'static,
325 {
326 self.remove_busy_handler()?;
327
328 unsafe {
329 let callback = Owned::new(callback)?;
330
331 let result = ffi::sqlite3_busy_handler(
332 self.raw.as_ptr(),
333 Some(busy_callback::<F>),
334 callback.as_ptr().cast(),
335 );
336
337 self.busy_callback = Some(callback);
338 sqlite3_try!(result);
339 }
340
341 Ok(())
342 }
343
344 /// Set an implicit callback for handling busy events that tries to repeat
345 /// rejected operations until a timeout expires.
346 #[inline]
347 pub fn set_busy_timeout(&mut self, ms: c_int) -> Result<()> {
348 unsafe {
349 sqlite3_try! {
350 ffi::sqlite3_busy_timeout(
351 self.raw.as_ptr(),
352 ms
353 )
354 };
355 }
356
357 Ok(())
358 }
359
360 /// Remove the callback handling busy events.
361 #[inline]
362 pub fn remove_busy_handler(&mut self) -> Result<()> {
363 unsafe {
364 sqlite3_try! {
365 ffi::sqlite3_busy_handler(
366 self.raw.as_ptr(),
367 None,
368 ptr::null_mut()
369 )
370 };
371 }
372
373 self.busy_callback = None;
374 Ok(())
375 }
376}
377
378impl Drop for Connection {
379 #[inline]
380 #[allow(unused_must_use)]
381 fn drop(&mut self) {
382 self.remove_busy_handler();
383
384 // Will close the connection unconditionally. The database will stay
385 // alive until all associated prepared statements have been closed since
386 // we're using v2.
387 let code = unsafe { ffi::sqlite3_close_v2(self.raw.as_ptr()) };
388 debug_assert_eq!(code, sqlite3_sys::SQLITE_OK);
389 }
390}
391
392/// Options that can be used to customize the opening of a SQLite database.
393#[derive(Default, Clone, Copy, Debug)]
394pub struct OpenOptions {
395 raw: c_int,
396}
397
398impl OpenOptions {
399 /// Create flags for opening a database connection.
400 #[inline]
401 pub fn new() -> Self {
402 Self::default()
403 }
404
405 /// Open a database connection with current flags.
406 ///
407 /// `path` can be a filesystem path, or `:memory:` to construct an in-memory
408 /// database.
409 #[cfg(feature = "std")]
410 pub fn open(&self, path: impl AsRef<Path>) -> Result<Connection> {
411 let path = crate::utils::path_to_cstring(path.as_ref())?;
412 self._open(&path)
413 }
414
415 /// Open an in-memory database connection with current flags.
416 pub fn memory(&self) -> Result<Connection> {
417 self._open(c":memory:")
418 }
419
420 fn _open(&self, path: &CStr) -> Result<Connection> {
421 unsafe {
422 let mut raw = MaybeUninit::uninit();
423 let code = ffi::sqlite3_open_v2(path.as_ptr(), raw.as_mut_ptr(), self.raw, ptr::null());
424 let raw = raw.assume_init();
425
426 if code != ffi::SQLITE_OK {
427 let code = ffi::sqlite3_errcode(raw);
428 ffi::sqlite3_close(raw);
429 return Err(Error::new(code));
430 }
431
432 Ok(Connection {
433 raw: NonNull::new_unchecked(raw),
434 busy_callback: None,
435 })
436 }
437 }
438
439 /// Create the database if it does not already exist.
440 pub fn set_create(mut self) -> Self {
441 self.raw |= ffi::SQLITE_OPEN_CREATE;
442 self
443 }
444
445 /// Open the database in the serialized [threading mode][1].
446 ///
447 /// [1]: https://www.sqlite.org/threadsafe.html
448 pub fn set_full_mutex(mut self) -> Self {
449 self.raw |= ffi::SQLITE_OPEN_FULLMUTEX;
450 self
451 }
452
453 /// Opens the database in the multi-thread [threading mode][1].
454 ///
455 /// [1]: https://www.sqlite.org/threadsafe.html
456 pub fn set_no_mutex(mut self) -> Self {
457 self.raw |= ffi::SQLITE_OPEN_NOMUTEX;
458 self
459 }
460
461 /// Open the database for reading only.
462 pub fn set_read_only(mut self) -> Self {
463 self.raw |= ffi::SQLITE_OPEN_READONLY;
464 self
465 }
466
467 /// Open the database for reading and writing.
468 pub fn set_read_write(mut self) -> Self {
469 self.raw |= ffi::SQLITE_OPEN_READWRITE;
470 self
471 }
472}
473
474extern "C" fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
475where
476 F: FnMut(usize) -> bool,
477{
478 unsafe {
479 if (*(callback as *mut F))(attempts as usize) {
480 1
481 } else {
482 0
483 }
484 }
485}