Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 51 additions & 6 deletions src/db/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::interpreter::ast::SqlStatement;
use std::collections::HashMap;

pub struct Database {
pub tables: HashMap<String, Table>,
pub tables: HashMap<String, Vec<Option<Table>>>,
pub transaction: TransactionLog,
}

Expand Down Expand Up @@ -54,7 +54,7 @@ impl Database {
Ok(None)
}
SqlStatement::DropTable(statement) => {
drop_table::drop_table(self, statement)?;
drop_table::drop_table(self, statement, self.transaction.in_transaction())?;
self.transaction.append_entry(sql_statement_clone, vec![])?;
Ok(None)
}
Expand Down Expand Up @@ -114,20 +114,65 @@ impl Database {

pub fn has_table(&self, table_name: &str) -> bool {
self.tables.contains_key(table_name)
&& !self.tables.get(table_name).is_none()
&& !self.tables.get(table_name).unwrap().is_empty()
&& self
.tables
.get(table_name)
.unwrap()
.last()
.unwrap()
.is_some()
}

pub fn get_table(&self, table_name: &str) -> Result<&Table, String> {
if !self.has_table(table_name) {
return Err(format!("Table `{}` does not exist", table_name));
}
Ok(self.tables.get(table_name).unwrap())
let table = self.tables.get(table_name).unwrap().last().unwrap();
match table {
Some(table) => Ok(table),
_ => Err(format!("Table `{}` does not exist", table_name)),
}
}

pub fn get_table_mut(&mut self, table_name: &str) -> Result<&mut Table, String> {
if !self.has_table(table_name) {
return Err(format!("Table `{}` does not exist", table_name));
}
Ok(self.tables.get_mut(table_name).unwrap())
let table = self.tables.get_mut(table_name).unwrap().last_mut().unwrap();
match table {
Some(table) => Ok(table),
_ => Err(format!("Table `{}` does not exist", table_name)),
}
}

pub fn push_table_change(&mut self, table_name: &str, table: Table) {
if !self.has_table(table_name) {
self.tables
.insert(table_name.to_string(), vec![Some(table)]);
} else {
self.tables.get_mut(table_name).unwrap().push(Some(table));
}
}

pub fn pop_table_change(&mut self, table_name: &str) -> Result<Table, String> {
if !self.has_table(table_name) {
return Err(format!("Table `{}` does not exist", table_name));
}

let table = self.tables.get_mut(table_name).unwrap().pop().unwrap();

// Check if vector is empty before removing key
let is_empty = self.tables.get(table_name).unwrap().is_empty();
if is_empty {
self.tables.remove(table_name);
}

match table {
Some(table) => Ok(table),
_ => Err(format!("Table `{}` does not exist", table_name)),
}
}
}

Expand All @@ -140,7 +185,7 @@ mod tests {
Database {
tables: HashMap::from([(
"users".to_string(),
Table::new(
vec![Some(Table::new(
"users".to_string(),
vec![
ColumnDefinition {
Expand All @@ -154,7 +199,7 @@ mod tests {
constraints: vec![],
},
],
),
))],
)]),
transaction: TransactionLog { entries: None },
}
Expand Down
17 changes: 6 additions & 11 deletions src/db/table/operations/alter_table/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,9 @@ pub fn alter_table(
) -> Result<(), String> {
return match statement.action {
AlterTableAction::RenameTable { new_table_name } => {
let table = database.tables.remove(&statement.table_name);
match table {
Some(mut 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)),
};
let mut table = database.pop_table_change(statement.table_name.as_str())?;
table.change_name(new_table_name.clone(), is_transaction);
database.push_table_change(new_table_name.as_str(), table);
Ok(())
}
AlterTableAction::RenameColumn {
Expand Down Expand Up @@ -113,9 +108,9 @@ mod tests {
};
let result = alter_table(&mut database, statement, false);
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().unwrap() == "new_users");
assert!(!database.has_table("users"));
assert!(database.has_table("new_users"));
assert!(database.get_table("new_users").unwrap().name().unwrap() == "new_users");
}

#[test]
Expand Down
4 changes: 3 additions & 1 deletion src/db/table/operations/create_table/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ 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(), vec![Some(table)]);
Ok(())
}

Expand Down
22 changes: 17 additions & 5 deletions src/db/table/operations/drop_table/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use crate::db::database::Database;
use crate::interpreter::ast::{DropTableStatement, ExistenceCheck};

pub fn drop_table(database: &mut Database, statement: DropTableStatement) -> Result<(), String> {
pub fn drop_table(
database: &mut Database,
statement: DropTableStatement,
is_transaction: bool,
) -> Result<(), String> {
if !database.has_table(&statement.table_name) {
match statement.existence_check {
Some(ExistenceCheck::IfExists) => {
Expand All @@ -12,7 +16,15 @@ pub fn drop_table(database: &mut Database, statement: DropTableStatement) -> Res
}
}
}
database.tables.remove(&statement.table_name);
if is_transaction {
database
.tables
.get_mut(&statement.table_name)
.unwrap()
.push(None);
} else {
database.tables.remove(&statement.table_name);
}
Ok(())
}

Expand All @@ -28,7 +40,7 @@ mod tests {
existence_check: None,
};
let mut database = default_database();
let result = drop_table(&mut database, statement);
let result = drop_table(&mut database, statement, false);
assert!(result.is_ok());
assert!(!database.has_table("users"));
}
Expand All @@ -40,7 +52,7 @@ mod tests {
existence_check: None,
};
let mut database = Database::new();
let result = drop_table(&mut database, statement);
let result = drop_table(&mut database, statement, false);
assert!(result.is_err());
assert_eq!("Table `users` does not exist", result.err().unwrap());
}
Expand All @@ -52,7 +64,7 @@ mod tests {
existence_check: Some(ExistenceCheck::IfExists),
};
let mut database = Database::new();
let result = drop_table(&mut database, statement);
let result = drop_table(&mut database, statement, false);
assert!(result.is_ok());
}
}
4 changes: 3 additions & 1 deletion src/db/table/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ pub fn default_table() -> Table {
#[cfg(test)]
pub fn default_database() -> Database {
let mut database = Database::new();
database.tables.insert("users".to_string(), default_table());
database
.tables
.insert("users".to_string(), vec![Some(default_table())]);
database
}

Expand Down
17 changes: 12 additions & 5 deletions src/db/transactions/rollback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,22 @@ 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.pop_table_change(new_table_name.as_str())?;
table.rollback_name();
database.tables.insert(table.name()?.clone(), table);
database.push_table_change(statement.table_name.as_str(), table);
}
},
SqlStatement::Select(_) => {} // These should be kept in the log but obv do nothing.
SqlStatement::CreateTable(_) => {
database.tables.remove(statement.table_name.as_str());
}
SqlStatement::DropTable(statement) => {
database
.tables
.get_mut(statement.table_name.as_str())
.unwrap()
.pop();
}
_ => return Err("UNSUPPORTED".to_string()),
}
return Ok(());
Expand Down
59 changes: 58 additions & 1 deletion tests/transaction_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ fn test_transaction() {
SELECT * FROM new_users;
";
let result = run_sql(&mut database, sql);
println!("{:?}", result);
let expected = vec![
Ok(None),
Ok(None),
Expand Down Expand Up @@ -62,3 +61,61 @@ fn test_transaction() {
assert_eq!(expected[i], *result);
}
}

#[test]
fn test_transaction_create_table() {
let mut database = Database::new();
let sql = "
BEGIN;
CREATE TABLE users (
id INTEGER,
name TEXT
);
SELECT * FROM users;
ROLLBACK;
SELECT * FROM users;
";
let result = run_sql(&mut database, sql);
let expected = vec![
Ok(None),
Ok(None),
Ok(Some(vec![])),
Ok(None),
Err("Execution Error with statement starting on line 9 \n Error: Table `users` does not exist".to_string()),
];
for (i, result) in result.iter().enumerate() {
assert_eq!(expected[i], *result);
}
}

#[test]
fn test_transaction_drop_table() {
let mut database = Database::new();
let sql = "
CREATE TABLE users (
id INTEGER,
name TEXT
);
INSERT INTO users (id, name) VALUES (1, 'John');
BEGIN;
SELECT * FROM users;
DROP TABLE users;
SELECT * FROM users;
ROLLBACK;
SELECT * FROM users;
";
let result = run_sql(&mut database, sql);
let expected = vec![
Ok(None),
Ok(None),
Ok(None),
Ok(Some(vec![Row(vec![Value::Integer(1), Value::Text("John".to_string())])])),
Ok(None),
Err("Execution Error with statement starting on line 10 \n Error: Table `users` does not exist".to_string()),
Ok(None),
Ok(Some(vec![Row(vec![Value::Integer(1), Value::Text("John".to_string())])])),
];
for (i, result) in result.iter().enumerate() {
assert_eq!(expected[i], *result);
}
}
Loading