/* * Copyright (c) 2021, Jan de Visser * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include namespace SQL { Value::Value(SQLType sql_type) { setup(sql_type); } void Value::setup(SQLType type) { switch (type) { #undef __ENUMERATE_SQL_TYPE #define __ENUMERATE_SQL_TYPE(name, cardinal, type, impl, size) \ case SQLType::type: \ m_impl.set(type##Impl()); \ break; ENUMERATE_SQL_TYPES(__ENUMERATE_SQL_TYPE) #undef __ENUMERATE_SQL_TYPE default: VERIFY_NOT_REACHED(); } } 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(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(); } String Value::to_string() const { if (is_null()) return "(null)"; return m_impl.visit([&](auto& impl) { return impl.to_string(); }); } Optional Value::to_int() const { if (is_null()) return {}; return m_impl.visit([&](auto& impl) { return impl.to_int(); }); } Optional Value::to_u32() const { if (is_null()) return {}; auto ret = to_int(); if (ret.has_value()) return static_cast(ret.value()); return {}; } Optional Value::to_double() const { if (is_null()) return {}; return m_impl.visit([&](auto& impl) { return impl.to_double(); }); } Optional Value::to_bool() const { if (is_null()) return {}; return m_impl.visit([&](auto& impl) { return impl.to_bool(); }); } 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 return {}; } Value::operator String() const { return to_string(); } Value::operator int() const { auto i = to_int(); VERIFY(i.has_value()); return i.value(); } Value::operator u32() const { auto i = to_u32(); VERIFY(i.has_value()); return i.value(); } Value::operator double() const { auto d = to_double(); VERIFY(d.has_value()); return d.value(); } Value::operator bool() const { auto b = to_bool(); VERIFY(b.has_value()); return b.value(); } void Value::assign(Value const& other_value) { m_impl.visit([&](auto& impl) { impl.assign(other_value); }); } void Value::assign(String const& string_value) { m_impl.visit([&](auto& impl) { impl.assign_string(string_value); }); } void Value::assign(int const& int_value) { m_impl.visit([&](auto& impl) { impl.assign_int(int_value); }); } void Value::assign(double const& double_value) { m_impl.visit([&](auto& impl) { impl.assign_double(double_value); }); } void Value::assign(bool const& 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 { 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); } Value& Value::operator=(int value) { assign(value); return (*this); } Value& Value::operator=(u32 value) { assign(static_cast(value)); return (*this); } Value& Value::operator=(double value) { assign(value); return (*this); } Value& Value::operator=(bool value) { assign(value); return (*this); } Value& Value::operator=(Vector const& vector) { assign(vector); return (*this); } size_t Value::length() const { return m_impl.visit([&](auto& impl) { return impl.length(); }); } u32 Value::hash() const { return (is_null()) ? 0u : m_impl.visit([&](auto& impl) { return impl.hash(); }); } 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); }); } int Value::compare(Value const& other) const { if (is_null()) return -1; if (other.is_null()) return 1; return m_impl.visit([&](auto& impl) { return impl.compare(other); }); } bool Value::operator==(Value const& other) const { return compare(other) == 0; } bool Value::operator==(String const& string_value) const { return to_string() == string_value; } bool Value::operator==(int int_value) const { auto i = to_int(); if (!i.has_value()) return false; return i.value() == int_value; } bool Value::operator==(double double_value) const { auto d = to_double(); if (!d.has_value()) return false; return d.value() == double_value; } bool Value::operator!=(Value const& other) const { return compare(other) != 0; } bool Value::operator<(Value const& other) const { return compare(other) < 0; } bool Value::operator<=(Value const& other) const { return compare(other) <= 0; } bool Value::operator>(Value const& other) const { return compare(other) > 0; } bool Value::operator>=(Value const& other) const { return compare(other) >= 0; } void Value::serialize(Serializer& serializer) const { u8 type_flags = (u8)type(); if (is_null()) type_flags |= (u8)SQLType::Null; serializer.serialize(type_flags); if (!is_null()) m_impl.visit([&](auto& impl) { serializer.serialize(impl); }); } 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 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") || value().equals_ignoring_case("t")) return true; if (value().equals_ignoring_case("false") || value().equals_ignoring_case("f")) 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; } return value() - casted.value(); } 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_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; } auto diff = value() - casted.value(); return (diff < NumericLimits::epsilon()) ? 0 : ((diff > 0) ? 1 : -1); } 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 = {}; return; } 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(", ", 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) { auto sz = serializer.deserialize(); m_value = Vector(); for (auto ix = 0u; ix < sz; ix++) { append(serializer.deserialize()); } } size_t ContainerValueImpl::length() const { size_t len = sizeof(u32); for (auto& impl : value()) { len += Value(impl).length(); } return len; } 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()); } 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) 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; } 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; } }