forked from transact-rs/sqlx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patharguments.rs
More file actions
135 lines (108 loc) 路 3.69 KB
/
Copy patharguments.rs
File metadata and controls
135 lines (108 loc) 路 3.69 KB
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
131
132
133
134
135
use core::ffi::c_void;
use core::mem;
use std::os::raw::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,
// TODO: Take by reference to remove the allocation
Text(String),
// TODO: Take by reference to remove the allocation
Blob(Vec<u8>),
Double(f64),
Int(i32),
Int64(i64),
}
#[derive(Default)]
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<()> {
// TODO: Handle error of trying to bind too many parameters here
let index = index as c_int;
// https://sqlite.org/c3ref/bind_blob.html
#[allow(unsafe_code)]
let status: c_int = match self {
SqliteArgumentValue::Blob(value) => {
// TODO: Handle bytes that are too large
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(
statement.handle(),
index,
bytes_ptr,
bytes_len,
SQLITE_TRANSIENT(),
)
}
}
SqliteArgumentValue::Text(value) => {
// TODO: Handle text that is too large
let bytes = value.as_bytes();
let bytes_ptr = bytes.as_ptr() as *const i8;
let bytes_len = bytes.len() as i32;
unsafe {
sqlite3_bind_text(
statement.handle(),
index,
bytes_ptr,
bytes_len,
SQLITE_TRANSIENT(),
)
}
}
SqliteArgumentValue::Double(value) => unsafe {
sqlite3_bind_double(statement.handle(), index, *value)
},
SqliteArgumentValue::Int(value) => unsafe {
sqlite3_bind_int(statement.handle(), index, *value)
},
SqliteArgumentValue::Int64(value) => unsafe {
sqlite3_bind_int64(statement.handle(), index, *value)
},
SqliteArgumentValue::Null => unsafe { sqlite3_bind_null(statement.handle(), index) },
};
if status != SQLITE_OK {
return Err(SqliteError::from_connection(statement.connection.0.as_ptr()).into());
}
Ok(())
}
}