/* * Copyright (c) 2021, Jan de Visser * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include namespace SQL { Tuple::Tuple() : m_descriptor() , m_data() { } Tuple::Tuple(TupleDescriptor const& descriptor, u32 pointer) : m_descriptor(descriptor) , m_data() , m_pointer(pointer) { for (auto& element : descriptor) { m_data.append(Value(element.type)); } } Tuple::Tuple(TupleDescriptor const& descriptor, ByteBuffer& buffer, size_t& offset) : Tuple(descriptor) { deserialize(buffer, offset); } Tuple::Tuple(TupleDescriptor const& descriptor, ByteBuffer& buffer) : Tuple(descriptor) { size_t offset = 0; deserialize(buffer, offset); } void Tuple::deserialize(ByteBuffer& buffer, size_t& offset) { dbgln_if(SQL_DEBUG, "deserialize tuple at offset {}", offset); deserialize_from(buffer, offset, m_pointer); dbgln_if(SQL_DEBUG, "pointer: {}", m_pointer); m_data.clear(); for (auto& part : m_descriptor) { m_data.append(Value(part.type, buffer, offset)); dbgln_if(SQL_DEBUG, "Deserialized element {} = {}", part.name, m_data.last().to_string().value()); } } void Tuple::serialize(ByteBuffer& buffer) const { VERIFY(m_descriptor.size() == m_data.size()); dbgln_if(SQL_DEBUG, "Serializing tuple pointer {}", pointer()); serialize_to(buffer, pointer()); for (auto ix = 0u; ix < m_descriptor.size(); ix++) { auto& key_part = m_data[ix]; if constexpr (SQL_DEBUG) { auto str_opt = key_part.to_string(); auto& key_part_definition = m_descriptor[ix]; dbgln("Serialized part {} = {}", key_part_definition.name, (str_opt.has_value()) ? str_opt.value() : "(null)"); } key_part.serialize(buffer); } } Tuple::Tuple(Tuple const& other) : m_descriptor() , m_data() { copy_from(other); } Tuple& Tuple::operator=(Tuple const& other) { if (this != &other) { copy_from(other); } return *this; } Optional Tuple::index_of(String name) const { auto n = move(name); for (auto ix = 0u; ix < m_descriptor.size(); ix++) { auto& part = m_descriptor[ix]; if (part.name == n) { return (int)ix; } } return {}; } Value const& Tuple::operator[](size_t ix) const { VERIFY(ix < m_data.size()); return m_data[ix]; } Value& Tuple::operator[](size_t ix) { VERIFY(ix < m_data.size()); return m_data[ix]; } Value const& Tuple::operator[](String const& name) const { auto index = index_of(name); VERIFY(index.has_value()); return (*this)[index.value()]; } Value& Tuple::operator[](String const& name) { auto index = index_of(name); VERIFY(index.has_value()); return (*this)[index.value()]; } void Tuple::append(const Value& value) { VERIFY(m_descriptor.size() == 0); m_data.append(value); } Tuple& Tuple::operator+=(Value const& value) { append(value); return *this; } bool Tuple::is_compatible(Tuple const& other) const { if ((m_descriptor.size() == 0) && (other.m_descriptor.size() == 0)) { return true; } if (m_descriptor.size() != other.m_descriptor.size()) { return false; } for (auto ix = 0u; ix < m_descriptor.size(); ix++) { auto& my_part = m_descriptor[ix]; auto& other_part = other.m_descriptor[ix]; if (my_part.type != other_part.type) { return false; } if (my_part.order != other_part.order) { return false; } } return true; } String Tuple::to_string() const { StringBuilder builder; for (auto& part : m_data) { if (!builder.is_empty()) { builder.append('|'); } auto str_opt = part.to_string(); builder.append((str_opt.has_value()) ? str_opt.value() : "(null)"); } if (pointer() != 0) { builder.appendff(":{}", pointer()); } return builder.build(); } Vector Tuple::to_string_vector() const { Vector ret; for (auto& value : m_data) { ret.append(value.to_string().value()); } return ret; } size_t Tuple::size() const { size_t sz = sizeof(u32); for (auto& part : m_data) { sz += part.size(); } return sz; } void Tuple::copy_from(const Tuple& other) { m_descriptor.clear(); for (TupleElement const& part : other.m_descriptor) { m_descriptor.append(part); } m_data.clear(); for (auto& part : other.m_data) { m_data.append(part); } m_pointer = other.pointer(); } int Tuple::compare(const Tuple& other) const { auto num_values = min(m_data.size(), other.m_data.size()); VERIFY(num_values > 0); for (auto ix = 0u; ix < num_values; ix++) { auto ret = m_data[ix].compare(other.m_data[ix]); if (ret != 0) { if ((ix < m_descriptor.size()) && m_descriptor[ix].order == Order::Descending) ret = -ret; return ret; } } return 0; } int Tuple::match(const Tuple& other) const { auto other_index = 0u; for (auto& part : other.descriptor()) { auto other_value = other[other_index]; if (other_value.is_null()) return 0; auto my_index = index_of(part.name); if (!my_index.has_value()) return -1; auto ret = m_data[my_index.value()].compare(other_value); if (ret != 0) return (m_descriptor[my_index.value()].order == Order::Descending) ? -ret : ret; other_index++; } return 0; } u32 Tuple::hash() const { u32 ret = 0u; for (auto& value : m_data) { // This is an extension of the pair_int_hash function from AK/HashFunctions.h: if (!ret) ret = value.hash(); else ret = int_hash((ret * 209) ^ (value.hash() * 413)); } return ret; } }