Serenity Operating System
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}