Skip to content

Commit

Permalink
reuse prepared statement in multi_insert
Browse files Browse the repository at this point in the history
  • Loading branch information
matt-codecov committed Jul 29, 2024
1 parent c0a4b65 commit 3b243d5
Showing 1 changed file with 19 additions and 13 deletions.
32 changes: 19 additions & 13 deletions src/report/sqlite/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,43 +71,49 @@ pub trait Insertable<const FIELD_COUNT: usize> {
I: Iterator<Item = &'a Self> + ExactSizeIterator,
Self: 'a,
{
let model_count = models.len();
if model_count == 0 {
return Ok(());
}

let var_limit = conn.limit(rusqlite::limits::Limit::SQLITE_LIMIT_VARIABLE_NUMBER) as usize;
// If each model takes up `FIELD_COUNT` variables, we can fit `var_limit /
// FIELD_COUNT` complete models in each "page" of our query
let page_size = var_limit / FIELD_COUNT;

// Integer division tells us how many full pages there are. If there is a
// non-zero remainder, there is one final incomplete page.
let model_count = models.len();
let page_count = match (model_count / page_size, model_count % page_size) {
(page_count, 0) => page_count,
(page_count, _) => page_count + 1,
};

let (mut query, mut previous_page_size) = (String::new(), 0);
// Helper function for creating query strings for differently-sized pages
let build_query_for_page = |page_size| {
let mut query = format!(" {},", Self::INSERT_PLACEHOLDER).repeat(page_size);
query.insert_str(0, Self::INSERT_QUERY_PRELUDE);
// Remove trailing comma
query.pop();
query
};

let first_page_size = std::cmp::min(model_count, page_size);
let mut stmt = conn.prepare_cached(build_query_for_page(first_page_size).as_str())?;

for _ in 0..page_count {
// If there are fewer than `page_size` pages left, the iterator will just take
// everything.
let page_iter = models.by_ref().take(page_size);

// We can reuse our query string if the current page is the same size as the
// last one. If not, we have to rebuild the query string.
let current_page_size = page_iter.len();
if current_page_size != previous_page_size {
query = format!(" {},", Self::INSERT_PLACEHOLDER).repeat(current_page_size);
query.insert_str(0, Self::INSERT_QUERY_PRELUDE);
// Remove trailing comma
query.pop();
previous_page_size = current_page_size;
if current_page_size != first_page_size {
stmt = conn.prepare_cached(build_query_for_page(current_page_size).as_str())?;
}

let mut stmt = conn.prepare_cached(query.as_str())?;
let params = page_iter.flat_map(|model| model.param_bindings());
stmt.execute(rusqlite::params_from_iter(params))?;
}

conn.flush_prepared_statement_cache();

Ok(())
}
}
Expand Down

0 comments on commit 3b243d5

Please sign in to comment.