mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-31 06:54:21 +01:00
Merge 'Fix numeric overflow in numeric string parsing in logical comparision' from
Closes #2077- This PR fixes an integer overflow bug that causes results from Turso to differ from SQLite. -Commit 1: Fixes incorrect logic that failed to detect integer overflow when parsing long numeric strings. -Commit 2: Handles the case where a parsed numeric string is stored as a float and classified as PureInteger, but lies outside the integer range. Previously, `parsed_value.as_integer()` would return None, causing Turso to fall back to text comparison against numeric values. This caused **another** erroneous result, as shown below. `$> SELECT (-104614899632619 || 45597) > CAST(0 AS NUMERIC); -- tursodb = 1(wrong), sqlite = 0` Now, if Turso fails to convert a very long numeric string to an integer, it tries to convert it to a float. This is in line with the `static void applyNumericAffinity` function in sqlite3 **Before** <img width="623" height="238" alt="Screenshot 2025-08-01 at 12 11 49 PM" src="https://github.com/user-attachments/assets/796d6ff6-768b-40ef- ac83-e0c55fff6bd9" /> **After** `SELECT (104614899632619 || 45597) > CAST(0 AS NUMERIC); -- tursodb = 1, sqlite = 1` `SELECT (-104614899632619 || 45597) > CAST(0 AS NUMERIC); -- tursodb = 0, sqlite = 0` Reviewed-by: Preston Thorpe <preston@turso.tech> Closes #2397
This commit is contained in:
@@ -8010,11 +8010,9 @@ fn create_result_from_significand(
|
||||
}
|
||||
|
||||
// For pure integers without exponent, try to return as integer
|
||||
if !has_decimal && !has_exponent && exponent == 0 {
|
||||
if !has_decimal && !has_exponent && exponent == 0 && significand <= i64::MAX as u64 {
|
||||
let signed_val = (significand as i64).wrapping_mul(sign);
|
||||
if (significand as i64) * sign == signed_val {
|
||||
return (parse_result, ParsedNumber::Integer(signed_val));
|
||||
}
|
||||
return (parse_result, ParsedNumber::Integer(signed_val));
|
||||
}
|
||||
|
||||
// Convert to float
|
||||
@@ -8111,6 +8109,12 @@ pub fn apply_numeric_affinity(register: &mut Register, try_for_int: bool) -> boo
|
||||
if let Some(int_val) = parsed_value.as_integer() {
|
||||
*register = Register::Value(Value::Integer(int_val));
|
||||
true
|
||||
} else if let Some(float_val) = parsed_value.as_float() {
|
||||
*register = Register::Value(Value::Float(float_val));
|
||||
if try_for_int {
|
||||
apply_integer_affinity(register);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -930,6 +930,15 @@ do_execsql_test cast-in-where {
|
||||
select age from users where age = cast('45' as integer) limit 1;
|
||||
} {45}
|
||||
|
||||
#Parsing test for large numeric strings in logical operations with numeric operands
|
||||
do_execsql_test parse-large-integral-numeric-string-as-number {
|
||||
SELECT (104614899632619 || 45597) > CAST(0 AS NUMERIC);
|
||||
} {1}
|
||||
|
||||
do_execsql_test parse-large-integral-numeric-string-as-number {
|
||||
SELECT (-104614899632619 || 45597) > CAST(0 AS NUMERIC);
|
||||
} {0}
|
||||
|
||||
# TODO: sqlite seems not enable soundex() by default unless build it with SQLITE_SOUNDEX enabled.
|
||||
# do_execsql_test soundex-text {
|
||||
# select soundex('Pfister'), soundex('husobee'), soundex('Tymczak'), soundex('Ashcraft'), soundex('Robert'), soundex('Rupert'), soundex('Rubin'), soundex('Kant'), soundex('Knuth'), soundex('x'), soundex('');
|
||||
|
||||
Reference in New Issue
Block a user