Serenity Operating System
at master 257 lines 7.8 kB view raw
1/* 2 * Copyright (c) 2021, Jan de Visser <jan@de-visser.net> 3 * Copyright (c) 2021, Mahmoud Mandour <ma.mandourr@gmail.com> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/DeprecatedString.h> 9#include <AK/RefPtr.h> 10 11#include <LibSQL/BTree.h> 12#include <LibSQL/Database.h> 13#include <LibSQL/Heap.h> 14#include <LibSQL/Meta.h> 15#include <LibSQL/Row.h> 16#include <LibSQL/Tuple.h> 17 18namespace SQL { 19 20Database::Database(DeprecatedString name) 21 : m_heap(Heap::construct(move(name))) 22 , m_serializer(m_heap) 23{ 24} 25 26ResultOr<void> Database::open() 27{ 28 TRY(m_heap->open()); 29 30 m_schemas = BTree::construct(m_serializer, SchemaDef::index_def()->to_tuple_descriptor(), m_heap->schemas_root()); 31 m_schemas->on_new_root = [&]() { 32 m_heap->set_schemas_root(m_schemas->root()); 33 }; 34 35 m_tables = BTree::construct(m_serializer, TableDef::index_def()->to_tuple_descriptor(), m_heap->tables_root()); 36 m_tables->on_new_root = [&]() { 37 m_heap->set_tables_root(m_tables->root()); 38 }; 39 40 m_table_columns = BTree::construct(m_serializer, ColumnDef::index_def()->to_tuple_descriptor(), m_heap->table_columns_root()); 41 m_table_columns->on_new_root = [&]() { 42 m_heap->set_table_columns_root(m_table_columns->root()); 43 }; 44 45 m_open = true; 46 47 auto ensure_schema_exists = [&](auto schema_name) -> ResultOr<NonnullRefPtr<SchemaDef>> { 48 if (auto result = get_schema(schema_name); result.is_error()) { 49 if (result.error().error() != SQLErrorCode::SchemaDoesNotExist) 50 return result.release_error(); 51 52 auto schema_def = SchemaDef::construct(schema_name); 53 TRY(add_schema(*schema_def)); 54 return schema_def; 55 } else { 56 return result.release_value(); 57 } 58 }; 59 60 (void)TRY(ensure_schema_exists("default"sv)); 61 auto master_schema = TRY(ensure_schema_exists("master"sv)); 62 63 if (auto result = get_table("master"sv, "internal_describe_table"sv); result.is_error()) { 64 if (result.error().error() != SQLErrorCode::TableDoesNotExist) 65 return result.release_error(); 66 67 auto internal_describe_table = TableDef::construct(master_schema, "internal_describe_table"); 68 internal_describe_table->append_column("Name", SQLType::Text); 69 internal_describe_table->append_column("Type", SQLType::Text); 70 TRY(add_table(*internal_describe_table)); 71 } 72 73 return {}; 74} 75 76Database::~Database() = default; 77 78ErrorOr<void> Database::commit() 79{ 80 VERIFY(is_open()); 81 TRY(m_heap->flush()); 82 return {}; 83} 84 85ResultOr<void> Database::add_schema(SchemaDef const& schema) 86{ 87 VERIFY(is_open()); 88 89 if (!m_schemas->insert(schema.key())) 90 return Result { SQLCommand::Unknown, SQLErrorCode::SchemaExists, schema.name() }; 91 return {}; 92} 93 94Key Database::get_schema_key(DeprecatedString const& schema_name) 95{ 96 auto key = SchemaDef::make_key(); 97 key["schema_name"] = schema_name; 98 return key; 99} 100 101ResultOr<NonnullRefPtr<SchemaDef>> Database::get_schema(DeprecatedString const& schema) 102{ 103 VERIFY(is_open()); 104 105 auto schema_name = schema; 106 if (schema.is_empty()) 107 schema_name = "default"sv; 108 109 Key key = get_schema_key(schema_name); 110 if (auto it = m_schema_cache.find(key.hash()); it != m_schema_cache.end()) 111 return it->value; 112 113 auto schema_iterator = m_schemas->find(key); 114 if (schema_iterator.is_end() || (*schema_iterator != key)) 115 return Result { SQLCommand::Unknown, SQLErrorCode::SchemaDoesNotExist, schema_name }; 116 117 auto schema_def = SchemaDef::construct(*schema_iterator); 118 m_schema_cache.set(key.hash(), schema_def); 119 return schema_def; 120} 121 122ResultOr<void> Database::add_table(TableDef& table) 123{ 124 VERIFY(is_open()); 125 126 if (!m_tables->insert(table.key())) 127 return Result { SQLCommand::Unknown, SQLErrorCode::TableExists, table.name() }; 128 129 for (auto& column : table.columns()) { 130 if (!m_table_columns->insert(column->key())) 131 VERIFY_NOT_REACHED(); 132 } 133 134 return {}; 135} 136 137Key Database::get_table_key(DeprecatedString const& schema_name, DeprecatedString const& table_name) 138{ 139 auto key = TableDef::make_key(get_schema_key(schema_name)); 140 key["table_name"] = table_name; 141 return key; 142} 143 144ResultOr<NonnullRefPtr<TableDef>> Database::get_table(DeprecatedString const& schema, DeprecatedString const& name) 145{ 146 VERIFY(is_open()); 147 148 auto schema_name = schema; 149 if (schema.is_empty()) 150 schema_name = "default"sv; 151 152 Key key = get_table_key(schema_name, name); 153 if (auto it = m_table_cache.find(key.hash()); it != m_table_cache.end()) 154 return it->value; 155 156 auto table_iterator = m_tables->find(key); 157 if (table_iterator.is_end() || (*table_iterator != key)) 158 return Result { SQLCommand::Unknown, SQLErrorCode::TableDoesNotExist, DeprecatedString::formatted("{}.{}", schema_name, name) }; 159 160 auto schema_def = TRY(get_schema(schema)); 161 auto table_def = TableDef::construct(schema_def, name); 162 table_def->set_pointer((*table_iterator).pointer()); 163 m_table_cache.set(key.hash(), table_def); 164 165 auto table_hash = table_def->hash(); 166 auto column_key = ColumnDef::make_key(table_def); 167 for (auto it = m_table_columns->find(column_key); !it.is_end() && ((*it)["table_hash"].to_int<u32>() == table_hash); ++it) 168 table_def->append_column(*it); 169 170 return table_def; 171} 172 173ErrorOr<Vector<Row>> Database::select_all(TableDef& table) 174{ 175 VERIFY(m_table_cache.get(table.key().hash()).has_value()); 176 Vector<Row> ret; 177 for (auto pointer = table.pointer(); pointer; pointer = ret.last().next_pointer()) { 178 ret.append(m_serializer.deserialize_block<Row>(pointer, table, pointer)); 179 } 180 return ret; 181} 182 183ErrorOr<Vector<Row>> Database::match(TableDef& table, Key const& key) 184{ 185 VERIFY(m_table_cache.get(table.key().hash()).has_value()); 186 Vector<Row> ret; 187 188 // TODO Match key against indexes defined on table. If found, 189 // use the index instead of scanning the table. 190 for (auto pointer = table.pointer(); pointer;) { 191 auto row = m_serializer.deserialize_block<Row>(pointer, table, pointer); 192 if (row.match(key)) 193 ret.append(row); 194 pointer = ret.last().next_pointer(); 195 } 196 return ret; 197} 198 199ErrorOr<void> Database::insert(Row& row) 200{ 201 VERIFY(m_table_cache.get(row.table().key().hash()).has_value()); 202 // TODO Check constraints 203 204 row.set_pointer(m_heap->new_record_pointer()); 205 row.set_next_pointer(row.table().pointer()); 206 TRY(update(row)); 207 208 // TODO update indexes defined on table. 209 210 auto table_key = row.table().key(); 211 table_key.set_pointer(row.pointer()); 212 VERIFY(m_tables->update_key_pointer(table_key)); 213 row.table().set_pointer(row.pointer()); 214 return {}; 215} 216 217ErrorOr<void> Database::remove(Row& row) 218{ 219 auto& table = row.table(); 220 VERIFY(m_table_cache.get(table.key().hash()).has_value()); 221 222 if (table.pointer() == row.pointer()) { 223 auto table_key = table.key(); 224 table_key.set_pointer(row.next_pointer()); 225 m_tables->update_key_pointer(table_key); 226 227 table.set_pointer(row.next_pointer()); 228 return {}; 229 } 230 231 for (auto pointer = table.pointer(); pointer;) { 232 auto current = m_serializer.deserialize_block<Row>(pointer, table, pointer); 233 234 if (current.next_pointer() == row.pointer()) { 235 current.set_next_pointer(row.next_pointer()); 236 TRY(update(current)); 237 break; 238 } 239 240 pointer = current.next_pointer(); 241 } 242 243 return {}; 244} 245 246ErrorOr<void> Database::update(Row& tuple) 247{ 248 VERIFY(m_table_cache.get(tuple.table().key().hash()).has_value()); 249 // TODO Check constraints 250 m_serializer.reset(); 251 m_serializer.serialize_and_write<Tuple>(tuple); 252 253 // TODO update indexes defined on table. 254 return {}; 255} 256 257}