From 69ff081b9cc29072a4544209fc46652d88d5e92c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 08:24:22 +0000 Subject: [PATCH] Optimize SQLite query mapping - Use `IndexMap::with_capacity` for map allocations based on column count. - Instead of filling a map with `RuntimeValue::Null` and fetching it again, pre-allocate the map and use `rusqlite::types::ValueRef` matching to avoid multiple lookups and unnecessary String allocations for native ints and floats. Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com> --- .jules/bolt.md | 3 +++ stdlib/src/sqlite.rs | 31 ++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 5034e016..27b98348 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -20,3 +20,6 @@ ## 2024-08-01 - Bytecode Disassembler String Allocation Optimization **Learning:** Formatting directly into a string buffer inside a tight loop with `write!(buffer, ...)` avoids unnecessary string heap allocations compared to `buffer.push_str(&format!(...))`. **Action:** Always prefer formatting directly into the target String buffer when concatenating strings in loops in performance-sensitive paths like debuggers or disassemblers. +## 2024-11-20 - [SQLite Query Mapping Optimization] +**Learning:** In dynamically typed environments, unconditionally casting database query results to strings (e.g., via `row.get::<_, String>`) before mapping them to internal types is highly inefficient and creates bugs. Direct iteration matching over native database memory representations (like `rusqlite::types::ValueRef`) preserves typing metadata and prevents unnecessary allocations. +**Action:** When extracting data from a database adapter layer to dynamic variants, use exact matching (e.g., `ValueRef::Integer`) and initialize the destination collections using `.with_capacity()` based on the column count. diff --git a/stdlib/src/sqlite.rs b/stdlib/src/sqlite.rs index 487d44da..5f69703d 100644 --- a/stdlib/src/sqlite.rs +++ b/stdlib/src/sqlite.rs @@ -183,16 +183,29 @@ impl StdlibRegistry { let mut rows = Vec::new(); let row_iter = stmt .query_map(rusqlite::params_from_iter(params), |row| { - let mut map = IndexMap::new(); - for name in &col_names { - map.insert(name.clone(), RuntimeValue::Null); - } + let mut map = IndexMap::with_capacity(col_count); for i in 0..col_count { - let val: String = - row.get::<_, String>(i).unwrap_or_default(); - if let Some((_, v)) = map.get_index_mut(i) { - *v = RuntimeValue::Str(val); - } + let val = row.get_ref(i)?; + let rt_val = match val { + rusqlite::types::ValueRef::Null => RuntimeValue::Null, + rusqlite::types::ValueRef::Integer(v) => { + RuntimeValue::Int(v) + } + rusqlite::types::ValueRef::Real(v) => { + RuntimeValue::Float(v) + } + rusqlite::types::ValueRef::Text(v) => { + RuntimeValue::Str( + String::from_utf8_lossy(v).into_owned(), + ) + } + rusqlite::types::ValueRef::Blob(v) => { + RuntimeValue::Str( + String::from_utf8_lossy(v).into_owned(), + ) + } + }; + map.insert(col_names[i].clone(), rt_val); } Ok(map) })