diff --git a/core/translate/mod.rs b/core/translate/mod.rs index ebfce59c6..60b2d991c 100644 --- a/core/translate/mod.rs +++ b/core/translate/mod.rs @@ -26,6 +26,7 @@ pub(crate) mod plan; pub(crate) mod planner; pub(crate) mod pragma; pub(crate) mod result_row; +pub(crate) mod rollback; pub(crate) mod schema; pub(crate) mod select; pub(crate) mod subquery; @@ -43,6 +44,7 @@ use alter::translate_alter_table; use index::{translate_create_index, translate_drop_index}; use insert::translate_insert; use limbo_sqlite3_parser::ast::{self, Delete, Insert}; +use rollback::translate_rollback; use schema::{translate_create_table, translate_create_virtual_table, translate_drop_table}; use select::translate_select; use std::rc::Rc; @@ -183,7 +185,10 @@ pub fn translate_inner( } ast::Stmt::Reindex { .. } => bail_parse_error!("REINDEX not supported yet"), ast::Stmt::Release(_) => bail_parse_error!("RELEASE not supported yet"), - ast::Stmt::Rollback { .. } => bail_parse_error!("ROLLBACK not supported yet"), + ast::Stmt::Rollback { + tx_name, + savepoint_name, + } => translate_rollback(query_mode, schema, syms, program, tx_name, savepoint_name)?, ast::Stmt::Savepoint(_) => bail_parse_error!("SAVEPOINT not supported yet"), ast::Stmt::Select(select) => { translate_select( diff --git a/core/translate/rollback.rs b/core/translate/rollback.rs new file mode 100644 index 000000000..2268da5e1 --- /dev/null +++ b/core/translate/rollback.rs @@ -0,0 +1,31 @@ +use limbo_sqlite3_parser::ast::Name; + +use crate::{ + schema::Schema, + translate::emitter::TransactionMode, + vdbe::{ + builder::{ProgramBuilder, QueryMode}, + insn::Insn, + }, + Result, SymbolTable, +}; + +pub fn translate_rollback( + _query_mode: QueryMode, + _schema: &Schema, + _syms: &SymbolTable, + mut program: ProgramBuilder, + txn_name: Option, + savepoint_name: Option, +) -> Result { + assert!( + txn_name.is_none() && savepoint_name.is_none(), + "txn_name and savepoint not supported yet" + ); + program.emit_insn(Insn::AutoCommit { + auto_commit: true, + rollback: true, + }); + program.epilogue_maybe_rollback(TransactionMode::None, true); + Ok(program) +} diff --git a/core/vdbe/builder.rs b/core/vdbe/builder.rs index c5e45b048..1f63a7c85 100644 --- a/core/vdbe/builder.rs +++ b/core/vdbe/builder.rs @@ -335,10 +335,14 @@ impl ProgramBuilder { self.emit_insn(Insn::ResultRow { start_reg, count }); } - fn emit_halt(&mut self) { + fn emit_halt(&mut self, rollback: bool) { self.emit_insn(Insn::Halt { err_code: 0, - description: String::new(), + description: if rollback { + "rollback".to_string() + } else { + String::new() + }, }); } @@ -745,8 +749,16 @@ impl ProgramBuilder { /// Note that although these are the final instructions, typically an SQLite /// query will jump to the Transaction instruction via init_label. pub fn epilogue(&mut self, txn_mode: TransactionMode) { + self.epilogue_maybe_rollback(txn_mode, false); + } + + /// Clean up and finalize the program, resolving any remaining labels + /// Note that although these are the final instructions, typically an SQLite + /// query will jump to the Transaction instruction via init_label. + /// "rollback" flag is used to determine if halt should rollback the transaction. + pub fn epilogue_maybe_rollback(&mut self, txn_mode: TransactionMode, rollback: bool) { if self.nested_level == 0 { - self.emit_halt(); + self.emit_halt(rollback); self.preassign_label_to_next_insn(self.init_label); match txn_mode {