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
128
129
130
use core::ffi::c_void;
use core::mem;
use std::os::raw::{c_char, c_int};
use libsqlite3_sys::{
sqlite3_bind_blob, sqlite3_bind_double, sqlite3_bind_int, sqlite3_bind_int64,
sqlite3_bind_null, sqlite3_bind_text, SQLITE_OK, SQLITE_TRANSIENT,
};
use crate::arguments::Arguments;
use crate::encode::{Encode, IsNull};
use crate::sqlite::statement::Statement;
use crate::sqlite::Sqlite;
use crate::sqlite::SqliteError;
use crate::types::Type;
#[derive(Debug, Clone)]
pub enum SqliteArgumentValue {
Null,
Text(String),
Blob(Vec<u8>),
Double(f64),
Int(i32),
Int64(i64),
}
#[derive(Default,Debug)]
pub struct SqliteArguments {
index: usize,
values: Vec<SqliteArgumentValue>,
}
impl SqliteArguments {
pub(crate) fn next(&mut self) -> Option<SqliteArgumentValue> {
if self.index >= self.values.len() {
return None;
}
let mut value = SqliteArgumentValue::Null;
mem::swap(&mut value, &mut self.values[self.index]);
self.index += 1;
Some(value)
}
}
impl Arguments for SqliteArguments {
type Database = Sqlite;
fn reserve(&mut self, len: usize, _size_hint: usize) {
self.values.reserve(len);
}
fn add<T>(&mut self, value: T)
where
T: Encode<Self::Database> + Type<Self::Database>,
{
if let IsNull::Yes = value.encode_nullable(&mut self.values) {
self.values.push(SqliteArgumentValue::Null);
}
}
}
impl SqliteArgumentValue {
pub(super) fn bind(&self, statement: &mut Statement, index: usize) -> crate::Result<()> {
let handle = unsafe {
if let Some(handle) = statement.handle() {
handle
} else {
return Ok(());
}
};
let index = index as c_int;
let status: c_int = match self {
SqliteArgumentValue::Blob(value) => {
let bytes = value.as_slice();
let bytes_ptr = bytes.as_ptr() as *const c_void;
let bytes_len = bytes.len() as i32;
unsafe {
sqlite3_bind_blob(handle, index, bytes_ptr, bytes_len, SQLITE_TRANSIENT())
}
}
SqliteArgumentValue::Text(value) => {
let bytes = value.as_bytes();
let bytes_ptr = bytes.as_ptr() as *const c_char;
let bytes_len = bytes.len() as i32;
unsafe {
sqlite3_bind_text(handle, index, bytes_ptr, bytes_len, SQLITE_TRANSIENT())
}
}
SqliteArgumentValue::Double(value) => unsafe {
sqlite3_bind_double(handle, index, *value)
},
SqliteArgumentValue::Int(value) => unsafe { sqlite3_bind_int(handle, index, *value) },
SqliteArgumentValue::Int64(value) => unsafe {
sqlite3_bind_int64(handle, index, *value)
},
SqliteArgumentValue::Null => unsafe { sqlite3_bind_null(handle, index) },
};
if status != SQLITE_OK {
return Err(SqliteError::from_connection(statement.connection.0.as_ptr()).into());
}
Ok(())
}
}