sqlx_build_trust_sqlite/
arguments.rs

1use crate::encode::{Encode, IsNull};
2use crate::error::Error;
3use crate::statement::StatementHandle;
4use crate::Sqlite;
5use atoi::atoi;
6use libsqlite3_sys::SQLITE_OK;
7use std::borrow::Cow;
8
9pub(crate) use sqlx_core::arguments::*;
10
11#[derive(Debug, Clone)]
12pub enum SqliteArgumentValue<'q> {
13    Null,
14    Text(Cow<'q, str>),
15    Blob(Cow<'q, [u8]>),
16    Double(f64),
17    Int(i32),
18    Int64(i64),
19}
20
21#[derive(Default, Debug, Clone)]
22pub struct SqliteArguments<'q> {
23    pub(crate) values: Vec<SqliteArgumentValue<'q>>,
24}
25
26impl<'q> SqliteArguments<'q> {
27    pub(crate) fn add<T>(&mut self, value: T)
28    where
29        T: Encode<'q, Sqlite>,
30    {
31        if let IsNull::Yes = value.encode(&mut self.values) {
32            self.values.push(SqliteArgumentValue::Null);
33        }
34    }
35
36    pub(crate) fn into_static(self) -> SqliteArguments<'static> {
37        SqliteArguments {
38            values: self
39                .values
40                .into_iter()
41                .map(SqliteArgumentValue::into_static)
42                .collect(),
43        }
44    }
45}
46
47impl<'q> Arguments<'q> for SqliteArguments<'q> {
48    type Database = Sqlite;
49
50    fn reserve(&mut self, len: usize, _size_hint: usize) {
51        self.values.reserve(len);
52    }
53
54    fn add<T>(&mut self, value: T)
55    where
56        T: Encode<'q, Self::Database>,
57    {
58        self.add(value)
59    }
60}
61
62impl SqliteArguments<'_> {
63    pub(super) fn bind(&self, handle: &mut StatementHandle, offset: usize) -> Result<usize, Error> {
64        let mut arg_i = offset;
65        // for handle in &statement.handles {
66
67        let cnt = handle.bind_parameter_count();
68
69        for param_i in 1..=cnt {
70            // figure out the index of this bind parameter into our argument tuple
71            let n: usize = if let Some(name) = handle.bind_parameter_name(param_i) {
72                if let Some(name) = name.strip_prefix('?') {
73                    // parameter should have the form ?NNN
74                    atoi(name.as_bytes()).expect("parameter of the form ?NNN")
75                } else if let Some(name) = name.strip_prefix('$') {
76                    // parameter should have the form $NNN
77                    atoi(name.as_bytes()).ok_or_else(|| {
78                        err_protocol!(
79                            "parameters with non-integer names are not currently supported: {}",
80                            name
81                        )
82                    })?
83                } else {
84                    return Err(err_protocol!("unsupported SQL parameter format: {}", name));
85                }
86            } else {
87                arg_i += 1;
88                arg_i
89            };
90
91            if n > self.values.len() {
92                // SQLite treats unbound variables as NULL
93                // we reproduce this here
94                // If you are reading this and think this should be an error, open an issue and we can
95                // discuss configuring this somehow
96                // Note that the query macros have a different way of enforcing
97                // argument arity
98                break;
99            }
100
101            self.values[n - 1].bind(handle, param_i)?;
102        }
103
104        Ok(arg_i - offset)
105    }
106}
107
108impl SqliteArgumentValue<'_> {
109    fn into_static(self) -> SqliteArgumentValue<'static> {
110        use SqliteArgumentValue::*;
111
112        match self {
113            Null => Null,
114            Text(text) => Text(text.into_owned().into()),
115            Blob(blob) => Blob(blob.into_owned().into()),
116            Int(v) => Int(v),
117            Int64(v) => Int64(v),
118            Double(v) => Double(v),
119        }
120    }
121
122    fn bind(&self, handle: &mut StatementHandle, i: usize) -> Result<(), Error> {
123        use SqliteArgumentValue::*;
124
125        let status = match self {
126            Text(v) => handle.bind_text(i, v),
127            Blob(v) => handle.bind_blob(i, v),
128            Int(v) => handle.bind_int(i, *v),
129            Int64(v) => handle.bind_int64(i, *v),
130            Double(v) => handle.bind_double(i, *v),
131            Null => handle.bind_null(i),
132        };
133
134        if status != SQLITE_OK {
135            return Err(handle.last_error().into());
136        }
137
138        Ok(())
139    }
140}