mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-10 10:44:22 +01:00
Merge 'Fix cast' from Nikita Sivukhin
Fix codegen for `CAST` expression and also adjust implementation of `CAST: Real -> Int` because `SQLite` use "closest integer between the REAL value and zero" as a CAST result. Closes #956
This commit is contained in:
@@ -835,15 +835,14 @@ 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_register();
|
||||
let reg_expr = program.alloc_registers(2);
|
||||
translate_expr(program, referenced_tables, expr, reg_expr, resolver)?;
|
||||
let reg_type = program.alloc_register();
|
||||
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_type,
|
||||
dest: reg_expr + 1,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
program.emit_insn(Insn::Function {
|
||||
|
||||
@@ -3484,7 +3484,7 @@ fn exec_cast(value: &OwnedValue, datatype: &str) -> OwnedValue {
|
||||
// then the result is the greatest possible signed integer and if the REAL is less than the least possible signed integer (-9223372036854775808)
|
||||
// then the result is the least possible signed integer.
|
||||
OwnedValue::Float(f) => {
|
||||
let i = f.floor() as i128;
|
||||
let i = f.trunc() as i128;
|
||||
if i > i64::MAX as i128 {
|
||||
OwnedValue::Integer(i64::MAX)
|
||||
} else if i < i64::MIN as i128 {
|
||||
|
||||
@@ -740,6 +740,21 @@ do_execsql_test cast-float-to-integer {
|
||||
SELECT CAST(123.45 AS INTEGER);
|
||||
} {123}
|
||||
|
||||
do_execsql_test cast-float-to-integer-rounding {
|
||||
SELECT CAST(0.6 AS INTEGER);
|
||||
SELECT CAST(1.0 AS INTEGER);
|
||||
SELECT CAST(1.6 AS INTEGER);
|
||||
SELECT CAST(-0.6 AS INTEGER);
|
||||
SELECT CAST(-1.0 AS INTEGER);
|
||||
SELECT CAST(-1.6 AS INTEGER);
|
||||
} {0
|
||||
1
|
||||
1
|
||||
0
|
||||
-1
|
||||
-1
|
||||
}
|
||||
|
||||
do_execsql_test cast-large-float-to-integer {
|
||||
SELECT CAST(9223372036854775808.0 AS INTEGER);
|
||||
} {9223372036854775807}
|
||||
|
||||
@@ -165,6 +165,7 @@ mod tests {
|
||||
"SELECT like('a%', 'a') = 1",
|
||||
"SELECT CASE ( NULL < NULL ) WHEN ( 0 ) THEN ( NULL ) ELSE ( 2.0 ) END;",
|
||||
"SELECT (COALESCE(0, COALESCE(0, 0)));",
|
||||
"SELECT CAST((1 > 0) AS INTEGER);",
|
||||
] {
|
||||
let limbo = limbo_exec_row(&limbo_conn, query);
|
||||
let sqlite = sqlite_exec_row(&sqlite_conn, query);
|
||||
@@ -238,6 +239,17 @@ mod tests {
|
||||
.push_str(")")
|
||||
.build();
|
||||
|
||||
let (cast_expr, cast_expr_builder) = g.create_handle();
|
||||
cast_expr_builder
|
||||
.concat(" ")
|
||||
.push_str("CAST ( (")
|
||||
.push(expr)
|
||||
.push_str(") AS ")
|
||||
// cast to INTEGER/REAL/TEXT types can be added when Limbo will use proper equality semantic between values (e.g. 1 = 1.0)
|
||||
.push(g.create().choice().options_str(["NUMERIC"]).build())
|
||||
.push_str(")")
|
||||
.build();
|
||||
|
||||
let (case_expr, case_expr_builder) = g.create_handle();
|
||||
case_expr_builder
|
||||
.concat(" ")
|
||||
@@ -309,6 +321,7 @@ mod tests {
|
||||
|
||||
expr_builder
|
||||
.choice()
|
||||
.option_w(cast_expr, 1.0)
|
||||
.option_w(case_expr, 1.0)
|
||||
.option_w(unary_infix_op, 2.0)
|
||||
.option_w(bin_op, 3.0)
|
||||
|
||||
Reference in New Issue
Block a user