1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 10:18:11 +00:00

LibSQL: Support 64-bit integer values and handle overflow errors

Currently, integers are stored in LibSQL as 32-bit signed integers, even
if the provided type is unsigned. This resulted in a series of unchecked
unsigned-to-signed conversions, and prevented storing 64-bit values.
Further, mathematical operations were performed without similar checks,
and without checking for overflow.

This changes SQL::Value to behave like SQLite for INTEGER types. In
SQLite, the INTEGER type does not imply a size or signedness of the
underlying type. Instead, SQLite determines on-the-fly what type is
needed as values are created and updated.

To do so, the SQL::Value variant can now hold an i64 or u64 integer. If
a specific type is requested, invalid conversions are now explictly an
error (e.g. converting a stored -1 to a u64 will fail). When binary
mathematical operations are performed, we now try to coerce the RHS
value to a type that works with the LHS value, failing the operation if
that isn't possible. Any overflow or invalid operation (e.g. bitshifting
a 64-bit value by more than 64 bytes) is an error.
This commit is contained in:
Timothy Flynn 2022-12-11 11:44:11 -05:00 committed by Tim Flynn
parent a1007c37a4
commit 72e41a7dbd
13 changed files with 1241 additions and 283 deletions

View file

@ -105,7 +105,7 @@ TEST_CASE(insert_into_table)
EXPECT(!rows_or_error.is_error());
for (auto& row : rows_or_error.value()) {
EXPECT_EQ(row["TEXTCOLUMN"].to_deprecated_string(), "Test");
EXPECT_EQ(row["INTCOLUMN"].to_int().value(), 42);
EXPECT_EQ(row["INTCOLUMN"].to_int<i32>(), 42);
count++;
}
EXPECT_EQ(count, 1);
@ -318,7 +318,7 @@ TEST_CASE(select_with_where)
result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable WHERE IntColumn > 44;");
EXPECT_EQ(result.size(), 2u);
for (auto& row : result) {
EXPECT(row.row[1].to_int().value() > 44);
EXPECT(row.row[1].to_int<i32>().value() > 44);
}
}
@ -348,10 +348,10 @@ TEST_CASE(select_cross_join)
EXPECT_EQ(result.size(), 25u);
for (auto& row : result) {
EXPECT(row.row.size() == 4);
EXPECT(row.row[1].to_int().value() >= 42);
EXPECT(row.row[1].to_int().value() <= 46);
EXPECT(row.row[3].to_int().value() >= 40);
EXPECT(row.row[3].to_int().value() <= 48);
EXPECT(row.row[1].to_int<i32>().value() >= 42);
EXPECT(row.row[1].to_int<i32>().value() <= 46);
EXPECT(row.row[3].to_int<i32>().value() >= 40);
EXPECT(row.row[3].to_int<i32>().value() <= 48);
}
}
@ -383,7 +383,7 @@ TEST_CASE(select_inner_join)
"WHERE TestTable1.IntColumn = TestTable2.IntColumn;");
EXPECT_EQ(result.size(), 1u);
EXPECT_EQ(result[0].row.size(), 3u);
EXPECT_EQ(result[0].row[0].to_int().value(), 42);
EXPECT_EQ(result[0].row[0].to_int<i32>(), 42);
EXPECT_EQ(result[0].row[1].to_deprecated_string(), "Test_1");
EXPECT_EQ(result[0].row[2].to_deprecated_string(), "Test_12");
}
@ -463,11 +463,11 @@ TEST_CASE(select_with_order)
result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
EXPECT_EQ(result.size(), 5u);
EXPECT_EQ(result[0].row[1].to_int().value(), 40);
EXPECT_EQ(result[1].row[1].to_int().value(), 41);
EXPECT_EQ(result[2].row[1].to_int().value(), 42);
EXPECT_EQ(result[3].row[1].to_int().value(), 44);
EXPECT_EQ(result[4].row[1].to_int().value(), 47);
EXPECT_EQ(result[0].row[1].to_int<i32>(), 40);
EXPECT_EQ(result[1].row[1].to_int<i32>(), 41);
EXPECT_EQ(result[2].row[1].to_int<i32>(), 42);
EXPECT_EQ(result[3].row[1].to_int<i32>(), 44);
EXPECT_EQ(result[4].row[1].to_int<i32>(), 47);
result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable ORDER BY TextColumn;");
EXPECT_EQ(result.size(), 5u);
@ -547,15 +547,15 @@ TEST_CASE(select_with_order_two_columns)
result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable ORDER BY TextColumn, IntColumn;");
EXPECT_EQ(result.size(), 5u);
EXPECT_EQ(result[0].row[0].to_deprecated_string(), "Test_1");
EXPECT_EQ(result[0].row[1].to_int().value(), 47);
EXPECT_EQ(result[0].row[1].to_int<i32>(), 47);
EXPECT_EQ(result[1].row[0].to_deprecated_string(), "Test_2");
EXPECT_EQ(result[1].row[1].to_int().value(), 40);
EXPECT_EQ(result[1].row[1].to_int<i32>(), 40);
EXPECT_EQ(result[2].row[0].to_deprecated_string(), "Test_2");
EXPECT_EQ(result[2].row[1].to_int().value(), 42);
EXPECT_EQ(result[2].row[1].to_int<i32>(), 42);
EXPECT_EQ(result[3].row[0].to_deprecated_string(), "Test_4");
EXPECT_EQ(result[3].row[1].to_int().value(), 41);
EXPECT_EQ(result[3].row[1].to_int<i32>(), 41);
EXPECT_EQ(result[4].row[0].to_deprecated_string(), "Test_5");
EXPECT_EQ(result[4].row[1].to_int().value(), 44);
EXPECT_EQ(result[4].row[1].to_int<i32>(), 44);
}
TEST_CASE(select_with_order_by_column_not_in_result)
@ -626,16 +626,16 @@ TEST_CASE(select_with_order_limit_and_offset)
}
auto result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable ORDER BY IntColumn LIMIT 10 OFFSET 10;");
EXPECT_EQ(result.size(), 10u);
EXPECT_EQ(result[0].row[1].to_int().value(), 10);
EXPECT_EQ(result[1].row[1].to_int().value(), 11);
EXPECT_EQ(result[2].row[1].to_int().value(), 12);
EXPECT_EQ(result[3].row[1].to_int().value(), 13);
EXPECT_EQ(result[4].row[1].to_int().value(), 14);
EXPECT_EQ(result[5].row[1].to_int().value(), 15);
EXPECT_EQ(result[6].row[1].to_int().value(), 16);
EXPECT_EQ(result[7].row[1].to_int().value(), 17);
EXPECT_EQ(result[8].row[1].to_int().value(), 18);
EXPECT_EQ(result[9].row[1].to_int().value(), 19);
EXPECT_EQ(result[0].row[1].to_int<i32>(), 10);
EXPECT_EQ(result[1].row[1].to_int<i32>(), 11);
EXPECT_EQ(result[2].row[1].to_int<i32>(), 12);
EXPECT_EQ(result[3].row[1].to_int<i32>(), 13);
EXPECT_EQ(result[4].row[1].to_int<i32>(), 14);
EXPECT_EQ(result[5].row[1].to_int<i32>(), 15);
EXPECT_EQ(result[6].row[1].to_int<i32>(), 16);
EXPECT_EQ(result[7].row[1].to_int<i32>(), 17);
EXPECT_EQ(result[8].row[1].to_int<i32>(), 18);
EXPECT_EQ(result[9].row[1].to_int<i32>(), 19);
}
TEST_CASE(select_with_limit_out_of_bounds)
@ -707,7 +707,7 @@ TEST_CASE(binary_operator_execution)
auto const& result_row = result.at(i).row;
EXPECT_EQ(result_row.size(), 1u);
auto result_column = result_row[0].to_int();
auto result_column = result_row[0].to_int<i32>();
result_values.append(result_column.value());
}