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.
This commit is contained in:
Pekka Enberg
2024-07-05 11:39:21 +03:00
parent 8a09f2a29e
commit 2f3c3b5404
2 changed files with 227 additions and 222 deletions

View File

@@ -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<u8>),
}
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<AggContext>), // 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

View File

@@ -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<BTreeMap<usize, Box<dyn Cursor>>>,
pub pc: BranchOffset,
cursors: RefCell<BTreeMap<CursorID, Box<dyn Cursor>>>,
registers: Vec<OwnedValue>,
}
@@ -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<Pager>,
) -> Result<StepResult<'a>> {
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