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::*;
10use sqlx_core::error::BoxDynError;
11
12#[derive(Debug, Clone)]
13pub enum SqliteArgumentValue<'q> {
14 Null,
15 Text(Cow<'q, str>),
16 Blob(Cow<'q, [u8]>),
17 Double(f64),
18 Int(i32),
19 Int64(i64),
20}
21
22#[derive(Default, Debug, Clone)]
23pub struct SqliteArguments<'q> {
24 pub(crate) values: Vec<SqliteArgumentValue<'q>>,
25}
26
27impl<'q> SqliteArguments<'q> {
28 pub(crate) fn add<T>(&mut self, value: T) -> Result<(), BoxDynError>
29 where
30 T: Encode<'q, Sqlite>,
31 {
32 let value_length_before_encoding = self.values.len();
33
34 match value.encode(&mut self.values) {
35 Ok(IsNull::Yes) => self.values.push(SqliteArgumentValue::Null),
36 Ok(IsNull::No) => {}
37 Err(error) => {
38 self.values.truncate(value_length_before_encoding);
40 return Err(error);
41 }
42 };
43
44 Ok(())
45 }
46
47 pub(crate) fn into_static(self) -> SqliteArguments<'static> {
48 SqliteArguments {
49 values: self
50 .values
51 .into_iter()
52 .map(SqliteArgumentValue::into_static)
53 .collect(),
54 }
55 }
56}
57
58impl<'q> Arguments<'q> for SqliteArguments<'q> {
59 type Database = Sqlite;
60
61 fn reserve(&mut self, len: usize, _size_hint: usize) {
62 self.values.reserve(len);
63 }
64
65 fn add<T>(&mut self, value: T) -> Result<(), BoxDynError>
66 where
67 T: Encode<'q, Self::Database>,
68 {
69 self.add(value)
70 }
71
72 fn len(&self) -> usize {
73 self.values.len()
74 }
75}
76
77impl SqliteArguments<'_> {
78 pub(super) fn bind(&self, handle: &mut StatementHandle, offset: usize) -> Result<usize, Error> {
79 let mut arg_i = offset;
80 let cnt = handle.bind_parameter_count();
83
84 for param_i in 1..=cnt {
85 let n: usize = if let Some(name) = handle.bind_parameter_name(param_i) {
87 if let Some(name) = name.strip_prefix('?') {
88 atoi(name.as_bytes()).expect("parameter of the form ?NNN")
90 } else if let Some(name) = name.strip_prefix('$') {
91 atoi(name.as_bytes()).ok_or_else(|| {
93 err_protocol!(
94 "parameters with non-integer names are not currently supported: {}",
95 name
96 )
97 })?
98 } else {
99 return Err(err_protocol!("unsupported SQL parameter format: {}", name));
100 }
101 } else {
102 arg_i += 1;
103 arg_i
104 };
105
106 if n > self.values.len() {
107 break;
114 }
115
116 self.values[n - 1].bind(handle, param_i)?;
117 }
118
119 Ok(arg_i - offset)
120 }
121}
122
123impl SqliteArgumentValue<'_> {
124 fn into_static(self) -> SqliteArgumentValue<'static> {
125 use SqliteArgumentValue::*;
126
127 match self {
128 Null => Null,
129 Text(text) => Text(text.into_owned().into()),
130 Blob(blob) => Blob(blob.into_owned().into()),
131 Int(v) => Int(v),
132 Int64(v) => Int64(v),
133 Double(v) => Double(v),
134 }
135 }
136
137 fn bind(&self, handle: &mut StatementHandle, i: usize) -> Result<(), Error> {
138 use SqliteArgumentValue::*;
139
140 let status = match self {
141 Text(v) => handle.bind_text(i, v),
142 Blob(v) => handle.bind_blob(i, v),
143 Int(v) => handle.bind_int(i, *v),
144 Int64(v) => handle.bind_int64(i, *v),
145 Double(v) => handle.bind_double(i, *v),
146 Null => handle.bind_null(i),
147 };
148
149 if status != SQLITE_OK {
150 return Err(handle.last_error().into());
151 }
152
153 Ok(())
154 }
155}