mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 14:36:08 +02:00
fix stor
insert/delete collision (#15838)
# Description Based on some testing in [Discord](https://discord.com/channels/601130461678272522/1349836000804995196/1353138803640111135) we were able to find that `insert` and `delete` happening at the same time caused problems in the `stor` command. So, I added `conn.is_busy()` with a sleep to try and avoid that problem.  /cc @NotTheDr01ds @132ikl # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> # Tests + Formatting <!-- Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # After Submitting <!-- If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. -->
This commit is contained in:
@ -112,16 +112,31 @@ impl SQLiteDatabase {
|
||||
if self.path == PathBuf::from(MEMORY_DB) {
|
||||
open_connection_in_memory_custom()
|
||||
} else {
|
||||
Connection::open(&self.path).map_err(|e| ShellError::GenericError {
|
||||
let conn = Connection::open(&self.path).map_err(|e| ShellError::GenericError {
|
||||
error: "Failed to open SQLite database from open_connection".into(),
|
||||
msg: e.to_string(),
|
||||
span: None,
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
})?;
|
||||
conn.busy_handler(Some(SQLiteDatabase::sleeper))
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Failed to set busy handler for SQLite database".into(),
|
||||
msg: e.to_string(),
|
||||
span: None,
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
Ok(conn)
|
||||
}
|
||||
}
|
||||
|
||||
fn sleeper(attempts: i32) -> bool {
|
||||
log::warn!("SQLITE_BUSY, retrying after 250ms (attempt {})", attempts);
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
true
|
||||
}
|
||||
|
||||
pub fn get_tables(&self, conn: &Connection) -> Result<Vec<DbTable>, SqliteError> {
|
||||
let mut table_names =
|
||||
conn.prepare("SELECT name FROM sqlite_master WHERE type = 'table'")?;
|
||||
@ -668,13 +683,23 @@ pub fn convert_sqlite_value_to_nu_value(value: ValueRef, span: Span) -> Value {
|
||||
|
||||
pub fn open_connection_in_memory_custom() -> Result<Connection, ShellError> {
|
||||
let flags = OpenFlags::default();
|
||||
Connection::open_with_flags(MEMORY_DB, flags).map_err(|e| ShellError::GenericError {
|
||||
error: "Failed to open SQLite custom connection in memory".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(Span::test_data()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
let conn =
|
||||
Connection::open_with_flags(MEMORY_DB, flags).map_err(|e| ShellError::GenericError {
|
||||
error: "Failed to open SQLite custom connection in memory".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(Span::test_data()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
conn.busy_handler(Some(SQLiteDatabase::sleeper))
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Failed to set busy handler for SQLite custom connection in memory".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(Span::test_data()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub fn open_connection_in_memory() -> Result<Connection, ShellError> {
|
||||
|
@ -109,7 +109,9 @@ impl Command for StorDelete {
|
||||
// dbg!(&sql_stmt);
|
||||
conn.execute(&sql_stmt, [])
|
||||
.map_err(|err| ShellError::GenericError {
|
||||
error: "Failed to open SQLite connection in memory from delete".into(),
|
||||
error:
|
||||
"Failed to delete using the SQLite connection in memory from delete.rs."
|
||||
.into(),
|
||||
msg: err.to_string(),
|
||||
span: Some(Span::test_data()),
|
||||
help: None,
|
||||
|
@ -164,34 +164,35 @@ fn process(
|
||||
}
|
||||
let new_table_name = table_name.unwrap_or("table".into());
|
||||
|
||||
let mut create_stmt = format!("INSERT INTO {} (", new_table_name);
|
||||
let mut column_placeholders: Vec<String> = Vec::new();
|
||||
|
||||
let cols = record.columns();
|
||||
cols.for_each(|col| {
|
||||
column_placeholders.push(col.to_string());
|
||||
});
|
||||
|
||||
create_stmt.push_str(&column_placeholders.join(", "));
|
||||
|
||||
// Values are set as placeholders.
|
||||
create_stmt.push_str(") VALUES (");
|
||||
let mut value_placeholders: Vec<String> = Vec::new();
|
||||
for (index, _) in record.columns().enumerate() {
|
||||
value_placeholders.push(format!("?{}", index + 1));
|
||||
}
|
||||
create_stmt.push_str(&value_placeholders.join(", "));
|
||||
create_stmt.push(')');
|
||||
|
||||
// dbg!(&create_stmt);
|
||||
|
||||
// Get the params from the passed values
|
||||
let params = values_to_sql(record.values().cloned())?;
|
||||
|
||||
if let Ok(conn) = db.open_connection() {
|
||||
let mut create_stmt = format!("INSERT INTO {} (", new_table_name);
|
||||
let mut column_placeholders: Vec<String> = Vec::new();
|
||||
|
||||
let cols = record.columns();
|
||||
cols.for_each(|col| {
|
||||
column_placeholders.push(col.to_string());
|
||||
});
|
||||
|
||||
create_stmt.push_str(&column_placeholders.join(", "));
|
||||
|
||||
// Values are set as placeholders.
|
||||
create_stmt.push_str(") VALUES (");
|
||||
let mut value_placeholders: Vec<String> = Vec::new();
|
||||
for (index, _) in record.columns().enumerate() {
|
||||
value_placeholders.push(format!("?{}", index + 1));
|
||||
}
|
||||
create_stmt.push_str(&value_placeholders.join(", "));
|
||||
create_stmt.push(')');
|
||||
|
||||
// dbg!(&create_stmt);
|
||||
|
||||
// Get the params from the passed values
|
||||
let params = values_to_sql(record.values().cloned())?;
|
||||
|
||||
conn.execute(&create_stmt, params_from_iter(params))
|
||||
.map_err(|err| ShellError::GenericError {
|
||||
error: "Failed to open SQLite connection in memory from insert".into(),
|
||||
error: "Failed to insert using the SQLite connection in memory from insert.rs."
|
||||
.into(),
|
||||
msg: err.to_string(),
|
||||
span: Some(Span::test_data()),
|
||||
help: None,
|
||||
|
Reference in New Issue
Block a user