refactor+fix: precompute default values from schema

This commit is contained in:
Levy A. 2025-05-23 20:10:01 -03:00
parent 7638b0dab7
commit 15e0cab8d8
13 changed files with 123 additions and 172 deletions

View file

@ -53,7 +53,6 @@ use super::{
insn::{Cookie, RegisterOrLiteral},
CommitState,
};
use limbo_sqlite3_parser::ast;
use parking_lot::RwLock;
use rand::thread_rng;
@ -1289,6 +1288,7 @@ pub fn op_column(
cursor_id,
column,
dest,
default,
} = insn
else {
unreachable!("unexpected Insn {:?}", insn)
@ -1349,54 +1349,7 @@ pub fn op_column(
break 'value value.to_owned();
}
// WARNING(levy): Work-around for the P4 parameter. This should be reworked to be
// more similar to sqlite: when emiting a OP_Column, also add a pre-computed
// contant default value from the schema.'
let literal = {
match cursor_type {
CursorType::BTreeIndex(index) => {
let Some(ast::Expr::Literal(literal)) = &index.columns[*column].default
else {
panic!("column added by ALTER TABLE should be constant")
};
literal
}
CursorType::BTreeTable(btree) => {
let Some(ast::Expr::Literal(literal)) = &btree.columns[*column].default
else {
panic!("column added by ALTER TABLE should be constant")
};
literal
}
_ => unreachable!(),
}
};
use crate::translate::expr::sanitize_string;
match literal {
ast::Literal::Numeric(s) => match Numeric::from(s) {
Numeric::Null => Value::Null,
Numeric::Integer(v) => Value::Integer(v),
Numeric::Float(v) => Value::Float(v.into()),
},
ast::Literal::Null => Value::Null,
ast::Literal::String(s) => Value::Text(Text::from_str(sanitize_string(s))),
ast::Literal::Blob(s) => Value::Blob(
// Taken from `translate_expr`
s.as_bytes()
.chunks_exact(2)
.map(|pair| {
// We assume that sqlite3-parser has already validated that
// the input is valid hex string, thus unwrap is safe.
let hex_byte = std::str::from_utf8(pair).unwrap();
u8::from_str_radix(hex_byte, 16).unwrap()
})
.collect(),
),
_ => panic!("column added by ALTER TABLE should be constant"),
}
default.clone().unwrap_or(Value::Null)
};
// If we are copying a text/blob, let's try to simply update size of text if we need to allocate more and reuse.
match (&value, &mut state.registers[*dest]) {
@ -1423,7 +1376,7 @@ pub fn op_column(
if let Some(record) = record {
state.registers[*dest] = Register::Value(match record.get_value_opt(*column) {
Some(val) => val.to_owned(),
None => Value::Null,
None => default.clone().unwrap_or(Value::Null),
});
} else {
state.registers[*dest] = Register::Value(Value::Null);