Skip to content

Commit

Permalink
Ensure batch inserts on SQLite run in a transaction
Browse files Browse the repository at this point in the history
While it's safe for us to do the inserts one query at a time, due to the
lack of round-trip time on SQLite, there's still a significant
performance difference if done outside of a transaction. If we're not in
a transaction, SQLite will perform table locking, and file IO for each
query individually.

This also means that batch insert on SQLite will have the same semantics
on failure as the other backends.

While I previously thought that we did not want a savepoint here if we
were already in a transaction, it's actually important that we create
one in order to match the semantics of other backends on failure.

Fixes #1177.
  • Loading branch information
sgrif committed Sep 21, 2017
1 parent 8d34632 commit 59f59e3
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 6 deletions.
15 changes: 9 additions & 6 deletions diesel/src/query_builder/insert_statement.rs
Expand Up @@ -170,12 +170,15 @@ where
Op: Copy,
{
fn execute(self, conn: &SqliteConnection) -> QueryResult<usize> {
let mut result = 0;
for record in self.records {
result += InsertStatement::new(self.target, record, self.operator, self.returning)
.execute(conn)?;
}
Ok(result)
use connection::Connection;
conn.transaction(|| {
let mut result = 0;
for record in self.records {
result += InsertStatement::new(self.target, record, self.operator, self.returning)
.execute(conn)?;
}
Ok(result)
})
}
}

Expand Down
13 changes: 13 additions & 0 deletions diesel_tests/tests/insert.rs
Expand Up @@ -489,3 +489,16 @@ fn insert_optional_field_with_default() {
let actual_data = users.select((name, hair_color)).load(&connection);
assert_eq!(Ok(expected_data), actual_data);
}

#[test]
#[cfg(feature = "sqlite")]
fn batch_insert_is_atomic_on_sqlite() {
use schema::users::dsl::*;
let connection = connection();

let new_users = vec![Some(name.eq("Sean")), None];
let result = insert(&new_users).into(users).execute(&connection);
assert!(result.is_err());

assert_eq!(Ok(0), users.count().get_result(&connection));
}

0 comments on commit 59f59e3

Please sign in to comment.