diff options
Diffstat (limited to 'Userland/Libraries/LibSQL/Value.cpp')
-rw-r--r-- | Userland/Libraries/LibSQL/Value.cpp | 542 |
1 files changed, 359 insertions, 183 deletions
diff --git a/Userland/Libraries/LibSQL/Value.cpp b/Userland/Libraries/LibSQL/Value.cpp index 5f36618993..86f2ecf94e 100644 --- a/Userland/Libraries/LibSQL/Value.cpp +++ b/Userland/Libraries/LibSQL/Value.cpp @@ -12,38 +12,115 @@ #include <LibSQL/Serializer.h> #include <LibSQL/TupleDescriptor.h> #include <LibSQL/Value.h> -#include <math.h> #include <string.h> namespace SQL { -Value::Value(SQLType type) - : m_type(type) +// We use the upper 4 bits of the encoded type to store extra information about the type. This +// includes if the value is null, and the encoded size of any integer type. Of course, this encoding +// only works if the SQL type itself fits in the lower 4 bits. +enum class SQLTypeWithCount { +#undef __ENUMERATE_SQL_TYPE +#define __ENUMERATE_SQL_TYPE(name, type) type, + ENUMERATE_SQL_TYPES(__ENUMERATE_SQL_TYPE) +#undef __ENUMERATE_SQL_TYPE + Count, +}; + +static_assert(to_underlying(SQLTypeWithCount::Count) <= 0x0f, "Too many SQL types for current encoding"); + +// Adding to this list is fine, but changing the order of any value here will result in LibSQL +// becoming unable to read existing .db files. If the order must absolutely be changed, be sure +// to bump Heap::current_version. +enum class TypeData : u8 { + Null = 1 << 4, + Int8 = 2 << 4, + Int16 = 3 << 4, + Int32 = 4 << 4, + Int64 = 5 << 4, + Uint8 = 6 << 4, + Uint16 = 7 << 4, + Uint32 = 8 << 4, + Uint64 = 9 << 4, +}; + +template<typename Callback> +static decltype(auto) downsize_integer(Integer auto value, Callback&& callback) +{ + if constexpr (IsSigned<decltype(value)>) { + if (AK::is_within_range<i8>(value)) + return callback(static_cast<i8>(value), TypeData::Int8); + if (AK::is_within_range<i16>(value)) + return callback(static_cast<i16>(value), TypeData::Int16); + if (AK::is_within_range<i32>(value)) + return callback(static_cast<i32>(value), TypeData::Int32); + return callback(value, TypeData::Int64); + } else { + if (AK::is_within_range<u8>(value)) + return callback(static_cast<i8>(value), TypeData::Uint8); + if (AK::is_within_range<u16>(value)) + return callback(static_cast<i16>(value), TypeData::Uint16); + if (AK::is_within_range<u32>(value)) + return callback(static_cast<i32>(value), TypeData::Uint32); + return callback(value, TypeData::Uint64); + } +} + +template<typename Callback> +static decltype(auto) downsize_integer(Value const& value, Callback&& callback) { + VERIFY(value.is_int()); + + if (value.value().has<i64>()) + return downsize_integer(value.value().get<i64>(), forward<Callback>(callback)); + return downsize_integer(value.value().get<u64>(), forward<Callback>(callback)); } -Value::Value(DeprecatedString value) - : m_type(SQLType::Text) - , m_value(move(value)) +template<typename Callback> +static ResultOr<Value> perform_integer_operation(Value const& lhs, Value const& rhs, Callback&& callback) { + VERIFY(lhs.is_int()); + VERIFY(rhs.is_int()); + + if (lhs.value().has<i64>()) { + if (auto rhs_value = rhs.to_int<i64>(); rhs_value.has_value()) + return callback(lhs.to_int<i64>().value(), rhs_value.value()); + } else { + if (auto rhs_value = rhs.to_int<u64>(); rhs_value.has_value()) + return callback(lhs.to_int<u64>().value(), rhs_value.value()); + } + + return Result { SQLCommand::Unknown, SQLErrorCode::IntegerOverflow }; } -Value::Value(int value) - : m_type(SQLType::Integer) - , m_value(value) +Value::Value(SQLType type) + : m_type(type) { } -Value::Value(u32 value) - : m_type(SQLType::Integer) - , m_value(static_cast<int>(value)) // FIXME: Handle signed overflow. +Value::Value(DeprecatedString value) + : m_type(SQLType::Text) + , m_value(move(value)) { } Value::Value(double value) - : m_type(SQLType::Float) - , m_value(value) { + if (trunc(value) == value) { + if (AK::is_within_range<i64>(value)) { + m_type = SQLType::Integer; + m_value = static_cast<i64>(value); + return; + } + if (AK::is_within_range<u64>(value)) { + m_type = SQLType::Integer; + m_value = static_cast<u64>(value); + return; + } + } + + m_type = SQLType::Float; + m_value = value; } Value::Value(NonnullRefPtr<TupleDescriptor> descriptor, Vector<Value> values) @@ -122,6 +199,11 @@ bool Value::is_null() const return !m_value.has_value(); } +bool Value::is_int() const +{ + return m_value.has_value() && (m_value->has<i64>() || m_value->has<u64>()); +} + DeprecatedString Value::to_deprecated_string() const { if (is_null()) @@ -129,7 +211,7 @@ DeprecatedString Value::to_deprecated_string() const return m_value->visit( [](DeprecatedString const& value) -> DeprecatedString { return value; }, - [](int value) -> DeprecatedString { return DeprecatedString::number(value); }, + [](Integer auto value) -> DeprecatedString { return DeprecatedString::number(value); }, [](double value) -> DeprecatedString { return DeprecatedString::number(value); }, [](bool value) -> DeprecatedString { return value ? "true"sv : "false"sv; }, [](TupleValue const& value) -> DeprecatedString { @@ -143,33 +225,6 @@ DeprecatedString Value::to_deprecated_string() const }); } -Optional<int> Value::to_int() const -{ - if (is_null()) - return {}; - - return m_value->visit( - [](DeprecatedString const& value) -> Optional<int> { return value.to_int(); }, - [](int value) -> Optional<int> { return value; }, - [](double value) -> Optional<int> { - if (value > static_cast<double>(NumericLimits<int>::max())) - return {}; - if (value < static_cast<double>(NumericLimits<int>::min())) - return {}; - return static_cast<int>(round(value)); - }, - [](bool value) -> Optional<int> { return static_cast<int>(value); }, - [](TupleValue const&) -> Optional<int> { return {}; }); -} - -Optional<u32> Value::to_u32() const -{ - // FIXME: Handle negative values. - if (auto result = to_int(); result.has_value()) - return static_cast<u32>(result.value()); - return {}; -} - Optional<double> Value::to_double() const { if (is_null()) @@ -184,7 +239,7 @@ Optional<double> Value::to_double() const return {}; return result; }, - [](int value) -> Optional<double> { return static_cast<double>(value); }, + [](Integer auto value) -> Optional<double> { return static_cast<double>(value); }, [](double value) -> Optional<double> { return value; }, [](bool value) -> Optional<double> { return static_cast<double>(value); }, [](TupleValue const&) -> Optional<double> { return {}; }); @@ -203,7 +258,7 @@ Optional<bool> Value::to_bool() const return false; return {}; }, - [](int value) -> Optional<bool> { return static_cast<bool>(value); }, + [](Integer auto value) -> Optional<bool> { return static_cast<bool>(value); }, [](double value) -> Optional<bool> { return fabs(value) > NumericLimits<double>::epsilon(); }, [](bool value) -> Optional<bool> { return value; }, [](TupleValue const& value) -> Optional<bool> { @@ -242,20 +297,6 @@ Value& Value::operator=(DeprecatedString value) return *this; } -Value& Value::operator=(int value) -{ - m_type = SQLType::Integer; - m_value = value; - return *this; -} - -Value& Value::operator=(u32 value) -{ - m_type = SQLType::Integer; - m_value = static_cast<int>(value); // FIXME: Handle signed overflow. - return *this; -} - Value& Value::operator=(double value) { m_type = SQLType::Float; @@ -318,7 +359,11 @@ size_t Value::length() const // FIXME: This seems to be more of an encoded byte size rather than a length. return m_value->visit( [](DeprecatedString const& value) -> size_t { return sizeof(u32) + value.length(); }, - [](int value) -> size_t { return sizeof(value); }, + [](Integer auto value) -> size_t { + return downsize_integer(value, [](auto integer, auto) { + return sizeof(integer); + }); + }, [](double value) -> size_t { return sizeof(value); }, [](bool value) -> size_t { return sizeof(value); }, [](TupleValue const& value) -> size_t { @@ -338,7 +383,14 @@ u32 Value::hash() const return m_value->visit( [](DeprecatedString const& value) -> u32 { return value.hash(); }, - [](int value) -> u32 { return int_hash(value); }, + [](Integer auto value) -> u32 { + return downsize_integer(value, [](auto integer, auto) { + if constexpr (sizeof(decltype(integer)) == 8) + return u64_hash(integer); + else + return int_hash(integer); + }); + }, [](double) -> u32 { VERIFY_NOT_REACHED(); }, [](bool value) -> u32 { return int_hash(value); }, [](TupleValue const& value) -> u32 { @@ -364,8 +416,8 @@ int Value::compare(Value const& other) const return m_value->visit( [&](DeprecatedString const& value) -> int { return value.view().compare(other.to_deprecated_string()); }, - [&](int value) -> int { - auto casted = other.to_int(); + [&](Integer auto value) -> int { + auto casted = other.to_int<IntegerType<decltype(value)>>(); if (!casted.has_value()) return 1; @@ -427,16 +479,6 @@ bool Value::operator==(StringView value) const return to_deprecated_string() == value; } -bool Value::operator==(int value) const -{ - return to_int() == value; -} - -bool Value::operator==(u32 value) const -{ - return to_u32() == value; -} - bool Value::operator==(double value) const { return to_double() == value; @@ -467,133 +509,218 @@ bool Value::operator>=(Value const& value) const return compare(value) >= 0; } -static Result invalid_type_for_numeric_operator(AST::BinaryOperator op) +template<typename Operator> +static Result invalid_type_for_numeric_operator(Operator op) { - return { SQLCommand::Unknown, SQLErrorCode::NumericOperatorTypeMismatch, BinaryOperator_name(op) }; + if constexpr (IsSame<Operator, AST::BinaryOperator>) + return { SQLCommand::Unknown, SQLErrorCode::NumericOperatorTypeMismatch, BinaryOperator_name(op) }; + else if constexpr (IsSame<Operator, AST::UnaryOperator>) + return { SQLCommand::Unknown, SQLErrorCode::NumericOperatorTypeMismatch, UnaryOperator_name(op) }; + else + static_assert(DependentFalse<Operator>); } ResultOr<Value> Value::add(Value const& other) const { - if (auto double_maybe = to_double(); double_maybe.has_value()) { - if (auto other_double_maybe = other.to_double(); other_double_maybe.has_value()) - return Value(double_maybe.value() + other_double_maybe.value()); - if (auto int_maybe = other.to_int(); int_maybe.has_value()) - return Value(double_maybe.value() + (double)int_maybe.value()); - } else if (auto int_maybe = to_int(); int_maybe.has_value()) { - if (auto other_double_maybe = other.to_double(); other_double_maybe.has_value()) - return Value(other_double_maybe.value() + (double)int_maybe.value()); - if (auto other_int_maybe = other.to_int(); other_int_maybe.has_value()) - return Value(int_maybe.value() + other_int_maybe.value()); + if (is_int() && other.is_int()) { + return perform_integer_operation(*this, other, [](auto lhs, auto rhs) -> ResultOr<Value> { + Checked result { lhs }; + result.add(rhs); + + if (result.has_overflow()) + return Result { SQLCommand::Unknown, SQLErrorCode::IntegerOverflow }; + return Value { result.value_unchecked() }; + }); } - return invalid_type_for_numeric_operator(AST::BinaryOperator::Plus); + + auto lhs = to_double(); + auto rhs = other.to_double(); + + if (!lhs.has_value() || !rhs.has_value()) + return invalid_type_for_numeric_operator(AST::BinaryOperator::Plus); + return Value { lhs.value() + rhs.value() }; } ResultOr<Value> Value::subtract(Value const& other) const { - if (auto double_maybe = to_double(); double_maybe.has_value()) { - if (auto other_double_maybe = other.to_double(); other_double_maybe.has_value()) - return Value(double_maybe.value() - other_double_maybe.value()); - if (auto int_maybe = other.to_int(); int_maybe.has_value()) - return Value(double_maybe.value() - (double)int_maybe.value()); - } else if (auto int_maybe = to_int(); int_maybe.has_value()) { - if (auto other_double_maybe = other.to_double(); other_double_maybe.has_value()) - return Value((double)int_maybe.value() - other_double_maybe.value()); - if (auto other_int_maybe = other.to_int(); other_int_maybe.has_value()) - return Value(int_maybe.value() - other_int_maybe.value()); + if (is_int() && other.is_int()) { + return perform_integer_operation(*this, other, [](auto lhs, auto rhs) -> ResultOr<Value> { + Checked result { lhs }; + result.sub(rhs); + + if (result.has_overflow()) + return Result { SQLCommand::Unknown, SQLErrorCode::IntegerOverflow }; + return Value { result.value_unchecked() }; + }); } - return invalid_type_for_numeric_operator(AST::BinaryOperator::Minus); + + auto lhs = to_double(); + auto rhs = other.to_double(); + + if (!lhs.has_value() || !rhs.has_value()) + return invalid_type_for_numeric_operator(AST::BinaryOperator::Minus); + return Value { lhs.value() - rhs.value() }; } ResultOr<Value> Value::multiply(Value const& other) const { - if (auto double_maybe = to_double(); double_maybe.has_value()) { - if (auto other_double_maybe = other.to_double(); other_double_maybe.has_value()) - return Value(double_maybe.value() * other_double_maybe.value()); - if (auto int_maybe = other.to_int(); int_maybe.has_value()) - return Value(double_maybe.value() * (double)int_maybe.value()); - } else if (auto int_maybe = to_int(); int_maybe.has_value()) { - if (auto other_double_maybe = other.to_double(); other_double_maybe.has_value()) - return Value((double)int_maybe.value() * other_double_maybe.value()); - if (auto other_int_maybe = other.to_int(); other_int_maybe.has_value()) - return Value(int_maybe.value() * other_int_maybe.value()); + if (is_int() && other.is_int()) { + return perform_integer_operation(*this, other, [](auto lhs, auto rhs) -> ResultOr<Value> { + Checked result { lhs }; + result.mul(rhs); + + if (result.has_overflow()) + return Result { SQLCommand::Unknown, SQLErrorCode::IntegerOverflow }; + return Value { result.value_unchecked() }; + }); } - return invalid_type_for_numeric_operator(AST::BinaryOperator::Multiplication); + + auto lhs = to_double(); + auto rhs = other.to_double(); + + if (!lhs.has_value() || !rhs.has_value()) + return invalid_type_for_numeric_operator(AST::BinaryOperator::Multiplication); + return Value { lhs.value() * rhs.value() }; } ResultOr<Value> Value::divide(Value const& other) const { - if (auto double_maybe = to_double(); double_maybe.has_value()) { - if (auto other_double_maybe = other.to_double(); other_double_maybe.has_value()) - return Value(double_maybe.value() / other_double_maybe.value()); - if (auto int_maybe = other.to_int(); int_maybe.has_value()) - return Value(double_maybe.value() / (double)int_maybe.value()); - } else if (auto int_maybe = to_int(); int_maybe.has_value()) { - if (auto other_double_maybe = other.to_double(); other_double_maybe.has_value()) - return Value((double)int_maybe.value() / other_double_maybe.value()); - if (auto other_int_maybe = other.to_int(); other_int_maybe.has_value()) - return Value(int_maybe.value() / other_int_maybe.value()); - } - return invalid_type_for_numeric_operator(AST::BinaryOperator::Division); + auto lhs = to_double(); + auto rhs = other.to_double(); + + if (!lhs.has_value() || !rhs.has_value()) + return invalid_type_for_numeric_operator(AST::BinaryOperator::Division); + if (rhs == 0.0) + return Result { SQLCommand::Unknown, SQLErrorCode::IntegerOverflow }; + + return Value { lhs.value() / rhs.value() }; } ResultOr<Value> Value::modulo(Value const& other) const { - auto int_maybe_1 = to_int(); - auto int_maybe_2 = other.to_int(); - if (!int_maybe_1.has_value() || !int_maybe_2.has_value()) + if (!is_int() || !other.is_int()) return invalid_type_for_numeric_operator(AST::BinaryOperator::Modulo); - return Value(int_maybe_1.value() % int_maybe_2.value()); + + return perform_integer_operation(*this, other, [](auto lhs, auto rhs) -> ResultOr<Value> { + Checked result { lhs }; + result.mod(rhs); + + if (result.has_overflow()) + return Result { SQLCommand::Unknown, SQLErrorCode::IntegerOverflow }; + return Value { result.value_unchecked() }; + }); +} + +ResultOr<Value> Value::negate() const +{ + if (type() == SQLType::Integer) { + auto value = to_int<i64>(); + if (!value.has_value()) + return invalid_type_for_numeric_operator(AST::UnaryOperator::Minus); + + return Value { value.value() * -1 }; + } + + if (type() == SQLType::Float) + return Value { -to_double().value() }; + + return invalid_type_for_numeric_operator(AST::UnaryOperator::Minus); } ResultOr<Value> Value::shift_left(Value const& other) const { - auto u32_maybe = to_u32(); - auto num_bytes_maybe = other.to_int(); - if (!u32_maybe.has_value() || !num_bytes_maybe.has_value()) + if (!is_int() || !other.is_int()) return invalid_type_for_numeric_operator(AST::BinaryOperator::ShiftLeft); - return Value(u32_maybe.value() << num_bytes_maybe.value()); + + return perform_integer_operation(*this, other, [](auto lhs, auto rhs) -> ResultOr<Value> { + using LHS = decltype(lhs); + using RHS = decltype(rhs); + + static constexpr auto max_shift = static_cast<RHS>(sizeof(LHS) * 8); + if (rhs < 0 || rhs >= max_shift) + return Result { SQLCommand::Unknown, SQLErrorCode::IntegerOverflow }; + + return Value { lhs << rhs }; + }); } ResultOr<Value> Value::shift_right(Value const& other) const { - auto u32_maybe = to_u32(); - auto num_bytes_maybe = other.to_int(); - if (!u32_maybe.has_value() || !num_bytes_maybe.has_value()) + if (!is_int() || !other.is_int()) return invalid_type_for_numeric_operator(AST::BinaryOperator::ShiftRight); - return Value(u32_maybe.value() >> num_bytes_maybe.value()); + + return perform_integer_operation(*this, other, [](auto lhs, auto rhs) -> ResultOr<Value> { + using LHS = decltype(lhs); + using RHS = decltype(rhs); + + static constexpr auto max_shift = static_cast<RHS>(sizeof(LHS) * 8); + if (rhs < 0 || rhs >= max_shift) + return Result { SQLCommand::Unknown, SQLErrorCode::IntegerOverflow }; + + return Value { lhs >> rhs }; + }); } ResultOr<Value> Value::bitwise_or(Value const& other) const { - auto u32_maybe_1 = to_u32(); - auto u32_maybe_2 = other.to_u32(); - if (!u32_maybe_1.has_value() || !u32_maybe_2.has_value()) + if (!is_int() || !other.is_int()) return invalid_type_for_numeric_operator(AST::BinaryOperator::BitwiseOr); - return Value(u32_maybe_1.value() | u32_maybe_2.value()); + + return perform_integer_operation(*this, other, [](auto lhs, auto rhs) { + return Value { lhs | rhs }; + }); } ResultOr<Value> Value::bitwise_and(Value const& other) const { - auto u32_maybe_1 = to_u32(); - auto u32_maybe_2 = other.to_u32(); - if (!u32_maybe_1.has_value() || !u32_maybe_2.has_value()) + if (!is_int() || !other.is_int()) return invalid_type_for_numeric_operator(AST::BinaryOperator::BitwiseAnd); - return Value(u32_maybe_1.value() & u32_maybe_2.value()); + + return perform_integer_operation(*this, other, [](auto lhs, auto rhs) { + return Value { lhs & rhs }; + }); } -static constexpr auto sql_type_null_as_flag = static_cast<u8>(SQLType::Null); +ResultOr<Value> Value::bitwise_not() const +{ + if (!is_int()) + return invalid_type_for_numeric_operator(AST::UnaryOperator::BitwiseNot); + + return downsize_integer(*this, [](auto value, auto) { + return Value { ~value }; + }); +} -void Value::serialize(Serializer& serializer) const +static u8 encode_type_flags(Value const& value) { - auto type_flags = static_cast<u8>(type()); - if (is_null()) - type_flags |= sql_type_null_as_flag; + auto type_flags = to_underlying(value.type()); + + if (value.is_null()) { + type_flags |= to_underlying(TypeData::Null); + } else if (value.is_int()) { + downsize_integer(value, [&](auto, auto type_data) { + type_flags |= to_underlying(type_data); + }); + } + return type_flags; +} + +void Value::serialize(Serializer& serializer) const +{ + auto type_flags = encode_type_flags(*this); serializer.serialize<u8>(type_flags); if (is_null()) return; + if (is_int()) { + downsize_integer(*this, [&](auto integer, auto) { + serializer.serialize(integer); + }); + return; + } + m_value->visit( [&](TupleValue const& value) { serializer.serialize<TupleDescriptor>(*value.descriptor); @@ -608,16 +735,11 @@ void Value::serialize(Serializer& serializer) const void Value::deserialize(Serializer& serializer) { auto type_flags = serializer.deserialize<u8>(); - bool has_value = true; - 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; - } - - m_type = static_cast<SQLType>(type_flags); + auto type_data = static_cast<TypeData>(type_flags & 0xf0); + m_type = static_cast<SQLType>(type_flags & 0x0f); - if (!has_value) + if (type_data == TypeData::Null) return; switch (m_type) { @@ -628,7 +750,35 @@ void Value::deserialize(Serializer& serializer) m_value = serializer.deserialize<DeprecatedString>(); break; case SQLType::Integer: - m_value = serializer.deserialize<int>(0); + switch (type_data) { + case TypeData::Int8: + m_value = static_cast<i64>(serializer.deserialize<i8>(0)); + break; + case TypeData::Int16: + m_value = static_cast<i64>(serializer.deserialize<i16>(0)); + break; + case TypeData::Int32: + m_value = static_cast<i64>(serializer.deserialize<i32>(0)); + break; + case TypeData::Int64: + m_value = static_cast<i64>(serializer.deserialize<i64>(0)); + break; + case TypeData::Uint8: + m_value = static_cast<u64>(serializer.deserialize<u8>(0)); + break; + case TypeData::Uint16: + m_value = static_cast<u64>(serializer.deserialize<u16>(0)); + break; + case TypeData::Uint32: + m_value = static_cast<u64>(serializer.deserialize<u32>(0)); + break; + case TypeData::Uint64: + m_value = static_cast<u64>(serializer.deserialize<u64>(0)); + break; + default: + VERIFY_NOT_REACHED(); + break; + } break; case SQLType::Float: m_value = serializer.deserialize<double>(0.0); @@ -673,11 +823,9 @@ ResultOr<NonnullRefPtr<TupleDescriptor>> Value::infer_tuple_descriptor(Vector<Va template<> bool IPC::encode(Encoder& encoder, SQL::Value const& value) { - auto type_flags = to_underlying(value.type()); - if (value.is_null()) - type_flags |= SQL::sql_type_null_as_flag; - + auto type_flags = encode_type_flags(value); encoder << type_flags; + if (value.is_null()) return true; @@ -688,7 +836,9 @@ bool IPC::encode(Encoder& encoder, SQL::Value const& value) encoder << value.to_deprecated_string(); break; case SQL::SQLType::Integer: - encoder << value.to_int().value(); + SQL::downsize_integer(value, [&](auto integer, auto) { + encoder << integer; + }); break; case SQL::SQLType::Float: encoder << value.to_double().value(); @@ -704,46 +854,72 @@ bool IPC::encode(Encoder& encoder, SQL::Value const& value) return true; } +template<typename T> +static ErrorOr<void> decode_scalar(IPC::Decoder& decoder, SQL::Value& value) +{ + T decoded {}; + TRY(decoder.decode(decoded)); + value = move(decoded); + return {}; +} + template<> ErrorOr<void> IPC::decode(Decoder& decoder, SQL::Value& value) { - UnderlyingType<SQL::SQLType> type_flags; + u8 type_flags { 0 }; TRY(decoder.decode(type_flags)); - if ((type_flags & SQL::sql_type_null_as_flag) && (type_flags != SQL::sql_type_null_as_flag)) { - type_flags &= ~SQL::sql_type_null_as_flag; + auto type_data = static_cast<SQL::TypeData>(type_flags & 0xf0); + auto type = static_cast<SQL::SQLType>(type_flags & 0x0f); - value = SQL::Value(static_cast<SQL::SQLType>(type_flags)); + if (type_data == SQL::TypeData::Null) { + value = SQL::Value(type); return {}; } - switch (static_cast<SQL::SQLType>(type_flags)) { + switch (type) { case SQL::SQLType::Null: break; - case SQL::SQLType::Text: { - DeprecatedString text; - TRY(decoder.decode(text)); - value = move(text); + case SQL::SQLType::Text: + TRY(decode_scalar<DeprecatedString>(decoder, value)); break; - } - case SQL::SQLType::Integer: { - int number { 0 }; - TRY(decoder.decode(number)); - value = number; + case SQL::SQLType::Integer: + switch (type_data) { + case SQL::TypeData::Int8: + TRY(decode_scalar<i8>(decoder, value)); + break; + case SQL::TypeData::Int16: + TRY(decode_scalar<i16>(decoder, value)); + break; + case SQL::TypeData::Int32: + TRY(decode_scalar<i32>(decoder, value)); + break; + case SQL::TypeData::Int64: + TRY(decode_scalar<i64>(decoder, value)); + break; + case SQL::TypeData::Uint8: + TRY(decode_scalar<u8>(decoder, value)); + break; + case SQL::TypeData::Uint16: + TRY(decode_scalar<u16>(decoder, value)); + break; + case SQL::TypeData::Uint32: + TRY(decode_scalar<u32>(decoder, value)); + break; + case SQL::TypeData::Uint64: + TRY(decode_scalar<u64>(decoder, value)); + break; + default: + VERIFY_NOT_REACHED(); + break; + } break; - } - case SQL::SQLType::Float: { - double number { 0.0 }; - TRY(decoder.decode(number)); - value = number; + case SQL::SQLType::Float: + TRY(decode_scalar<double>(decoder, value)); break; - } - case SQL::SQLType::Boolean: { - bool boolean { false }; - TRY(decoder.decode(boolean)); - value = boolean; + case SQL::SQLType::Boolean: + TRY(decode_scalar<bool>(decoder, value)); break; - } case SQL::SQLType::Tuple: { Vector<SQL::Value> tuple; TRY(decoder.decode(tuple)); |