Skip to content

Commit fbb3446

Browse files
refactor: optimize SQLite bindings with zero-copy parameters
Replaced the eager allocation of String parameters and deep cloning of parameter lists in `std.sqlite` module `execute` and `query` functions. Implemented a zero-copy wrapper `SqlParam` that directly implements `rusqlite::types::ToSql` on borrowed references, significantly reducing memory allocation overhead on repeated query executions. Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com>
1 parent 43c970d commit fbb3446

1 file changed

Lines changed: 32 additions & 32 deletions

File tree

‎stdlib/src/sqlite.rs‎

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,30 @@ thread_local! {
1212

1313
static NEXT_ID: AtomicI64 = AtomicI64::new(1);
1414

15-
fn runtime_to_sql_value(v: &RuntimeValue) -> rusqlite::types::Value {
16-
match v {
17-
RuntimeValue::Null => rusqlite::types::Value::Null,
18-
RuntimeValue::Bool(b) => rusqlite::types::Value::Integer(if *b { 1 } else { 0 }),
19-
RuntimeValue::Int(i) => rusqlite::types::Value::Integer(*i),
20-
RuntimeValue::Float(f) => rusqlite::types::Value::Real(*f),
21-
RuntimeValue::Str(s) => rusqlite::types::Value::Text(s.clone()),
22-
_ => rusqlite::types::Value::Text(v.to_string()),
15+
struct SqlParam<'a>(&'a RuntimeValue);
16+
17+
impl<'a> rusqlite::types::ToSql for SqlParam<'a> {
18+
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
19+
match self.0 {
20+
RuntimeValue::Null => Ok(rusqlite::types::ToSqlOutput::Borrowed(
21+
rusqlite::types::ValueRef::Null,
22+
)),
23+
RuntimeValue::Bool(b) => Ok(rusqlite::types::ToSqlOutput::Borrowed(
24+
rusqlite::types::ValueRef::Integer(if *b { 1 } else { 0 }),
25+
)),
26+
RuntimeValue::Int(i) => Ok(rusqlite::types::ToSqlOutput::Borrowed(
27+
rusqlite::types::ValueRef::Integer(*i),
28+
)),
29+
RuntimeValue::Float(f) => Ok(rusqlite::types::ToSqlOutput::Borrowed(
30+
rusqlite::types::ValueRef::Real(*f),
31+
)),
32+
RuntimeValue::Str(s) => Ok(rusqlite::types::ToSqlOutput::Borrowed(
33+
rusqlite::types::ValueRef::Text(s.as_bytes()),
34+
)),
35+
_ => Ok(rusqlite::types::ToSqlOutput::Owned(
36+
rusqlite::types::Value::Text(self.0.to_string()),
37+
)),
38+
}
2339
}
2440
}
2541

@@ -63,19 +79,11 @@ impl StdlibRegistry {
6379
)
6480
})?;
6581
let sql = args[1].to_string();
66-
let params_list = if args.len() > 2 {
67-
if let RuntimeValue::List { items, .. } = &args[2] {
68-
items.borrow().clone()
69-
} else {
70-
Vec::new()
71-
}
72-
} else {
73-
Vec::new()
74-
};
75-
76-
let params: Vec<rusqlite::types::Value> = if let Some(arg) = args.get(2) {
82+
let _items_borrow;
83+
let params: Vec<SqlParam> = if let Some(arg) = args.get(2) {
7784
if let RuntimeValue::List { items, .. } = arg {
78-
items.borrow().iter().map(runtime_to_sql_value).collect()
85+
_items_borrow = items.borrow();
86+
_items_borrow.iter().map(SqlParam).collect()
7987
} else {
8088
return Err(RuntimeError::new(
8189
RuntimeErrorKind::TypeMismatch {
@@ -138,19 +146,11 @@ impl StdlibRegistry {
138146
)
139147
})?;
140148
let sql = args[1].to_string();
141-
let params_list = if args.len() > 2 {
142-
if let RuntimeValue::List { items, .. } = &args[2] {
143-
items.borrow().clone()
144-
} else {
145-
Vec::new()
146-
}
147-
} else {
148-
Vec::new()
149-
};
150-
151-
let params: Vec<rusqlite::types::Value> = if let Some(arg) = args.get(2) {
149+
let _items_borrow;
150+
let params: Vec<SqlParam> = if let Some(arg) = args.get(2) {
152151
if let RuntimeValue::List { items, .. } = arg {
153-
items.borrow().iter().map(runtime_to_sql_value).collect()
152+
_items_borrow = items.borrow();
153+
_items_borrow.iter().map(SqlParam).collect()
154154
} else {
155155
return Err(RuntimeError::new(
156156
RuntimeErrorKind::TypeMismatch {

0 commit comments

Comments
 (0)