/
germanubis
/
sqlx
Обзор
Документация
Войти
/
germanubis
/
sqlx
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
sqlx-sqlite/src/arguments.rs
148 строк
4 KB
iamjpotts
refactor(core): Remove lifetime parameter from Arguments trait (#3960)
14 сен 2025, 07:47
Не верифицирован
14 сен 2025, 07:47
8152689
Код
Авторство
О чём код?
use crate::encode::{Encode, IsNull}; use crate::error::Error; use crate::statement::StatementHandle; use crate::Sqlite; use atoi::atoi; use libsqlite3_sys::SQLITE_OK; use std::sync::Arc; pub(crate) use sqlx_core::arguments::*; use sqlx_core::error::BoxDynError; #[derive(Debug, Clone)] pub enum SqliteArgumentValue { Null, Text(Arc<String>), TextSlice(Arc<str>), Blob(Arc<Vec<u8>>), Double(f64), Int(i32), Int64(i64), } #[derive(Default, Debug, Clone)] pub struct SqliteArguments { pub(crate) values: SqliteArgumentsBuffer, } #[derive(Default, Debug, Clone)] pub struct SqliteArgumentsBuffer(Vec<SqliteArgumentValue>); impl SqliteArguments { pub(crate) fn add<'t, T>(&mut self, value: T) -> Result<(), BoxDynError> where T: Encode<'t, Sqlite>, { let value_length_before_encoding = self.values.0.len(); match value.encode(&mut self.values) { Ok(IsNull::Yes) => self.values.0.push(SqliteArgumentValue::Null), Ok(IsNull::No) => {} Err(error) => { // reset the value buffer to its previous value if encoding failed so we don't leave a half-encoded value behind self.values.0.truncate(value_length_before_encoding); return Err(error); } }; Ok(()) } } impl Arguments for SqliteArguments { type Database = Sqlite; fn reserve(&mut self, len: usize, _size_hint: usize) { self.values.0.reserve(len); } fn add<'t, T>(&mut self, value: T) -> Result<(), BoxDynError> where T: Encode<'t, Self::Database>, { self.add(value) } fn len(&self) -> usize { self.values.0.len() } } impl SqliteArguments { pub(super) fn bind(&self, handle: &mut StatementHandle, offset: usize) -> Result<usize, Error> { let mut arg_i = offset; // for handle in &statement.handles { let cnt = handle.bind_parameter_count(); for param_i in 1..=cnt { // figure out the index of this bind parameter into our argument tuple let n: usize = if let Some(name) = handle.bind_parameter_name(param_i) { if let Some(name) = name.strip_prefix('?') { // parameter should have the form ?NNN atoi(name.as_bytes()).expect("parameter of the form ?NNN") } else if let Some(name) = name.strip_prefix('$') { // parameter should have the form $NNN 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.0.len() { // SQLite treats unbound variables as NULL // we reproduce this here // If you are reading this and think this should be an error, open an issue and we can // discuss configuring this somehow // Note that the query macros have a different way of enforcing // argument arity break; } self.values.0[n - 1].bind(handle, param_i)?; } Ok(arg_i - offset) } } impl SqliteArgumentsBuffer { #[allow(dead_code)] // clippy incorrectly reports this as unused pub(crate) fn new(values: Vec<SqliteArgumentValue>) -> SqliteArgumentsBuffer { Self(values) } pub(crate) fn push(&mut self, value: SqliteArgumentValue) { self.0.push(value); } } impl SqliteArgumentValue { fn bind(&self, handle: &mut StatementHandle, i: usize) -> Result<(), Error> { use SqliteArgumentValue::*; let status = match self { Text(v) => handle.bind_text(i, v), TextSlice(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(()) } }