min_sqlite3_sys/
operations.rs

1//! This module contains operational SQL functions that provides
2//! you to execute statements like read/write/update/delete,
3//! begin/commit transactions, etc.
4
5#![forbid(missing_docs)]
6#![allow(clippy::not_unsafe_ptr_arg_deref)] // not stable, has false-positive results. so just keep it off for this module.
7
8use std::{
9    ffi::{CStr, CString},
10    os, ptr,
11};
12
13use crate::connection::Database;
14use crate::{bindings::sqlite3_stmt, ehandle::MinSqliteWrapperError};
15use crate::{bindings::*, statement::SqlStatement};
16
17/// Defines the helper functions that work on the columns of the data rows received.
18pub trait ColumnCapabilities<'a> {
19    /// Reads the column data of the rows that returns from the SQL query.
20    ///
21    /// # Panics
22    /// - If the data type is incorrectly specified.
23    /// - If the column index doesn't match.
24    ///
25    /// # Usage
26    /// ```
27    /// #[derive(Debug)]
28    /// struct Item {
29    ///     id: i64,
30    ///     name: String,
31    ///     tag: String,
32    /// }
33    ///
34    /// let db_path = Path::new("./example.db");
35    /// let db = Database::open(db_path).unwrap();
36    ///
37    /// let statement = String::from(
38    ///     "SELECT * FROM example_table WHERE ID = '15';"
39    /// );
40    ///
41    /// let mut sql = db.prepare(statement, None::<Box<dyn FnOnce(SqlitePrimaryResult, String)>>).unwrap();
42    ///
43    /// while let PreparedStatementStatus::FoundRow = sql.execute_prepared() {
44    ///     println!(
45    ///         "id = {}, name = {}, tag = {}",
46    ///         sql.get_data::<i64>(0).unwrap(),
47    ///         sql.get_data::<String>(1).unwrap(),
48    ///         sql.get_data::<String>(2).unwrap(),
49    ///     );
50    ///
51    ///     // OR
52    ///
53    ///     println!(
54    ///         "{:?}",
55    ///         Item {
56    ///             id: sql.get_data(0).unwrap(),
57    ///             name: sql.get_data(1).unwrap(),
58    ///             tag: sql.get_data(2).unwrap(),
59    ///         }
60    ///     );
61    /// }
62    ///
63    /// sql.kill();
64    /// db.close();
65    /// ```
66    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
67    where
68        Self: Sized;
69
70    /// Binds the value of a parameter to a prepared statement indicator.
71    ///
72    /// Supported indicator patterns:
73    /// - ?
74    /// - ?NNN
75    /// - :VVV
76    /// - @VVV
77    /// - $VVV
78    ///
79    /// Returns `SqlitePrimaryResult:Ok` on success or an error code if anything goes wrong.
80    /// `SqlitePrimaryResult::Range` is returned if the parameter index is out of range.
81    ///
82    /// # IMPORTANT
83    /// The first argument isn't index of the column. It's simply index of the
84    /// indicator and always starts at 1. If the first argument is given zero,
85    /// the function will return `SqlitePrimaryResult::Range`.
86    ///
87    /// # Usage
88    /// ```
89    /// let db_path = Path::new("./example.db");
90    /// let db = Database::open(db_path).unwrap();
91    ///
92    /// let statement = String::from(
93    ///     "SELECT * FROM example_table WHERE ID = ;"
94    /// );
95    ///
96    /// let mut sql = db.prepare(statement, None::<Box<dyn FnOnce(SqlitePrimaryResult, String)>>).unwrap();
97    ///
98    /// let status = sql.bind_val(1, 5);
99    /// // You can do some checks by
100    /// assert_eq!(status, SqlitePrimaryResult::Ok);
101    /// // or
102    /// if status == SqlitePrimaryResult::Range {
103    ///     panic!("Out of index on sql.bind_val!");
104    /// }
105    ///
106    /// sql.kill();
107    /// db.close();
108    /// ```
109    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
110    where
111        Self: Sized;
112}
113
114/// Null type alias that equals to ()
115pub type SqliteNull = ();
116
117/// An alias to imitate null value for some of the
118/// sqlite3 operations
119pub const SQLITE_NULL: SqliteNull = ();
120
121impl<'a> ColumnCapabilities<'a> for Option<i8> {
122    #[inline]
123    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
124    where
125        Self: Sized,
126    {
127        unsafe {
128            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
129                return Ok(None);
130            }
131
132            Ok(Some(sqlite3_column_int64(stmt, i as os::raw::c_int) as i8))
133        }
134    }
135
136    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
137    where
138        Self: Sized,
139    {
140        if let Some(t) = self {
141            unsafe {
142                return SqlitePrimaryResult::from(sqlite3_bind_int64(
143                    stmt,
144                    i as os::raw::c_int,
145                    t as os::raw::c_longlong,
146                ));
147            }
148        }
149
150        SqlitePrimaryResult::MisMatch
151    }
152}
153
154impl<'a> ColumnCapabilities<'a> for i8 {
155    #[inline]
156    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
157    where
158        Self: Sized,
159    {
160        unsafe { Ok(sqlite3_column_int64(stmt, i as os::raw::c_int) as Self) }
161    }
162
163    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
164    where
165        Self: Sized,
166    {
167        unsafe {
168            SqlitePrimaryResult::from(sqlite3_bind_int64(
169                stmt,
170                i as os::raw::c_int,
171                self as os::raw::c_longlong,
172            ))
173        }
174    }
175}
176
177impl<'a> ColumnCapabilities<'a> for Option<u8> {
178    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
179    where
180        Self: Sized,
181    {
182        unsafe {
183            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
184                return Ok(None);
185            }
186
187            Ok(Some(sqlite3_column_int64(stmt, i as os::raw::c_int) as u8))
188        }
189    }
190
191    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
192    where
193        Self: Sized,
194    {
195        if let Some(t) = self {
196            unsafe {
197                return SqlitePrimaryResult::from(sqlite3_bind_int64(
198                    stmt,
199                    i as os::raw::c_int,
200                    t as os::raw::c_longlong,
201                ));
202            }
203        }
204
205        SqlitePrimaryResult::MisMatch
206    }
207}
208
209impl<'a> ColumnCapabilities<'a> for u8 {
210    #[inline]
211    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
212    where
213        Self: Sized,
214    {
215        unsafe { Ok(sqlite3_column_int64(stmt, i as os::raw::c_int) as Self) }
216    }
217
218    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
219    where
220        Self: Sized,
221    {
222        unsafe {
223            SqlitePrimaryResult::from(sqlite3_bind_int64(
224                stmt,
225                i as os::raw::c_int,
226                self as os::raw::c_longlong,
227            ))
228        }
229    }
230}
231
232impl<'a> ColumnCapabilities<'a> for Option<i16> {
233    #[inline]
234    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
235    where
236        Self: Sized,
237    {
238        unsafe {
239            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
240                return Ok(None);
241            }
242
243            Ok(Some(sqlite3_column_int64(stmt, i as os::raw::c_int) as i16))
244        }
245    }
246
247    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
248    where
249        Self: Sized,
250    {
251        if let Some(t) = self {
252            unsafe {
253                return SqlitePrimaryResult::from(sqlite3_bind_int64(
254                    stmt,
255                    i as os::raw::c_int,
256                    t as os::raw::c_longlong,
257                ));
258            }
259        }
260
261        SqlitePrimaryResult::MisMatch
262    }
263}
264
265impl<'a> ColumnCapabilities<'a> for i16 {
266    #[inline]
267    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
268    where
269        Self: Sized,
270    {
271        unsafe { Ok(sqlite3_column_int64(stmt, i as os::raw::c_int) as Self) }
272    }
273
274    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
275    where
276        Self: Sized,
277    {
278        unsafe {
279            SqlitePrimaryResult::from(sqlite3_bind_int64(
280                stmt,
281                i as os::raw::c_int,
282                self as os::raw::c_longlong,
283            ))
284        }
285    }
286}
287
288impl<'a> ColumnCapabilities<'a> for Option<u16> {
289    #[inline]
290    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
291    where
292        Self: Sized,
293    {
294        unsafe {
295            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
296                return Ok(None);
297            }
298
299            Ok(Some(sqlite3_column_int64(stmt, i as os::raw::c_int) as u16))
300        }
301    }
302
303    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
304    where
305        Self: Sized,
306    {
307        if let Some(t) = self {
308            unsafe {
309                return SqlitePrimaryResult::from(sqlite3_bind_int64(
310                    stmt,
311                    i as os::raw::c_int,
312                    t as os::raw::c_longlong,
313                ));
314            }
315        }
316
317        SqlitePrimaryResult::MisMatch
318    }
319}
320
321impl<'a> ColumnCapabilities<'a> for u16 {
322    #[inline]
323    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
324    where
325        Self: Sized,
326    {
327        unsafe { Ok(sqlite3_column_int64(stmt, i as os::raw::c_int) as Self) }
328    }
329
330    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
331    where
332        Self: Sized,
333    {
334        unsafe {
335            SqlitePrimaryResult::from(sqlite3_bind_int64(
336                stmt,
337                i as os::raw::c_int,
338                self as os::raw::c_longlong,
339            ))
340        }
341    }
342}
343
344impl<'a> ColumnCapabilities<'a> for Option<i32> {
345    #[inline]
346    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
347    where
348        Self: Sized,
349    {
350        unsafe {
351            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
352                return Ok(None);
353            }
354
355            Ok(Some(sqlite3_column_int64(stmt, i as os::raw::c_int) as i32))
356        }
357    }
358
359    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
360    where
361        Self: Sized,
362    {
363        if let Some(t) = self {
364            unsafe {
365                return SqlitePrimaryResult::from(sqlite3_bind_int64(
366                    stmt,
367                    i as os::raw::c_int,
368                    t as os::raw::c_longlong,
369                ));
370            }
371        }
372
373        SqlitePrimaryResult::MisMatch
374    }
375}
376
377impl<'a> ColumnCapabilities<'a> for i32 {
378    #[inline]
379    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
380    where
381        Self: Sized,
382    {
383        unsafe { Ok(sqlite3_column_int64(stmt, i as os::raw::c_int) as Self) }
384    }
385
386    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
387    where
388        Self: Sized,
389    {
390        unsafe {
391            SqlitePrimaryResult::from(sqlite3_bind_int64(
392                stmt,
393                i as os::raw::c_int,
394                self as os::raw::c_longlong,
395            ))
396        }
397    }
398}
399
400impl<'a> ColumnCapabilities<'a> for Option<u32> {
401    #[inline]
402    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
403    where
404        Self: Sized,
405    {
406        unsafe {
407            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
408                return Ok(None);
409            }
410
411            Ok(Some(sqlite3_column_int64(stmt, i as os::raw::c_int) as u32))
412        }
413    }
414
415    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
416    where
417        Self: Sized,
418    {
419        if let Some(t) = self {
420            unsafe {
421                return SqlitePrimaryResult::from(sqlite3_bind_int64(
422                    stmt,
423                    i as os::raw::c_int,
424                    t as os::raw::c_longlong,
425                ));
426            }
427        }
428
429        SqlitePrimaryResult::MisMatch
430    }
431}
432
433impl<'a> ColumnCapabilities<'a> for u32 {
434    #[inline]
435    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
436    where
437        Self: Sized,
438    {
439        unsafe { Ok(sqlite3_column_int64(stmt, i as os::raw::c_int) as Self) }
440    }
441
442    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
443    where
444        Self: Sized,
445    {
446        unsafe {
447            SqlitePrimaryResult::from(sqlite3_bind_int64(
448                stmt,
449                i as os::raw::c_int,
450                self as os::raw::c_longlong,
451            ))
452        }
453    }
454}
455
456impl<'a> ColumnCapabilities<'a> for Option<i64> {
457    #[inline]
458    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
459    where
460        Self: Sized,
461    {
462        unsafe {
463            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
464                return Ok(None);
465            }
466
467            Ok(Some(sqlite3_column_int64(stmt, i as os::raw::c_int)))
468        }
469    }
470
471    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
472    where
473        Self: Sized,
474    {
475        if let Some(t) = self {
476            unsafe {
477                return SqlitePrimaryResult::from(sqlite3_bind_int64(
478                    stmt,
479                    i as os::raw::c_int,
480                    t as os::raw::c_longlong,
481                ));
482            }
483        }
484
485        SqlitePrimaryResult::MisMatch
486    }
487}
488
489impl<'a> ColumnCapabilities<'a> for i64 {
490    #[inline]
491    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
492    where
493        Self: Sized,
494    {
495        unsafe { Ok(sqlite3_column_int64(stmt, i as os::raw::c_int) as Self) }
496    }
497
498    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
499    where
500        Self: Sized,
501    {
502        unsafe {
503            SqlitePrimaryResult::from(sqlite3_bind_int64(
504                stmt,
505                i as os::raw::c_int,
506                self as os::raw::c_longlong,
507            ))
508        }
509    }
510}
511
512impl<'a> ColumnCapabilities<'a> for Option<f32> {
513    #[inline]
514    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
515    where
516        Self: Sized,
517    {
518        unsafe {
519            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
520                return Ok(None);
521            }
522
523            Ok(Some(sqlite3_column_double(stmt, i as os::raw::c_int) as f32))
524        }
525    }
526
527    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
528    where
529        Self: Sized,
530    {
531        if let Some(t) = self {
532            unsafe {
533                return SqlitePrimaryResult::from(sqlite3_bind_double(
534                    stmt,
535                    i as os::raw::c_int,
536                    t.into(),
537                ));
538            }
539        }
540
541        SqlitePrimaryResult::MisMatch
542    }
543}
544
545impl<'a> ColumnCapabilities<'a> for f32 {
546    #[inline]
547    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
548    where
549        Self: Sized,
550    {
551        unsafe { Ok(sqlite3_column_double(stmt, i as os::raw::c_int) as Self) }
552    }
553
554    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
555    where
556        Self: Sized,
557    {
558        unsafe {
559            SqlitePrimaryResult::from(sqlite3_bind_double(stmt, i as os::raw::c_int, self.into()))
560        }
561    }
562}
563
564impl<'a> ColumnCapabilities<'a> for Option<f64> {
565    #[inline]
566    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
567    where
568        Self: Sized,
569    {
570        unsafe {
571            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
572                return Ok(None);
573            }
574
575            Ok(Some(sqlite3_column_double(stmt, i as os::raw::c_int)))
576        }
577    }
578
579    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
580    where
581        Self: Sized,
582    {
583        if let Some(t) = self {
584            unsafe {
585                return SqlitePrimaryResult::from(sqlite3_bind_double(
586                    stmt,
587                    i as os::raw::c_int,
588                    t,
589                ));
590            }
591        }
592
593        SqlitePrimaryResult::MisMatch
594    }
595}
596
597impl<'a> ColumnCapabilities<'a> for f64 {
598    #[inline]
599    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
600    where
601        Self: Sized,
602    {
603        unsafe { Ok(sqlite3_column_double(stmt, i as os::raw::c_int) as Self) }
604    }
605
606    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
607    where
608        Self: Sized,
609    {
610        unsafe { SqlitePrimaryResult::from(sqlite3_bind_double(stmt, i as os::raw::c_int, self)) }
611    }
612}
613
614impl<'a> ColumnCapabilities<'a> for Option<&str> {
615    #[inline]
616    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
617    where
618        Self: Sized,
619    {
620        unsafe {
621            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
622                return Ok(None);
623            }
624
625            let result = sqlite3_column_text(stmt, i as os::raw::c_int);
626            Ok(Some(CStr::from_ptr(result as *const _).to_str()?))
627        }
628    }
629
630    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
631    where
632        Self: Sized,
633    {
634        if let Some(t) = self {
635            unsafe {
636                return SqlitePrimaryResult::from(sqlite3_bind_text(
637                    stmt,
638                    i as os::raw::c_int,
639                    t.as_ptr() as *const _,
640                    t.len() as os::raw::c_int,
641                    sqlite_transient(),
642                ));
643            }
644        }
645
646        SqlitePrimaryResult::MisMatch
647    }
648}
649
650impl<'a> ColumnCapabilities<'a> for &str {
651    #[inline]
652    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
653    where
654        Self: Sized,
655    {
656        unsafe {
657            let result = sqlite3_column_text(stmt, i as os::raw::c_int);
658            Ok(CStr::from_ptr(result as *const _).to_str()?)
659        }
660    }
661
662    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
663    where
664        Self: Sized,
665    {
666        unsafe {
667            SqlitePrimaryResult::from(sqlite3_bind_text(
668                stmt,
669                i as os::raw::c_int,
670                self.as_ptr() as *const _,
671                self.len() as os::raw::c_int,
672                sqlite_transient(),
673            ))
674        }
675    }
676}
677
678impl<'a> ColumnCapabilities<'a> for Option<String> {
679    #[inline]
680    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
681    where
682        Self: Sized,
683    {
684        unsafe {
685            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
686                return Ok(None);
687            }
688
689            let result = sqlite3_column_text(stmt, i as os::raw::c_int);
690            Ok(Some(
691                CStr::from_ptr(result as *const _).to_str()?.to_owned(),
692            ))
693        }
694    }
695
696    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
697    where
698        Self: Sized,
699    {
700        if let Some(t) = self {
701            unsafe {
702                return SqlitePrimaryResult::from(sqlite3_bind_text(
703                    stmt,
704                    i as os::raw::c_int,
705                    t.as_ptr() as *const _,
706                    t.len() as os::raw::c_int,
707                    sqlite_transient(),
708                ));
709            }
710        }
711
712        SqlitePrimaryResult::MisMatch
713    }
714}
715
716impl<'a> ColumnCapabilities<'a> for String {
717    #[inline]
718    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
719    where
720        Self: Sized,
721    {
722        unsafe {
723            let result = sqlite3_column_text(stmt, i as os::raw::c_int);
724            Ok(CStr::from_ptr(result as *const _).to_str()?.to_owned())
725        }
726    }
727
728    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
729    where
730        Self: Sized,
731    {
732        unsafe {
733            SqlitePrimaryResult::from(sqlite3_bind_text(
734                stmt,
735                i as os::raw::c_int,
736                self.as_ptr() as *const _,
737                self.len() as os::raw::c_int,
738                sqlite_transient(),
739            ))
740        }
741    }
742}
743
744impl<'a> ColumnCapabilities<'a> for Option<Vec<u8>> {
745    #[inline]
746    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
747    where
748        Self: Sized,
749    {
750        use ptr::copy_nonoverlapping as copy;
751        unsafe {
752            if sqlite3_column_type(stmt, i as os::raw::c_int) as u32 == COLUMN_NULL {
753                return Ok(None);
754            }
755
756            let pointer = sqlite3_column_blob(stmt, i as os::raw::c_int);
757            if pointer.is_null() {
758                return Ok(Some(vec![]));
759            }
760
761            let count = sqlite3_column_bytes(stmt, i as os::raw::c_int) as usize;
762            let mut buffer = Vec::with_capacity(count);
763            #[allow(clippy::uninit_vec)]
764            buffer.set_len(count); // need to allocate every single location in vec before copying the buffer
765            copy(pointer as *const u8, buffer.as_mut_ptr(), count);
766            Ok(Some(buffer))
767        }
768    }
769
770    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
771    where
772        Self: Sized,
773    {
774        unsafe {
775            if let Some(t) = self {
776                if t.is_empty() {
777                    return SqlitePrimaryResult::from(sqlite3_bind_zeroblob64(
778                        stmt,
779                        i as os::raw::c_int,
780                        0,
781                    ));
782                }
783
784                return SqlitePrimaryResult::from(sqlite3_bind_blob(
785                    stmt,
786                    i as os::raw::c_int,
787                    t.as_ptr() as *const _,
788                    t.len() as os::raw::c_int,
789                    sqlite_transient(),
790                ));
791            }
792        }
793
794        SqlitePrimaryResult::MisMatch
795    }
796}
797
798impl<'a> ColumnCapabilities<'a> for Vec<u8> {
799    #[inline]
800    fn get_data(stmt: *mut sqlite3_stmt, i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
801    where
802        Self: Sized,
803    {
804        use ptr::copy_nonoverlapping as copy;
805        unsafe {
806            let pointer = sqlite3_column_blob(stmt, i as os::raw::c_int);
807            if pointer.is_null() {
808                return Ok(vec![]);
809            }
810
811            let count = sqlite3_column_bytes(stmt, i as os::raw::c_int) as usize;
812            let mut buffer = Vec::with_capacity(count);
813            #[allow(clippy::uninit_vec)]
814            buffer.set_len(count); // need to allocate every single location in vec before copying the buffer
815            copy(pointer as *const u8, buffer.as_mut_ptr(), count);
816            Ok(buffer)
817        }
818    }
819
820    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
821    where
822        Self: Sized,
823    {
824        unsafe {
825            if self.is_empty() {
826                return SqlitePrimaryResult::from(sqlite3_bind_zeroblob64(
827                    stmt,
828                    i as os::raw::c_int,
829                    0,
830                ));
831            }
832
833            SqlitePrimaryResult::from(sqlite3_bind_blob(
834                stmt,
835                i as os::raw::c_int,
836                self.as_ptr() as *const _,
837                self.len() as os::raw::c_int,
838                sqlite_transient(),
839            ))
840        }
841    }
842}
843
844impl<'a> ColumnCapabilities<'a> for Option<&[u8]> {
845    fn get_data(_stmt: *mut sqlite3_stmt, _i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
846    where
847        Self: Sized,
848    {
849        unimplemented!()
850    }
851
852    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
853    where
854        Self: Sized,
855    {
856        if let Some(t) = self {
857            unsafe {
858                if t.is_empty() {
859                    return SqlitePrimaryResult::from(sqlite3_bind_zeroblob64(
860                        stmt,
861                        i as os::raw::c_int,
862                        0,
863                    ));
864                }
865
866                return SqlitePrimaryResult::from(sqlite3_bind_blob(
867                    stmt,
868                    i as os::raw::c_int,
869                    t.as_ptr() as *const _,
870                    t.len() as os::raw::c_int,
871                    sqlite_transient(),
872                ));
873            }
874        }
875
876        SqlitePrimaryResult::MisMatch
877    }
878}
879
880impl<'a> ColumnCapabilities<'a> for &[u8] {
881    fn get_data(_stmt: *mut sqlite3_stmt, _i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
882    where
883        Self: Sized,
884    {
885        unimplemented!()
886    }
887
888    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
889    where
890        Self: Sized,
891    {
892        unsafe {
893            if self.is_empty() {
894                return SqlitePrimaryResult::from(sqlite3_bind_zeroblob64(
895                    stmt,
896                    i as os::raw::c_int,
897                    0,
898                ));
899            }
900
901            SqlitePrimaryResult::from(sqlite3_bind_blob(
902                stmt,
903                i as os::raw::c_int,
904                self.as_ptr() as *const _,
905                self.len() as os::raw::c_int,
906                sqlite_transient(),
907            ))
908        }
909    }
910}
911
912impl<'a> ColumnCapabilities<'a> for Option<SqliteNull> {
913    fn get_data(_stmt: *mut sqlite3_stmt, _i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
914    where
915        Self: Sized,
916    {
917        unimplemented!()
918    }
919
920    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
921    where
922        Self: Sized,
923    {
924        unsafe { SqlitePrimaryResult::from(sqlite3_bind_null(stmt, i as os::raw::c_int)) }
925    }
926}
927
928impl<'a> ColumnCapabilities<'a> for SqliteNull {
929    fn get_data(_stmt: *mut sqlite3_stmt, _i: usize) -> Result<Self, MinSqliteWrapperError<'a>>
930    where
931        Self: Sized,
932    {
933        unimplemented!()
934    }
935
936    fn bind_val(self, stmt: *mut sqlite3_stmt, i: usize) -> SqlitePrimaryResult
937    where
938        Self: Sized,
939    {
940        unsafe { SqlitePrimaryResult::from(sqlite3_bind_null(stmt, i as os::raw::c_int)) }
941    }
942}
943
944/// Defines SQL functions.
945pub trait Operations {
946    /// A wrapper around prepare(), execute_prepared(), and kill(), that allows an
947    /// application to run multiple statements of SQL without having to use a lot of Rust code.
948    ///
949    /// # Warning
950    /// This function does not provide to read data from SQLite.
951    ///
952    /// # Usage
953    /// let db_path = Path::new("./example.db");
954    /// let db = Database::open(db_path).unwrap();
955    ///
956    /// let status = db.execute(statement, None::<Box<dyn FnOnce(SqlitePrimaryResult, String)>>).unwrap();
957    ///
958    /// if status != SqlitePrimaryResult::Ok {
959    ///    ...
960    /// }
961    ///
962    /// db.close();
963    /// ```
964    fn execute<'a, F>(
965        &self,
966        statement: String,
967        callback_fn: Option<F>,
968    ) -> Result<SqlitePrimaryResult, MinSqliteWrapperError<'a>>
969    where
970        F: FnOnce(SqlitePrimaryResult, String);
971
972    /// Prepares SQL operation to be executed and then destroy.
973    ///
974    /// # Warning
975    /// kill() must be called for each result of the prepare() function in order to avoid resource leak.
976    ///
977    ///
978    /// # Usage
979    /// let db_path = Path::new("./example.db");
980    /// let db = Database::open(db_path).unwrap();
981    ///
982    /// let statement = String::from(
983    ///     "SELECT * FROM example_table WHERE ID = '15';"
984    /// );
985    ///
986    /// let mut sql = db.prepare(statement, None::<Box<dyn FnOnce(SqlitePrimaryResult, String)>>).unwrap();
987    ///
988    /// while let PreparedStatementStatus::FoundRow = sql.execute_prepared() {
989    ///     ...
990    /// }
991    ///
992    /// sql.kill();
993    /// db.close();
994    /// ```
995    fn prepare<'a, F>(
996        &self,
997        statement: String,
998        callback_fn: Option<F>,
999    ) -> Result<SqlStatement, MinSqliteWrapperError<'a>>
1000    where
1001        F: FnOnce(SqlitePrimaryResult, String);
1002}
1003
1004impl Operations for Database {
1005    fn execute<'a, F>(
1006        &self,
1007        statement: String,
1008        callback_fn: Option<F>,
1009    ) -> Result<SqlitePrimaryResult, MinSqliteWrapperError<'a>>
1010    where
1011        F: FnOnce(SqlitePrimaryResult, String),
1012    {
1013        let st = CString::new(&*statement)?;
1014        unsafe {
1015            let status: SqlitePrimaryResult =
1016                sqlite3_exec(self.rp, st.as_ptr(), None, ptr::null_mut(), ptr::null_mut()).into();
1017
1018            if status != SqlitePrimaryResult::Ok {
1019                if let Some(func) = callback_fn {
1020                    func(status, statement);
1021                }
1022            }
1023
1024            Ok(status)
1025        }
1026    }
1027
1028    fn prepare<'a, F>(
1029        &self,
1030        statement: String,
1031        callback_fn: Option<F>,
1032    ) -> Result<SqlStatement, MinSqliteWrapperError<'a>>
1033    where
1034        F: FnOnce(SqlitePrimaryResult, String),
1035    {
1036        let st = CString::new(&*statement)?;
1037        let mut stmt = ptr::null_mut();
1038        let mut tail = ptr::null();
1039
1040        unsafe {
1041            let status: SqlitePrimaryResult = sqlite3_prepare_v2(
1042                self.rp,
1043                st.as_ptr(),
1044                statement.len() as os::raw::c_int,
1045                &mut stmt,
1046                &mut tail,
1047            )
1048            .into();
1049
1050            if status != SqlitePrimaryResult::Ok {
1051                if let Some(func) = callback_fn {
1052                    func(status, statement);
1053                }
1054            }
1055        }
1056
1057        Ok(SqlStatement::new(stmt))
1058    }
1059}