diff --git a/Tests/LibSQL/TestSqlValueAndTuple.cpp b/Tests/LibSQL/TestSqlValueAndTuple.cpp index 4d055307004..3ff7d14f871 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 8e6cdd2ef2a..63a39c3b210 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 dd2a786d75e..663634c0a27 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 a3a79e58a64..419abc8909e 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 7b6b5ca2d29..5611cbaadd0 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 e731abadacb..bbd9a0ced8f 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 477e783a515..00000000000 --- 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; - -}