Implement ShiftLeft

This commit is contained in:
psvri 2025-01-15 00:37:54 +05:30
parent ffe65140c1
commit 5b4d82abbf
6 changed files with 133 additions and 2 deletions

View file

@ -445,7 +445,7 @@ Feature support of [sqlite expr syntax](https://www.sqlite.org/lang_expr.html).
| SeekRowid | Yes |
| Sequence | No |
| SetCookie | No |
| ShiftLeft | No |
| ShiftLeft | Yes |
| ShiftRight | No |
| SoftNull | Yes |
| Sort | No |

View file

@ -613,6 +613,13 @@ pub fn translate_expr(
dest: target_register,
});
}
ast::Operator::LeftShift => {
program.emit_insn(Insn::ShiftLeft {
lhs: e1_reg,
rhs: e2_reg,
dest: target_register,
});
}
#[cfg(feature = "json")]
op @ (ast::Operator::ArrowRight | ast::Operator::ArrowRightShift) => {
let json_func = match op {

View file

@ -1044,6 +1044,15 @@ pub fn insn_to_str(
0,
"".to_string(),
),
Insn::ShiftLeft { lhs, rhs, dest } => (
"ShiftLeft",
*rhs as i32,
*lhs as i32,
*dest as i32,
OwnedValue::build_text(Rc::new("".to_string())),
0,
format!("r[{}]=r[{}] << r[{}]", dest, lhs, rhs),
),
};
format!(
"{:<4} {:<17} {:<4} {:<4} {:<4} {:<13} {:<2} {}",

View file

@ -487,6 +487,12 @@ pub enum Insn {
db: usize,
where_clause: String,
},
// Place the result of lhs >> rhs in dest register.
ShiftLeft {
lhs: usize,
rhs: usize,
dest: usize,
},
}
fn cast_text_to_numerical(value: &str) -> OwnedValue {
@ -720,3 +726,51 @@ pub fn exec_bit_not(mut reg: &OwnedValue) -> OwnedValue {
_ => todo!(),
}
}
pub fn exec_shift_left(mut lhs: &OwnedValue, mut rhs: &OwnedValue) -> OwnedValue {
if let OwnedValue::Agg(agg) = lhs {
lhs = agg.final_value();
}
if let OwnedValue::Agg(agg) = rhs {
rhs = agg.final_value();
}
match (lhs, rhs) {
(OwnedValue::Null, _) | (_, OwnedValue::Null) => OwnedValue::Null,
(OwnedValue::Integer(lh), OwnedValue::Integer(rh)) => {
OwnedValue::Integer(compute_shl(*lh, *rh))
}
(OwnedValue::Float(lh), OwnedValue::Integer(rh)) => {
OwnedValue::Integer(compute_shl(*lh as i64, *rh))
}
(OwnedValue::Integer(lh), OwnedValue::Float(rh)) => {
OwnedValue::Integer(compute_shl(*lh, *rh as i64))
}
(OwnedValue::Float(lh), OwnedValue::Float(rh)) => {
OwnedValue::Integer(compute_shl(*lh as i64, *rh as i64))
}
(OwnedValue::Text(lhs), OwnedValue::Text(rhs)) => exec_shift_left(
&cast_text_to_numerical(&lhs.value),
&cast_text_to_numerical(&rhs.value),
),
(OwnedValue::Text(text), other) => {
exec_shift_left(&cast_text_to_numerical(&text.value), other)
}
(other, OwnedValue::Text(text)) => {
exec_shift_left(other, &cast_text_to_numerical(&text.value))
}
_ => todo!(),
}
}
fn compute_shl(lhs: i64, rhs: i64) -> i64 {
if rhs == 0 {
lhs
} else if rhs >= 64 || rhs <= -64 {
0
} else if rhs < 0 {
// if negative do right shift
lhs >> (-rhs)
} else {
lhs << rhs
}
}

View file

@ -45,7 +45,7 @@ use crate::{resolve_ext_path, Connection, Result, Rows, TransactionState, DATABA
use datetime::{exec_date, exec_datetime_full, exec_julianday, exec_time, exec_unixepoch};
use insn::{
exec_add, exec_bit_and, exec_bit_not, exec_bit_or, exec_divide, exec_multiply, exec_remainder,
exec_subtract,
exec_shift_left, exec_subtract,
};
use likeop::{construct_like_escape_arg, exec_glob, exec_like_with_escape};
use rand::distributions::{Distribution, Uniform};
@ -2158,6 +2158,11 @@ impl Program {
parse_schema_rows(Some(rows), &mut schema, conn.pager.io.clone())?;
state.pc += 1;
}
Insn::ShiftLeft { lhs, rhs, dest } => {
state.registers[*dest] =
exec_shift_left(&state.registers[*lhs], &state.registers[*rhs]);
state.pc += 1;
}
}
}
}

View file

@ -459,6 +459,62 @@ do_execsql_test bitwise-and-int-agg-int-agg {
} {66}
foreach {testname lhs rhs ans} {
int-int 1 2 4
int-neg_int 8 -2 2
int-float 1 4.0 16
int-text 1 'a' 1
int-text_float 1 '3.0' 8
int-text_int 1 '1' 2
int-null 1 NULL {}
int-int-overflow 1 64 0
int-int-underflow 1 -64 0
int-float-overflow 1 64.0 0
int-float-underflow 1 -64.0 0
} {
do_execsql_test shift-left-$testname "SELECT $lhs << $rhs" $::ans
}
foreach {testname lhs rhs ans} {
float-int 1.0 2 4
float-neg_int 8.0 -2 2
float-float 1.0 4.0 16
float-text 1.0 'a' 1
float-text_float 1.0 '3.0' 8
float-text_int 1.0 '1' 2
float-null 1.0 NULL {}
float-int-overflow 1.0 64 0
float-int-underflow 1.0 -64 0
float-float-overflow 1.0 64.0 0
float-float-underflow 1.0 -64.0 0
} {
do_execsql_test shift-left-$testname "SELECT $lhs << $rhs" $::ans
}
foreach {testname lhs rhs ans} {
text-int 'a' 2 0
text-float 'a' 4.0 0
text-text 'a' 'a' 0
text_int-text_int '1' '1' 2
text_int-text_float '1' '3.0' 8
text_int-text '1' 'a' 1
text_float-text_int '1.0' '1' 2
text_float-text_float '1.0' '3.0' 8
text_float-text '1.0' 'a' 1
text-null '1' NULL {}
} {
do_execsql_test shift-left-$testname "SELECT $lhs << $rhs" $::ans
}
foreach {testname lhs rhs ans} {
null-int NULL 2 {}
null-float NULL 4.0 {}
null-text NULL 'a' {}
null-null NULL NULL {}
} {
do_execsql_test shift-left-$testname "SELECT $lhs << $rhs" $::ans
}
do_execsql_test bitwise-not-null {
SELECT ~NULL
} {}