mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 01:58:16 +00:00
Fix null compares giving incorrect results
This commit is contained in:
parent
554244209d
commit
e16b3491c4
5 changed files with 75 additions and 12 deletions
|
@ -483,6 +483,7 @@ Modifiers:
|
|||
| Variable | No |
|
||||
| VerifyCookie | No |
|
||||
| Yield | Yes |
|
||||
| ZeroOrNull | Yes |
|
||||
|
||||
## Extensions
|
||||
|
||||
|
|
|
@ -453,7 +453,7 @@ pub fn translate_expr(
|
|||
match op {
|
||||
ast::Operator::NotEquals => {
|
||||
let if_true_label = program.allocate_label();
|
||||
wrap_eval_jump_expr(
|
||||
wrap_eval_jump_expr_zero_or_null(
|
||||
program,
|
||||
Insn::Ne {
|
||||
lhs: e1_reg,
|
||||
|
@ -462,11 +462,13 @@ pub fn translate_expr(
|
|||
},
|
||||
target_register,
|
||||
if_true_label,
|
||||
e1_reg,
|
||||
e2_reg,
|
||||
);
|
||||
}
|
||||
ast::Operator::Equals => {
|
||||
let if_true_label = program.allocate_label();
|
||||
wrap_eval_jump_expr(
|
||||
wrap_eval_jump_expr_zero_or_null(
|
||||
program,
|
||||
Insn::Eq {
|
||||
lhs: e1_reg,
|
||||
|
@ -475,11 +477,13 @@ pub fn translate_expr(
|
|||
},
|
||||
target_register,
|
||||
if_true_label,
|
||||
e1_reg,
|
||||
e2_reg,
|
||||
);
|
||||
}
|
||||
ast::Operator::Less => {
|
||||
let if_true_label = program.allocate_label();
|
||||
wrap_eval_jump_expr(
|
||||
wrap_eval_jump_expr_zero_or_null(
|
||||
program,
|
||||
Insn::Lt {
|
||||
lhs: e1_reg,
|
||||
|
@ -488,11 +492,13 @@ pub fn translate_expr(
|
|||
},
|
||||
target_register,
|
||||
if_true_label,
|
||||
e1_reg,
|
||||
e2_reg,
|
||||
);
|
||||
}
|
||||
ast::Operator::LessEquals => {
|
||||
let if_true_label = program.allocate_label();
|
||||
wrap_eval_jump_expr(
|
||||
wrap_eval_jump_expr_zero_or_null(
|
||||
program,
|
||||
Insn::Le {
|
||||
lhs: e1_reg,
|
||||
|
@ -501,11 +507,13 @@ pub fn translate_expr(
|
|||
},
|
||||
target_register,
|
||||
if_true_label,
|
||||
e1_reg,
|
||||
e2_reg,
|
||||
);
|
||||
}
|
||||
ast::Operator::Greater => {
|
||||
let if_true_label = program.allocate_label();
|
||||
wrap_eval_jump_expr(
|
||||
wrap_eval_jump_expr_zero_or_null(
|
||||
program,
|
||||
Insn::Gt {
|
||||
lhs: e1_reg,
|
||||
|
@ -514,11 +522,13 @@ pub fn translate_expr(
|
|||
},
|
||||
target_register,
|
||||
if_true_label,
|
||||
e1_reg,
|
||||
e2_reg,
|
||||
);
|
||||
}
|
||||
ast::Operator::GreaterEquals => {
|
||||
let if_true_label = program.allocate_label();
|
||||
wrap_eval_jump_expr(
|
||||
wrap_eval_jump_expr_zero_or_null(
|
||||
program,
|
||||
Insn::Ge {
|
||||
lhs: e1_reg,
|
||||
|
@ -527,6 +537,8 @@ pub fn translate_expr(
|
|||
},
|
||||
target_register,
|
||||
if_true_label,
|
||||
e1_reg,
|
||||
e2_reg,
|
||||
);
|
||||
}
|
||||
ast::Operator::Add => {
|
||||
|
@ -1796,6 +1808,27 @@ fn wrap_eval_jump_expr(
|
|||
program.preassign_label_to_next_insn(if_true_label);
|
||||
}
|
||||
|
||||
fn wrap_eval_jump_expr_zero_or_null(
|
||||
program: &mut ProgramBuilder,
|
||||
insn: Insn,
|
||||
target_register: usize,
|
||||
if_true_label: BranchOffset,
|
||||
e1_reg: usize,
|
||||
e2_reg: usize,
|
||||
) {
|
||||
program.emit_insn(Insn::Integer {
|
||||
value: 1, // emit True by default
|
||||
dest: target_register,
|
||||
});
|
||||
program.emit_insn(insn);
|
||||
program.emit_insn(Insn::ZeroOrNull {
|
||||
rg1: e1_reg,
|
||||
rg2: e2_reg,
|
||||
dest: target_register,
|
||||
});
|
||||
program.preassign_label_to_next_insn(if_true_label);
|
||||
}
|
||||
|
||||
pub fn maybe_apply_affinity(col_type: Type, target_register: usize, program: &mut ProgramBuilder) {
|
||||
if col_type == crate::schema::Type::Real {
|
||||
program.emit_insn(Insn::RealAffinity {
|
||||
|
|
|
@ -1071,6 +1071,18 @@ pub fn insn_to_str(
|
|||
0,
|
||||
format!("r[{}]=parameter({})", *dest, *index),
|
||||
),
|
||||
Insn::ZeroOrNull { rg1, rg2, dest } => (
|
||||
"ZeroOrNull",
|
||||
*rg1 as i32,
|
||||
*dest as i32,
|
||||
*rg2 as i32,
|
||||
OwnedValue::build_text(Rc::new("".to_string())),
|
||||
0,
|
||||
format!(
|
||||
"((r[{}]=NULL)|(r[{}]=NULL)) ? r[{}]=NULL : r[{}]=0",
|
||||
rg1, rg2, dest, dest
|
||||
),
|
||||
),
|
||||
};
|
||||
format!(
|
||||
"{:<4} {:<17} {:<4} {:<4} {:<4} {:<13} {:<2} {}",
|
||||
|
|
|
@ -509,6 +509,13 @@ pub enum Insn {
|
|||
index: NonZero<usize>,
|
||||
dest: usize,
|
||||
},
|
||||
/// If either register is null put null else put 0
|
||||
ZeroOrNull {
|
||||
/// Source register (P1).
|
||||
rg1: usize,
|
||||
rg2: usize,
|
||||
dest: usize,
|
||||
},
|
||||
}
|
||||
|
||||
fn cast_text_to_numerical(value: &str) -> OwnedValue {
|
||||
|
|
|
@ -495,7 +495,7 @@ impl Program {
|
|||
let target_pc = *target_pc;
|
||||
match (&state.registers[lhs], &state.registers[rhs]) {
|
||||
(_, OwnedValue::Null) | (OwnedValue::Null, _) => {
|
||||
state.pc = target_pc.to_offset_int();
|
||||
state.pc += 1;
|
||||
}
|
||||
_ => {
|
||||
if state.registers[lhs] == state.registers[rhs] {
|
||||
|
@ -517,7 +517,7 @@ impl Program {
|
|||
let target_pc = *target_pc;
|
||||
match (&state.registers[lhs], &state.registers[rhs]) {
|
||||
(_, OwnedValue::Null) | (OwnedValue::Null, _) => {
|
||||
state.pc = target_pc.to_offset_int();
|
||||
state.pc += 1;
|
||||
}
|
||||
_ => {
|
||||
if state.registers[lhs] != state.registers[rhs] {
|
||||
|
@ -539,7 +539,7 @@ impl Program {
|
|||
let target_pc = *target_pc;
|
||||
match (&state.registers[lhs], &state.registers[rhs]) {
|
||||
(_, OwnedValue::Null) | (OwnedValue::Null, _) => {
|
||||
state.pc = target_pc.to_offset_int();
|
||||
state.pc += 1;
|
||||
}
|
||||
_ => {
|
||||
if state.registers[lhs] < state.registers[rhs] {
|
||||
|
@ -561,7 +561,7 @@ impl Program {
|
|||
let target_pc = *target_pc;
|
||||
match (&state.registers[lhs], &state.registers[rhs]) {
|
||||
(_, OwnedValue::Null) | (OwnedValue::Null, _) => {
|
||||
state.pc = target_pc.to_offset_int();
|
||||
state.pc += 1;
|
||||
}
|
||||
_ => {
|
||||
if state.registers[lhs] <= state.registers[rhs] {
|
||||
|
@ -583,7 +583,7 @@ impl Program {
|
|||
let target_pc = *target_pc;
|
||||
match (&state.registers[lhs], &state.registers[rhs]) {
|
||||
(_, OwnedValue::Null) | (OwnedValue::Null, _) => {
|
||||
state.pc = target_pc.to_offset_int();
|
||||
state.pc += 1;
|
||||
}
|
||||
_ => {
|
||||
if state.registers[lhs] > state.registers[rhs] {
|
||||
|
@ -605,7 +605,7 @@ impl Program {
|
|||
let target_pc = *target_pc;
|
||||
match (&state.registers[lhs], &state.registers[rhs]) {
|
||||
(_, OwnedValue::Null) | (OwnedValue::Null, _) => {
|
||||
state.pc = target_pc.to_offset_int();
|
||||
state.pc += 1;
|
||||
}
|
||||
_ => {
|
||||
if state.registers[lhs] >= state.registers[rhs] {
|
||||
|
@ -2250,6 +2250,16 @@ impl Program {
|
|||
.clone();
|
||||
state.pc += 1;
|
||||
}
|
||||
Insn::ZeroOrNull { rg1, rg2, dest } => {
|
||||
if state.registers[*rg1] == OwnedValue::Null
|
||||
|| state.registers[*rg2] == OwnedValue::Null
|
||||
{
|
||||
state.registers[*dest] = OwnedValue::Null
|
||||
} else {
|
||||
state.registers[*dest] = OwnedValue::Integer(0);
|
||||
}
|
||||
state.pc += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue