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 database to the given path.
94 ///
95 /// Note that it is possible to open an in-memory database by passing
96 /// `":memory:"` here, this call might require allocating depending on the
97 /// platform, so it should be avoided in favor of using [`memory`]. To avoid
98 /// allocating for regular paths, you can use [`open_c_str`], however you
99 /// are responsible for ensuring the c-string is a valid path.
100 ///
101 /// [`memory`]: Self::memory
102 /// [`open_c_str`]: Self::open_c_str
103 #[cfg(feature = "std")]
104 #[cfg_attr(docsrs, cfg(feature = "std"))]
105 #[inline]
106 pub fn open(path: impl AsRef<Path>) -> Result<Connection> {
107 OpenOptions::new().set_create().set_read_write().open(path)
108 }
109
110 /// Open a database connection with a raw c-string.
111 ///
112 /// This can be used to open in-memory databases by passing `c":memory:"` or
113 /// a regular open call with a filesystem path like
114 /// `c"/path/to/database.sql"`.
115 #[inline]
116 pub fn open_c_str(name: &CStr) -> Result<Connection> {
117 OpenOptions::new()
118 .set_create()
119 .set_read_write()
120 .open_c_str(name)
121 }
122
123 /// Open an in-memory database.
124 #[inline]
125 pub fn memory() -> Result<Connection> {
126 OpenOptions::new().set_create().set_read_write().memory()
127 }
128
129 /// Execute a statement without processing the resulting rows if any.
130 #[inline]
131 pub fn execute(&self, stmt: impl AsRef<str>) -> Result<()> {
132 self._execute(stmt.as_ref())
133 }
134
135 fn _execute(&self, stmt: &str) -> Result<()> {
136 unsafe {
137 let mut ptr = stmt.as_ptr().cast();
138 let mut len = stmt.len();
139
140 while len > 0 {
141 let mut raw = MaybeUninit::uninit();
142 let mut rest = MaybeUninit::uninit();
143
144 let l = i32::try_from(len).unwrap_or(i32::MAX);
145
146 let res = ffi::sqlite3_prepare_v3(
147 self.raw.as_ptr(),
148 ptr,
149 l,
150 0,
151 raw.as_mut_ptr(),
152 rest.as_mut_ptr(),
153 );
154
155 if res != ffi::SQLITE_OK {
156 return Err(Error::new(ffi::sqlite3_errcode(self.raw.as_ptr())));
157 }
158
159 let rest = rest.assume_init();
160
161 // If statement is null then it's simply empty, so we can safely
162 // skip it, otherwise iterate over all rows.
163 if let Some(raw) = NonNull::new(raw.assume_init()) {
164 let mut statement = Statement::from_raw(raw);
165 while let State::Row = statement.step()? {}
166 }
167
168 // Skip over empty statements.
169 let o = rest.offset_from_unsigned(ptr);
170 len -= o;
171 ptr = rest;
172 }
173
174 Ok(())
175 }
176 }
177
178 /// Build a prepared statement.
179 ///
180 /// This is the same as calling `prepare_with` with `Prepare::EMPTY`.
181 ///
182 /// The database connection will be kept open for the lifetime of this
183 /// statement.
184 ///
185 /// # Errors
186 ///
187 /// If the prepare call contains multiple statements, it will error. To
188 /// execute multiple statements, use [`execute`] instead.
189 ///
190 /// ```
191 /// use sqlite_ll::{Connection, Code};
192 ///
193 /// let c = Connection::memory()?;
194 ///
195 /// let e = c.prepare(
196 /// "
197 /// CREATE TABLE test (id INTEGER) /* test */;
198 /// INSERT INTO test (id) VALUES (1);
199 /// "
200 /// ).unwrap_err();
201 ///
202 /// assert_eq!(e.code(), Code::ERROR);
203 /// # Ok::<_, sqlite_ll::Error>(())
204 /// ```
205 ///
206 /// [`execute`]: Self::execute
207 ///
208 /// # Examples
209 ///
210 /// ```
211 /// use sqlite_ll::{Connection, State, Prepare};
212 ///
213 /// let c = Connection::memory()?;
214 /// c.execute("CREATE TABLE test (id INTEGER);")?;
215 ///
216 /// let mut insert_stmt = c.prepare("INSERT INTO test (id) VALUES (?);")?;
217 /// let mut query_stmt = c.prepare("SELECT id FROM test;")?;
218 ///
219 /// drop(c);
220 ///
221 /// insert_stmt.reset()?;
222 /// insert_stmt.bind(1, 42)?;
223 /// assert_eq!(insert_stmt.step()?, State::Done);
224 ///
225 /// query_stmt.reset()?;
226 ///
227 /// while let State::Row = query_stmt.step()? {
228 /// let id: i64 = query_stmt.read(0)?;
229 /// assert_eq!(id, 42);
230 /// }
231 /// # Ok::<_, sqlite_ll::Error>(())
232 /// ```
233 #[inline]
234 pub fn prepare(&self, stmt: impl AsRef<str>) -> Result<Statement> {
235 self.prepare_with(stmt, Prepare::EMPTY)
236 }
237
238 /// Build a prepared statement with custom flags.
239 ///
240 /// For long-running statements it is recommended that they have the
241 /// [`Prepare::PERSISTENT`] flag set.
242 ///
243 /// The database connection will be kept open for the lifetime of this
244 /// statement.
245 ///
246 /// # Errors
247 ///
248 /// If the prepare call contains multiple statements, it will error. To
249 /// execute multiple statements, use [`execute`] instead.
250 ///
251 /// ```
252 /// use sqlite_ll::{Connection, Code, Prepare};
253 ///
254 /// let c = Connection::memory()?;
255 ///
256 /// let e = c.prepare_with(
257 /// "
258 /// CREATE TABLE test (id INTEGER) /* test */;
259 /// INSERT INTO test (id) VALUES (1);
260 /// ",
261 /// Prepare::PERSISTENT
262 /// ).unwrap_err();
263 /// assert_eq!(e.code(), Code::ERROR);
264 /// # Ok::<_, sqlite_ll::Error>(())
265 /// ```
266 ///
267 /// [`execute`]: Self::execute
268 ///
269 /// # Examples
270 ///
271 /// ```
272 /// use sqlite_ll::{Connection, State, Prepare};
273 ///
274 /// let c = Connection::memory()?;
275 /// c.execute("CREATE TABLE test (id INTEGER);")?;
276 ///
277 /// let mut insert_stmt = c.prepare_with("INSERT INTO test (id) VALUES (?);", Prepare::PERSISTENT)?;
278 /// let mut query_stmt = c.prepare_with("SELECT id FROM test;", Prepare::PERSISTENT)?;
279 ///
280 /// drop(c);
281 ///
282 /// /* .. */
283 ///
284 /// insert_stmt.reset()?;
285 /// insert_stmt.bind(1, 42)?;
286 /// assert_eq!(insert_stmt.step()?, State::Done);
287 ///
288 /// query_stmt.reset()?;
289 ///
290 /// while let State::Row = query_stmt.step()? {
291 /// let id: i64 = query_stmt.read(0)?;
292 /// assert_eq!(id, 42);
293 /// }
294 /// # Ok::<_, sqlite_ll::Error>(())
295 /// ```
296 pub fn prepare_with(&self, stmt: impl AsRef<str>, flags: Prepare) -> Result<Statement> {
297 let stmt = stmt.as_ref();
298
299 unsafe {
300 let mut raw = MaybeUninit::uninit();
301 let mut rest = MaybeUninit::uninit();
302
303 let ptr = stmt.as_ptr().cast();
304 let len = i32::try_from(stmt.len()).unwrap_or(i32::MAX);
305
306 sqlite3_try! {
307 ffi::sqlite3_prepare_v3(
308 self.raw.as_ptr(),
309 ptr,
310 len,
311 flags.0,
312 raw.as_mut_ptr(),
313 rest.as_mut_ptr(),
314 )
315 };
316
317 let rest = rest.assume_init();
318
319 let o = rest.offset_from_unsigned(ptr);
320
321 if o != stmt.len() {
322 return Err(Error::new(ffi::SQLITE_ERROR));
323 }
324
325 let raw = ptr::NonNull::new_unchecked(raw.assume_init());
326 Ok(Statement::from_raw(raw))
327 }
328 }
329
330 /// Return the number of rows inserted, updated, or deleted by the most
331 /// recent INSERT, UPDATE, or DELETE statement.
332 #[inline]
333 pub fn change_count(&self) -> usize {
334 unsafe { ffi::sqlite3_changes(self.raw.as_ptr()) as usize }
335 }
336
337 /// Return the total number of rows inserted, updated, and deleted by all
338 /// INSERT, UPDATE, and DELETE statements since the connection was opened.
339 #[inline]
340 pub fn total_change_count(&self) -> usize {
341 unsafe { ffi::sqlite3_total_changes(self.raw.as_ptr()) as usize }
342 }
343
344 /// Set a callback for handling busy events.
345 ///
346 /// The callback is triggered when the database cannot perform an operation
347 /// due to processing of some other request. If the callback returns `true`,
348 /// the operation will be repeated.
349 pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()>
350 where
351 F: FnMut(usize) -> bool + Send + 'static,
352 {
353 self.remove_busy_handler()?;
354
355 unsafe {
356 let callback = Owned::new(callback)?;
357
358 let result = ffi::sqlite3_busy_handler(
359 self.raw.as_ptr(),
360 Some(busy_callback::<F>),
361 callback.as_ptr().cast(),
362 );
363
364 self.busy_callback = Some(callback);
365 sqlite3_try!(result);
366 }
367
368 Ok(())
369 }
370
371 /// Set an implicit callback for handling busy events that tries to repeat
372 /// rejected operations until a timeout expires.
373 #[inline]
374 pub fn set_busy_timeout(&mut self, ms: c_int) -> Result<()> {
375 unsafe {
376 sqlite3_try! {
377 ffi::sqlite3_busy_timeout(
378 self.raw.as_ptr(),
379 ms
380 )
381 };
382 }
383
384 Ok(())
385 }
386
387 /// Remove the callback handling busy events.
388 #[inline]
389 pub fn remove_busy_handler(&mut self) -> Result<()> {
390 unsafe {
391 sqlite3_try! {
392 ffi::sqlite3_busy_handler(
393 self.raw.as_ptr(),
394 None,
395 ptr::null_mut()
396 )
397 };
398 }
399
400 self.busy_callback = None;
401 Ok(())
402 }
403}
404
405impl Drop for Connection {
406 #[inline]
407 #[allow(unused_must_use)]
408 fn drop(&mut self) {
409 self.remove_busy_handler();
410
411 // Will close the connection unconditionally. The database will stay
412 // alive until all associated prepared statements have been closed since
413 // we're using v2.
414 let code = unsafe { ffi::sqlite3_close_v2(self.raw.as_ptr()) };
415 debug_assert_eq!(code, sqlite3_sys::SQLITE_OK);
416 }
417}
418
419/// Options that can be used to customize the opening of a SQLite database.
420#[derive(Default, Clone, Copy, Debug)]
421pub struct OpenOptions {
422 raw: c_int,
423}
424
425impl OpenOptions {
426 /// Create flags for opening a database connection.
427 #[inline]
428 pub fn new() -> Self {
429 Self::default()
430 }
431
432 /// Open a database to the given path.
433 ///
434 /// Note that it is possible to open an in-memory database by passing
435 /// `":memory:"` here, this call might require allocating depending on the
436 /// platform, so it should be avoided in favor of using [`memory`]. To avoid
437 /// allocating for regular paths, you can use [`open_c_str`], however you
438 /// are responsible for ensuring the c-string is a valid path.
439 ///
440 /// [`memory`]: Self::memory
441 /// [`open_c_str`]: Self::open_c_str
442 #[cfg(feature = "std")]
443 #[cfg_attr(docsrs, cfg(feature = "std"))]
444 pub fn open(&self, path: impl AsRef<Path>) -> Result<Connection> {
445 let path = crate::utils::path_to_cstring(path.as_ref())?;
446 self._open(&path)
447 }
448
449 /// Open a database connection with a raw c-string.
450 ///
451 /// This can be used to open in-memory databases by passing `c":memory:"` or
452 /// a regular open call with a filesystem path like
453 /// `c"/path/to/database.sql"`.
454 pub fn open_c_str(&self, name: &CStr) -> Result<Connection> {
455 self._open(name)
456 }
457
458 /// Open an in-memory database.
459 pub fn memory(&self) -> Result<Connection> {
460 self._open(c":memory:")
461 }
462
463 fn _open(&self, name: &CStr) -> Result<Connection> {
464 unsafe {
465 let mut raw = MaybeUninit::uninit();
466
467 let code = ffi::sqlite3_open_v2(name.as_ptr(), raw.as_mut_ptr(), self.raw, ptr::null());
468
469 let raw = raw.assume_init();
470
471 if code != ffi::SQLITE_OK {
472 ffi::sqlite3_close(raw);
473 return Err(Error::new(code));
474 }
475
476 Ok(Connection {
477 raw: NonNull::new_unchecked(raw),
478 busy_callback: None,
479 })
480 }
481 }
482
483 /// Create the database if it does not already exist.
484 pub fn set_create(mut self) -> Self {
485 self.raw |= ffi::SQLITE_OPEN_CREATE;
486 self
487 }
488
489 /// Open the database in the serialized [threading mode][1].
490 ///
491 /// [1]: https://www.sqlite.org/threadsafe.html
492 pub fn set_full_mutex(mut self) -> Self {
493 self.raw |= ffi::SQLITE_OPEN_FULLMUTEX;
494 self
495 }
496
497 /// Opens the database in the multi-thread [threading mode][1].
498 ///
499 /// [1]: https://www.sqlite.org/threadsafe.html
500 pub fn set_no_mutex(mut self) -> Self {
501 self.raw |= ffi::SQLITE_OPEN_NOMUTEX;
502 self
503 }
504
505 /// Open the database for reading only.
506 pub fn set_read_only(mut self) -> Self {
507 self.raw |= ffi::SQLITE_OPEN_READONLY;
508 self
509 }
510
511 /// Open the database for reading and writing.
512 pub fn set_read_write(mut self) -> Self {
513 self.raw |= ffi::SQLITE_OPEN_READWRITE;
514 self
515 }
516}
517
518extern "C" fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
519where
520 F: FnMut(usize) -> bool,
521{
522 unsafe {
523 if (*(callback as *mut F))(attempts as usize) {
524 1
525 } else {
526 0
527 }
528 }
529}