1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::encode::{Encode, IsNull};
use crate::statement::StatementHandle;
use atoi::atoi;
use libsqlite3_sys::SQLITE_OK;
use rbdc::err_protocol;
use rbdc::error::Error;
#[derive(Debug, Clone)]
pub enum SqliteArgumentValue {
Null,
Text(String),
Blob(Vec<u8>),
Double(f64),
Int(i32),
Int64(i64),
}
#[derive(Default, Debug, Clone)]
pub struct SqliteArguments {
pub(crate) values: Vec<SqliteArgumentValue>,
}
impl SqliteArguments {
pub fn add<T>(&mut self, value: T) -> Result<(), Error>
where
T: Encode,
{
if let IsNull::Yes = value.encode(&mut self.values)? {
self.values.push(SqliteArgumentValue::Null);
}
Ok(())
}
pub(crate) fn into_static(self) -> SqliteArguments {
SqliteArguments {
values: self
.values
.into_iter()
.map(SqliteArgumentValue::into_static)
.collect(),
}
}
pub fn reserve(&mut self, len: usize, _size_hint: usize) {
self.values.reserve(len);
}
}
impl SqliteArguments {
pub(super) fn bind(&self, handle: &mut StatementHandle, offset: usize) -> Result<usize, Error> {
let mut arg_i = offset;
let cnt = handle.bind_parameter_count();
for param_i in 1..=cnt {
let n: usize = if let Some(name) = handle.bind_parameter_name(param_i) {
if let Some(name) = name.strip_prefix('?') {
atoi(name.as_bytes()).expect("parameter of the form ?NNN")
} else if let Some(name) = name.strip_prefix('$') {
atoi(name.as_bytes()).ok_or_else(|| {
err_protocol!(
"parameters with non-integer names are not currently supported: {}",
name
)
})?
} else {
return Err(err_protocol!("unsupported SQL parameter format: {}", name));
}
} else {
arg_i += 1;
arg_i
};
if n > self.values.len() {
break;
}
self.values[n - 1].bind(handle, param_i)?;
}
Ok(arg_i - offset)
}
}
impl SqliteArgumentValue {
fn into_static(self) -> SqliteArgumentValue {
use SqliteArgumentValue::*;
match self {
Null => Null,
Text(text) => Text(text),
Blob(blob) => Blob(blob),
Int(v) => Int(v),
Int64(v) => Int64(v),
Double(v) => Double(v),
}
}
fn bind(&self, handle: &mut StatementHandle, i: usize) -> Result<(), Error> {
use SqliteArgumentValue::*;
let status = match self {
Text(v) => handle.bind_text(i, v),
Blob(v) => handle.bind_blob(i, v),
Int(v) => handle.bind_int(i, *v),
Int64(v) => handle.bind_int64(i, *v),
Double(v) => handle.bind_double(i, *v),
Null => handle.bind_null(i),
};
if status != SQLITE_OK {
return Err(handle.last_error().into());
}
Ok(())
}
}