sqlx_core_oldapi/sqlite/
arguments.rs

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