From 152428812745f601bb2ecc237f91029e323c57e7 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Wed, 21 Sep 2022 13:48:02 -0400 Subject: [PATCH] LibSQL: Rewrite the SQL::Value type to be contained within one class Currently, the Value class is essentially a "pImpl" wrapper around the ValueImpl hierarchy of classes. This is a bit difficult to follow and reason about, as methods jump between the Value class and its impl classes. This changes the Variant held by Value to instead store the specified types (String, int, etc.) directly. In doing so, the ValueImpl classes are removed, and all methods are now just concise Variant visitors. As part of this rewrite, support for the "array" type is dropped (or rather, just not re-implemented) as it was unused. If it's needed in the future, support can be re-added. This does retain the ability for non-NULL types to store NULL values (i.e. an empty Optional). I tried dropping this support as well, but it is depended upon by the on-disk storage classes in non-trivial ways. --- Tests/LibSQL/TestSqlValueAndTuple.cpp | 397 +++--- Userland/Libraries/LibSQL/AST/Expression.cpp | 12 +- Userland/Libraries/LibSQL/AST/Select.cpp | 2 +- Userland/Libraries/LibSQL/Type.h | 3 +- Userland/Libraries/LibSQL/Value.cpp | 1211 ++++++------------ Userland/Libraries/LibSQL/Value.h | 126 +- Userland/Libraries/LibSQL/ValueImpl.h | 298 ----- 7 files changed, 640 insertions(+), 1409 deletions(-) delete mode 100644 Userland/Libraries/LibSQL/ValueImpl.h diff --git a/Tests/LibSQL/TestSqlValueAndTuple.cpp b/Tests/LibSQL/TestSqlValueAndTuple.cpp index 4d05530700..3ff7d14f87 100644 --- a/Tests/LibSQL/TestSqlValueAndTuple.cpp +++ b/Tests/LibSQL/TestSqlValueAndTuple.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Jan de Visser + * Copyright (c) 2022, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -15,121 +16,170 @@ TEST_CASE(null_value) { SQL::Value v(SQL::SQLType::Null); - EXPECT(v.type() == SQL::SQLType::Null); + EXPECT_EQ(v.type(), SQL::SQLType::Null); + EXPECT_EQ(v.to_string(), "(null)"sv); + EXPECT(!v.to_bool().has_value()); + EXPECT(!v.to_int().has_value()); + EXPECT(!v.to_u32().has_value()); + EXPECT(!v.to_double().has_value()); +} + +TEST_CASE(assign_null) +{ + SQL::Value v("Test"); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT(!v.is_null()); + + v = SQL::Value(); + EXPECT_EQ(v.type(), SQL::SQLType::Null); EXPECT(v.is_null()); - v = "Test"; - EXPECT(v.is_null()); - EXPECT(v.to_string() == "(null)"); } TEST_CASE(text_value) { { SQL::Value v(SQL::SQLType::Text); + EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT(v.is_null()); - v = "Test"; - EXPECT(!v.is_null()); - EXPECT(v.to_string() == "Test"); - } - { - SQL::Value v(SQL::SQLType::Text, String("String Test")); - EXPECT(!v.is_null()); - EXPECT(v.to_string() == "String Test"); - } - { - SQL::Value v(SQL::SQLType::Text, "const char * Test"); - EXPECT(!v.is_null()); - EXPECT_EQ(v.to_string(), "const char * Test"); - } - { - SQL::Value v(String("String Test")); - EXPECT(v.type() == SQL::SQLType::Text); - EXPECT(!v.is_null()); - EXPECT(v.to_string() == "String Test"); - } - { - SQL::Value v(SQL::SQLType::Text, SQL::Value(42)); - EXPECT(v.type() == SQL::SQLType::Text); - EXPECT(!v.is_null()); - EXPECT(v.to_string() == "42"); - } -} -TEST_CASE(assign_null) -{ - SQL::Value v("Test"); - EXPECT(!v.is_null()); - v = SQL::Value::null(); - EXPECT(v.is_null()); + v = "Test"sv; + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT_EQ(v.to_string(), "Test"sv); + } + { + SQL::Value v(String("String Test"sv)); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT_EQ(v.to_string(), "String Test"sv); + + v = String("String Test 2"sv); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT_EQ(v.to_string(), "String Test 2"sv); + } + { + SQL::Value v("const char * Test"); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT_EQ(v.to_string(), "const char * Test"sv); + + v = "const char * Test 2"; + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT_EQ(v.to_string(), "const char * Test 2"sv); + } } TEST_CASE(text_value_to_other_types) { { - SQL::Value v(SQL::SQLType::Text, "42"); + SQL::Value v("42"); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 42); + EXPECT(v.to_double().has_value()); - EXPECT(v.to_double().value() - 42.0 < NumericLimits().epsilon()); + EXPECT((v.to_double().value() - 42.0) < NumericLimits().epsilon()); } { SQL::Value v("true"); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT(v.to_bool().has_value()); EXPECT(v.to_bool().value()); } { SQL::Value v("false"); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT(v.to_bool().has_value()); EXPECT(!v.to_bool().value()); } + { + SQL::Value v("foo"); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + + EXPECT(!v.to_bool().has_value()); + EXPECT(!v.to_int().has_value()); + EXPECT(!v.to_u32().has_value()); + EXPECT(!v.to_double().has_value()); + } + { + SQL::Value v("3.14"); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + + EXPECT(v.to_double().has_value()); + EXPECT((v.to_double().value() - 3.14) < NumericLimits().epsilon()); + } +} + +TEST_CASE(assign_int_to_text_value) +{ + SQL::Value v(SQL::SQLType::Text); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT(v.is_null()); + + v = 42; + EXPECT_EQ(v.type(), SQL::SQLType::Integer); + EXPECT_EQ(v, 42); } TEST_CASE(serialize_text_value) { SQL::Value v("Test"); - EXPECT(v.to_string() == "Test"); + EXPECT_EQ(v.type(), SQL::SQLType::Text); + EXPECT_EQ(v, "Test"sv); SQL::Serializer serializer; serializer.serialize(v); serializer.rewind(); auto v2 = serializer.deserialize(); - EXPECT(v2.to_string() == "Test"); + EXPECT_EQ(v2.type(), SQL::SQLType::Text); + EXPECT_EQ(v2, "Test"sv); + EXPECT_EQ(v2, v); } TEST_CASE(integer_value) { { SQL::Value v(SQL::SQLType::Integer); + EXPECT_EQ(v.type(), SQL::SQLType::Integer); EXPECT(v.is_null()); + v = 42; - EXPECT(!v.is_null()); - EXPECT(v.to_int().value() == 42); - EXPECT(v.to_string() == "42"); + EXPECT_EQ(v.type(), SQL::SQLType::Integer); + + EXPECT(v.to_int().has_value()); + EXPECT_EQ(v.to_int().value(), 42); + EXPECT_EQ(v.to_string(), "42"sv); + EXPECT(v.to_double().has_value()); - EXPECT(v.to_double().value() - 42.0 < NumericLimits().epsilon()); + EXPECT((v.to_double().value() - 42.0) < NumericLimits().epsilon()); + EXPECT(v.to_bool().has_value()); EXPECT(v.to_bool().value()); } { SQL::Value v(0); - EXPECT(!v.is_null()); - EXPECT(v.to_int().value() == 0); + EXPECT_EQ(v.type(), SQL::SQLType::Integer); + + EXPECT(v.to_int().has_value()); + EXPECT_EQ(v.to_int().value(), 0); + EXPECT(v.to_bool().has_value()); EXPECT(!v.to_bool().value()); } { - SQL::Value v(SQL::SQLType::Integer, "42"); - EXPECT_EQ(v.to_int().value(), 42); - } - { - SQL::Value v(SQL::SQLType::Integer, SQL::Value("42")); + SQL::Value v(42); + EXPECT_EQ(v.type(), SQL::SQLType::Integer); + + EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 42); } { SQL::Value text("42"); SQL::Value integer(SQL::SQLType::Integer); integer = text; + + EXPECT(integer.to_int().has_value()); EXPECT_EQ(integer.to_int().value(), 42); } } @@ -138,66 +188,77 @@ TEST_CASE(serialize_int_value) { SQL::Value v(42); EXPECT_EQ(v.type(), SQL::SQLType::Integer); - EXPECT_EQ(v.to_int().value(), 42); + EXPECT_EQ(v, 42); SQL::Serializer serializer; serializer.serialize(v); serializer.rewind(); auto v2 = serializer.deserialize(); - EXPECT(!v2.is_null()); EXPECT_EQ(v2.type(), SQL::SQLType::Integer); - EXPECT_EQ(v2.to_int().value(), 42); - EXPECT(v2 == v); + EXPECT_EQ(v2, 42); + EXPECT_EQ(v2, v); } TEST_CASE(float_value) { { SQL::Value v(SQL::SQLType::Float); + EXPECT_EQ(v.type(), SQL::SQLType::Float); EXPECT(v.is_null()); + v = 3.14; - EXPECT(!v.is_null()); + EXPECT_EQ(v.type(), SQL::SQLType::Float); + EXPECT(v.to_double().has_value()); - EXPECT(v.to_double().value() - 3.14 < NumericLimits().epsilon()); + EXPECT((v.to_double().value() - 3.14) < NumericLimits().epsilon()); + EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 3); EXPECT_EQ(v.to_string(), "3.14"); + EXPECT(v.to_bool().has_value()); EXPECT(v.to_bool().value()); v = 0.0; - EXPECT(!v.is_null()); + EXPECT_EQ(v.type(), SQL::SQLType::Float); + EXPECT(v.to_double().has_value()); EXPECT(v.to_double().value() < NumericLimits().epsilon()); + EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 0); - EXPECT_EQ(v.to_string(), "0"); + EXPECT_EQ(v.to_string(), "0"sv); + EXPECT(v.to_bool().has_value()); EXPECT(!v.to_bool().value()); } { SQL::Value v(3.14); - EXPECT(!v.is_null()); - EXPECT(v.to_double().value() - 3.14 < NumericLimits().epsilon()); + EXPECT_EQ(v.type(), SQL::SQLType::Float); + EXPECT((v.to_double().value() - 3.14) < NumericLimits().epsilon()); } { SQL::Value v(3.51); - EXPECT(!v.is_null()); + EXPECT_EQ(v.type(), SQL::SQLType::Float); + + EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 4); } { SQL::Value v(-3.14); + EXPECT_EQ(v.type(), SQL::SQLType::Float); + + EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), -3); } { SQL::Value v(-3.51); + EXPECT_EQ(v.type(), SQL::SQLType::Float); + + EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), -4); } - { - SQL::Value v(SQL::SQLType::Float, "3.14"); - EXPECT(v.to_double().value() - 3.14 < NumericLimits().epsilon()); - } } TEST_CASE(serialize_float_value) @@ -211,63 +272,73 @@ TEST_CASE(serialize_float_value) serializer.rewind(); auto v2 = serializer.deserialize(); - EXPECT(!v2.is_null()); EXPECT_EQ(v2.type(), SQL::SQLType::Float); - EXPECT(v.to_double().value() - 3.14 < NumericLimits().epsilon()); -} - -TEST_CASE(assign_int_to_text_value) -{ - SQL::Value text(SQL::SQLType::Text); - text = 42; - EXPECT_EQ(text.to_string(), "42"); + EXPECT((v.to_double().value() - 3.14) < NumericLimits().epsilon()); + EXPECT_EQ(v2, v); } TEST_CASE(copy_value) { - SQL::Value text(SQL::SQLType::Text, 42); + SQL::Value text("42"); SQL::Value copy(text); - EXPECT_EQ(copy.to_string(), "42"); + EXPECT_EQ(copy, "42"sv); } TEST_CASE(compare_text_to_int) { - SQL::Value text(SQL::SQLType::Text); - text = 42; - SQL::Value integer(SQL::SQLType::Integer); - integer = 42; - EXPECT(text == integer); - EXPECT(integer == text); + SQL::Value text("42"); + SQL::Value integer(42); + EXPECT_EQ(text, integer); + EXPECT_EQ(integer, text); } TEST_CASE(bool_value) { { SQL::Value v(SQL::SQLType::Boolean); + EXPECT_EQ(v.type(), SQL::SQLType::Boolean); EXPECT(v.is_null()); + v = true; - EXPECT(!v.is_null()); + EXPECT_EQ(v.type(), SQL::SQLType::Boolean); + EXPECT(v.to_bool().has_value()); EXPECT(v.to_bool().value()); + + EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 1); - EXPECT_EQ(v.to_string(), "true"); - EXPECT(!v.to_double().has_value()); + EXPECT_EQ(v.to_string(), "true"sv); + + EXPECT(v.to_double().has_value()); + EXPECT((v.to_double().value() - 1.0) < NumericLimits().epsilon()); } { - SQL::Value v(SQL::SQLType::Boolean, false); - EXPECT(!v.is_null()); + SQL::Value v(false); + EXPECT_EQ(v.type(), SQL::SQLType::Boolean); + EXPECT(v.to_bool().has_value()); EXPECT(!v.to_bool().value()); + + EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 0); - EXPECT_EQ(v.to_string(), "false"); - EXPECT(!v.to_double().has_value()); + EXPECT_EQ(v.to_string(), "false"sv); + + EXPECT(v.to_double().has_value()); + EXPECT(v.to_double().value() < NumericLimits().epsilon()); } { SQL::Value v(true); EXPECT_EQ(v.type(), SQL::SQLType::Boolean); - EXPECT(!v.is_null()); + EXPECT(v.to_bool().has_value()); EXPECT(v.to_bool().value()); + + EXPECT(v.to_int().has_value()); + EXPECT_EQ(v.to_int().value(), 1); + EXPECT_EQ(v.to_string(), "true"sv); + + EXPECT(v.to_double().has_value()); + EXPECT((v.to_double().value() - 1.0) < NumericLimits().epsilon()); } } @@ -282,7 +353,6 @@ TEST_CASE(serialize_boolean_value) serializer.rewind(); auto v2 = serializer.deserialize(); - EXPECT(!v2.is_null()); EXPECT_EQ(v2.type(), SQL::SQLType::Boolean); EXPECT_EQ(v2.to_bool(), true); EXPECT_EQ(v, v2); @@ -293,12 +363,12 @@ TEST_CASE(tuple_value) NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending }); + auto v = MUST(SQL::Value::create_tuple(move(descriptor))); - auto v = SQL::Value::create_tuple(descriptor); Vector values; - values.append(SQL::Value("Test")); - values.append(SQL::Value(42)); - v = values; + values.empend("Test"); + values.empend(42); + MUST(v.assign_tuple(values)); auto values2 = v.to_vector(); EXPECT(values2.has_value()); @@ -310,16 +380,16 @@ TEST_CASE(copy_tuple_value) NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending }); + auto v = MUST(SQL::Value::create_tuple(move(descriptor))); - auto v = SQL::Value::create_tuple(descriptor); Vector values; - values.append(SQL::Value("Test")); - values.append(SQL::Value(42)); - v = values; + values.empend("Test"); + values.empend(42); + MUST(v.assign_tuple(values)); auto values2 = v; - EXPECT(values2.type() == v.type()); - EXPECT(!values2.is_null()); + EXPECT_EQ(values2.type(), v.type()); + EXPECT_EQ(v.type(), SQL::SQLType::Tuple); EXPECT_EQ(values, values2.to_vector().value()); } @@ -327,25 +397,27 @@ TEST_CASE(tuple_value_wrong_type) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); + auto v = MUST(SQL::Value::create_tuple(move(descriptor))); - auto v = SQL::Value::create_tuple(descriptor); Vector values; - values.append(SQL::Value(42)); - v = values; - EXPECT(v.is_null()); + values.empend(42); + + auto result = v.assign_tuple(move(values)); + EXPECT(result.is_error()); } TEST_CASE(tuple_value_too_many_values) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); + auto v = MUST(SQL::Value::create_tuple(move(descriptor))); - auto v = SQL::Value::create_tuple(descriptor); Vector values; - values.append(SQL::Value("Test")); - values.append(SQL::Value(42)); - v = values; - EXPECT(v.is_null()); + values.empend("Test"); + values.empend(42); + + auto result = v.assign_tuple(move(values)); + EXPECT(result.is_error()); } TEST_CASE(tuple_value_not_enough_values) @@ -353,18 +425,20 @@ TEST_CASE(tuple_value_not_enough_values) NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Ascending }); + auto v = MUST(SQL::Value::create_tuple(move(descriptor))); - auto v = SQL::Value::create_tuple(descriptor); Vector values; - values.append(SQL::Value("Test")); - v = values; - EXPECT(!v.is_null()); + values.empend("Test"); + MUST(v.assign_tuple(values)); + + EXPECT_EQ(v.type(), SQL::SQLType::Tuple); + auto values_opt = v.to_vector(); EXPECT(values_opt.has_value()); EXPECT_EQ(values_opt.value().size(), 2u); + auto col2 = values_opt.value()[1]; EXPECT_EQ(col2.type(), SQL::SQLType::Integer); - EXPECT(col2.is_null()); } TEST_CASE(serialize_tuple_value) @@ -372,89 +446,22 @@ TEST_CASE(serialize_tuple_value) NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending }); + auto v = MUST(SQL::Value::create_tuple(move(descriptor))); - auto v = SQL::Value::create_tuple(descriptor); Vector values; - values.append(SQL::Value("Test")); - values.append(SQL::Value(42)); - v = values; + values.empend("Test"); + values.empend(42); + MUST(v.assign_tuple(values)); SQL::Serializer serializer; serializer.serialize(v); serializer.rewind(); auto v2 = serializer.deserialize(); - EXPECT(!v2.is_null()); EXPECT_EQ(v2.type(), SQL::SQLType::Tuple); EXPECT_EQ(v, v2); } -TEST_CASE(array_value) -{ - auto v = SQL::Value::create_array(SQL::SQLType::Text, 3); - Vector values; - values.append(SQL::Value("Test 1")); - values.append(SQL::Value("Test 2")); - v = values; - - auto values2 = v.to_vector(); - EXPECT(values2.has_value()); - EXPECT_EQ(values, values2.value()); -} - -TEST_CASE(array_value_wrong_type) -{ - auto v = SQL::Value::create_array(SQL::SQLType::Text, 2); - Vector values; - values.append(SQL::Value("Test 1")); - values.append(SQL::Value(42)); - v = values; - EXPECT(v.is_null()); -} - -TEST_CASE(array_value_too_many_values) -{ - auto v = SQL::Value::create_array(SQL::SQLType::Text, 2); - Vector values; - values.append(SQL::Value("Test 1")); - values.append(SQL::Value("Test 2")); - values.append(SQL::Value("Test 3")); - v = values; - EXPECT(v.is_null()); -} - -TEST_CASE(copy_array_value) -{ - auto v = SQL::Value::create_array(SQL::SQLType::Text, 3); - Vector values; - values.append(SQL::Value("Test 1")); - values.append(SQL::Value("Test 2")); - v = values; - - auto values2 = v; - EXPECT(values2.type() == v.type()); - EXPECT(!values2.is_null()); - EXPECT_EQ(values, values2.to_vector().value()); -} - -TEST_CASE(serialize_array_value) -{ - auto v = SQL::Value::create_array(SQL::SQLType::Text, 3); - Vector values; - values.append(SQL::Value("Test 1")); - values.append(SQL::Value("Test 2")); - v = values; - - SQL::Serializer serializer; - serializer.serialize(v); - - serializer.rewind(); - auto v2 = serializer.deserialize(); - EXPECT(!v2.is_null()); - EXPECT_EQ(v2.type(), SQL::SQLType::Array); - EXPECT_EQ(v, v2); -} - TEST_CASE(order_text_values) { SQL::Value v1(SQL::SQLType::Text); @@ -488,8 +495,8 @@ TEST_CASE(tuple) tuple["col1"] = "Test"; tuple["col2"] = 42; - EXPECT(tuple[0] == "Test"); - EXPECT(tuple[1] == 42); + EXPECT_EQ(tuple[0], "Test"sv); + EXPECT_EQ(tuple[1], 42); } TEST_CASE(serialize_tuple) @@ -502,7 +509,7 @@ TEST_CASE(serialize_tuple) tuple["col1"] = "Test"; tuple["col2"] = 42; - EXPECT_EQ(tuple[0], "Test"); + EXPECT_EQ(tuple[0], "Test"sv); EXPECT_EQ(tuple[1], 42); SQL::Serializer serializer; @@ -510,8 +517,8 @@ TEST_CASE(serialize_tuple) serializer.rewind(); auto tuple2 = serializer.deserialize(); - EXPECT(tuple2[0] == "Test"); - EXPECT(tuple2[1] == 42); + EXPECT_EQ(tuple2[0], "Test"sv); + EXPECT_EQ(tuple2[1], 42); } TEST_CASE(copy_tuple) @@ -526,10 +533,10 @@ TEST_CASE(copy_tuple) SQL::Tuple copy; copy = tuple; - EXPECT(tuple == copy); + EXPECT_EQ(tuple, copy); SQL::Tuple copy_2(copy); - EXPECT(tuple == copy_2); + EXPECT_EQ(tuple, copy_2); } TEST_CASE(compare_tuples) diff --git a/Userland/Libraries/LibSQL/AST/Expression.cpp b/Userland/Libraries/LibSQL/AST/Expression.cpp index 8e6cdd2ef2..63a39c3b21 100644 --- a/Userland/Libraries/LibSQL/AST/Expression.cpp +++ b/Userland/Libraries/LibSQL/AST/Expression.cpp @@ -16,21 +16,17 @@ static constexpr auto s_posix_basic_metacharacters = ".^$*[]+\\"sv; ResultOr NumericLiteral::evaluate(ExecutionContext&) const { - Value ret(SQLType::Float); - ret = value(); - return ret; + return Value { value() }; } ResultOr StringLiteral::evaluate(ExecutionContext&) const { - Value ret(SQLType::Text); - ret = value(); - return ret; + return Value { value() }; } ResultOr NullLiteral::evaluate(ExecutionContext&) const { - return Value::null(); + return Value {}; } ResultOr NestedExpression::evaluate(ExecutionContext& context) const @@ -46,7 +42,7 @@ ResultOr ChainedExpression::evaluate(ExecutionContext& context) const for (auto& expression : expressions()) values.unchecked_append(TRY(expression.evaluate(context))); - return Value { move(values) }; + return Value::create_tuple(move(values)); } ResultOr BinaryOperatorExpression::evaluate(ExecutionContext& context) const diff --git a/Userland/Libraries/LibSQL/AST/Select.cpp b/Userland/Libraries/LibSQL/AST/Select.cpp index dd2a786d75..663634c0a2 100644 --- a/Userland/Libraries/LibSQL/AST/Select.cpp +++ b/Userland/Libraries/LibSQL/AST/Select.cpp @@ -54,7 +54,7 @@ ResultOr Select::execute(ExecutionContext& context) const Tuple tuple(descriptor); Vector rows; descriptor->empend("__unity__"sv); - tuple.append(Value(SQLType::Boolean, true)); + tuple.append(Value { true }); rows.append(tuple); for (auto& table_descriptor : table_or_subquery_list()) { diff --git a/Userland/Libraries/LibSQL/Type.h b/Userland/Libraries/LibSQL/Type.h index a3a79e58a6..419abc8909 100644 --- a/Userland/Libraries/LibSQL/Type.h +++ b/Userland/Libraries/LibSQL/Type.h @@ -18,8 +18,7 @@ namespace SQL { S("int", 4, Integer, int, sizeof(int)) \ S("float", 8, Float, double, sizeof(double)) \ S("bool", 16, Boolean, bool, sizeof(bool)) \ - S("tuple", 32, Tuple, int, sizeof(int)) \ - S("array", 64, Array, int, sizeof(int)) + S("tuple", 32, Tuple, int, sizeof(int)) enum class SQLType { #undef __ENUMERATE_SQL_TYPE diff --git a/Userland/Libraries/LibSQL/Value.cpp b/Userland/Libraries/LibSQL/Value.cpp index 7b6b5ca2d2..5611cbaadd 100644 --- a/Userland/Libraries/LibSQL/Value.cpp +++ b/Userland/Libraries/LibSQL/Value.cpp @@ -1,30 +1,98 @@ /* * Copyright (c) 2021, Jan de Visser + * Copyright (c) 2022, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include +#include #include #include #include namespace SQL { -Value::Value(SQLType sql_type) +Value::Value(SQLType type) + : m_type(type) { - setup(sql_type); } -void Value::setup(SQLType type) +Value::Value(String value) + : m_type(SQLType::Text) + , m_value(move(value)) { - switch (type) { +} + +Value::Value(int value) + : m_type(SQLType::Integer) + , m_value(value) +{ +} + +Value::Value(u32 value) + : m_type(SQLType::Integer) + , m_value(static_cast(value)) // FIXME: Handle signed overflow. +{ +} + +Value::Value(double value) + : m_type(SQLType::Float) + , m_value(value) +{ +} + +Value::Value(NonnullRefPtr descriptor, Vector values) + : m_type(SQLType::Tuple) + , m_value(TupleValue { move(descriptor), move(values) }) +{ +} + +Value::Value(Value const& other) + : m_type(other.m_type) + , m_value(other.m_value) +{ +} + +Value::Value(Value&& other) + : m_type(other.m_type) + , m_value(move(other.m_value)) +{ +} + +Value::~Value() = default; + +ResultOr Value::create_tuple(NonnullRefPtr descriptor) +{ + Vector values; + TRY(values.try_resize(descriptor->size())); + + for (size_t i = 0; i < descriptor->size(); ++i) + values[i].m_type = descriptor->at(i).type; + + return Value { move(descriptor), move(values) }; +} + +ResultOr Value::create_tuple(Vector values) +{ + auto descriptor = TRY(infer_tuple_descriptor(values)); + return Value { move(descriptor), move(values) }; +} + +SQLType Value::type() const +{ + return m_type; +} + +StringView Value::type_name() const +{ + switch (type()) { #undef __ENUMERATE_SQL_TYPE #define __ENUMERATE_SQL_TYPE(name, cardinal, type, impl, size) \ case SQLType::type: \ - m_impl.set(type##Impl()); \ - break; + return name##sv; ENUMERATE_SQL_TYPES(__ENUMERATE_SQL_TYPE) #undef __ENUMERATE_SQL_TYPE default: @@ -32,135 +100,56 @@ void Value::setup(SQLType type) } } -Value::Value(SQLType sql_type, Value const& value) - : Value(sql_type) -{ - assign(value); -} - -Value::Value(SQLType sql_type, String const& string) - : Value(sql_type) -{ - assign(string); -} - -Value::Value(SQLType sql_type, char const* string) - : Value(sql_type) -{ - assign(String(string)); -} - -Value::Value(SQLType sql_type, int integer) - : Value(sql_type) -{ - assign(integer); -} - -Value::Value(SQLType sql_type, double dbl) - : Value(sql_type) -{ - assign(dbl); -} - -Value::Value(SQLType sql_type, bool boolean) - : Value(sql_type) -{ - assign(boolean); -} - -Value::Value(String const& string) - : Value(SQLType::Text) -{ - assign(string); -} - -Value::Value(char const* string) - : Value(SQLType::Text) -{ - assign(String(string)); -} - -Value::Value(int integer) - : Value(SQLType::Integer) -{ - assign(integer); -} - -Value::Value(u32 unsigned_integer) - : Value(SQLType::Integer) -{ - assign(unsigned_integer); -} - -Value::Value(double dbl) - : Value(SQLType::Float) -{ - assign(dbl); -} - -Value::Value(bool boolean) - : Value(SQLType::Boolean) -{ - assign(boolean); -} - -Value Value::create_tuple(NonnullRefPtr const& tuple_descriptor) -{ - return Value(Value::SetImplementationSingleton, TupleImpl(tuple_descriptor)); -} - -Value Value::create_array(SQLType element_type, Optional const& max_size) -{ - return Value(Value::SetImplementationSingleton, ArrayImpl(element_type, max_size)); -} - -Value const& Value::null() -{ - static Value s_null(SQLType::Null); - return s_null; -} - bool Value::is_null() const { - return m_impl.visit([&](auto& impl) { return impl.is_null(); }); -} - -SQLType Value::type() const -{ - return m_impl.visit([&](auto& impl) { return impl.type(); }); -} - -String Value::type_name() const -{ - return m_impl.visit([&](auto& impl) { return impl.type_name(); }); -} - -BaseTypeImpl Value::downcast_to_basetype() const -{ - return m_impl.downcast(); + return !m_value.has_value(); } String Value::to_string() const { if (is_null()) - return "(null)"; - return m_impl.visit([&](auto& impl) { return impl.to_string(); }); + return "(null)"sv; + + return m_value->visit( + [](String const& value) -> String { return value; }, + [](int value) -> String { return String::number(value); }, + [](double value) -> String { return String::number(value); }, + [](bool value) -> String { return value ? "true"sv : "false"sv; }, + [](TupleValue const& value) -> String { + StringBuilder builder; + + builder.append('('); + builder.join(',', value.values); + builder.append(')'); + + return builder.build(); + }); } Optional Value::to_int() const { if (is_null()) return {}; - return m_impl.visit([&](auto& impl) { return impl.to_int(); }); + + return m_value->visit( + [](String const& value) -> Optional { return value.to_int(); }, + [](int value) -> Optional { return value; }, + [](double value) -> Optional { + if (value > static_cast(NumericLimits::max())) + return {}; + if (value < static_cast(NumericLimits::min())) + return {}; + return static_cast(round(value)); + }, + [](bool value) -> Optional { return static_cast(value); }, + [](TupleValue const&) -> Optional { return {}; }); } Optional Value::to_u32() const { - if (is_null()) - return {}; - auto ret = to_int(); - if (ret.has_value()) - return static_cast(ret.value()); + // FIXME: Handle negative values. + if (auto result = to_int(); result.has_value()) + return static_cast(result.value()); return {}; } @@ -168,134 +157,185 @@ Optional Value::to_double() const { if (is_null()) return {}; - return m_impl.visit([&](auto& impl) { return impl.to_double(); }); + + return m_value->visit( + [](String const& value) -> Optional { + char* end = nullptr; + double result = strtod(value.characters(), &end); + + if (end == value.characters()) + return {}; + return result; + }, + [](int value) -> Optional { return static_cast(value); }, + [](double value) -> Optional { return value; }, + [](bool value) -> Optional { return static_cast(value); }, + [](TupleValue const&) -> Optional { return {}; }); } Optional Value::to_bool() const { if (is_null()) return {}; - return m_impl.visit([&](auto& impl) { return impl.to_bool(); }); + + return m_value->visit( + [](String const& value) -> Optional { + if (value.equals_ignoring_case("true"sv) || value.equals_ignoring_case("t"sv)) + return true; + if (value.equals_ignoring_case("false"sv) || value.equals_ignoring_case("f"sv)) + return false; + return {}; + }, + [](int value) -> Optional { return static_cast(value); }, + [](double value) -> Optional { return fabs(value) > NumericLimits::epsilon(); }, + [](bool value) -> Optional { return value; }, + [](TupleValue const& value) -> Optional { + for (auto const& element : value.values) { + auto as_bool = element.to_bool(); + if (!as_bool.has_value()) + return {}; + if (!as_bool.value()) + return false; + } + + return true; + }); } Optional> Value::to_vector() const { - if (is_null()) - return {}; - Vector vector; - if (m_impl.visit([&](auto& impl) { return impl.to_vector(vector); })) - return vector; - else + if (is_null() || (type() != SQLType::Tuple)) return {}; + + auto const& tuple = m_value->get(); + return tuple.values; } -void Value::assign(Value const& other_value) +Value& Value::operator=(Value value) { - m_impl.visit([&](auto& impl) { impl.assign(other_value); }); + m_type = value.m_type; + m_value = move(value.m_value); + return *this; } -void Value::assign(String const& string_value) +Value& Value::operator=(String value) { - m_impl.visit([&](auto& impl) { impl.assign_string(string_value); }); -} - -void Value::assign(int int_value) -{ - m_impl.visit([&](auto& impl) { impl.assign_int(int_value); }); -} - -void Value::assign(u32 unsigned_int_value) -{ - m_impl.visit([&](auto& impl) { impl.assign_int(unsigned_int_value); }); -} - -void Value::assign(double double_value) -{ - m_impl.visit([&](auto& impl) { impl.assign_double(double_value); }); -} - -void Value::assign(bool bool_value) -{ - m_impl.visit([&](auto& impl) { impl.assign_bool(bool_value); }); -} - -void Value::assign(Vector const& values) -{ - m_impl.visit([&](auto& impl) { impl.assign_vector(values); }); -} - -Value& Value::operator=(Value const& other) -{ - if (this != &other) { - if (other.is_null()) { - assign(null()); - } else if (is_null()) { - assign(other); - } else { - VERIFY(can_cast(other)); - assign(other); - } - } - return (*this); -} - -Value& Value::operator=(String const& value) -{ - assign(value); - return (*this); -} - -Value& Value::operator=(char const* value) -{ - assign(String(value)); - return (*this); + m_type = SQLType::Text; + m_value = move(value); + return *this; } Value& Value::operator=(int value) { - assign(value); - return (*this); + m_type = SQLType::Integer; + m_value = value; + return *this; } Value& Value::operator=(u32 value) { - assign(static_cast(value)); - return (*this); + m_type = SQLType::Integer; + m_value = static_cast(value); // FIXME: Handle signed overflow. + return *this; } Value& Value::operator=(double value) { - assign(value); - return (*this); + m_type = SQLType::Float; + m_value = value; + return *this; } -Value& Value::operator=(bool value) +ResultOr Value::assign_tuple(NonnullRefPtr descriptor) { - assign(value); - return (*this); + Vector values; + TRY(values.try_resize(descriptor->size())); + + for (size_t i = 0; i < descriptor->size(); ++i) + values[i].m_type = descriptor->at(i).type; + + m_type = SQLType::Tuple; + m_value = TupleValue { move(descriptor), move(values) }; + + return {}; } -Value& Value::operator=(Vector const& vector) +ResultOr Value::assign_tuple(Vector values) { - assign(vector); - return (*this); + if (is_null() || (type() != SQLType::Tuple)) { + auto descriptor = TRY(infer_tuple_descriptor(values)); + + m_type = SQLType::Tuple; + m_value = TupleValue { move(descriptor), move(values) }; + + return {}; + } + + auto& tuple = m_value->get(); + + if (values.size() > tuple.descriptor->size()) + return Result { SQLCommand::Unknown, SQLErrorCode::InvalidNumberOfValues }; + + for (size_t i = 0; i < values.size(); ++i) { + if (values[i].type() != tuple.descriptor->at(i).type) + return Result { SQLCommand::Unknown, SQLErrorCode::InvalidType, SQLType_name(values[i].type()) }; + } + + if (values.size() < tuple.descriptor->size()) { + size_t original_size = values.size(); + MUST(values.try_resize(tuple.descriptor->size())); + + for (size_t i = original_size; i < values.size(); ++i) + values[i].m_type = tuple.descriptor->at(i).type; + } + + m_value = TupleValue { move(tuple.descriptor), move(values) }; + return {}; } size_t Value::length() const { - return m_impl.visit([&](auto& impl) { return impl.length(); }); + if (is_null()) + return 0; + + // FIXME: This seems to be more of an encoded byte size rather than a length. + return m_value->visit( + [](String const& value) -> size_t { return sizeof(u32) + value.length(); }, + [](int value) -> size_t { return sizeof(value); }, + [](double value) -> size_t { return sizeof(value); }, + [](bool value) -> size_t { return sizeof(value); }, + [](TupleValue const& value) -> size_t { + auto size = value.descriptor->length() + sizeof(u32); + + for (auto const& element : value.values) + size += element.length(); + + return size; + }); } u32 Value::hash() const { - return (is_null()) ? 0u : m_impl.visit([&](auto& impl) { return impl.hash(); }); -} + if (is_null()) + return 0; -bool Value::can_cast(Value const& other_value) const -{ - if (type() == other_value.type()) - return true; - return m_impl.visit([&](auto& impl) { return impl.can_cast(other_value); }); + return m_value->visit( + [](String const& value) -> u32 { return value.hash(); }, + [](int value) -> u32 { return int_hash(value); }, + [](double) -> u32 { VERIFY_NOT_REACHED(); }, + [](bool value) -> u32 { return int_hash(value); }, + [](TupleValue const& value) -> u32 { + u32 hash = 0; + + for (auto const& element : value.values) { + if (hash == 0) + hash = element.hash(); + else + hash = pair_int_hash(hash, element.hash()); + } + + return hash; + }); } int Value::compare(Value const& other) const @@ -304,58 +344,105 @@ int Value::compare(Value const& other) const return -1; if (other.is_null()) return 1; - return m_impl.visit([&](auto& impl) { return impl.compare(other); }); + + return m_value->visit( + [&](String const& value) -> int { return value.view().compare(other.to_string()); }, + [&](int value) -> int { + auto casted = other.to_int(); + if (!casted.has_value()) + return 1; + + if (value == *casted) + return 0; + return value < *casted ? -1 : 1; + }, + [&](double value) -> int { + auto casted = other.to_double(); + if (!casted.has_value()) + return 1; + + auto diff = value - *casted; + if (fabs(diff) < NumericLimits::epsilon()) + return 0; + return diff < 0 ? -1 : 1; + }, + [&](bool value) -> int { + auto casted = other.to_bool(); + if (!casted.has_value()) + return 1; + return value ^ *casted; + }, + [&](TupleValue const& value) -> int { + if (other.is_null() || (other.type() != SQLType::Tuple)) { + if (value.values.size() == 1) + return value.values[0].compare(other); + return 1; + } + + auto const& other_value = other.m_value->get(); + if (auto result = value.descriptor->compare_ignoring_names(*other_value.descriptor); result != 0) + return 1; + + if (value.values.size() != other_value.values.size()) + return value.values.size() < other_value.values.size() ? -1 : 1; + + for (size_t i = 0; i < value.values.size(); ++i) { + auto result = value.values[i].compare(other_value.values[i]); + if (result == 0) + continue; + + if (value.descriptor->at(i).order == Order::Descending) + result = -result; + return result; + } + + return 0; + }); } -bool Value::operator==(Value const& other) const +bool Value::operator==(Value const& value) const { - return compare(other) == 0; + return compare(value) == 0; } -bool Value::operator==(String const& string_value) const +bool Value::operator==(StringView value) const { - return to_string() == string_value; + return to_string() == value; } -bool Value::operator==(int int_value) const +bool Value::operator==(int value) const { - auto i = to_int(); - if (!i.has_value()) - return false; - return i.value() == int_value; + return to_int() == value; } -bool Value::operator==(double double_value) const +bool Value::operator==(double value) const { - auto d = to_double(); - if (!d.has_value()) - return false; - return d.value() == double_value; + return to_double() == value; } -bool Value::operator!=(Value const& other) const +bool Value::operator!=(Value const& value) const { - return compare(other) != 0; + return compare(value) != 0; } -bool Value::operator<(Value const& other) const +bool Value::operator<(Value const& value) const { - return compare(other) < 0; + return compare(value) < 0; } -bool Value::operator<=(Value const& other) const +bool Value::operator<=(Value const& value) const { - return compare(other) <= 0; + return compare(value) <= 0; } -bool Value::operator>(Value const& other) const +bool Value::operator>(Value const& value) const { - return compare(other) > 0; + return compare(value) > 0; } -bool Value::operator>=(Value const& other) const +bool Value::operator>=(Value const& value) const { - return compare(other) >= 0; + return compare(value) >= 0; } static Result invalid_type_for_numeric_operator(AST::BinaryOperator op) @@ -472,639 +559,91 @@ ResultOr Value::bitwise_and(Value const& other) const return Value(u32_maybe_1.value() & u32_maybe_2.value()); } +static constexpr auto sql_type_null_as_flag = static_cast(SQLType::Null); + void Value::serialize(Serializer& serializer) const { - u8 type_flags = (u8)type(); + auto type_flags = static_cast(type()); if (is_null()) - type_flags |= (u8)SQLType::Null; + type_flags |= sql_type_null_as_flag; + serializer.serialize(type_flags); - if (!is_null()) - m_impl.visit([&](auto& impl) { serializer.serialize(impl); }); + + if (is_null()) + return; + + m_value->visit( + [&](TupleValue const& value) { + serializer.serialize(*value.descriptor); + serializer.serialize(static_cast(value.values.size())); + + for (auto const& element : value.values) + serializer.serialize(element); + }, + [&](auto const& value) { serializer.serialize(value); }); } void Value::deserialize(Serializer& serializer) { auto type_flags = serializer.deserialize(); - bool is_null = false; - if ((type_flags & (u8)SQLType::Null) && (type_flags != (u8)SQLType::Null)) { - type_flags &= ~((u8)SQLType::Null); - is_null = true; - } - auto type = (SQLType)type_flags; - VERIFY(!is_null || (type != SQLType::Tuple && type != SQLType::Array)); - setup(type); - if (!is_null) { - m_impl.visit([&](auto& impl) { impl.deserialize(serializer); }); - } -} + bool has_value = true; -bool NullImpl::can_cast(Value const& value) -{ - return value.is_null(); -} - -int NullImpl::compare(Value const& other) -{ - return other.type() == SQLType::Null; -} - -String TextImpl::to_string() const -{ - return value(); -} - -Optional TextImpl::to_int() const -{ - if (!m_value.has_value()) - return {}; - return value().to_int(); -} - -Optional TextImpl::to_double() const -{ - if (!m_value.has_value()) - return {}; - char* end_ptr; - double ret = strtod(value().characters(), &end_ptr); - if (end_ptr == value().characters()) { - return {}; - } - return ret; -} - -Optional TextImpl::to_bool() const -{ - if (!m_value.has_value()) - return {}; - if (value().equals_ignoring_case("true"sv) || value().equals_ignoring_case("t"sv)) - return true; - if (value().equals_ignoring_case("false"sv) || value().equals_ignoring_case("f"sv)) - return false; - return {}; -} - -void TextImpl::assign(Value const& other_value) -{ - if (other_value.type() == SQLType::Null) { - m_value = {}; - } else { - m_value = other_value.to_string(); - } -} - -void TextImpl::assign_string(String const& string_value) -{ - m_value = string_value; -} - -void TextImpl::assign_int(int int_value) -{ - m_value = String::number(int_value); -} - -void TextImpl::assign_double(double double_value) -{ - m_value = String::number(double_value); -} - -void TextImpl::assign_bool(bool bool_value) -{ - m_value = (bool_value) ? "true" : "false"; -} - -size_t TextImpl::length() const -{ - return (is_null()) ? 0 : sizeof(u32) + value().length(); -} - -int TextImpl::compare(Value const& other) const -{ - if (is_null()) - return -1; - auto s1 = value(); - auto s2 = other.to_string(); - if (s1 == s2) - return 0; - return (s1 < s2) ? -1 : 1; -} - -u32 TextImpl::hash() const -{ - return value().hash(); -} - -String IntegerImpl::to_string() const -{ - return String::formatted("{}", value()); -} - -Optional IntegerImpl::to_int() const -{ - return value(); -} - -Optional IntegerImpl::to_double() const -{ - return static_cast(value()); -} - -Optional IntegerImpl::to_bool() const -{ - return value() != 0; -} - -void IntegerImpl::assign(Value const& other_value) -{ - auto i = other_value.to_int(); - if (!i.has_value()) - m_value = {}; - else - m_value = i.value(); -} - -void IntegerImpl::assign_string(String const& string_value) -{ - auto i = string_value.to_int(); - if (!i.has_value()) - m_value = {}; - else - m_value = i.value(); -} - -void IntegerImpl::assign_int(int int_value) -{ - m_value = int_value; -} - -void IntegerImpl::assign_double(double double_value) -{ - m_value = static_cast(round(double_value)); -} - -void IntegerImpl::assign_bool(bool bool_value) -{ - m_value = (bool_value) ? 1 : 0; -} - -bool IntegerImpl::can_cast(Value const& other_value) -{ - return other_value.to_int().has_value(); -} - -int IntegerImpl::compare(Value const& other) const -{ - auto casted = other.to_int(); - if (!casted.has_value()) - return 1; - - if (value() == casted.value()) - return 0; - - return value() < casted.value() ? -1 : 1; -} - -u32 IntegerImpl::hash() const -{ - return int_hash(value()); -} - -String FloatImpl::to_string() const -{ - return String::formatted("{}", value()); -} - -Optional FloatImpl::to_int() const -{ - return static_cast(round(value())); -} - -Optional FloatImpl::to_bool() const -{ - return fabs(value()) > NumericLimits::epsilon(); -} - -Optional FloatImpl::to_double() const -{ - return value(); -} - -void FloatImpl::assign(Value const& other_value) -{ - auto i = other_value.to_double(); - if (!i.has_value()) - m_value = {}; - else - m_value = i.value(); -} - -void FloatImpl::assign_string(String const& string_value) -{ - char* end_ptr; - auto dbl = strtod(string_value.characters(), &end_ptr); - if (end_ptr == string_value.characters()) - m_value = {}; - else - m_value = dbl; -} - -void FloatImpl::assign_int(int int_value) -{ - m_value = int_value; -} - -void FloatImpl::assign_double(double double_value) -{ - m_value = double_value; -} - -bool FloatImpl::can_cast(Value const& other_value) -{ - return other_value.to_double().has_value(); -} - -int FloatImpl::compare(Value const& other) const -{ - auto casted = other.to_double(); - if (!casted.has_value()) { - return 1; + if ((type_flags & sql_type_null_as_flag) && (type_flags != sql_type_null_as_flag)) { + type_flags &= ~sql_type_null_as_flag; + has_value = false; } - auto diff = value() - casted.value(); - if (fabs(diff) < NumericLimits::epsilon()) - return 0; - return diff < 0 ? -1 : 1; -} + m_type = static_cast(type_flags); -String BooleanImpl::to_string() const -{ - return (value()) ? "true" : "false"; -} - -Optional BooleanImpl::to_int() const -{ - return (value()) ? 1 : 0; -} - -Optional BooleanImpl::to_double() -{ - return {}; -} - -Optional BooleanImpl::to_bool() const -{ - return value(); -} - -void BooleanImpl::assign(Value const& other_value) -{ - auto b = other_value.to_bool(); - if (!b.has_value()) - m_value = {}; - else - m_value = b.value(); -} - -void BooleanImpl::assign_string(String const& string_value) -{ - return assign(Value(string_value)); -} - -void BooleanImpl::assign_int(int int_value) -{ - m_value = (int_value != 0); -} - -void BooleanImpl::assign_double(double) -{ - m_value = {}; -} - -void BooleanImpl::assign_bool(bool bool_value) -{ - m_value = bool_value; -} - -bool BooleanImpl::can_cast(Value const& other_value) -{ - return other_value.to_bool().has_value(); -} - -int BooleanImpl::compare(Value const& other) const -{ - auto casted = other.to_bool(); - if (!casted.has_value()) { - return 1; - } - return value() ^ casted.value(); // xor - zero if both true or both false, 1 otherwise. -} - -u32 BooleanImpl::hash() const -{ - return int_hash(value()); -} - -void ContainerValueImpl::assign_vector(Vector const& vector_values) -{ - if (!validate_before_assignment(vector_values)) { - m_value = {}; + if (!has_value) return; + + switch (m_type) { + case SQLType::Null: + VERIFY_NOT_REACHED(); + break; + case SQLType::Text: + m_value = serializer.deserialize(); + break; + case SQLType::Integer: + m_value = serializer.deserialize(0); + break; + case SQLType::Float: + m_value = serializer.deserialize(0.0); + break; + case SQLType::Boolean: + m_value = serializer.deserialize(false); + break; + case SQLType::Tuple: { + auto descriptor = serializer.adopt_and_deserialize(); + auto size = serializer.deserialize(); + + Vector values; + values.ensure_capacity(size); + + for (size_t i = 0; i < size; ++i) + values.unchecked_append(serializer.deserialize()); + + m_value = TupleValue { move(descriptor), move(values) }; + break; } - m_value = Vector(); - for (auto& value : vector_values) { - if (!append(value)) { - m_value = {}; - return; - } - } - if (!validate_after_assignment()) - m_value = {}; -} - -bool ContainerValueImpl::to_vector(Vector& vector) const -{ - vector.clear(); - for (auto& value : value()) { - vector.empend(Value(value)); - } - return true; -} - -Vector ContainerValueImpl::to_string_vector() const -{ - Vector ret; - for (auto& value : value()) { - ret.append(Value(value).to_string()); - } - return ret; -} - -String ContainerValueImpl::to_string() const -{ - StringBuilder builder; - builder.append('('); - StringBuilder joined; - joined.join(", "sv, to_string_vector()); - builder.append(joined.string_view()); - builder.append(')'); - return builder.build(); -} - -u32 ContainerValueImpl::hash() const -{ - u32 ret = 0u; - for (auto& value : value()) { - Value v(value); - // This is an extension of the pair_int_hash function from AK/HashFunctions.h: - if (!ret) - ret = v.hash(); - else - ret = int_hash((ret * 209) ^ (v.hash() * 413)); - } - return ret; -} - -bool ContainerValueImpl::append(Value const& value) -{ - if (value.type() == SQLType::Tuple || value.type() == SQLType::Array) - return false; - return append(value.downcast_to_basetype()); -} - -bool ContainerValueImpl::append(BaseTypeImpl const& impl) -{ - if (!validate(impl)) - return false; - m_value.value().empend(impl); - return true; -} - -void ContainerValueImpl::serialize_values(Serializer& serializer) const -{ - serializer.serialize((u32)size()); - for (auto& impl : value()) { - serializer.serialize(Value(impl)); } } -void ContainerValueImpl::deserialize_values(Serializer& serializer) +TupleElementDescriptor Value::descriptor() const { - auto sz = serializer.deserialize(); - m_value = Vector(); - for (auto ix = 0u; ix < sz; ix++) { - append(serializer.deserialize()); - } + return { "", "", "", type(), Order::Ascending }; } -size_t ContainerValueImpl::length() const +ResultOr> Value::infer_tuple_descriptor(Vector const& values) { - size_t len = sizeof(u32); - for (auto& impl : value()) { - len += Value(impl).length(); - } - return len; -} + auto descriptor = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) SQL::TupleDescriptor)); + TRY(descriptor->try_ensure_capacity(values.size())); -void TupleImpl::assign(Value const& other) -{ - if (other.type() != SQLType::Tuple) { - m_value = {}; - return; - } - auto& other_impl = other.get_impl({}); - auto other_descriptor = other_impl.m_descriptor; - if (m_descriptor && other_descriptor && m_descriptor->compare_ignoring_names(*other_descriptor)) { - m_value = {}; - return; - } - assign_vector(other.to_vector().value()); -} + for (auto const& element : values) + descriptor->unchecked_append({ ""sv, ""sv, ""sv, element.type(), Order::Ascending }); -size_t TupleImpl::length() const -{ - return m_descriptor->length() + ContainerValueImpl::length(); -} - -bool TupleImpl::can_cast(Value const& other_value) const -{ - if (other_value.type() != SQLType::Tuple) - return false; - return (m_descriptor == other_value.get_impl({}).m_descriptor); -} - -int TupleImpl::compare(Value const& other) const -{ - if (other.type() != SQLType::Tuple) { - if (size() == 1) - return Value(value().at(0)).compare(other); - return 1; - } - - auto& other_impl = other.get_impl({}); - if (m_descriptor && other_impl.m_descriptor && m_descriptor->compare_ignoring_names(*other_impl.m_descriptor)) - return 1; - - auto other_values = other_impl.value(); - if (size() != other_impl.size()) - return (int)value().size() - (int)other_impl.size(); - for (auto ix = 0u; ix < value().size(); ix++) { - auto ret = Value(value()[ix]).compare(Value(other_impl.value()[ix])); - if (ret != 0) { - if (m_descriptor && (ix < m_descriptor->size()) && (*m_descriptor)[ix].order == Order::Descending) - ret = -ret; - return ret; - } - } - return 0; -} - -Optional TupleImpl::to_bool() const -{ - for (auto const& value : value()) { - auto as_bool = Value(value).to_bool(); - if (!as_bool.has_value()) - return {}; - if (!as_bool.value()) - return false; - } - - return true; -} - -void TupleImpl::serialize(Serializer& serializer) const -{ - serializer.serialize(*m_descriptor); - serialize_values(serializer); -} - -void TupleImpl::deserialize(Serializer& serializer) -{ - m_descriptor = serializer.adopt_and_deserialize(); - deserialize_values(serializer); -} - -void TupleImpl::infer_descriptor() -{ - if (!m_descriptor) { - m_descriptor = adopt_ref(*new TupleDescriptor); - m_descriptor_inferred = true; - } -} - -void TupleImpl::extend_descriptor(Value const& value) -{ - VERIFY(m_descriptor_inferred); - m_descriptor->empend("", "", "", value.type(), Order::Ascending); -} - -bool TupleImpl::validate_before_assignment(Vector const& values) -{ - if (m_descriptor_inferred) - m_descriptor = nullptr; - if (!m_descriptor) { - infer_descriptor(); - if (values.size() > m_descriptor->size()) { - for (auto ix = m_descriptor->size(); ix < values.size(); ix++) { - extend_descriptor(values[ix]); - } - } - } - return true; -} - -bool TupleImpl::validate(BaseTypeImpl const& value) -{ - if (!m_descriptor) - infer_descriptor(); - if (m_descriptor_inferred && (this->value().size() == m_descriptor->size())) - extend_descriptor(Value(value)); - if (m_descriptor->size() == this->value().size()) - return false; - auto required_type = (*m_descriptor)[this->value().size()].type; - return Value(value).type() == required_type; -} - -bool TupleImpl::validate_after_assignment() -{ - for (auto ix = value().size(); ix < m_descriptor->size(); ++ix) { - auto required_type = (*m_descriptor)[ix].type; - append(Value(required_type)); - } - return true; -} - -void ArrayImpl::assign(Value const& other) -{ - if (other.type() != SQLType::Array) { - m_value = {}; - return; - } - auto& other_impl = other.get_impl({}); - if (m_max_size != other_impl.m_max_size || m_element_type != other_impl.m_element_type) { - m_value = {}; - return; - } - assign_vector(other.to_vector().value()); -} - -size_t ArrayImpl::length() const -{ - return sizeof(u8) + sizeof(u32) + ContainerValueImpl::length(); -} - -bool ArrayImpl::can_cast(Value const& other_value) const -{ - if (other_value.type() != SQLType::Array) - return false; - auto& other_impl = other_value.get_impl({}); - return (m_max_size != other_impl.m_max_size || m_element_type != other_impl.m_element_type); -} - -int ArrayImpl::compare(Value const& other) const -{ - if (other.type() != SQLType::Array) - return 1; - auto other_impl = other.get_impl({}); - if (other_impl.m_element_type != m_element_type) - return 1; - if (other_impl.m_max_size.has_value() && m_max_size.has_value() && other_impl.m_max_size != m_max_size) - return (int)m_max_size.value() - (int)other_impl.m_max_size.value(); - if (size() != other_impl.size()) - return (int)size() - (int)other_impl.size(); - for (auto ix = 0u; ix < size(); ix++) { - auto ret = Value(value()[ix]).compare(Value(other_impl.value()[ix])); - if (ret != 0) { - return ret; - } - } - return 0; -} - -void ArrayImpl::serialize(Serializer& serializer) const -{ - serializer.serialize((u8)m_element_type); - if (m_max_size.has_value()) - serializer.serialize((u32)m_max_size.value()); - else - serializer.serialize((u32)0); - serialize_values(serializer); -} - -void ArrayImpl::deserialize(Serializer& serializer) -{ - m_element_type = (SQLType)serializer.deserialize(); - auto max_sz = serializer.deserialize(); - if (max_sz) - m_max_size = max_sz; - else - m_max_size = {}; - deserialize_values(serializer); -} - -bool ArrayImpl::validate(BaseTypeImpl const& impl) -{ - if (m_max_size.has_value() && (size() >= m_max_size.value())) - return false; - return Value(impl).type() == m_element_type; + return descriptor; } } diff --git a/Userland/Libraries/LibSQL/Value.h b/Userland/Libraries/LibSQL/Value.h index e731abadac..bbd9a0ced8 100644 --- a/Userland/Libraries/LibSQL/Value.h +++ b/Userland/Libraries/LibSQL/Value.h @@ -1,22 +1,21 @@ /* * Copyright (c) 2021, Jan de Visser + * Copyright (c) 2022, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once -#include -#include -#include +#include +#include #include +#include #include +#include #include #include -#include #include -#include -#include namespace SQL { @@ -27,49 +26,28 @@ namespace SQL { */ class Value { public: - Value(Value&) = default; - Value(Value const&) = default; - explicit Value(SQLType sql_type = SQLType::Null); - - template - explicit Value(Variant impl) - : m_impl(impl) - { - } - - enum SetImplementation { - SetImplementationSingleton - }; - - template - Value(SetImplementation, I&& impl) - { - m_impl.set(forward(impl)); - } - - Value(SQLType, Value const&); - Value(SQLType, String const&); - Value(SQLType, char const*); - Value(SQLType, int); - Value(SQLType, double); - Value(SQLType, bool); - explicit Value(String const&); - explicit Value(char const*); + explicit Value(String); explicit Value(int); explicit Value(u32); explicit Value(double); - explicit Value(bool); + Value(Value const&); + Value(Value&&); + ~Value(); - ~Value() = default; + static ResultOr create_tuple(NonnullRefPtr); + static ResultOr create_tuple(Vector); + + template + requires(SameAs, bool>) explicit Value(T value) + : m_type(SQLType::Boolean) + , m_value(value) + { + } - [[nodiscard]] bool is_null() const; [[nodiscard]] SQLType type() const; - [[nodiscard]] String type_name() const; - [[nodiscard]] BaseTypeImpl downcast_to_basetype() const; - - template - Impl const& get_impl(Badge) const { return m_impl.get(); } + [[nodiscard]] StringView type_name() const; + [[nodiscard]] bool is_null() const; [[nodiscard]] String to_string() const; [[nodiscard]] Optional to_int() const; @@ -78,34 +56,33 @@ public: [[nodiscard]] Optional to_bool() const; [[nodiscard]] Optional> to_vector() const; - void assign(Value const& other_value); - void assign(String const& string_value); - void assign(int int_value); - void assign(u32 unsigned_int_value); - void assign(double double_value); - void assign(bool bool_value); - void assign(Vector const& values); - - Value& operator=(Value const& other); - - Value& operator=(String const&); - Value& operator=(char const*); + Value& operator=(Value); + Value& operator=(String); Value& operator=(int); Value& operator=(u32); Value& operator=(double); - Value& operator=(bool); - Value& operator=(Vector const&); + + ResultOr assign_tuple(NonnullRefPtr); + ResultOr assign_tuple(Vector); + + template + requires(SameAs, bool>) Value& operator=(T value) + { + m_type = SQLType::Boolean; + m_value = value; + return *this; + } [[nodiscard]] size_t length() const; [[nodiscard]] u32 hash() const; - [[nodiscard]] bool can_cast(Value const&) const; void serialize(Serializer&) const; void deserialize(Serializer&); [[nodiscard]] int compare(Value const&) const; bool operator==(Value const&) const; - bool operator==(String const&) const; + bool operator==(StringView) const; bool operator==(int) const; + bool operator==(u32) const; bool operator==(double) const; bool operator!=(Value const&) const; bool operator<(Value const&) const; @@ -123,20 +100,31 @@ public: ResultOr bitwise_or(Value const&) const; ResultOr bitwise_and(Value const&) const; - [[nodiscard]] TupleElementDescriptor descriptor() const - { - return { "", "", "", type(), Order::Ascending }; - } - - static Value const& null(); - static Value create_tuple(NonnullRefPtr const&); - static Value create_array(SQLType element_type, Optional const& max_size = {}); + [[nodiscard]] TupleElementDescriptor descriptor() const; private: - void setup(SQLType type); - - ValueTypeImpl m_impl { NullImpl() }; friend Serializer; + + struct TupleValue { + NonnullRefPtr descriptor; + Vector values; + }; + + using ValueType = Variant; + + static ResultOr> infer_tuple_descriptor(Vector const& values); + Value(NonnullRefPtr descriptor, Vector values); + + SQLType m_type { SQLType::Null }; + Optional m_value; }; } + +template<> +struct AK::Formatter : Formatter { + ErrorOr format(FormatBuilder& builder, SQL::Value const& value) + { + return Formatter::format(builder, value.to_string()); + } +}; diff --git a/Userland/Libraries/LibSQL/ValueImpl.h b/Userland/Libraries/LibSQL/ValueImpl.h deleted file mode 100644 index 477e783a51..0000000000 --- a/Userland/Libraries/LibSQL/ValueImpl.h +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2021, Jan de Visser - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace SQL { - -class Value; - -class BaseImpl { -public: - explicit BaseImpl(SQLType type = SQLType::Null) - : m_type(type) - { - } - - [[nodiscard]] SQLType type() const { return m_type; } - [[nodiscard]] String type_name() const { return SQLType_name(type()); } - -private: - SQLType m_type { SQLType::Null }; -}; - -class NullImpl : public BaseImpl { -public: - explicit NullImpl() - : BaseImpl(SQLType::Null) - { - } - - [[nodiscard]] static bool is_null() { return true; } - [[nodiscard]] static String to_string() { return "(null)"; } - [[nodiscard]] static Optional to_int() { return {}; } - [[nodiscard]] static Optional to_double() { return {}; } - [[nodiscard]] static Optional to_bool() { return {}; } - [[nodiscard]] static bool to_vector(Vector&) { return false; } - static void assign(Value const&) { } - static void assign_string(String const&) { } - static void assign_int(int) { } - static void assign_double(double) { } - static void assign_bool(bool) { } - static void assign_vector(Vector const&) { } - [[nodiscard]] static size_t length() { return 0; } - [[nodiscard]] static bool can_cast(Value const&); - [[nodiscard]] static int compare(Value const&); - static void serialize(Serializer&) { } - static void deserialize(Serializer&) { } - [[nodiscard]] static u32 hash() { return 0; } -}; - -template -class Impl : public BaseImpl { -public: - [[nodiscard]] bool is_null() const - { - return !m_value.has_value(); - } - - [[nodiscard]] T const& value() const - { - VERIFY(m_value.has_value()); - return m_value.value(); - } - - [[nodiscard]] size_t length() const - { - return sizeof(T); - } - - void serialize(Serializer& serializer) const - { - serializer.serialize(value()); - } - - void deserialize(Serializer& serializer) - { - T value; - serializer.deserialize_to(value); - m_value = value; - } - -protected: - explicit Impl(SQLType sql_type) - : BaseImpl(sql_type) - { - } - - Optional m_value {}; -}; - -class TextImpl : public Impl { -public: - explicit TextImpl() - : Impl(SQLType::Text) - { - } - - [[nodiscard]] String to_string() const; - [[nodiscard]] Optional to_int() const; - [[nodiscard]] Optional to_double() const; - [[nodiscard]] Optional to_bool() const; - [[nodiscard]] static bool to_vector(Vector&) { return false; } - void assign(Value const&); - void assign_string(String const&); - void assign_int(int); - void assign_double(double); - void assign_bool(bool); - void assign_vector(Vector const&) { m_value = {}; } - [[nodiscard]] size_t length() const; - [[nodiscard]] static bool can_cast(Value const&) { return true; } - [[nodiscard]] int compare(Value const& other) const; - [[nodiscard]] u32 hash() const; -}; - -class IntegerImpl : public Impl { -public: - IntegerImpl() - : Impl(SQLType::Integer) - { - } - - [[nodiscard]] String to_string() const; - [[nodiscard]] Optional to_int() const; - [[nodiscard]] Optional to_double() const; - [[nodiscard]] Optional to_bool() const; - [[nodiscard]] static bool to_vector(Vector&) { return false; } - void assign(Value const&); - void assign_string(String const&); - void assign_int(int); - void assign_double(double); - void assign_bool(bool); - void assign_vector(Vector const&) { m_value = {}; } - [[nodiscard]] static bool can_cast(Value const&); - [[nodiscard]] int compare(Value const& other) const; - [[nodiscard]] u32 hash() const; -}; - -class FloatImpl : public Impl { -public: - explicit FloatImpl() - : Impl(SQLType::Float) - { - } - - [[nodiscard]] String to_string() const; - [[nodiscard]] Optional to_int() const; - [[nodiscard]] Optional to_double() const; - [[nodiscard]] Optional to_bool() const; - [[nodiscard]] static bool to_vector(Vector&) { return false; } - void assign(Value const&); - void assign_string(String const&); - void assign_int(int); - void assign_double(double); - void assign_bool(bool) { m_value = {}; } - void assign_vector(Vector const&) { m_value = {}; } - [[nodiscard]] static bool can_cast(Value const&); - [[nodiscard]] int compare(Value const& other) const; - - // Using floats in hash functions is a bad idea. Let's disable that for now. - [[nodiscard]] static u32 hash() { VERIFY_NOT_REACHED(); } -}; - -class BooleanImpl : public Impl { -public: - explicit BooleanImpl() - : Impl(SQLType::Boolean) - { - } - - [[nodiscard]] String to_string() const; - [[nodiscard]] Optional to_int() const; - [[nodiscard]] static Optional to_double(); - [[nodiscard]] Optional to_bool() const; - [[nodiscard]] static bool to_vector(Vector&) { return false; } - void assign(Value const&); - void assign_string(String const&); - void assign_int(int); - void assign_double(double); - void assign_bool(bool); - void assign_vector(Vector const&) { m_value = {}; } - [[nodiscard]] static bool can_cast(Value const&); - [[nodiscard]] int compare(Value const& other) const; - [[nodiscard]] u32 hash() const; -}; - -using BaseTypeImpl = Variant; - -class ContainerValueImpl : public Impl> { -public: - virtual ~ContainerValueImpl() = default; - - [[nodiscard]] String to_string() const; - [[nodiscard]] static Optional to_int() { return {}; } - [[nodiscard]] static Optional to_double() { return {}; } - [[nodiscard]] static Optional to_bool() { return {}; } - [[nodiscard]] bool to_vector(Vector&) const; - void assign_string(String const&) { m_value = {}; } - void assign_int(int) { m_value = {}; } - void assign_double(double) { m_value = {}; } - void assign_bool(bool) { m_value = {}; } - void assign_vector(Vector const&); - [[nodiscard]] u32 hash() const; - - virtual bool validate_before_assignment(Vector const&) { return true; } - virtual bool validate(BaseTypeImpl const&) { return true; } - virtual bool validate_after_assignment() { return true; } - [[nodiscard]] Vector to_string_vector() const; - [[nodiscard]] size_t length() const; - [[nodiscard]] size_t size() const { return is_null() ? 0 : value().size(); } - bool append(Value const&); - bool append(BaseTypeImpl const& value); - void serialize_values(Serializer&) const; - void deserialize_values(Serializer&); - -protected: - explicit ContainerValueImpl(SQLType sql_type) - : Impl(sql_type) - { - } -}; - -class TupleImpl : public ContainerValueImpl { -public: - explicit TupleImpl(NonnullRefPtr const& descriptor) - : ContainerValueImpl(SQLType::Tuple) - , m_descriptor(descriptor) - { - } - - explicit TupleImpl() - : ContainerValueImpl(SQLType::Tuple) - { - } - - void assign(Value const&); - [[nodiscard]] size_t length() const; - [[nodiscard]] bool can_cast(Value const&) const; - [[nodiscard]] int compare(Value const& other) const; - [[nodiscard]] Optional to_bool() const; - - virtual bool validate_before_assignment(Vector const&) override; - virtual bool validate(BaseTypeImpl const&) override; - virtual bool validate_after_assignment() override; - void serialize(Serializer&) const; - void deserialize(Serializer&); - -private: - void infer_descriptor(); - void extend_descriptor(Value const&); - RefPtr m_descriptor; - bool m_descriptor_inferred { false }; -}; - -class ArrayImpl : public ContainerValueImpl { -public: - explicit ArrayImpl(SQLType element_type, Optional const& max_size = {}) - : ContainerValueImpl(SQLType::Array) - , m_element_type(element_type) - , m_max_size(max_size) - { - } - - explicit ArrayImpl() - : ContainerValueImpl(SQLType::Array) - , m_element_type(SQLType::Null) - { - } - - void assign(Value const&); - [[nodiscard]] size_t length() const; - [[nodiscard]] bool can_cast(Value const&) const; - [[nodiscard]] int compare(Value const& other) const; - void serialize(Serializer&) const; - void deserialize(Serializer&); - virtual bool validate(BaseTypeImpl const&) override; - -private: - SQLType m_element_type { SQLType::Text }; - Optional m_max_size {}; -}; - -using ValueTypeImpl = Variant; - -}