Joedb 10.4.6
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Database_Writable_h.cpp
Go to the documentation of this file.
3#include "joedb/ui/type_io.h"
4
5#include <set>
6
7namespace joedb::generator
8{
9 ////////////////////////////////////////////////////////////////////////////
11 ////////////////////////////////////////////////////////////////////////////
12 (
14 ):
15 Generator(".", "Database_Writable.h", options)
16 {
17 }
18
19 ////////////////////////////////////////////////////////////////////////////
20 void Database_Writable_h::write(std::ostream &out)
21 ////////////////////////////////////////////////////////////////////////////
22 {
23 const Database_Schema &db = options.get_db();
24 auto tables = db.get_tables();
25
26 namespace_include_guard_open(out, "Database_Writable", options.get_name_space());
27
28 out << R"RRR(
29#include "joedb/journal/Writable_Journal.h"
30#include "joedb/journal/Memory_File.h"
31#include "joedb/error/Out_Of_Date.h"
32#include "Database.h"
33
34#include <string>
35#include <stdint.h>
36#include <cstring>
37#include <vector>
38
39)RRR";
40
41 namespace_open(out, options.get_name_space());
42
43 out << R"RRR(
44 namespace detail
45 {
46 extern const char * schema_string;
47 inline constexpr size_t schema_string_size = )RRR";
48
49 out << options.schema_file.get_size() << ";\n }\n\n";
50
51 for (const auto &[tid, tname]: tables)
52 out << " class container_of_" << tname << ";\n";
53
54 out << R"RRR(
55 /// implement @ref joedb::Writable in a @ref Database
56 class Database_Writable: public Database, public joedb::Writable
57 {
58 protected:
59 joedb::index_t max_record_id;
60 Table_Id current_table_id = Table_Id{0};
61)RRR";
62
63 //
64 // delete_from writable function
65 //
66 out << '\n';
67 out << " void delete_from(Table_Id table_id, Record_Id record_id) override\n";
68 out << " {\n";
69 {
70 bool first = true;
71 for (const auto &[tid, tname]: tables)
72 {
73 out << " ";
74 if (first)
75 first = false;
76 else
77 out << "else ";
78
79 out << "if (table_id == Table_Id(" << tid << "))\n";
80 out << " internal_delete_" << tname << "(record_id);\n";
81 }
82 }
83 out << " }\n";
84
85 //
86 // insert_into
87 //
88 out << '\n';
89 out << " void insert_into(Table_Id table_id, Record_Id record_id) override\n";
90 out << " {\n";
91 out << " if (to_underlying(record_id) < 0 || (max_record_id && to_underlying(record_id) >= max_record_id))\n";
92 out << " throw_exception(\"insert_into: too big\");\n";
93 {
94 bool first = true;
95 for (const auto &[tid, tname]: tables)
96 {
97 out << " ";
98 if (first)
99 first = false;
100 else
101 out << "else ";
102
103 out << "if (table_id == Table_Id(" << tid << "))\n";
104 out << " {\n";
105 out << " if (is_valid_record_id_for_" << tname << "(record_id))\n";
106 out << " throw_exception(\"Duplicate insert into table " << tname << "\");\n";
107 out << " if (storage_of_" << tname << ".size() <= size_t(record_id))\n";
108 out << " storage_of_" << tname << ".resize(to_underlying(record_id) + 1);\n";
109 out << " internal_insert_" << tname << "(record_id);\n";
110 out << " }\n";
111 }
112 }
113 out << " }\n";
114
115 //
116 // insert_vector
117 //
118 out << R"RRR(
119 void delete_vector
120 (
121 Table_Id table_id,
122 Record_Id record_id,
123 size_t size
124 ) override
125 {
126 joedb::Freedom_Keeper *fk = nullptr;
127
128)RRR";
129
130 {
131 bool first = true;
132 for (const auto &[tid, tname]: tables)
133 {
134 out << " ";
135 if (first)
136 first = false;
137 else
138 out << "else ";
139
140 out << "if (table_id == Table_Id(" << tid << "))\n";
141 out << " fk = &storage_of_" << tname << ".freedom_keeper;\n";
142 }
143 }
144
145 out << R"RRR(
146 if (fk)
147 {
148 JOEDB_RELEASE_ASSERT(fk->is_used_vector(record_id, size));
149 joedb::Writable::delete_vector(table_id, record_id, size);
150 }
151 }
152
153 void insert_vector
154 (
155 Table_Id table_id,
156 Record_Id record_id,
157 size_t size
158 ) override
159 {
160 if
161 (
162 to_underlying(record_id) < 0 ||
163 (max_record_id && (to_underlying(record_id) >= max_record_id || joedb::index_t(size) >= max_record_id))
164 )
165 {
166 throw_exception("insert_vector: null record_id, or too big");
167 }
168)RRR";
169
170 {
171 bool first = true;
172 for (const auto &[tid, tname]: tables)
173 {
174 out << " ";
175 if (first)
176 first = false;
177 else
178 out << "else ";
179
180 out << "if (table_id == Table_Id(" << tid << "))\n";
181 out << " {\n";
182 out << " if (storage_of_" << tname << ".size() < size_t(record_id) + size)\n";
183 out << " storage_of_" << tname << ".resize(to_underlying(record_id) + size);\n";
184 out << " internal_vector_insert_" << tname << "(record_id, size);\n";
185 out << " }\n";
186 }
187 }
188 out << " }\n";
189
190 //
191 // set of existing types in the database
192 //
193 std::set<Type::Type_Id> db_types;
194
195 for (const auto &[tid, tname]: tables)
196 for (const auto &[fid, fname]: db.get_fields(tid))
197 db_types.insert(db.get_field_type(tid, fid).get_type_id());
198
199 //
200 // update
201 //
202 {
203 for (int type_index = 1; type_index < int(Type::type_ids); type_index++)
204 {
205 const Type::Type_Id type_id = Type::Type_Id(type_index);
206 if (db_types.find(type_id) == db_types.end())
207 continue;
208
209 out << '\n';
210 out << " void update_" << get_type_string(type_id) << '\n';
211 out << " (\n";
212 out << " Table_Id table_id,\n";
213 out << " Record_Id record_id,\n";
214 out << " Field_Id field_id,\n";
215 out << " " << get_cpp_type_string(type_id) << " value\n";
216 out << " )\n";
217 out << " override\n";
218 out << " {\n";
219
220 for (const auto &[tid, tname]: tables)
221 {
222 if (table_has_field_type(tid, type_id))
223 {
224 out << " if (table_id == Table_Id(" << tid << "))\n";
225 out << " {\n";
226
227 for (const auto &[fid, fname]: db.get_fields(tid))
228 {
229 const Type &type = db.get_field_type(tid, fid);
230 if (type.get_type_id() == type_id)
231 {
232 out << " if (field_id == Field_Id(" << fid << "))\n";
233 out << " {\n";
234 out << " internal_update_" << tname;
235 out << "__" << fname << "(record_id, ";
237 out << "value";
238 else
239 {
240 out << "id_of_" << db.get_table_name(type.get_table_id());
241 out << "(value)";
242 }
243 out << ");\n";
244 out << " return;\n";
245 out << " }\n";
246 }
247 }
248
249 out << " return;\n";
250 out << " }\n";
251 }
252 }
253
254 out << " }\n";
255 }
256 }
257
258 //
259 // update_vector
260 //
261 {
262 for (int type_index = 1; type_index < int(Type::type_ids); type_index++)
263 {
264 const auto type_id = Type::Type_Id(type_index);
265 if (db_types.find(Type::Type_Id(type_id)) == db_types.end())
266 continue;
267
268 out << '\n';
269 out << " void update_vector_" << get_type_string(type_id) << '\n';
270 out << " (\n";
271 out << " Table_Id table_id,\n";
272 out << " Record_Id record_id,\n";
273 out << " Field_Id field_id,\n";
274 out << " size_t size,\n";
275 out << " const " << get_storage_type_string(type_id) << " *value\n";
276 out << " )\n";
277 out << " override\n";
278 out << " {\n";
279
280 for (const auto &[tid, tname]: tables)
281 {
282 if (table_has_field_type(tid, type_id))
283 {
284 out << " if (table_id == Table_Id(" << tid << "))\n";
285 out << " {\n";
286
287 for (const auto &[fid, fname]: db.get_fields(tid))
288 {
289 const Type &type = db.get_field_type(tid, fid);
290 if (type.get_type_id() == type_id)
291 {
292 out << " if (field_id == Field_Id(" << fid << "))\n";
293 out << " {\n";
294 out << " internal_update_vector_" << tname;
295 out << "__" << fname << "(record_id, size, ";
296
297 if (type_id != joedb::Type::Type_Id::reference)
298 out << "value";
299 else
300 {
301 out << "reinterpret_cast<const ";
302 write_type(out, type, false, false);
303 out << "*>(value)";
304 }
305
306 out << ");\n";
307 out << " return;\n";
308 out << " }\n";
309 }
310 }
311
312 out << " return;\n";
313 out << " }\n";
314 }
315 }
316
317 out << " }\n";
318 }
319 }
320
321 //
322 // get_own_storage
323 //
324 {
325 for (int type_index = 1; type_index < int(Type::type_ids); type_index++)
326 {
327 const Type::Type_Id type_id = Type::Type_Id(type_index);
328 if (db_types.find(Type::Type_Id(type_id)) == db_types.end())
329 continue;
330
331 out << '\n';
332 out << " " << get_storage_type_string(type_id);
333 out << " *get_own_" << get_type_string(type_id) << "_storage\n";
334 out << " (\n";
335 out << " Table_Id table_id,\n";
336 out << " Record_Id record_id,\n";
337 out << " Field_Id field_id,\n";
338 out << " size_t &capacity\n";
339 out << " )\n";
340 out << " override\n";
341 out << " {\n";
342
343 for (const auto &[tid, tname]: tables)
344 {
345 if (table_has_field_type(tid, type_id))
346 {
347 out << " if (table_id == Table_Id(" << tid << "))\n";
348 out << " {\n";
349 out << " capacity = size_t(storage_of_" << tname << ".freedom_keeper.size());\n";
350
351 for (const auto &[fid, fname]: db.get_fields(tid))
352 {
353 const Type &type = db.get_field_type(tid, fid);
354 if (type.get_type_id() == type_id)
355 {
356 out << " if (field_id == Field_Id(" << fid << "))\n"
357 << " {\n"
358 << " return ";
359
360 if (type_id == Type::Type_Id::reference)
361 out << "reinterpret_cast<Record_Id *>";
362
363 out << "(storage_of_" << tname;
364 out << ".field_value_of_" << fname << ".data() + to_underlying(record_id));\n"
365 << " }\n";
366 }
367 }
368
369 out << " return nullptr;\n";
370 out << " }\n";
371 }
372 }
373
374 out << " return nullptr;\n";
375 out << " }\n";
376 }
377 }
378
379 //
380 // Informative events are ignored
381 //
382 out << R"RRR(
383 void comment(const std::string &comment) override {}
384 void timestamp(int64_t timestamp) override {}
385 void valid_data() override {}
386)RRR";
387
388 //
389 // Schema changes are forwarded to the schema string
390 //
391 out << R"RRR(
392 bool upgrading_schema = false;
393 joedb::Memory_File schema_file;
394 joedb::Writable_Journal schema_journal;
395
396 bool requires_schema_upgrade() const
397 {
398 return schema_file.get_data().size() < detail::schema_string_size;
399 }
400
401 void check_schema()
402 {
403 constexpr size_t pos = joedb::Header::size;
404 const size_t schema_file_size = schema_file.get_data().size();
405
406 if
407 (
408 schema_file_size < pos ||
409 schema_file_size > detail::schema_string_size ||
410 std::memcmp
411 (
412 detail::schema_string + pos,
413 schema_file.get_data().data() + pos,
414 schema_file_size - pos
415 ) != 0
416 )
417 {
418 throw_exception("Trying to open a file with incompatible schema");
419 }
420 }
421
422 void create_table(const std::string &name) override
423 {
424 ++current_table_id;
425 schema_journal.create_table(name);
426 schema_journal.soft_checkpoint();
427 }
428
429 void drop_table(Table_Id table_id) override
430 {
431 schema_journal.drop_table(table_id);
432 schema_journal.soft_checkpoint();
433 }
434
435 void rename_table
436 (
437 Table_Id table_id,
438 const std::string &name
439 ) override
440 {
441 schema_journal.rename_table(table_id, name);
442 schema_journal.soft_checkpoint();
443 }
444
445 void add_field
446 (
447 Table_Id table_id,
448 const std::string &name,
449 joedb::Type type
450 ) override
451 {
452 schema_journal.add_field(table_id, name, type);
453 schema_journal.soft_checkpoint();
454 }
455
456 void drop_field(Table_Id table_id, Field_Id field_id) override
457 {
458 schema_journal.drop_field(table_id, field_id);
459 schema_journal.soft_checkpoint();
460 }
461
462 void rename_field
463 (
464 Table_Id table_id,
465 Field_Id field_id,
466 const std::string &name
467 ) override
468 {
469 schema_journal.rename_field(table_id, field_id, name);
470 schema_journal.soft_checkpoint();
471 }
472
473 void custom(const std::string &name) override
474 {
475 schema_journal.custom(name);
476 schema_journal.soft_checkpoint();
477 }
478)RRR";
479
480 //
481 // Public stuff
482 //
483 out << R"RRR(
484 public:
485 Database_Writable():
486 max_record_id(0),
487 schema_journal(schema_file)
488 {}
489
490 void set_max_record_id(joedb::index_t record_id)
491 {
492 max_record_id = record_id;
493 }
494
495 int64_t get_schema_checkpoint() const
496 {
497 return schema_journal.get_checkpoint();
498 }
499
500 void initialize_with_readonly_journal(joedb::Readonly_Journal &journal)
501 {
502 max_record_id = journal.get_checkpoint();
503 journal.replay_log(*this);
504 max_record_id = 0;
505
506 check_schema();
507
508 if (requires_schema_upgrade())
509 throw_exception<joedb::Out_Of_Date>("Schema is out of date. Can't upgrade a read-only database.");
510 }
511 };
512)RRR";
513
514 namespace_close(out, options.get_name_space());
516 }
517}
Table_Id get_table_id() const
Definition Type.h:42
Type_Id get_type_id() const
Definition Type.h:41
@ type_ids
Definition Type.h:25
Database_Writable_h(const Compiler_Options &options)
void write(std::ostream &out) override
static const char * get_storage_type_string(Type type)
static const char * get_type_string(Type type)
static const char * get_cpp_type_string(Type type)
const Compiler_Options & options
Definition Generator.h:16
bool table_has_field_type(Table_Id table_id, Type::Type_Id type_id) const
Definition Generator.cpp:23
Generator(std::string dir_name, std::string file_name, const Compiler_Options &options)
void write_type(std::ostream &out, Type type, bool return_type, bool setter_type)
Definition Generator.cpp:52
void namespace_open(std::ostream &out, const std::vector< std::string > &n)
void namespace_close(std::ostream &out, const std::vector< std::string > &n)
void namespace_include_guard_open(std::ostream &out, const char *name, const std::vector< std::string > &n)
void namespace_include_guard_close(std::ostream &out)
One code generator for each of the file generated by joedbc.
Definition Client_h.cpp:5