mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-31 13:54:27 +01:00
Merge 'Implement the Cast opcode' from Glauber Costa
Our compat matrix mentions a couple of opcodes: ToInt, ToBlob, etc. Those opcodes do not exist. Instead, there is a single Cast opcode, that takes the affinity as a parameter. Currently we just call a function when we need to cast. This PR fixes the compat file, implements the cast opcode, and in at least one instance, when explicitly using the CAST keyword, uses that opcode instead of a function in the generated bytecode. Reviewed-by: Preston Thorpe (@PThorpe92) Reviewed-by: Preston Thorpe (@PThorpe92) Closes #2352
This commit is contained in:
@@ -427,6 +427,7 @@ Modifiers:
|
||||
| BitOr | Yes | |
|
||||
| Blob | Yes | |
|
||||
| BeginSubrtn | Yes | |
|
||||
| Cast | Yes | |
|
||||
| Checkpoint | Yes | |
|
||||
| Clear | No | |
|
||||
| Close | Yes | |
|
||||
@@ -554,11 +555,6 @@ Modifiers:
|
||||
| String8 | Yes | |
|
||||
| Subtract | Yes | |
|
||||
| TableLock | No | |
|
||||
| ToBlob | No | |
|
||||
| ToInt | No | |
|
||||
| ToNumeric | No | |
|
||||
| ToReal | No | |
|
||||
| ToText | No | |
|
||||
| Trace | No | |
|
||||
| Transaction | Yes | |
|
||||
| VBegin | No | |
|
||||
|
||||
@@ -8,7 +8,7 @@ use super::plan::TableReferences;
|
||||
use crate::function::JsonFunc;
|
||||
use crate::function::{Func, FuncCtx, MathFuncArity, ScalarFunc, VectorFunc};
|
||||
use crate::functions::datetime;
|
||||
use crate::schema::{Affinity, Table, Type};
|
||||
use crate::schema::{affinity, Affinity, Table, Type};
|
||||
use crate::util::{exprs_are_equivalent, parse_numeric_literal};
|
||||
use crate::vdbe::builder::CursorKey;
|
||||
use crate::vdbe::{
|
||||
@@ -651,24 +651,11 @@ pub fn translate_expr(
|
||||
}
|
||||
ast::Expr::Cast { expr, type_name } => {
|
||||
let type_name = type_name.as_ref().unwrap(); // TODO: why is this optional?
|
||||
let reg_expr = program.alloc_registers(2);
|
||||
translate_expr(program, referenced_tables, expr, reg_expr, resolver)?;
|
||||
program.emit_insn(Insn::String8 {
|
||||
// we make a comparison against uppercase static strs in the affinity() function,
|
||||
// so we need to make sure we're comparing against the uppercase version,
|
||||
// and it's better to do this once instead of every time we check affinity
|
||||
value: type_name.name.to_uppercase(),
|
||||
dest: reg_expr + 1,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
program.emit_insn(Insn::Function {
|
||||
constant_mask: 0,
|
||||
start_reg: reg_expr,
|
||||
dest: target_register,
|
||||
func: FuncCtx {
|
||||
func: Func::Scalar(ScalarFunc::Cast),
|
||||
arg_count: 2,
|
||||
},
|
||||
translate_expr(program, referenced_tables, expr, target_register, resolver)?;
|
||||
let type_affinity = affinity(&type_name.name.to_uppercase());
|
||||
program.emit_insn(Insn::Cast {
|
||||
reg: target_register,
|
||||
affinity: type_affinity,
|
||||
});
|
||||
Ok(target_register)
|
||||
}
|
||||
|
||||
@@ -6651,6 +6651,31 @@ pub fn op_integrity_check(
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
pub fn op_cast(
|
||||
_program: &Program,
|
||||
state: &mut ProgramState,
|
||||
insn: &Insn,
|
||||
_pager: &Rc<Pager>,
|
||||
_mv_store: Option<&Rc<MvStore>>,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
let Insn::Cast { reg, affinity } = insn else {
|
||||
unreachable!("unexpected Insn {:?}", insn)
|
||||
};
|
||||
|
||||
let value = state.registers[*reg].get_owned_value().clone();
|
||||
let result = match affinity {
|
||||
Affinity::Blob => value.exec_cast("BLOB"),
|
||||
Affinity::Text => value.exec_cast("TEXT"),
|
||||
Affinity::Numeric => value.exec_cast("NUMERIC"),
|
||||
Affinity::Integer => value.exec_cast("INTEGER"),
|
||||
Affinity::Real => value.exec_cast("REAL"),
|
||||
};
|
||||
|
||||
state.registers[*reg] = Register::Value(result);
|
||||
state.pc += 1;
|
||||
Ok(InsnFunctionStepResult::Step)
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn exec_lower(&self) -> Option<Self> {
|
||||
match self {
|
||||
|
||||
@@ -1609,6 +1609,15 @@ pub fn insn_to_str(
|
||||
0,
|
||||
format!("r[{}] = data", *dest),
|
||||
),
|
||||
Insn::Cast { reg, affinity } => (
|
||||
"Cast",
|
||||
*reg as i32,
|
||||
0,
|
||||
0,
|
||||
Value::build_text(""),
|
||||
0,
|
||||
format!("affinity(r[{}]={:?})", *reg, affinity),
|
||||
),
|
||||
};
|
||||
format!(
|
||||
"{:<4} {:<17} {:<4} {:<4} {:<4} {:<13} {:<2} {}",
|
||||
|
||||
@@ -706,6 +706,12 @@ pub enum Insn {
|
||||
func: FuncCtx, // P4
|
||||
},
|
||||
|
||||
/// Cast register P1 to affinity P2 and store in register P1
|
||||
Cast {
|
||||
reg: usize,
|
||||
affinity: Affinity,
|
||||
},
|
||||
|
||||
InitCoroutine {
|
||||
yield_reg: usize,
|
||||
jump_on_definition: BranchOffset,
|
||||
@@ -1075,6 +1081,7 @@ impl Insn {
|
||||
Insn::SorterData { .. } => execute::op_sorter_data,
|
||||
Insn::SorterNext { .. } => execute::op_sorter_next,
|
||||
Insn::Function { .. } => execute::op_function,
|
||||
Insn::Cast { .. } => execute::op_cast,
|
||||
Insn::InitCoroutine { .. } => execute::op_init_coroutine,
|
||||
Insn::EndCoroutine { .. } => execute::op_end_coroutine,
|
||||
Insn::Yield { .. } => execute::op_yield,
|
||||
|
||||
Reference in New Issue
Block a user