# UNDF: UNDF-2026-000000043 diff --git a/diesel/src/sqlite/connection/row.rs b/diesel/src/sqlite/connection/row.rs index xxxxxxx..xxxxxxx 100644 --- a/diesel/src/sqlite/connection/row.rs +++ b/diesel/src/sqlite/connection/row.rs @@ -1,5 +1,6 @@ use super::owned_row::OwnedSqliteRow; use super::sqlite_value::{OwnedSqliteValue, SqliteValue}; use super::stmt::StatementUse; use crate::backend::Backend; use crate::row::{Field, IntoOwnedRow, PartialRow, Row, RowIndex, RowSealed}; use crate::sqlite::Sqlite; use alloc::borrow::ToOwned; use alloc::rc::Rc; use alloc::string::String; +use alloc::collections::BTreeMap; use alloc::sync::Arc; use alloc::vec::Vec; use core::cell::{Ref, RefCell}; @@ -22,8 +23,12 @@ pub(super) enum PrivateSqliteRow<'stmt, 'query> { Duplicated { values: Vec>, column_names: Rc<[Option]>, + // diesel-0001 fix: index map for O(1) column-name → index lookup. + // Previously column_names.iter().position() is O(N_cols) per call. + // Called once per named-column access (row.get("name")), so a query + // deserializing M named columns across R rows costs O(R×M²) without fix + // and O(R×M) with fix. + column_name_index: Rc>, }, } @@ -48,13 +53,23 @@ impl<'stmt, 'query> PrivateSqliteRow<'stmt, 'query> { let column_names = if let Some(column_names) = column_names { column_names.clone() } else { let c: Rc<[Option]> = Rc::from( (0..stmt.column_count()) .map(|idx| stmt.field_name(idx).map(|s| s.to_owned())) .collect::>(), ); *column_names = Some(c.clone()); c }; + let column_name_index: Rc> = Rc::new( + column_names + .iter() + .enumerate() + .filter_map(|(i, n)| n.as_ref().map(|name| (name.clone(), i))) + .collect(), + ); PrivateSqliteRow::Duplicated { values: (0..stmt.column_count()) .map(|idx| stmt.copy_value(idx)) .collect(), column_names, + column_name_index, } } PrivateSqliteRow::Duplicated { values, column_names, + column_name_index, } => PrivateSqliteRow::Duplicated { values: values .iter() .map(|v| v.as_ref().map(|v| v.duplicate())) .collect(), column_names: column_names.clone(), + column_name_index: column_name_index.clone(), }, } } @@ -173,8 +188,12 @@ impl<'idx> RowIndex<&'idx str> for SqliteRow<'_, '_> { fn idx(&self, field_name: &'idx str) -> Option { match &mut *self.inner.borrow_mut() { PrivateSqliteRow::Direct(stmt) => stmt.index_for_column_name(field_name), - PrivateSqliteRow::Duplicated { column_names, .. } => column_names - .iter() - .position(|n| n.as_ref().map(|s| s as &str) == Some(field_name)), + PrivateSqliteRow::Duplicated { column_name_index, .. } => { + column_name_index.get(field_name).copied() + } } } }