Fix null compares giving incorrect results

This commit is contained in:
psvri 2025-01-19 00:44:38 +05:30
parent 554244209d
commit e16b3491c4
5 changed files with 75 additions and 12 deletions

View file

@ -483,6 +483,7 @@ Modifiers:
| Variable | No |
| VerifyCookie | No |
| Yield | Yes |
| ZeroOrNull | Yes |
## Extensions

View file

@ -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 {

View file

@ -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} {}",

View file

@ -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 {

View file

@ -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;
}
}
}
}