diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 49011f112..93578b657 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -101,12 +101,18 @@ use super::{make_record, Program, ProgramState, Register}; use crate::resolve_ext_path; use crate::{bail_constraint_error, must_be_btree_cursor, MvStore, Pager, Result}; -/// Macro to destructure an Insn, only to be used when it +/// Macro to destructure an Insn enum variant, only to be used when it /// is *impossible* to be another variant. -macro_rules! assert_insn { - ($pat:pat = $insn:expr) => { - let $pat = $insn else { - unsafe { std::hint::unreachable_unchecked() } +macro_rules! load_insn { + ($variant:ident { $($field:tt $(: $binding:pat)?),* $(,)? }, $insn:expr) => { + #[cfg(debug_assertions)] + let Insn::$variant { $($field $(: $binding)?),* } = $insn else { + panic!("Expected Insn::{}, got {:?}", stringify!($variant), $insn); + }; + #[cfg(not(debug_assertions))] + let Insn::$variant { $($field $(: $binding)?),*} = $insn else { + // this will optimize away the branch + unsafe { std::hint::unreachable_unchecked() }; }; }; } @@ -155,7 +161,7 @@ pub fn op_init( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Init { target_pc } = insn); + load_insn!(Init { target_pc }, insn); assert!(target_pc.is_offset()); state.pc = target_pc.as_offset_int(); Ok(InsnFunctionStepResult::Step) @@ -168,7 +174,7 @@ pub fn op_add( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Add { lhs, rhs, dest } = insn); + load_insn!(Add { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -185,7 +191,7 @@ pub fn op_subtract( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Subtract { lhs, rhs, dest } = insn); + load_insn!(Subtract { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -202,7 +208,7 @@ pub fn op_multiply( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Multiply { lhs, rhs, dest } = insn); + load_insn!(Multiply { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -219,7 +225,7 @@ pub fn op_divide( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Divide { lhs, rhs, dest } = insn); + load_insn!(Divide { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -236,7 +242,7 @@ pub fn op_drop_index( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::DropIndex { index, db: _ } = insn); + load_insn!(DropIndex { index, db: _ }, insn); program .connection .with_schema_mut(|schema| schema.remove_index(index)); @@ -251,7 +257,7 @@ pub fn op_remainder( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Remainder { lhs, rhs, dest } = insn); + load_insn!(Remainder { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -268,7 +274,7 @@ pub fn op_bit_and( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::BitAnd { lhs, rhs, dest } = insn); + load_insn!(BitAnd { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -285,7 +291,7 @@ pub fn op_bit_or( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::BitOr { lhs, rhs, dest } = insn); + load_insn!(BitOr { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -302,7 +308,7 @@ pub fn op_bit_not( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::BitNot { reg, dest } = insn); + load_insn!(BitNot { reg, dest }, insn); state.registers[*dest] = Register::Value(state.registers[*reg].get_owned_value().exec_bit_not()); state.pc += 1; @@ -316,12 +322,13 @@ pub fn op_checkpoint( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Checkpoint { + load_insn!( + Checkpoint { database: _, checkpoint_mode, dest, - } = insn + }, + insn ); if !program.connection.auto_commit.get() { // TODO: sqlite returns "Runtime error: database table is locked (6)" when a table is in use @@ -383,7 +390,7 @@ pub fn op_null_row( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::NullRow { cursor_id } = insn); + load_insn!(NullRow { cursor_id }, insn); { let mut cursor = must_be_btree_cursor!(*cursor_id, program.cursor_ref, state, "NullRow"); let cursor = cursor.as_btree_mut(); @@ -400,13 +407,14 @@ pub fn op_compare( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Compare { + load_insn!( + Compare { start_reg_a, start_reg_b, count, collation, - } = insn + }, + insn ); let start_reg_a = *start_reg_a; let start_reg_b = *start_reg_b; @@ -445,12 +453,13 @@ pub fn op_jump( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Jump { + load_insn!( + Jump { target_pc_lt, target_pc_eq, target_pc_gt, - } = insn + }, + insn ); assert!(target_pc_lt.is_offset()); assert!(target_pc_eq.is_offset()); @@ -477,12 +486,13 @@ pub fn op_move( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Move { + load_insn!( + Move { source_reg, dest_reg, count, - } = insn + }, + insn ); let source_reg = *source_reg; let dest_reg = *dest_reg; @@ -504,12 +514,13 @@ pub fn op_if_pos( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::IfPos { + load_insn!( + IfPos { reg, target_pc, decrement_by, - } = insn + }, + insn ); assert!(target_pc.is_offset()); let reg = *reg; @@ -538,7 +549,7 @@ pub fn op_not_null( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::NotNull { reg, target_pc } = insn); + load_insn!(NotNull { reg, target_pc }, insn); assert!(target_pc.is_offset()); let reg = *reg; let target_pc = *target_pc; @@ -848,12 +859,13 @@ pub fn op_if( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::If { + load_insn!( + If { reg, target_pc, jump_if_null, - } = insn + }, + insn ); assert!(target_pc.is_offset()); if state.registers[*reg] @@ -874,12 +886,13 @@ pub fn op_if_not( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::IfNot { + load_insn!( + IfNot { reg, target_pc, jump_if_null, - } = insn + }, + insn ); assert!(target_pc.is_offset()); if state.registers[*reg] @@ -900,12 +913,13 @@ pub fn op_open_read( _pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::OpenRead { + load_insn!( + OpenRead { cursor_id, root_page, db, - } = insn + }, + insn ); let pager = program.get_pager_from_database_index(db); @@ -971,7 +985,7 @@ pub fn op_vopen( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::VOpen { cursor_id } = insn); + load_insn!(VOpen { cursor_id }, insn); let (_, cursor_type) = program.cursor_ref.get(*cursor_id).unwrap(); let CursorType::VirtualTable(virtual_table) = cursor_type else { panic!("VOpen on non-virtual table cursor"); @@ -994,12 +1008,13 @@ pub fn op_vcreate( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::VCreate { + load_insn!( + VCreate { module_name, table_name, args_reg, - } = insn + }, + insn ); let module_name = state.registers[*module_name].get_owned_value().to_string(); let table_name = state.registers[*table_name].get_owned_value().to_string(); @@ -1034,15 +1049,16 @@ pub fn op_vfilter( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::VFilter { + load_insn!( + VFilter { cursor_id, pc_if_empty, arg_count, args_reg, idx_str, idx_num, - } = insn + }, + insn ); let has_rows = { let mut cursor = state.get_cursor(*cursor_id); @@ -1073,12 +1089,13 @@ pub fn op_vcolumn( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::VColumn { + load_insn!( + VColumn { cursor_id, column, dest, - } = insn + }, + insn ); let value = { let mut cursor = state.get_cursor(*cursor_id); @@ -1097,14 +1114,15 @@ pub fn op_vupdate( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::VUpdate { + load_insn!( + VUpdate { cursor_id, arg_count, start_reg, conflict_action, .. - } = insn + }, + insn ); let (_, cursor_type) = program.cursor_ref.get(*cursor_id).unwrap(); let CursorType::VirtualTable(virtual_table) = cursor_type else { @@ -1160,11 +1178,12 @@ pub fn op_vnext( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::VNext { + load_insn!( + VNext { cursor_id, pc_if_next, - } = insn + }, + insn ); let has_more = { let mut cursor = state.get_cursor(*cursor_id); @@ -1186,7 +1205,7 @@ pub fn op_vdestroy( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::VDestroy { db, table_name } = insn); + load_insn!(VDestroy { db, table_name }, insn); let conn = program.connection.clone(); { let Some(vtab) = conn.syms.borrow_mut().vtabs.remove(table_name) else { @@ -1208,12 +1227,13 @@ pub fn op_open_pseudo( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::OpenPseudo { + load_insn!( + OpenPseudo { cursor_id, content_reg: _, num_fields: _, - } = insn + }, + insn ); { let mut cursors = state.cursors.borrow_mut(); @@ -1234,11 +1254,12 @@ pub fn op_rewind( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Rewind { + load_insn!( + Rewind { cursor_id, pc_if_empty, - } = insn + }, + insn ); assert!(pc_if_empty.is_offset()); let is_empty = { @@ -1262,11 +1283,12 @@ pub fn op_last( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Last { + load_insn!( + Last { cursor_id, pc_if_empty, - } = insn + }, + insn ); assert!(pc_if_empty.is_offset()); let is_empty = { @@ -1382,13 +1404,14 @@ pub fn op_column( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Column { + load_insn!( + Column { cursor_id, column, dest, default, - } = insn + }, + insn ); if let Some((index_cursor_id, table_cursor_id)) = state.deferred_seeks[*cursor_id].take() { let deferred_seek = 'd: { @@ -1676,13 +1699,14 @@ pub fn op_type_check( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::TypeCheck { + load_insn!( + TypeCheck { start_reg, count, check_generated, table_reference, - } = insn + }, + insn ); assert!(table_reference.is_strict); state.registers[*start_reg..*start_reg + *count] @@ -1737,13 +1761,14 @@ pub fn op_make_record( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::MakeRecord { + load_insn!( + MakeRecord { start_reg, count, dest_reg, .. - } = insn + }, + insn ); let record = make_record(&state.registers, start_reg, count); state.registers[*dest_reg] = Register::Record(record); @@ -1758,7 +1783,7 @@ pub fn op_result_row( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::ResultRow { start_reg, count } = insn); + load_insn!(ResultRow { start_reg, count }, insn); let row = Row { values: &state.registers[*start_reg] as *const Register, count: *count, @@ -1775,11 +1800,12 @@ pub fn op_next( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Next { + load_insn!( + Next { cursor_id, pc_if_next, - } = insn + }, + insn ); assert!(pc_if_next.is_offset()); let is_empty = { @@ -1805,11 +1831,12 @@ pub fn op_prev( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Prev { + load_insn!( + Prev { cursor_id, pc_if_prev, - } = insn + }, + insn ); assert!(pc_if_prev.is_offset()); let is_empty = { @@ -1874,11 +1901,12 @@ pub fn op_halt( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Halt { + load_insn!( + Halt { err_code, description, - } = insn + }, + insn ); if *err_code > 0 { // invalidate page cache in case of error @@ -1924,12 +1952,13 @@ pub fn op_halt_if_null( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::HaltIfNull { + load_insn!( + HaltIfNull { target_reg, err_code, description, - } = insn + }, + insn ); if state.registers[*target_reg].get_owned_value() == &Value::Null { halt(program, state, pager, mv_store, *err_code, description) @@ -1946,12 +1975,13 @@ pub fn op_transaction( _pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Transaction { + load_insn!( + Transaction { db, write, schema_cookie, - } = insn + }, + insn ); let conn = program.connection.clone(); if *write && conn._db.open_flags.contains(OpenFlags::ReadOnly) { @@ -2075,11 +2105,12 @@ pub fn op_auto_commit( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::AutoCommit { + load_insn!( + AutoCommit { auto_commit, rollback, - } = insn + }, + insn ); let conn = program.connection.clone(); if state.commit_state == CommitState::Committing { @@ -2128,7 +2159,7 @@ pub fn op_goto( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Goto { target_pc } = insn); + load_insn!(Goto { target_pc }, insn); assert!(target_pc.is_offset()); state.pc = target_pc.as_offset_int(); Ok(InsnFunctionStepResult::Step) @@ -2141,11 +2172,12 @@ pub fn op_gosub( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Gosub { + load_insn!( + Gosub { target_pc, return_reg, - } = insn + }, + insn ); assert!(target_pc.is_offset()); state.registers[*return_reg] = Register::Value(Value::Integer((state.pc + 1) as i64)); @@ -2160,11 +2192,12 @@ pub fn op_return( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Return { + load_insn!( + Return { return_reg, can_fallthrough, - } = insn + }, + insn ); if let Value::Integer(pc) = state.registers[*return_reg].get_owned_value() { let pc: u32 = (*pc) @@ -2189,7 +2222,7 @@ pub fn op_integer( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Integer { value, dest } = insn); + load_insn!(Integer { value, dest }, insn); state.registers[*dest] = Register::Value(Value::Integer(*value)); state.pc += 1; Ok(InsnFunctionStepResult::Step) @@ -2202,7 +2235,7 @@ pub fn op_real( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Real { value, dest } = insn); + load_insn!(Real { value, dest }, insn); state.registers[*dest] = Register::Value(Value::Float(*value)); state.pc += 1; Ok(InsnFunctionStepResult::Step) @@ -2215,7 +2248,7 @@ pub fn op_real_affinity( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::RealAffinity { register } = insn); + load_insn!(RealAffinity { register }, insn); if let Value::Integer(i) = &state.registers[*register].get_owned_value() { state.registers[*register] = Register::Value(Value::Float(*i as f64)); }; @@ -2230,7 +2263,7 @@ pub fn op_string8( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::String8 { value, dest } = insn); + load_insn!(String8 { value, dest }, insn); state.registers[*dest] = Register::Value(Value::build_text(value)); state.pc += 1; Ok(InsnFunctionStepResult::Step) @@ -2243,7 +2276,7 @@ pub fn op_blob( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Blob { value, dest } = insn); + load_insn!(Blob { value, dest }, insn); state.registers[*dest] = Register::Value(Value::Blob(value.clone())); state.pc += 1; Ok(InsnFunctionStepResult::Step) @@ -2256,7 +2289,7 @@ pub fn op_row_data( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::RowData { cursor_id, dest } = insn); + load_insn!(RowData { cursor_id, dest }, insn); let record = { let mut cursor_ref = @@ -2285,7 +2318,7 @@ pub fn op_row_id( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::RowId { cursor_id, dest } = insn); + load_insn!(RowId { cursor_id, dest }, insn); if let Some((index_cursor_id, table_cursor_id)) = state.deferred_seeks[*cursor_id].take() { let deferred_seek = 'd: { let rowid = { @@ -2348,7 +2381,7 @@ pub fn op_idx_row_id( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::IdxRowId { cursor_id, dest } = insn); + load_insn!(IdxRowId { cursor_id, dest }, insn); let mut cursors = state.cursors.borrow_mut(); let cursor = cursors.get_mut(*cursor_id).unwrap().as_mut().unwrap(); let cursor = cursor.as_btree_mut(); @@ -2368,12 +2401,13 @@ pub fn op_seek_rowid( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::SeekRowid { + load_insn!( + SeekRowid { cursor_id, src_reg, target_pc, - } = insn + }, + insn ); assert!(target_pc.is_offset()); let pc = { @@ -2423,11 +2457,12 @@ pub fn op_deferred_seek( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::DeferredSeek { + load_insn!( + DeferredSeek { index_cursor_id, table_cursor_id, - } = insn + }, + insn ); state.deferred_seeks[*table_cursor_id] = Some((*index_cursor_id, *table_cursor_id)); state.pc += 1; @@ -2848,13 +2883,14 @@ pub fn op_idx_ge( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::IdxGE { + load_insn!( + IdxGE { cursor_id, start_reg, num_regs, target_pc, - } = insn + }, + insn ); assert!(target_pc.is_offset()); @@ -2898,7 +2934,7 @@ pub fn op_seek_end( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::SeekEnd { cursor_id } = *insn); + load_insn!(SeekEnd { cursor_id }, *insn); { let mut cursor = state.get_cursor(cursor_id); let cursor = cursor.as_btree_mut(); @@ -2916,13 +2952,14 @@ pub fn op_idx_le( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::IdxLE { + load_insn!( + IdxLE { cursor_id, start_reg, num_regs, target_pc, - } = insn + }, + insn ); assert!(target_pc.is_offset()); @@ -2966,13 +3003,14 @@ pub fn op_idx_gt( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::IdxGT { + load_insn!( + IdxGT { cursor_id, start_reg, num_regs, target_pc, - } = insn + }, + insn ); assert!(target_pc.is_offset()); @@ -3016,13 +3054,14 @@ pub fn op_idx_lt( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::IdxLT { + load_insn!( + IdxLT { cursor_id, start_reg, num_regs, target_pc, - } = insn + }, + insn ); assert!(target_pc.is_offset()); @@ -3066,7 +3105,7 @@ pub fn op_decr_jump_zero( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::DecrJumpZero { reg, target_pc } = insn); + load_insn!(DecrJumpZero { reg, target_pc }, insn); assert!(target_pc.is_offset()); match state.registers[*reg].get_owned_value() { Value::Integer(n) => { @@ -3117,13 +3156,14 @@ pub fn op_agg_step( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::AggStep { + load_insn!( + AggStep { acc_reg, col, delimiter, func, - } = insn + }, + insn ); if let Register::Value(Value::Null) = state.registers[*acc_reg] { state.registers[*acc_reg] = match func { @@ -3421,7 +3461,7 @@ pub fn op_agg_final( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::AggFinal { register, func } = insn); + load_insn!(AggFinal { register, func }, insn); match state.registers[*register].borrow_mut() { Register::Aggregate(agg) => match func { AggFunc::Avg => { @@ -3559,13 +3599,14 @@ pub fn op_sorter_open( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::SorterOpen { + load_insn!( + SorterOpen { cursor_id, columns: _, order, collations, - } = insn + }, + insn ); let cache_size = program.connection.get_cache_size(); // Set the buffer size threshold to be roughly the same as the limit configured for the page-cache. @@ -3606,12 +3647,13 @@ pub fn op_sorter_data( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::SorterData { + load_insn!( + SorterData { cursor_id, dest_reg, pseudo_cursor, - } = insn + }, + insn ); let record = { let mut cursor = state.get_cursor(*cursor_id); @@ -3641,11 +3683,12 @@ pub fn op_sorter_insert( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::SorterInsert { + load_insn!( + SorterInsert { cursor_id, record_reg, - } = insn + }, + insn ); { let mut cursor = state.get_cursor(*cursor_id); @@ -3667,11 +3710,12 @@ pub fn op_sorter_sort( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::SorterSort { + load_insn!( + SorterSort { cursor_id, pc_if_empty, - } = insn + }, + insn ); let is_empty = { let mut cursor = state.get_cursor(*cursor_id); @@ -3699,11 +3743,12 @@ pub fn op_sorter_next( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::SorterNext { + load_insn!( + SorterNext { cursor_id, pc_if_next, - } = insn + }, + insn ); assert!(pc_if_next.is_offset()); let has_more = { @@ -3729,13 +3774,14 @@ pub fn op_function( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Function { + load_insn!( + Function { constant_mask, func, start_reg, dest, - } = insn + }, + insn ); let arg_count = func.arg_count; @@ -4946,12 +4992,13 @@ pub fn op_init_coroutine( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::InitCoroutine { + load_insn!( + InitCoroutine { yield_reg, jump_on_definition, start_offset, - } = insn + }, + insn ); assert!(jump_on_definition.is_offset()); let start_offset = start_offset.as_offset_int(); @@ -4973,7 +5020,7 @@ pub fn op_end_coroutine( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::EndCoroutine { yield_reg } = insn); + load_insn!(EndCoroutine { yield_reg }, insn); if let Value::Integer(pc) = state.registers[*yield_reg].get_owned_value() { state.ended_coroutine.set(*yield_reg); @@ -4994,11 +5041,12 @@ pub fn op_yield( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Yield { + load_insn!( + Yield { yield_reg, end_offset, - } = insn + }, + insn ); if let Value::Integer(pc) = state.registers[*yield_reg].get_owned_value() { if state.ended_coroutine.get(*yield_reg) { @@ -5036,14 +5084,15 @@ pub fn op_insert( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Insert { + load_insn!( + Insert { cursor: cursor_id, key_reg, record_reg, flag, table_name: _, - } = insn + }, + insn ); if state.op_insert_state == OpInsertState::UpdateLastRowid { @@ -5116,13 +5165,14 @@ pub fn op_int_64( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Int64 { + load_insn!( + Int64 { _p1, out_reg, _p3, value, - } = insn + }, + insn ); state.registers[*out_reg] = Register::Value(Value::Integer(*value)); state.pc += 1; @@ -5136,7 +5186,7 @@ pub fn op_delete( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Delete { cursor_id } = insn); + load_insn!(Delete { cursor_id }, insn); { let mut cursor = state.get_cursor(*cursor_id); let cursor = cursor.as_btree_mut(); @@ -5161,13 +5211,14 @@ pub fn op_idx_delete( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::IdxDelete { + load_insn!( + IdxDelete { cursor_id, start_reg, num_regs, raise_error_if_no_matching_entry, - } = insn + }, + insn ); loop { @@ -5267,13 +5318,14 @@ pub fn op_idx_insert( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::IdxInsert { + load_insn!( + IdxInsert { cursor_id, record_reg, flags, .. - } = *insn + }, + *insn ); let record_to_insert = match &state.registers[record_reg] { @@ -5414,12 +5466,13 @@ pub fn op_new_rowid( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::NewRowid { + load_insn!( + NewRowid { cursor, rowid_reg, .. - } = insn + }, + insn ); if let Some(mv_store) = mv_store { @@ -5548,7 +5601,7 @@ pub fn op_must_be_int( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::MustBeInt { reg } = insn); + load_insn!(MustBeInt { reg }, insn); match &state.registers[*reg].get_owned_value() { Value::Integer(_) => {} Value::Float(f) => match cast_real_to_integer(*f) { @@ -5581,7 +5634,7 @@ pub fn op_soft_null( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::SoftNull { reg } = insn); + load_insn!(SoftNull { reg }, insn); state.registers[*reg] = Register::Value(Value::Null); state.pc += 1; Ok(InsnFunctionStepResult::Step) @@ -5601,13 +5654,14 @@ pub fn op_no_conflict( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::NoConflict { + load_insn!( + NoConflict { cursor_id, target_pc, record_reg, num_regs, - } = insn + }, + insn ); loop { @@ -5696,12 +5750,13 @@ pub fn op_not_exists( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::NotExists { + load_insn!( + NotExists { cursor, rowid_reg, target_pc, - } = insn + }, + insn ); let exists = if let Some(mv_store) = mv_store { let mut cursor = must_be_btree_cursor!(*cursor, program.cursor_ref, state, "NotExists"); @@ -5728,12 +5783,13 @@ pub fn op_offset_limit( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::OffsetLimit { + load_insn!( + OffsetLimit { limit_reg, combined_reg, offset_reg, - } = insn + }, + insn ); let limit_val = match state.registers[*limit_reg].get_owned_value() { Value::Integer(val) => val, @@ -5772,12 +5828,13 @@ pub fn op_open_write( _pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::OpenWrite { + load_insn!( + OpenWrite { cursor_id, root_page, db, - } = insn + }, + insn ); if program.connection.is_readonly(*db) { return Err(LimboError::ReadOnly); @@ -5855,12 +5912,13 @@ pub fn op_copy( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Copy { + load_insn!( + Copy { src_reg, dst_reg, extra_amount, - } = insn + }, + insn ); for i in 0..=*extra_amount { state.registers[*dst_reg + i] = state.registers[*src_reg + i].clone(); @@ -5876,7 +5934,7 @@ pub fn op_create_btree( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::CreateBtree { db, root, flags } = insn); + load_insn!(CreateBtree { db, root, flags }, insn); assert_eq!(*db, 0); @@ -5901,12 +5959,13 @@ pub fn op_destroy( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Destroy { + load_insn!( + Destroy { root, former_root_reg, is_temp, - } = insn + }, + insn ); if *is_temp == 1 { todo!("temp databases not implemented yet."); @@ -5929,7 +5988,7 @@ pub fn op_drop_table( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::DropTable { db, table_name, .. } = insn); + load_insn!(DropTable { db, table_name, .. }, insn); if *db > 0 { todo!("temp databases not implemented yet"); } @@ -5951,7 +6010,7 @@ pub fn op_close( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Close { cursor_id } = insn); + load_insn!(Close { cursor_id }, insn); let mut cursors = state.cursors.borrow_mut(); cursors.get_mut(*cursor_id).unwrap().take(); state.pc += 1; @@ -5965,7 +6024,7 @@ pub fn op_is_null( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::IsNull { reg, target_pc } = insn); + load_insn!(IsNull { reg, target_pc }, insn); if matches!(state.registers[*reg], Register::Value(Value::Null)) { state.pc = target_pc.as_offset_int(); } else { @@ -5981,7 +6040,7 @@ pub fn op_page_count( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::PageCount { db, dest } = insn); + load_insn!(PageCount { db, dest }, insn); if *db > 0 { // TODO: implement temp databases todo!("temp databases not implemented yet"); @@ -6003,11 +6062,12 @@ pub fn op_parse_schema( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::ParseSchema { + load_insn!( + ParseSchema { db: _, where_clause, - } = insn + }, + insn ); let conn = program.connection.clone(); // set auto commit to false in order for parse schema to not commit changes as transaction state is stored in connection, @@ -6042,7 +6102,7 @@ pub fn op_read_cookie( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::ReadCookie { db, dest, cookie } = insn); + load_insn!(ReadCookie { db, dest, cookie }, insn); if *db > 0 { // TODO: implement temp databases todo!("temp databases not implemented yet"); @@ -6072,13 +6132,14 @@ pub fn op_set_cookie( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::SetCookie { + load_insn!( + SetCookie { db, cookie, value, p5, - } = insn + }, + insn ); if *db > 0 { todo!("temp databases not implemented yet"); @@ -6126,7 +6187,7 @@ pub fn op_shift_right( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::ShiftRight { lhs, rhs, dest } = insn); + load_insn!(ShiftRight { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -6143,7 +6204,7 @@ pub fn op_shift_left( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::ShiftLeft { lhs, rhs, dest } = insn); + load_insn!(ShiftLeft { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -6160,7 +6221,7 @@ pub fn op_add_imm( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::AddImm { register, value } = insn); + load_insn!(AddImm { register, value }, insn); let current = &state.registers[*register]; let current_value = match current { @@ -6189,7 +6250,7 @@ pub fn op_variable( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Variable { index, dest } = insn); + load_insn!(Variable { index, dest }, insn); state.registers[*dest] = Register::Value(state.get_parameter(*index)); state.pc += 1; Ok(InsnFunctionStepResult::Step) @@ -6202,7 +6263,7 @@ pub fn op_zero_or_null( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::ZeroOrNull { rg1, rg2, dest } = insn); + load_insn!(ZeroOrNull { rg1, rg2, dest }, insn); if *state.registers[*rg1].get_owned_value() == Value::Null || *state.registers[*rg2].get_owned_value() == Value::Null { @@ -6221,7 +6282,7 @@ pub fn op_not( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Not { reg, dest } = insn); + load_insn!(Not { reg, dest }, insn); state.registers[*dest] = Register::Value(state.registers[*reg].get_owned_value().exec_boolean_not()); state.pc += 1; @@ -6235,7 +6296,7 @@ pub fn op_concat( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Concat { lhs, rhs, dest } = insn); + load_insn!(Concat { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -6252,7 +6313,7 @@ pub fn op_and( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::And { lhs, rhs, dest } = insn); + load_insn!(And { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -6269,7 +6330,7 @@ pub fn op_or( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Or { lhs, rhs, dest } = insn); + load_insn!(Or { lhs, rhs, dest }, insn); state.registers[*dest] = Register::Value( state.registers[*lhs] .get_owned_value() @@ -6479,10 +6540,11 @@ pub fn op_once( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Once { + load_insn!( + Once { target_pc_when_reentered, - } = insn + }, + insn ); assert!(target_pc_when_reentered.is_offset()); let offset = state.pc; @@ -6564,12 +6626,13 @@ pub fn op_affinity( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Affinity { + load_insn!( + Affinity { start_reg, count, affinities, - } = insn + }, + insn ); if affinities.len() != count.get() { @@ -6597,12 +6660,13 @@ pub fn op_count( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::Count { + load_insn!( + Count { cursor_id, target_reg, exact, - } = insn + }, + insn ); let count = { @@ -6633,12 +6697,13 @@ pub fn op_integrity_check( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!( - Insn::IntegrityCk { + load_insn!( + IntegrityCk { max_errors, roots, message_register, - } = insn + }, + insn ); match &mut state.op_integrity_check_state { OpIntegrityCheckState::Start => { @@ -6685,7 +6750,7 @@ pub fn op_cast( _pager: &Rc, _mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::Cast { reg, affinity } = insn); + load_insn!(Cast { reg, affinity }, insn); let value = state.registers[*reg].get_owned_value().clone(); let result = match affinity { @@ -6708,7 +6773,7 @@ pub fn op_rename_table( pager: &Rc, mv_store: Option<&Arc>, ) -> Result { - assert_insn!(Insn::RenameTable { from, to } = insn); + load_insn!(RenameTable { from, to }, insn); let conn = program.connection.clone();