From e81958f0de0f7821f9611d6727e5cbc7248aa1c5 Mon Sep 17 00:00:00 2001 From: Fletcher555 Date: Thu, 18 Sep 2025 12:32:26 -0400 Subject: [PATCH 1/7] Add test for add column w/ transaction --- src/db/table/operations/alter_table/mod.rs | 85 ++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/db/table/operations/alter_table/mod.rs b/src/db/table/operations/alter_table/mod.rs index c0608e0..959bb13 100644 --- a/src/db/table/operations/alter_table/mod.rs +++ b/src/db/table/operations/alter_table/mod.rs @@ -336,4 +336,89 @@ mod tests { ]; assert_eq!(expected_row_stacks, table.get_row_stacks_clone()); } + + #[test] + fn alter_table_add_column_works_correctly_with_transaction() { + let mut database = default_database(); + let statement = AlterTableStatement { + table_name: "users".to_string(), + action: AlterTableAction::AddColumn { + column_def: ColumnDefinition { + name: "new_column".to_string(), + data_type: DataType::Integer, + constraints: vec![], + }, + }, + }; + let result = alter_table(&mut database, statement, true); + assert!(result.is_ok()); + let table = database.get_table("users"); + assert!(table.is_ok()); + let table = table.unwrap(); + assert!(table.get_columns().last().unwrap().name == "new_column"); + assert!(table.get_columns().len() == table[0].len()); + let expected_row_stacks = vec![ + RowStack::new_with_stack(vec![ + Row(vec![ + Value::Integer(1), + Value::Text("John".to_string()), + Value::Integer(25), + Value::Real(1000.0), + ]), + Row(vec![ + Value::Integer(1), + Value::Text("John".to_string()), + Value::Integer(25), + Value::Real(1000.0), + Value::Null, + ]), + ]), + RowStack::new_with_stack(vec![ + Row(vec![ + Value::Integer(2), + Value::Text("Jane".to_string()), + Value::Integer(30), + Value::Real(2000.0), + ]), + Row(vec![ + Value::Integer(2), + Value::Text("Jane".to_string()), + Value::Integer(30), + Value::Real(2000.0), + Value::Null, + ]), + ]), + RowStack::new_with_stack(vec![ + Row(vec![ + Value::Integer(3), + Value::Text("Jim".to_string()), + Value::Integer(35), + Value::Real(3000.0), + ]), + Row(vec![ + Value::Integer(3), + Value::Text("Jim".to_string()), + Value::Integer(35), + Value::Real(3000.0), + Value::Null, + ]), + ]), + RowStack::new_with_stack(vec![ + Row(vec![ + Value::Integer(4), + Value::Null, + Value::Integer(40), + Value::Real(4000.0), + ]), + Row(vec![ + Value::Integer(4), + Value::Null, + Value::Integer(40), + Value::Real(4000.0), + Value::Null, + ]), + ]), + ]; + assert_eq!(expected_row_stacks, table.get_row_stacks_clone()); + } } From 755f0ae6ab7f81f8ceba35910491bb088aa0f736 Mon Sep 17 00:00:00 2001 From: Fletcher555 Date: Thu, 18 Sep 2025 13:25:16 -0400 Subject: [PATCH 2/7] Add tests and implementation of the alter table statement with add column --- src/db/database.rs | 21 +++++-- src/db/table/core/table.rs | 56 +++++++++++-------- src/db/table/operations/alter_table/mod.rs | 54 ++++++++++++------ src/db/table/operations/helpers/common.rs | 10 ++-- .../helpers/where_clause/where_condition.rs | 4 +- src/db/table/operations/insert/mod.rs | 4 +- src/db/table/operations/select/mod.rs | 8 +-- src/db/table/operations/update/mod.rs | 2 +- src/db/transactions/mod.rs | 1 + src/db/transactions/rollback.rs | 27 +++++++++ tests/crud_test.rs | 2 +- ...set_operators.rs => set_operators_test.rs} | 4 +- tests/test_utils.rs | 7 +-- tests/transaction_test.rs | 45 +++++++++++++++ 14 files changed, 179 insertions(+), 66 deletions(-) create mode 100644 src/db/transactions/rollback.rs rename tests/{set_operators.rs => set_operators_test.rs} (97%) create mode 100644 tests/transaction_test.rs diff --git a/src/db/database.rs b/src/db/database.rs index 5895df9..e7230bd 100644 --- a/src/db/database.rs +++ b/src/db/database.rs @@ -81,10 +81,23 @@ impl Database { Ok(None) } SqlStatement::Rollback(_) => { - self.transaction.commit_transaction()?; - self.tables.iter_mut().for_each(|(_, table)| { - table.rollback_transaction(); - }); + if let Some(transaction_log) = self.transaction.commit_transaction()?.entries { + for transaction_entry in transaction_log.iter() { + match transaction_entry { + TransactionEntry::Statement(statement) => { + // TODO: Some matching needs to be here for table based operations. + let table = self.get_table_mut(statement.table_name.as_str())?; + // CURRENTLY SUPPORTED STATEMENTS ARE: + // - ALTER TABLE RENAME COLUMN, ALTER TABLE ADD COLUMN, ALTER TABLE DROP COLUMN + table.rollback_transaction_entry(&statement)?; + } + TransactionEntry::Savepoint(_) => {} + } + } + } + else { + return Err("No transaction is currently active".to_string()); + } Ok(None) } SqlStatement::Savepoint(_) => { diff --git a/src/db/table/core/table.rs b/src/db/table/core/table.rs index 8389f14..83f4996 100644 --- a/src/db/table/core/table.rs +++ b/src/db/table/core/table.rs @@ -3,6 +3,8 @@ use crate::db::table::core::column::ColumnStack; use crate::db::table::core::row::Row; use crate::db::table::core::row::RowStack; use crate::db::table::core::value::Value; +use crate::db::transactions::StatementEntry; +use crate::db::transactions::rollback::rollback_transaction_on_table; use std::ops::{Index, IndexMut}; #[derive(Debug)] @@ -106,29 +108,39 @@ impl Table { Ok(()) } - pub fn rollback_transaction(&mut self) { - todo!() + pub fn rollback_transaction_entry(&mut self, statement: &StatementEntry) -> Result<(), String> { + rollback_transaction_on_table(self, statement) } - pub fn get_column_from_row<'a>(&self, row: &'a Vec, column: &String) -> &'a Value { + pub fn rollback_columns(&mut self) { + self.columns.stack.pop(); + } + + pub fn rollback_all_rows(&mut self) { + for row_stack in self.rows.iter_mut() { + row_stack.stack.pop(); + } + } + + pub fn get_column_from_row<'a>(&self, row: &'a Vec, column: &String) -> Result<&'a Value, String> { for (i, value) in row.iter().enumerate() { - if self.get_column_names()[i] == column { - return &value; + if self.get_column_names()?[i] == column { + return Ok(&value); } } - return &Value::Null; + return Ok(&Value::Null); } - pub fn has_column(&self, column: &String) -> bool { - self.get_columns().iter().any(|c| c.name == *column) + pub fn has_column(&self, column: &String) -> Result { + Ok(self.get_columns()?.iter().any(|c| c.name == *column)) } - pub fn width(&self) -> usize { - self.get_columns().len() + pub fn width(&self) -> Result { + Ok(self.get_columns()?.len()) } pub fn get_index_of_column(&self, column: &String) -> Result { - for (i, c) in self.get_columns().iter().enumerate() { + for (i, c) in self.get_columns()?.iter().enumerate() { if c.name == *column { return Ok(i); } @@ -139,27 +151,27 @@ impl Table { )); } - pub fn get_columns(&self) -> Vec<&ColumnDefinition> { - self.columns.stack.last().unwrap().iter().collect() + pub fn get_columns(&self) -> Result, String> { + Ok(self.columns.stack.last().ok_or("Column stack is empty".to_string())?.iter().collect()) } - pub fn get_columns_mut(&mut self) -> Vec<&mut ColumnDefinition> { - self.columns.stack.last_mut().unwrap().iter_mut().collect() + pub fn get_columns_mut(&mut self) -> Result, String> { + Ok(self.columns.stack.last_mut().ok_or("Column stack is empty".to_string())?.iter_mut().collect()) } - pub fn get_column_names(&self) -> Vec<&String> { - self.get_columns() + pub fn get_column_names(&self) -> Result, String> { + Ok(self.get_columns()? .iter() .map(|column| &column.name) - .collect() + .collect()) } - pub fn push_column(&mut self, column: ColumnDefinition) { - self.columns.push_column(column, false); + pub fn push_column(&mut self, column: ColumnDefinition, is_transaction: bool) { + self.columns.push_column(column, is_transaction); } #[cfg(test)] - pub fn get_columns_clone(&self) -> Vec { - self.get_columns().iter().map(|c| (*c).clone()).collect() + pub fn get_columns_clone(&self) -> Result, String> { + Ok(self.get_columns()?.iter().map(|c| (*c).clone()).collect()) } } diff --git a/src/db/table/operations/alter_table/mod.rs b/src/db/table/operations/alter_table/mod.rs index 959bb13..4f9c2d8 100644 --- a/src/db/table/operations/alter_table/mod.rs +++ b/src/db/table/operations/alter_table/mod.rs @@ -33,18 +33,18 @@ pub fn alter_table( } AlterTableAction::AddColumn { column_def } => { let table = database.get_table_mut(&statement.table_name)?; - if table.has_column(&column_def.name) { + if table.has_column(&column_def.name)? { return Err(format!( "Column `{}` already exists in table `{}`", column_def.name, statement.table_name )); } - table.push_column(column_def); if is_transaction { table.get_row_stacks_mut().iter_mut().for_each(|row_stack| { row_stack.append_clone(); }); } + table.push_column(column_def, is_transaction); table.get_rows_mut().iter_mut().for_each(|row| { row.push(Value::Null); }); @@ -52,7 +52,7 @@ pub fn alter_table( } AlterTableAction::DropColumn { column_name } => { let table = database.get_table_mut(&statement.table_name)?; - if !table.has_column(&column_name) { + if !table.has_column(&column_name)? { return Err(format!( "Column `{}` does not exist in table `{}`", column_name, statement.table_name @@ -117,10 +117,14 @@ mod tests { assert!(result.is_ok()); let table = database.get_table("users"); assert!(table.is_ok()); + let table_columns = table.unwrap().get_columns().unwrap(); assert!( - table - .unwrap() - .get_columns() + table_columns + .iter() + .any(|column| column.name == "new_name") + ); + assert!( + table_columns .iter() .any(|column| column.name == "new_name") ); @@ -144,8 +148,9 @@ mod tests { let table = database.get_table("users"); assert!(table.is_ok()); let table = table.unwrap(); - assert!(table.get_columns().last().unwrap().name == "new_column"); - assert!(table.get_columns().len() == table[0].len()); + let table_columns = table.get_columns().unwrap(); + assert!(table_columns.last().unwrap().name == "new_column"); + assert!(table_columns.len() == table[0].len()); assert!( table .get_rows() @@ -168,13 +173,14 @@ mod tests { let table = database.get_table("users"); assert!(table.is_ok()); let table = table.unwrap(); + let table_columns = table.get_columns().unwrap(); assert!( - !table - .get_columns() + !table_columns .iter() .any(|column| column.name == "age") ); - assert!(table.get_columns().len() == table[0].len()); + let table_columns_len = table_columns.len(); + assert!(table_columns_len == table[0].len()); let expected_columns_in_order = vec![ ColumnDefinition { name: "id".to_string(), @@ -192,7 +198,7 @@ mod tests { constraints: vec![], }, ]; - assert_eq!(expected_columns_in_order, table.get_columns_clone()); + assert_eq!(expected_columns_in_order, table.get_columns_clone().unwrap()); let expected_rows = vec![ Row(vec![ Value::Integer(1), @@ -229,9 +235,9 @@ mod tests { let table = database.get_table("users"); assert!(table.is_ok()); let table = table.unwrap(); + let table_columns = table.get_columns().unwrap(); assert!( - table - .get_columns() + table_columns .iter() .any(|column| column.name == "new_name") ); @@ -255,9 +261,9 @@ mod tests { let table = database.get_table("users"); assert!(table.is_ok()); let table = table.unwrap(); + let table_columns = table.get_columns().unwrap(); assert!( - !table - .get_columns() + !table_columns .iter() .any(|column| column.name == "age") ); @@ -355,8 +361,20 @@ mod tests { let table = database.get_table("users"); assert!(table.is_ok()); let table = table.unwrap(); - assert!(table.get_columns().last().unwrap().name == "new_column"); - assert!(table.get_columns().len() == table[0].len()); + let table_columns = table.get_columns().unwrap(); + assert!(table_columns.last().unwrap().name == "new_column"); + assert!(table_columns.len() == table[0].len()); + assert!(table.columns.stack.len() == 2); + let expected_column_names = vec![ + vec![ + "id".to_string(), + "name".to_string(), + "age".to_string(), + "money".to_string(), + ], + vec!["id".to_string(), "name".to_string(), "age".to_string(), "money".to_string(), "new_column".to_string()], + ]; + assert_eq!(expected_column_names, table.columns.stack.iter().map(|column| column.iter().map(|column| column.name.clone()).collect::>()).collect::>>()); let expected_row_stacks = vec![ RowStack::new_with_stack(vec![ Row(vec![ diff --git a/src/db/table/operations/helpers/common.rs b/src/db/table/operations/helpers/common.rs index 2c6228b..8c6f892 100644 --- a/src/db/table/operations/helpers/common.rs +++ b/src/db/table/operations/helpers/common.rs @@ -10,18 +10,18 @@ use crate::interpreter::ast::{ }; pub fn validate_and_clone_row(table: &Table, row: &Row) -> Result { - if row.len() != table.width() { + if row.len() != table.width()? { return Err(format!("Rows have incorrect width")); } let mut row_values: Row = Row(vec![]); for (i, value) in row.iter().enumerate() { - if value.get_type() != table.get_columns()[i].data_type + if value.get_type() != table.get_columns()?[i].data_type && value.get_type() != DataType::Null { return Err(format!( "Data type mismatch for column {}", - table.get_columns()[i].name + table.get_columns()?[i].name )); } row_values.push(row[i].clone()); @@ -37,13 +37,13 @@ pub fn get_columns_from_row( let mut row_values: Row = Row(vec![]); let mut column_values = HashMap::new(); - for (i, column) in table.get_column_names().into_iter().enumerate() { + for (i, column) in table.get_column_names()?.into_iter().enumerate() { if let Some(value) = row.get(i) { column_values.insert(column, value); } else { return Err(format!( "Row does not have the expected number of columns (expected: {}, got: {}", - table.get_columns().len(), + table.get_columns()?.len(), row.len() )); } diff --git a/src/db/table/operations/helpers/where_clause/where_condition.rs b/src/db/table/operations/helpers/where_clause/where_condition.rs index f096765..9bb2e96 100644 --- a/src/db/table/operations/helpers/where_clause/where_condition.rs +++ b/src/db/table/operations/helpers/where_clause/where_condition.rs @@ -103,13 +103,13 @@ fn operand_to_value<'a>( match operand { Operand::Value(value) => Ok(value), Operand::Identifier(column) => { - if !table.has_column(column) { + if !table.has_column(column)? { return Err(format!( "Column {} does not exist in table {}", column, table.name )); } - Ok(table.get_column_from_row(row, column)) + Ok(table.get_column_from_row(row, column)?) } _ => Err(format!("Found invalid operand: {:?}", operand)), } diff --git a/src/db/table/operations/insert/mod.rs b/src/db/table/operations/insert/mod.rs index 944c339..17fe9a9 100644 --- a/src/db/table/operations/insert/mod.rs +++ b/src/db/table/operations/insert/mod.rs @@ -9,7 +9,7 @@ pub fn insert(table: &mut Table, statement: InsertIntoStatement) -> Result Result { let table = database.get_table(&select_statement.table_name)?; let expanded_column_names = - expand_all_column_names(table, &select_statement.column_names); + expand_all_column_names(table, &select_statement.column_names)?; match &column_names { Some(column_names) => { if expanded_column_names.len() != column_names.len() { @@ -118,11 +118,11 @@ pub fn select_statement_stack( } // TODO: add this logic in evaluation too -fn expand_all_column_names(table: &Table, column_names: &Vec) -> Vec { +fn expand_all_column_names(table: &Table, column_names: &Vec) -> Result, String> { let mut new = vec![]; for column in column_names { if *column == "*".to_string() { - for name in table.get_column_names() { + for name in table.get_column_names()? { if !column_names.contains(name) { new.push(name.clone()); } @@ -131,7 +131,7 @@ fn expand_all_column_names(table: &Table, column_names: &Vec) -> Vec Result<(), String> { + match &statement.statement { + SqlStatement::AlterTable(alter_table) => { + match alter_table.action { + AlterTableAction::RenameColumn { .. } => { + table.rollback_columns(); + } + AlterTableAction::AddColumn { .. } => { + table.rollback_columns(); + table.rollback_all_rows(); + } + AlterTableAction::DropColumn { .. } => { + table.rollback_columns(); + table.rollback_all_rows(); + } + _ => return Err("UNSUPPORTED".to_string()), + } + } + SqlStatement::Select(_) => {} // These should be kept in the log but obv do nothing. + _ => return Err("UNSUPPORTED".to_string()), + } + return Ok(()); +} \ No newline at end of file diff --git a/tests/crud_test.rs b/tests/crud_test.rs index af894f2..8b12839 100644 --- a/tests/crud_test.rs +++ b/tests/crud_test.rs @@ -74,7 +74,7 @@ fn test_complex_statements_crud() { Row(vec![Value::Text("John".to_string()), Value::Integer(25)]), ]; let expected_second = vec![Row(vec![Value::Integer(80)])]; - test_utils::assert_table_rows_eq_unordered( + test_utils::assert_eq_table_rows_unordered( expected_second, result.pop().unwrap().unwrap().unwrap(), ); diff --git a/tests/set_operators.rs b/tests/set_operators_test.rs similarity index 97% rename from tests/set_operators.rs rename to tests/set_operators_test.rs index e1570d3..261038c 100644 --- a/tests/set_operators.rs +++ b/tests/set_operators_test.rs @@ -22,7 +22,7 @@ fn test_set_operators() { Row(vec![Value::Text("Jack".to_string())]), ]; let row = result.pop().unwrap().unwrap().unwrap(); - test_utils::assert_table_rows_eq_unordered(expected, row); + test_utils::assert_eq_table_rows_unordered(expected, row); assert!( result .into_iter() @@ -97,7 +97,7 @@ fn test_set_operators_with_different_tables_and_clause() { Row(vec![Value::Text("Jim".to_string())]), Row(vec![Value::Text("Jack".to_string())]), ]; - test_utils::assert_table_rows_eq_unordered( + test_utils::assert_eq_table_rows_unordered( expected_first, result.pop().unwrap().unwrap().unwrap(), ); diff --git a/tests/test_utils.rs b/tests/test_utils.rs index edd43c1..936ba97 100644 --- a/tests/test_utils.rs +++ b/tests/test_utils.rs @@ -1,12 +1,9 @@ -#[cfg(test)] use mollycache::db::table::core::row::Row; -#[cfg(test)] use mollycache::interpreter::ast::OrderByDirection; -#[cfg(test)] use std::cmp::Ordering; -#[cfg(test)] -pub fn assert_table_rows_eq_unordered(mut expected: Vec, mut actual: Vec) { +#[allow(dead_code)] // For some reason it can't pick up that this is used in integration tests. I'm prolly doing smth wrong. +pub fn assert_eq_table_rows_unordered(mut expected: Vec, mut actual: Vec) { expected.sort_by(|a, b| { let mut i = 0; while i < a.len() diff --git a/tests/transaction_test.rs b/tests/transaction_test.rs new file mode 100644 index 0000000..aa98e63 --- /dev/null +++ b/tests/transaction_test.rs @@ -0,0 +1,45 @@ +mod test_utils; + +use mollycache::db::database::Database; +use mollycache::db::table::core::{row::Row, value::Value}; +use mollycache::interpreter::run_sql; + +#[test] +fn test_transaction() { + let mut database = Database::new(); + let sql = " + CREATE TABLE users ( + id INTEGER, + name TEXT + ); + INSERT INTO users (id, name) VALUES (1, 'John'); + SELECT * FROM users; + BEGIN; + ALTER TABLE users ADD COLUMN age INTEGER; + SELECT * FROM users; + ROLLBACK; + SELECT * FROM users; + "; + let result = run_sql(&mut database, sql); + println!("{:?}", result); + let expected = vec![ + Ok(None), + Ok(None), + Ok(Some(vec![ + Row(vec![Value::Integer(1), Value::Text("John".to_string())]), + ])), + Ok(None), + Ok(None), + Ok(Some(vec![ + Row(vec![Value::Integer(1), Value::Text("John".to_string()), Value::Null]), + ])), + Ok(None), + Ok(Some(vec![ + Row(vec![Value::Integer(1), Value::Text("John".to_string())]), + ])), + ]; + for (i, result) in result.iter().enumerate() { + assert!(result.is_ok()); + assert_eq!(expected[i], *result); + } +} \ No newline at end of file From d8ce396cba074e3f747cbd6c1280588c9f5509bc Mon Sep 17 00:00:00 2001 From: Fletcher555 Date: Thu, 18 Sep 2025 13:27:05 -0400 Subject: [PATCH 3/7] Add tests for the rest of the ALTER TABLE statements except for rename table --- tests/transaction_test.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/transaction_test.rs b/tests/transaction_test.rs index aa98e63..bb1a3cd 100644 --- a/tests/transaction_test.rs +++ b/tests/transaction_test.rs @@ -17,6 +17,10 @@ fn test_transaction() { BEGIN; ALTER TABLE users ADD COLUMN age INTEGER; SELECT * FROM users; + ALTER TABLE users RENAME COLUMN age TO new_age; + SELECT new_age FROM users; + ALTER TABLE users DROP COLUMN name; + SELECT * FROM users; ROLLBACK; SELECT * FROM users; "; @@ -34,6 +38,14 @@ fn test_transaction() { Row(vec![Value::Integer(1), Value::Text("John".to_string()), Value::Null]), ])), Ok(None), + Ok(Some(vec![ + Row(vec![Value::Null]), + ])), + Ok(None), + Ok(Some(vec![ + Row(vec![Value::Integer(1), Value::Null]), + ])), + Ok(None), Ok(Some(vec![ Row(vec![Value::Integer(1), Value::Text("John".to_string())]), ])), From 1c1a6b20780e67d4c238ea542d2e927b77487f47 Mon Sep 17 00:00:00 2001 From: Fletcher555 Date: Thu, 18 Sep 2025 13:35:06 -0400 Subject: [PATCH 4/7] Fix testing issue with ALTER TABLE transaction integration test that was causing failures --- src/db/database.rs | 3 +- src/db/table/core/table.rs | 25 ++++++++-- src/db/table/operations/alter_table/mod.rs | 56 +++++++++++----------- src/db/table/operations/select/mod.rs | 5 +- src/db/transactions/rollback.rs | 35 +++++++------- tests/transaction_test.rs | 32 ++++++------- 6 files changed, 88 insertions(+), 68 deletions(-) diff --git a/src/db/database.rs b/src/db/database.rs index e7230bd..7ccc37c 100644 --- a/src/db/database.rs +++ b/src/db/database.rs @@ -94,8 +94,7 @@ impl Database { TransactionEntry::Savepoint(_) => {} } } - } - else { + } else { return Err("No transaction is currently active".to_string()); } Ok(None) diff --git a/src/db/table/core/table.rs b/src/db/table/core/table.rs index 83f4996..1b52c8c 100644 --- a/src/db/table/core/table.rs +++ b/src/db/table/core/table.rs @@ -122,7 +122,11 @@ impl Table { } } - pub fn get_column_from_row<'a>(&self, row: &'a Vec, column: &String) -> Result<&'a Value, String> { + pub fn get_column_from_row<'a>( + &self, + row: &'a Vec, + column: &String, + ) -> Result<&'a Value, String> { for (i, value) in row.iter().enumerate() { if self.get_column_names()?[i] == column { return Ok(&value); @@ -152,15 +156,28 @@ impl Table { } pub fn get_columns(&self) -> Result, String> { - Ok(self.columns.stack.last().ok_or("Column stack is empty".to_string())?.iter().collect()) + Ok(self + .columns + .stack + .last() + .ok_or("Column stack is empty".to_string())? + .iter() + .collect()) } pub fn get_columns_mut(&mut self) -> Result, String> { - Ok(self.columns.stack.last_mut().ok_or("Column stack is empty".to_string())?.iter_mut().collect()) + Ok(self + .columns + .stack + .last_mut() + .ok_or("Column stack is empty".to_string())? + .iter_mut() + .collect()) } pub fn get_column_names(&self) -> Result, String> { - Ok(self.get_columns()? + Ok(self + .get_columns()? .iter() .map(|column| &column.name) .collect()) diff --git a/src/db/table/operations/alter_table/mod.rs b/src/db/table/operations/alter_table/mod.rs index 4f9c2d8..345a04d 100644 --- a/src/db/table/operations/alter_table/mod.rs +++ b/src/db/table/operations/alter_table/mod.rs @@ -118,16 +118,8 @@ mod tests { let table = database.get_table("users"); assert!(table.is_ok()); let table_columns = table.unwrap().get_columns().unwrap(); - assert!( - table_columns - .iter() - .any(|column| column.name == "new_name") - ); - assert!( - table_columns - .iter() - .any(|column| column.name == "new_name") - ); + assert!(table_columns.iter().any(|column| column.name == "new_name")); + assert!(table_columns.iter().any(|column| column.name == "new_name")); } #[test] @@ -174,11 +166,7 @@ mod tests { assert!(table.is_ok()); let table = table.unwrap(); let table_columns = table.get_columns().unwrap(); - assert!( - !table_columns - .iter() - .any(|column| column.name == "age") - ); + assert!(!table_columns.iter().any(|column| column.name == "age")); let table_columns_len = table_columns.len(); assert!(table_columns_len == table[0].len()); let expected_columns_in_order = vec![ @@ -198,7 +186,10 @@ mod tests { constraints: vec![], }, ]; - assert_eq!(expected_columns_in_order, table.get_columns_clone().unwrap()); + assert_eq!( + expected_columns_in_order, + table.get_columns_clone().unwrap() + ); let expected_rows = vec![ Row(vec![ Value::Integer(1), @@ -236,11 +227,7 @@ mod tests { assert!(table.is_ok()); let table = table.unwrap(); let table_columns = table.get_columns().unwrap(); - assert!( - table_columns - .iter() - .any(|column| column.name == "new_name") - ); + assert!(table_columns.iter().any(|column| column.name == "new_name")); let index_of_column = table.get_index_of_column(&"new_name".to_string()).unwrap(); assert!(table.columns.stack.len() == 2); assert!(table.columns.stack[0][index_of_column].name == "name"); @@ -262,11 +249,7 @@ mod tests { assert!(table.is_ok()); let table = table.unwrap(); let table_columns = table.get_columns().unwrap(); - assert!( - !table_columns - .iter() - .any(|column| column.name == "age") - ); + assert!(!table_columns.iter().any(|column| column.name == "age")); assert!(table.columns.stack.len() == 2); let expected_column_names = vec![ vec![ @@ -372,9 +355,26 @@ mod tests { "age".to_string(), "money".to_string(), ], - vec!["id".to_string(), "name".to_string(), "age".to_string(), "money".to_string(), "new_column".to_string()], + vec![ + "id".to_string(), + "name".to_string(), + "age".to_string(), + "money".to_string(), + "new_column".to_string(), + ], ]; - assert_eq!(expected_column_names, table.columns.stack.iter().map(|column| column.iter().map(|column| column.name.clone()).collect::>()).collect::>>()); + assert_eq!( + expected_column_names, + table + .columns + .stack + .iter() + .map(|column| column + .iter() + .map(|column| column.name.clone()) + .collect::>()) + .collect::>>() + ); let expected_row_stacks = vec![ RowStack::new_with_stack(vec![ Row(vec![ diff --git a/src/db/table/operations/select/mod.rs b/src/db/table/operations/select/mod.rs index 19cb311..6368f9f 100644 --- a/src/db/table/operations/select/mod.rs +++ b/src/db/table/operations/select/mod.rs @@ -118,7 +118,10 @@ pub fn select_statement_stack( } // TODO: add this logic in evaluation too -fn expand_all_column_names(table: &Table, column_names: &Vec) -> Result, String> { +fn expand_all_column_names( + table: &Table, + column_names: &Vec, +) -> Result, String> { let mut new = vec![]; for column in column_names { if *column == "*".to_string() { diff --git a/src/db/transactions/rollback.rs b/src/db/transactions/rollback.rs index a462d7d..aa71e26 100644 --- a/src/db/transactions/rollback.rs +++ b/src/db/transactions/rollback.rs @@ -2,26 +2,27 @@ use crate::db::table::core::table::Table; use crate::db::transactions::StatementEntry; use crate::interpreter::ast::{AlterTableAction, SqlStatement}; -pub fn rollback_transaction_on_table(table: &mut Table, statement: &StatementEntry) -> Result<(), String> { +pub fn rollback_transaction_on_table( + table: &mut Table, + statement: &StatementEntry, +) -> Result<(), String> { match &statement.statement { - SqlStatement::AlterTable(alter_table) => { - match alter_table.action { - AlterTableAction::RenameColumn { .. } => { - table.rollback_columns(); - } - AlterTableAction::AddColumn { .. } => { - table.rollback_columns(); - table.rollback_all_rows(); - } - AlterTableAction::DropColumn { .. } => { - table.rollback_columns(); - table.rollback_all_rows(); - } - _ => return Err("UNSUPPORTED".to_string()), + SqlStatement::AlterTable(alter_table) => match alter_table.action { + AlterTableAction::RenameColumn { .. } => { + table.rollback_columns(); } - } + AlterTableAction::AddColumn { .. } => { + table.rollback_columns(); + table.rollback_all_rows(); + } + AlterTableAction::DropColumn { .. } => { + table.rollback_columns(); + table.rollback_all_rows(); + } + _ => return Err("UNSUPPORTED".to_string()), + }, SqlStatement::Select(_) => {} // These should be kept in the log but obv do nothing. _ => return Err("UNSUPPORTED".to_string()), } return Ok(()); -} \ No newline at end of file +} diff --git a/tests/transaction_test.rs b/tests/transaction_test.rs index bb1a3cd..847b0c0 100644 --- a/tests/transaction_test.rs +++ b/tests/transaction_test.rs @@ -29,29 +29,29 @@ fn test_transaction() { let expected = vec![ Ok(None), Ok(None), - Ok(Some(vec![ - Row(vec![Value::Integer(1), Value::Text("John".to_string())]), - ])), + Ok(Some(vec![Row(vec![ + Value::Integer(1), + Value::Text("John".to_string()), + ])])), Ok(None), Ok(None), - Ok(Some(vec![ - Row(vec![Value::Integer(1), Value::Text("John".to_string()), Value::Null]), - ])), + Ok(Some(vec![Row(vec![ + Value::Integer(1), + Value::Text("John".to_string()), + Value::Null, + ])])), Ok(None), - Ok(Some(vec![ - Row(vec![Value::Null]), - ])), + Ok(Some(vec![Row(vec![Value::Null])])), Ok(None), - Ok(Some(vec![ - Row(vec![Value::Integer(1), Value::Null]), - ])), + Ok(Some(vec![Row(vec![Value::Integer(1), Value::Null])])), Ok(None), - Ok(Some(vec![ - Row(vec![Value::Integer(1), Value::Text("John".to_string())]), - ])), + Ok(Some(vec![Row(vec![ + Value::Integer(1), + Value::Text("John".to_string()), + ])])), ]; for (i, result) in result.iter().enumerate() { assert!(result.is_ok()); assert_eq!(expected[i], *result); } -} \ No newline at end of file +} From d8a3fcf819dec6f296c7f6327c46bc5e6ab25dae Mon Sep 17 00:00:00 2001 From: Fletcher555 Date: Thu, 18 Sep 2025 14:01:02 -0400 Subject: [PATCH 5/7] Add name stack to support transactions on table renames --- src/db/database.rs | 4 +-- src/db/table/core/column.rs | 12 ++------ src/db/table/core/table.rs | 23 +++++++++++++-- src/db/table/operations/alter_table/mod.rs | 28 +++++++++++++------ src/db/table/operations/create_table/mod.rs | 2 +- .../helpers/where_clause/where_condition.rs | 2 +- 6 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/db/database.rs b/src/db/database.rs index 7ccc37c..7d5c0d2 100644 --- a/src/db/database.rs +++ b/src/db/database.rs @@ -171,13 +171,13 @@ mod tests { let mut database = default_database(); let table = database.get_table("users"); assert!(table.is_ok()); - assert_eq!("users", table.unwrap().name); + assert_eq!("users", table.unwrap().name().unwrap()); let table = database.get_table("not_users"); assert!(table.is_err()); assert_eq!("Table `not_users` does not exist", table.unwrap_err()); let table = database.get_table_mut("users"); assert!(table.is_ok()); - assert_eq!("users", table.unwrap().name); + assert_eq!("users", table.unwrap().name().unwrap()); let table = database.get_table_mut("not_users"); assert!(table.is_err()); assert_eq!("Table `not_users` does not exist", table.unwrap_err()); diff --git a/src/db/table/core/column.rs b/src/db/table/core/column.rs index a9c6fbb..c4d7588 100644 --- a/src/db/table/core/column.rs +++ b/src/db/table/core/column.rs @@ -40,7 +40,6 @@ impl ColumnStack { &mut self, old_column_name: &String, new_column_name: &String, - table_name: &String, is_transaction: bool, ) -> Result<(), String> { if is_transaction { @@ -53,10 +52,7 @@ impl ColumnStack { match columns { Some(column) => column.name = new_column_name.clone(), None => { - return Err(format!( - "Column `{}` does not exist in table `{}`", - old_column_name, table_name - )); + return Err("Column does not exist".to_string()); } } Ok(()) @@ -65,7 +61,6 @@ impl ColumnStack { pub fn drop_column( &mut self, column_name: &String, - table_name: &String, is_transaction: bool, ) -> Result<(), String> { if is_transaction { @@ -74,10 +69,7 @@ impl ColumnStack { match self.get_index_of_column(column_name) { Ok(index) => self.peek_mut()?.remove(index), Err(_) => { - return Err(format!( - "Column `{}` does not exist in table `{}`", - column_name, table_name - )); + return Err("Column does not exist".to_string()); } }; Ok(()) diff --git a/src/db/table/core/table.rs b/src/db/table/core/table.rs index 1b52c8c..d7994aa 100644 --- a/src/db/table/core/table.rs +++ b/src/db/table/core/table.rs @@ -9,11 +9,16 @@ use std::ops::{Index, IndexMut}; #[derive(Debug)] pub struct Table { - pub name: String, + pub name: NameStack, pub columns: ColumnStack, rows: Vec, } +#[derive(Debug)] +pub struct NameStack { + pub stack: Vec, +} + impl Index for Table { type Output = Row; @@ -31,12 +36,24 @@ impl IndexMut for Table { impl Table { pub fn new(name: String, columns: Vec) -> Self { Self { - name, + name: NameStack { stack: vec![name] }, columns: ColumnStack::new(columns), rows: vec![], } } + pub fn name(&self) -> Result<&String, String> { + self.name.stack.last().ok_or("Error fetching table name.".to_string()) + } + + pub fn change_name(&mut self, new_name: String, is_transaction: bool) { + if is_transaction { + self.name.stack.push(new_name); + } else { + self.name.stack = vec![new_name]; + } + } + pub fn get(&self, i: usize) -> Option<&Row> { self.rows.get(i)?.stack.last() } @@ -151,7 +168,7 @@ impl Table { } return Err(format!( "Column {} does not exist in table {}", - column, self.name + column, self.name()? )); } diff --git a/src/db/table/operations/alter_table/mod.rs b/src/db/table/operations/alter_table/mod.rs index 345a04d..ba3a54f 100644 --- a/src/db/table/operations/alter_table/mod.rs +++ b/src/db/table/operations/alter_table/mod.rs @@ -12,8 +12,8 @@ pub fn alter_table( let table = database.tables.remove(&statement.table_name); match table { Some(mut table) => { - table.name = new_table_name; - database.tables.insert(table.name.clone(), table); + table.change_name(new_table_name, is_transaction); + database.tables.insert(table.name()?.clone(), table); } None => return Err(format!("Table `{}` does not exist", statement.table_name)), }; @@ -24,12 +24,21 @@ pub fn alter_table( new_column_name, } => { let table = database.get_table_mut(&statement.table_name)?; - table.columns.rename_column( + if !table.has_column(&old_column_name)? { + return Err(format!( + "Column `{}` does not exist in table `{}`", + old_column_name, statement.table_name + )); + } + let res = table.columns.rename_column( &old_column_name, &new_column_name, - &table.name, is_transaction, - ) + ); + if res.is_err() { + return Err(format!("Error renaming column: `{}` to `{}` in Table: `{}`", old_column_name, new_column_name, statement.table_name)); + } + Ok(()) } AlterTableAction::AddColumn { column_def } => { let table = database.get_table_mut(&statement.table_name)?; @@ -59,9 +68,12 @@ pub fn alter_table( )); } let index = table.columns.get_index_of_column(&column_name)?; - table + let res = table .columns - .drop_column(&column_name, &table.name, is_transaction)?; + .drop_column(&column_name, is_transaction); + if res.is_err() { + return Err(format!("Error dropping column: `{}` from Table: `{}`", column_name, statement.table_name)); + } // This is kind of bad because it's an O(n^2) operation however SQLite // preserves the order of the columns after drop column statements. if is_transaction { @@ -100,7 +112,7 @@ mod tests { assert!(result.is_ok()); assert!(!database.tables.contains_key("users")); assert!(database.tables.contains_key("new_users")); - assert!(database.tables.get("new_users").unwrap().name == "new_users"); + assert!(database.tables.get("new_users").unwrap().name().unwrap() == "new_users"); } #[test] diff --git a/src/db/table/operations/create_table/mod.rs b/src/db/table/operations/create_table/mod.rs index d61d419..8336be9 100644 --- a/src/db/table/operations/create_table/mod.rs +++ b/src/db/table/operations/create_table/mod.rs @@ -17,7 +17,7 @@ pub fn create_table( } } let table = Table::new(statement.table_name, statement.columns); - database.tables.insert(table.name.clone(), table); + database.tables.insert(table.name()?.clone(), table); Ok(()) } diff --git a/src/db/table/operations/helpers/where_clause/where_condition.rs b/src/db/table/operations/helpers/where_clause/where_condition.rs index 9bb2e96..4a8cb8b 100644 --- a/src/db/table/operations/helpers/where_clause/where_condition.rs +++ b/src/db/table/operations/helpers/where_clause/where_condition.rs @@ -106,7 +106,7 @@ fn operand_to_value<'a>( if !table.has_column(column)? { return Err(format!( "Column {} does not exist in table {}", - column, table.name + column, table.name()? )); } Ok(table.get_column_from_row(row, column)?) From 19f904d65a6404cffb6b60aa8450c6f777e5cd36 Mon Sep 17 00:00:00 2001 From: Fletcher555 Date: Thu, 18 Sep 2025 14:19:37 -0400 Subject: [PATCH 6/7] Fix bugs with changing name and add tests to ensure that it is working --- src/db/database.rs | 7 ++++--- src/db/table/core/table.rs | 10 ++++------ src/db/table/operations/alter_table/mod.rs | 23 ++++++++++++++++++++++ src/db/transactions/rollback.rs | 16 +++++++++++---- tests/transaction_test.rs | 9 ++++++++- 5 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/db/database.rs b/src/db/database.rs index 7d5c0d2..5329690 100644 --- a/src/db/database.rs +++ b/src/db/database.rs @@ -2,6 +2,7 @@ use crate::db::table::core::{row::Row, table::Table}; use crate::db::table::operations::{ alter_table, create_table, delete, drop_table, insert, select, update, }; +use crate::db::transactions::rollback::rollback_transaction_entry; use crate::db::transactions::{TransactionEntry, TransactionLog}; use crate::interpreter::ast::SqlStatement; use std::collections::HashMap; @@ -82,14 +83,14 @@ impl Database { } SqlStatement::Rollback(_) => { if let Some(transaction_log) = self.transaction.commit_transaction()?.entries { - for transaction_entry in transaction_log.iter() { + // We roll back in reverse order because of dependencies. + for transaction_entry in transaction_log.iter().rev() { match transaction_entry { TransactionEntry::Statement(statement) => { // TODO: Some matching needs to be here for table based operations. - let table = self.get_table_mut(statement.table_name.as_str())?; // CURRENTLY SUPPORTED STATEMENTS ARE: // - ALTER TABLE RENAME COLUMN, ALTER TABLE ADD COLUMN, ALTER TABLE DROP COLUMN - table.rollback_transaction_entry(&statement)?; + rollback_transaction_entry(self, &statement)?; } TransactionEntry::Savepoint(_) => {} } diff --git a/src/db/table/core/table.rs b/src/db/table/core/table.rs index d7994aa..2bacdd8 100644 --- a/src/db/table/core/table.rs +++ b/src/db/table/core/table.rs @@ -3,8 +3,6 @@ use crate::db::table::core::column::ColumnStack; use crate::db::table::core::row::Row; use crate::db::table::core::row::RowStack; use crate::db::table::core::value::Value; -use crate::db::transactions::StatementEntry; -use crate::db::transactions::rollback::rollback_transaction_on_table; use std::ops::{Index, IndexMut}; #[derive(Debug)] @@ -125,10 +123,6 @@ impl Table { Ok(()) } - pub fn rollback_transaction_entry(&mut self, statement: &StatementEntry) -> Result<(), String> { - rollback_transaction_on_table(self, statement) - } - pub fn rollback_columns(&mut self) { self.columns.stack.pop(); } @@ -139,6 +133,10 @@ impl Table { } } + pub fn rollback_name(&mut self) { + self.name.stack.pop(); + } + pub fn get_column_from_row<'a>( &self, row: &'a Vec, diff --git a/src/db/table/operations/alter_table/mod.rs b/src/db/table/operations/alter_table/mod.rs index ba3a54f..c4af177 100644 --- a/src/db/table/operations/alter_table/mod.rs +++ b/src/db/table/operations/alter_table/mod.rs @@ -451,4 +451,27 @@ mod tests { ]; assert_eq!(expected_row_stacks, table.get_row_stacks_clone()); } + + #[test] + fn alter_table_rename_table_works_correctly_with_transaction() { + let mut database = default_database(); + let statement = AlterTableStatement { + table_name: "users".to_string(), + action: AlterTableAction::RenameTable { + new_table_name: "new_users".to_string(), + }, + }; + let result = alter_table(&mut database, statement, true); + assert!(result.is_ok()); + let table = database.get_table("new_users"); + assert!(table.is_ok()); + let expected_table_name_stack = vec![ + "users".to_string(), + "new_users".to_string(), + ]; + let table = table.unwrap(); + for (i, name) in expected_table_name_stack.iter().enumerate() { + assert_eq!(*name, table.name.stack[i].clone()); + } + } } diff --git a/src/db/transactions/rollback.rs b/src/db/transactions/rollback.rs index aa71e26..d1e8e25 100644 --- a/src/db/transactions/rollback.rs +++ b/src/db/transactions/rollback.rs @@ -1,25 +1,33 @@ -use crate::db::table::core::table::Table; +use crate::db::database::Database; use crate::db::transactions::StatementEntry; use crate::interpreter::ast::{AlterTableAction, SqlStatement}; -pub fn rollback_transaction_on_table( - table: &mut Table, +pub fn rollback_transaction_entry( + database: &mut Database, statement: &StatementEntry, ) -> Result<(), String> { match &statement.statement { SqlStatement::AlterTable(alter_table) => match alter_table.action { AlterTableAction::RenameColumn { .. } => { + let table = database.get_table_mut(statement.table_name.as_str())?; table.rollback_columns(); } AlterTableAction::AddColumn { .. } => { + let table = database.get_table_mut(statement.table_name.as_str())?; table.rollback_columns(); table.rollback_all_rows(); } AlterTableAction::DropColumn { .. } => { + let table = database.get_table_mut(statement.table_name.as_str())?; table.rollback_columns(); table.rollback_all_rows(); } - _ => return Err("UNSUPPORTED".to_string()), + AlterTableAction::RenameTable { ref new_table_name } => { + // It is now under the new name + let mut table = database.tables.remove(new_table_name.as_str()).ok_or(format!("Table `{}` does not exist", new_table_name))?; + table.rollback_name(); + database.tables.insert(table.name()?.clone(), table); + } }, SqlStatement::Select(_) => {} // These should be kept in the log but obv do nothing. _ => return Err("UNSUPPORTED".to_string()), diff --git a/tests/transaction_test.rs b/tests/transaction_test.rs index 847b0c0..2eef1e3 100644 --- a/tests/transaction_test.rs +++ b/tests/transaction_test.rs @@ -21,8 +21,12 @@ fn test_transaction() { SELECT new_age FROM users; ALTER TABLE users DROP COLUMN name; SELECT * FROM users; + ALTER TABLE users RENAME TO new_users; + SELECT * FROM new_users; + SELECT * FROM users; ROLLBACK; SELECT * FROM users; + SELECT * FROM new_users; "; let result = run_sql(&mut database, sql); println!("{:?}", result); @@ -45,13 +49,16 @@ fn test_transaction() { Ok(None), Ok(Some(vec![Row(vec![Value::Integer(1), Value::Null])])), Ok(None), + Ok(Some(vec![Row(vec![Value::Integer(1), Value::Null])])), + Err("Execution Error with statement starting on line 17 \n Error: Table `users` does not exist".to_string()), + Ok(None), Ok(Some(vec![Row(vec![ Value::Integer(1), Value::Text("John".to_string()), ])])), + Err("Execution Error with statement starting on line 20 \n Error: Table `new_users` does not exist".to_string()), ]; for (i, result) in result.iter().enumerate() { - assert!(result.is_ok()); assert_eq!(expected[i], *result); } } From 5be0128337bebf7e5a0a53fbe0ed543b36d459f8 Mon Sep 17 00:00:00 2001 From: Fletcher555 Date: Thu, 18 Sep 2025 14:20:20 -0400 Subject: [PATCH 7/7] Fix an error with the way we are handling the assertions in the transaction testS --- src/db/table/core/table.rs | 8 ++++-- src/db/table/operations/alter_table/mod.rs | 28 +++++++++---------- .../helpers/where_clause/where_condition.rs | 3 +- src/db/transactions/rollback.rs | 5 +++- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/db/table/core/table.rs b/src/db/table/core/table.rs index 2bacdd8..97fb729 100644 --- a/src/db/table/core/table.rs +++ b/src/db/table/core/table.rs @@ -41,7 +41,10 @@ impl Table { } pub fn name(&self) -> Result<&String, String> { - self.name.stack.last().ok_or("Error fetching table name.".to_string()) + self.name + .stack + .last() + .ok_or("Error fetching table name.".to_string()) } pub fn change_name(&mut self, new_name: String, is_transaction: bool) { @@ -166,7 +169,8 @@ impl Table { } return Err(format!( "Column {} does not exist in table {}", - column, self.name()? + column, + self.name()? )); } diff --git a/src/db/table/operations/alter_table/mod.rs b/src/db/table/operations/alter_table/mod.rs index c4af177..ee9fa98 100644 --- a/src/db/table/operations/alter_table/mod.rs +++ b/src/db/table/operations/alter_table/mod.rs @@ -30,13 +30,15 @@ pub fn alter_table( old_column_name, statement.table_name )); } - let res = table.columns.rename_column( - &old_column_name, - &new_column_name, - is_transaction, - ); + let res = + table + .columns + .rename_column(&old_column_name, &new_column_name, is_transaction); if res.is_err() { - return Err(format!("Error renaming column: `{}` to `{}` in Table: `{}`", old_column_name, new_column_name, statement.table_name)); + return Err(format!( + "Error renaming column: `{}` to `{}` in Table: `{}`", + old_column_name, new_column_name, statement.table_name + )); } Ok(()) } @@ -68,11 +70,12 @@ pub fn alter_table( )); } let index = table.columns.get_index_of_column(&column_name)?; - let res = table - .columns - .drop_column(&column_name, is_transaction); + let res = table.columns.drop_column(&column_name, is_transaction); if res.is_err() { - return Err(format!("Error dropping column: `{}` from Table: `{}`", column_name, statement.table_name)); + return Err(format!( + "Error dropping column: `{}` from Table: `{}`", + column_name, statement.table_name + )); } // This is kind of bad because it's an O(n^2) operation however SQLite // preserves the order of the columns after drop column statements. @@ -465,10 +468,7 @@ mod tests { assert!(result.is_ok()); let table = database.get_table("new_users"); assert!(table.is_ok()); - let expected_table_name_stack = vec![ - "users".to_string(), - "new_users".to_string(), - ]; + let expected_table_name_stack = vec!["users".to_string(), "new_users".to_string()]; let table = table.unwrap(); for (i, name) in expected_table_name_stack.iter().enumerate() { assert_eq!(*name, table.name.stack[i].clone()); diff --git a/src/db/table/operations/helpers/where_clause/where_condition.rs b/src/db/table/operations/helpers/where_clause/where_condition.rs index 4a8cb8b..52d09c7 100644 --- a/src/db/table/operations/helpers/where_clause/where_condition.rs +++ b/src/db/table/operations/helpers/where_clause/where_condition.rs @@ -106,7 +106,8 @@ fn operand_to_value<'a>( if !table.has_column(column)? { return Err(format!( "Column {} does not exist in table {}", - column, table.name()? + column, + table.name()? )); } Ok(table.get_column_from_row(row, column)?) diff --git a/src/db/transactions/rollback.rs b/src/db/transactions/rollback.rs index d1e8e25..7277b33 100644 --- a/src/db/transactions/rollback.rs +++ b/src/db/transactions/rollback.rs @@ -24,7 +24,10 @@ pub fn rollback_transaction_entry( } AlterTableAction::RenameTable { ref new_table_name } => { // It is now under the new name - let mut table = database.tables.remove(new_table_name.as_str()).ok_or(format!("Table `{}` does not exist", new_table_name))?; + let mut table = database + .tables + .remove(new_table_name.as_str()) + .ok_or(format!("Table `{}` does not exist", new_table_name))?; table.rollback_name(); database.tables.insert(table.name()?.clone(), table); }