From 2f3c3b540427dc5eaad51d30d5b3a535730ad76e Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Fri, 5 Jul 2024 11:39:21 +0300 Subject: [PATCH] Clean up insn_to_str() The SQLite documentation explicitly says that P1, P2, and P3 are 32-bit signed integers. P4 is a value, and P5 is a 16-bit unsigned integer. Although we use different types for operands, the `EXPLAIN` output should be compatible with SQLite and, therefore, use those types. --- core/types.rs | 29 ++++ core/vdbe.rs | 420 ++++++++++++++++++++++++-------------------------- 2 files changed, 227 insertions(+), 222 deletions(-) diff --git a/core/types.rs b/core/types.rs index 847f55947..5d060ad57 100644 --- a/core/types.rs +++ b/core/types.rs @@ -1,3 +1,4 @@ +use std::fmt::Display; use std::{cell::Ref, rc::Rc}; use anyhow::Result; @@ -11,6 +12,18 @@ pub enum Value<'a> { Blob(&'a Vec), } +impl<'a> Display for Value<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Value::Null => write!(f, "NULL"), + Value::Integer(i) => write!(f, "{}", i), + Value::Float(fl) => write!(f, "{}", fl), + Value::Text(s) => write!(f, "{}", s), + Value::Blob(b) => write!(f, "{:?}", b), + } + } +} + #[derive(Debug, Clone, PartialEq)] pub enum OwnedValue { Null, @@ -21,6 +34,22 @@ pub enum OwnedValue { Agg(Box), // TODO(pere): make this without Box. Currently this might cause cache miss but let's leave it for future analysis } +impl Display for OwnedValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + OwnedValue::Null => write!(f, "NULL"), + OwnedValue::Integer(i) => write!(f, "{}", i), + OwnedValue::Float(fl) => write!(f, "{}", fl), + OwnedValue::Text(s) => write!(f, "{}", s), + OwnedValue::Blob(b) => write!(f, "{:?}", b), + OwnedValue::Agg(a) => match a.as_ref() { + AggContext::Avg(acc, _count) => write!(f, "{}", acc), + AggContext::Sum(acc) => write!(f, "{}", acc), + }, + } + } +} + #[derive(Debug, Clone, PartialEq)] pub enum AggContext { Avg(OwnedValue, OwnedValue), // acc and count diff --git a/core/vdbe.rs b/core/vdbe.rs index 075c62197..c59f89be1 100644 --- a/core/vdbe.rs +++ b/core/vdbe.rs @@ -4,7 +4,6 @@ use crate::pager::Pager; use crate::types::{AggContext, Cursor, CursorResult, OwnedValue, Record}; use anyhow::Result; -use core::fmt; use std::borrow::BorrowMut; use std::cell::RefCell; use std::collections::BTreeMap; @@ -190,8 +189,8 @@ pub enum StepResult<'a> { /// The program state describes the environment in which the program executes. pub struct ProgramState { - pub pc: usize, - cursors: RefCell>>, + pub pc: BranchOffset, + cursors: RefCell>>, registers: Vec, } @@ -226,7 +225,7 @@ impl Program { println!("addr opcode p1 p2 p3 p4 p5 comment"); println!("---- ------------- ---- ---- ---- ------------- -- -------"); for (addr, insn) in self.insns.iter().enumerate() { - print_insn(addr, insn); + print_insn(addr.try_into().unwrap(), insn); } } @@ -236,7 +235,7 @@ impl Program { pager: Rc, ) -> Result> { loop { - let insn = &self.insns[state.pc]; + let insn = &self.insns[state.pc as usize]; trace_insn(state.pc, insn); let mut cursors = state.cursors.borrow_mut(); match insn { @@ -247,7 +246,7 @@ impl Program { cursor_id, root_page, } => { - let cursor = Box::new(BTreeCursor::new(pager.clone(), *root_page)); + let cursor = Box::new(BTreeCursor::new(pager.clone(), *root_page as usize)); cursors.insert(*cursor_id, cursor); state.pc += 1; } @@ -444,232 +443,209 @@ fn make_record<'a>( Record::new(values) } -fn trace_insn(addr: usize, insn: &Insn) { +fn trace_insn(addr: BranchOffset, insn: &Insn) { if !log::log_enabled!(log::Level::Trace) { return; } log::trace!("{}", insn_to_str(addr, insn)); } -fn print_insn(addr: usize, insn: &Insn) { +fn print_insn(addr: BranchOffset, insn: &Insn) { let s = insn_to_str(addr, insn); println!("{}", s); } -enum IntValue { - Int(i64), - Usize(usize), - Float(f64), -} - -impl fmt::Display for IntValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - IntValue::Int(i) => f.pad(i.to_string().as_str()), - IntValue::Usize(i) => f.pad(i.to_string().as_str()), - IntValue::Float(float_val) => write!(f, "{}", float_val), - } - } -} - -fn insn_to_str(addr: usize, insn: &Insn) -> String { - let (opcode, p1, p2, p3, p4, p5, comment): ( - &str, - IntValue, - IntValue, - IntValue, - &str, - IntValue, - String, - ) = match insn { - Insn::Init { target_pc } => ( - "Init", - IntValue::Usize(0), - IntValue::Usize(*target_pc), - IntValue::Usize(0), - "", - IntValue::Usize(0), - format!("Start at {}", target_pc), - ), - Insn::OpenReadAsync { - cursor_id, - root_page, - } => ( - "OpenReadAsync", - IntValue::Usize(*cursor_id), - IntValue::Usize(*root_page), - IntValue::Usize(0), - "", - IntValue::Usize(0), - format!("root={}", root_page), - ), - Insn::OpenReadAwait => ( - "OpenReadAwait", - IntValue::Usize(0), - IntValue::Usize(0), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::RewindAsync { cursor_id } => ( - "RewindAsync", - IntValue::Usize(*cursor_id), - IntValue::Usize(0), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::RewindAwait { - cursor_id, - pc_if_empty, - } => ( - "RewindAwait", - IntValue::Usize(*cursor_id), - IntValue::Usize(*pc_if_empty), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::Column { - cursor_id, - column, - dest, - } => ( - "Column", - IntValue::Usize(*cursor_id), - IntValue::Usize(*column), - IntValue::Usize(*dest), - "", - IntValue::Usize(0), - format!("r[{}]= cursor {} column {}", dest, cursor_id, column), - ), - Insn::ResultRow { - register_start, - register_end, - } => ( - "ResultRow", - IntValue::Usize(*register_start), - IntValue::Usize(*register_end), - IntValue::Usize(0), - "", - IntValue::Usize(0), - format!("output=r[{}..{}]", register_start, register_end), - ), - Insn::NextAsync { cursor_id } => ( - "NextAsync", - IntValue::Usize(*cursor_id), - IntValue::Usize(0), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::NextAwait { - cursor_id, - pc_if_next, - } => ( - "NextAwait", - IntValue::Usize(*cursor_id), - IntValue::Usize(*pc_if_next), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::Halt => ( - "Halt", - IntValue::Usize(0), - IntValue::Usize(0), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::Transaction => ( - "Transaction", - IntValue::Usize(0), - IntValue::Usize(0), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::Goto { target_pc } => ( - "Goto", - IntValue::Usize(0), - IntValue::Usize(*target_pc), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::Integer { value, dest } => ( - "Integer", - IntValue::Usize(*dest), - IntValue::Int(*value), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::Real { value, dest } => ( - "Real", - IntValue::Usize(*dest), - IntValue::Float(*value), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::String8 { value, dest } => ( - "String8", - IntValue::Usize(*dest), - IntValue::Usize(0), - IntValue::Usize(0), - value.as_str(), - IntValue::Usize(0), - format!("r[{}]= '{}'", dest, value), - ), - Insn::RowId { cursor_id, dest } => ( - "RowId", - IntValue::Usize(*cursor_id), - IntValue::Usize(*dest), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::DecrJumpZero { reg, target_pc } => ( - "DecrJumpZero", - IntValue::Usize(*reg), - IntValue::Usize(*target_pc), - IntValue::Usize(0), - "", - IntValue::Usize(0), - "".to_string(), - ), - Insn::AggStep { func, acc_reg, col } => ( - "AggStep", - IntValue::Usize(0), - IntValue::Usize(*col), - IntValue::Usize(*acc_reg), - func.to_string(), - IntValue::Usize(0), - format!("accum=r[{}] step({})", *acc_reg, *col), - ), - Insn::AggFinal { register, func } => ( - "AggFinal", - IntValue::Usize(0), - IntValue::Usize(*register), - IntValue::Usize(0), - func.to_string(), - IntValue::Usize(0), - format!("accum=r[{}]", *register), - ), - }; +fn insn_to_str(addr: BranchOffset, insn: &Insn) -> String { + let (opcode, p1, p2, p3, p4, p5, comment): (&str, i32, i32, i32, OwnedValue, u16, String) = + match insn { + Insn::Init { target_pc } => ( + "Init", + 0, + *target_pc as i32, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + format!("Start at {}", target_pc), + ), + Insn::OpenReadAsync { + cursor_id, + root_page, + } => ( + "OpenReadAsync", + *cursor_id as i32, + *root_page as i32, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + format!("root={}", root_page), + ), + Insn::OpenReadAwait => ( + "OpenReadAwait", + 0, + 0, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::RewindAsync { cursor_id } => ( + "RewindAsync", + *cursor_id as i32, + 0, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::RewindAwait { + cursor_id, + pc_if_empty, + } => ( + "RewindAwait", + *cursor_id as i32, + *pc_if_empty as i32, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::Column { + cursor_id, + column, + dest, + } => ( + "Column", + *cursor_id as i32, + *column as i32, + *dest as i32, + OwnedValue::Text(Rc::new("".to_string())), + 0, + format!("r[{}]= cursor {} column {}", dest, cursor_id, column), + ), + Insn::ResultRow { + register_start, + register_end, + } => ( + "ResultRow", + *register_start as i32, + *register_end as i32, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + format!("output=r[{}..{}]", register_start, register_end), + ), + Insn::NextAsync { cursor_id } => ( + "NextAsync", + *cursor_id as i32, + 0, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::NextAwait { + cursor_id, + pc_if_next, + } => ( + "NextAwait", + *cursor_id as i32, + *pc_if_next as i32, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::Halt => ( + "Halt", + 0, + 0, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::Transaction => ( + "Transaction", + 0, + 0, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::Goto { target_pc } => ( + "Goto", + 0, + *target_pc as i32, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::Integer { value, dest } => ( + "Integer", + *dest as i32, + *value as i32, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::Real { value, dest } => ( + "Real", + *dest as i32, + *value as i32, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::String8 { value, dest } => ( + "String8", + *dest as i32, + 0, + 0, + OwnedValue::Text(Rc::new(value.clone())), + 0, + format!("r[{}]= '{}'", dest, value), + ), + Insn::RowId { cursor_id, dest } => ( + "RowId", + *cursor_id as i32, + *dest as i32, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::DecrJumpZero { reg, target_pc } => ( + "DecrJumpZero", + *reg as i32, + *target_pc as i32, + 0, + OwnedValue::Text(Rc::new("".to_string())), + 0, + "".to_string(), + ), + Insn::AggStep { func, acc_reg, col } => ( + "AggStep", + 0, + *col as i32, + *acc_reg as i32, + OwnedValue::Text(Rc::new(func.to_string().into())), + 0, + format!("accum=r[{}] step({})", *acc_reg, *col), + ), + Insn::AggFinal { register, func } => ( + "AggFinal", + 0, + *register as i32, + 0, + OwnedValue::Text(Rc::new(func.to_string().into())), + 0, + format!("accum=r[{}]", *register), + ), + }; format!( "{:<4} {:<13} {:<4} {:<4} {:<4} {:<13} {:<2} {}", addr, opcode, p1, p2, p3, p4, p5, comment