Joedb 9.1.4
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Database_h.cpp
Go to the documentation of this file.
3#include "joedb/get_version.h"
4#include "joedb/ui/type_io.h"
5
6#include <set>
7
8namespace joedb::generator
9{
10 ////////////////////////////////////////////////////////////////////////////
12 ////////////////////////////////////////////////////////////////////////////
13 (
14 const Compiler_Options &options
15 ):
16 Generator(".", "Database.h", options)
17 {
18 }
19
20 ////////////////////////////////////////////////////////////////////////////
22 ////////////////////////////////////////////////////////////////////////////
23 {
24 const Database_Schema &db = options.get_db();
25 auto tables = db.get_tables();
26
28
29 out << R"RRR(
30#include "joedb/Freedom_Keeper.h"
31#include "joedb/journal/Writable_Journal.h"
32#include "joedb/journal/Memory_File.h"
33#include "joedb/error/Exception.h"
34#include "joedb/error/Out_Of_Date.h"
35#include "joedb/error/assert.h"
36#include "joedb/get_version.h"
37#include "ids.h"
38
39#include <string>
40#include <cstdint>
41#include <cstring>
42#include <vector>
43#include <algorithm>
44#include <string_view>
45
46)RRR";
47
48 if (options.has_index())
49 out << "#include <map>\n\n";
50
52 {
53 out << "#include \"joedb/ui/type_io.h\"\n";
54 out << "#include <sstream>\n\n";
55 }
56
57 out << "static_assert(std::string_view(joedb::get_version()) == \"";
58 out << joedb::get_version() << "\");\n\n";
59
61
62 out << "\n /// @namespace " << namespace_string(options.get_name_space());
63 out << R"RRR(
64 ///
65 /// Automatically generated by joedbc
66)RRR";
67
68 out << R"RRR(
69 using joedb::Record_Id;
70 using joedb::Table_Id;
71 using joedb::Field_Id;
72
73 namespace detail
74 {
75 extern const char * schema_string;
76 inline constexpr size_t schema_string_size = )RRR";
77
78 out << options.schema_file.get_size() << ";\n }\n";
79
80 for (const auto &[tid, tname]: tables)
81 out << " class container_of_" << tname << ";\n";
82
83 out << "\n namespace detail\n {";
84 for (const auto &[tid, tname]: tables)
85 {
86 out << "\n struct data_of_" << tname;
87
88 out <<"\n {\n";
89 if (db.get_freedom(tid).size() > 0)
90 out <<" Field_Id current_field_id = Field_Id(0);\n";
91
92 std::vector<std::string> fields;
93
94 for (const auto &[fid, fname]: db.get_fields(tid))
95 {
96 fields.emplace_back("field_value_of_" + fname);
97
98 const joedb::Type &type = db.get_field_type(tid, fid);
99
100 out << " std::vector<";
101 write_type(type, false, false);
102 out << "> " << fields.back() << ";\n";
103 }
104
105 for (const auto &index: options.get_indices())
106 if (index.table_id == tid)
107 {
108 out << " std::vector<";
109 write_index_type(index);
110 out << "::iterator> ";
111 fields.emplace_back("iterator_over_" + index.name);
112 out << fields.back() << ";\n";
113 }
114
115 out << R"RRR(
116 joedb::Compact_Freedom_Keeper freedom_keeper;
117
118 size_t size() const {return freedom_keeper.size();}
119
120 void resize(size_t new_size)
121 {
122)RRR";
123
124 fields.emplace_back("freedom_keeper");
125 for (const std::string &field: fields)
126 out << " " << field << ".resize(new_size);\n";
127
128 out << " }\n };\n";
129 }
130 out << " }\n\n";
131
132 for (const auto &index: options.get_indices())
133 if (!index.unique)
134 out << " class range_of_" << index.name << ";\n";
135 out << '\n';
136
137 out << " /// Store all the tables of the database\n";
138 out << " class Database: public joedb::Writable\n {\n";
139 out << " friend class Readable;\n";
140
141 for (const auto &[tid, tname]: tables)
142 {
143 out << " friend class id_of_" << tname << ";\n";
144 out << " friend class container_of_" << tname << ";\n";
145 }
146
147 for (const auto &index: options.get_indices())
148 if (!index.unique)
149 out << " friend class range_of_" << index.name << ";\n";
150
151 out << R"RRR(
152 public:
153 template<typename E = joedb::Exception>
154 static void throw_exception(const std::string &message)
155 {
156 throw E(")RRR" <<
158 << R"RRR(: " + message);
159 }
160
161 size_t max_record_id;
162 Table_Id current_table_id = Table_Id{0};
163
164 void set_max_record_id(size_t record_id)
165 {
166 max_record_id = record_id;
167 }
168
169)RRR";
170
171 //
172 // Validity checks
173 //
174 for (const auto &[tid, tname]: tables)
175 {
176 out << " bool is_valid(id_of_" << tname << " id) const {return is_valid_record_id_for_" << tname << "(id.get_record_id());}\n";
177 }
178
179 out << "\n protected:\n";
180
181 for (const auto &[tid, tname]: tables)
182 {
183 out << " detail::data_of_" << tname << " storage_of_" << tname << ";\n";
184
185 out << " bool is_valid_record_id_for_" << tname;
186 out << "(Record_Id record_id) const {return storage_of_" << tname;
187 out << ".freedom_keeper.is_used(size_t(record_id) + 1);}\n";
188 }
189
190 //
191 // Indices
192 //
193 if (!options.get_indices().empty())
194 out << '\n';
195
196 for (const auto &index: options.get_indices())
197 {
198 const std::string &tname = db.get_table_name(index.table_id);
199
200 out << " ";
201 write_index_type(index);
202 out << " index_of_" << index.name << ";\n";
203
204 out << " void remove_index_of_" << index.name << "(Record_Id record_id)\n";
205 out << " {\n";
206 out << " auto &iterator = storage_of_" << tname;
207 out << ".iterator_over_" << index.name << "[size_t(record_id) - 1];\n";
208 out << " if (iterator != index_of_" << index.name << ".end())\n";
209 out << " {\n";
210 out << " index_of_" << index.name << ".erase(iterator);\n";
211 out << " iterator = index_of_" << index.name << ".end();\n";
212 out << " }\n";
213 out << " }\n";
214
215 out << " void add_index_of_" << index.name << "(Record_Id record_id)\n";
216 out << " {\n";
217 out << " auto result = index_of_" << index.name;
218 out << ".insert\n (\n ";
219 write_index_type(index);
220 out << "::value_type\n (\n ";
221 write_tuple_type(index);
222 out << '(';
223 for (size_t i = 0; i < index.field_ids.size(); i++)
224 {
225 if (i > 0)
226 out << ", ";
227 out << "storage_of_" << tname << ".field_value_of_";
228 out << db.get_field_name(index.table_id, index.field_ids[i]);
229 out << "[size_t(record_id) - 1]";
230 }
231 out << ')';
232 out << ",\n id_of_" << tname << "(record_id)\n )\n );\n";
233 if (index.unique)
234 {
235 out << " if (!result.second)\n";
236 out << " {\n";
237 out << " std::ostringstream out;\n";
238 out << " out << \"" << index.name << " unique index failure: (\";\n";
239 for (size_t i = 0; i < index.field_ids.size(); i++)
240 {
241 if (i > 0)
242 out << " out << \", \";\n";
243 const auto type = db.get_field_type(index.table_id, index.field_ids[i]);
244 out << " joedb::write_" << get_type_string(type) << "(out, ";
245 out << "storage_of_" << tname << ".field_value_of_";
246 out << db.get_field_name(index.table_id, index.field_ids[i]);
247 out << "[size_t(record_id) - 1]";
248 if (type.get_type_id() == joedb::Type::Type_Id::reference)
249 out << ".get_record_id()";
250 out << ");\n";
251 }
252 out << " out << \") at id = \" << record_id << ' ';\n";
253 out << " out << \"was already at id = \" << result.first->second.get_id();\n";
254 out << " throw_exception(out.str());\n";
255 out << " }\n";
256 out << " storage_of_" << tname << ".iterator_over_" << index.name << "[size_t(record_id) - 1] = result.first;\n";
257 }
258 else
259 out << " storage_of_" << tname << ".iterator_over_" << index.name << "[size_t(record_id) - 1] = result;\n";
260 out << " }\n";
261 }
262
263 //
264 // Internal data-modification functions
265 //
266 out << '\n';
267 for (const auto &[tid, tname]: tables)
268 {
269 out << " void internal_delete_" << tname << "(Record_Id record_id)\n";
270 out << " {\n";
271 out << " JOEDB_ASSERT(is_valid_record_id_for_" << tname << "(record_id));\n";
272
273 for (const auto &index: options.get_indices())
274 if (index.table_id == tid)
275 out << " remove_index_of_" << index.name << "(record_id);\n";
276
277 for (const auto &[fid, fname]: db.get_fields(tid))
278 {
279 const Type &type = db.get_field_type(tid, fid);
280
281 out << " storage_of_" << tname << ".field_value_of_";
282 out << fname << "[size_t(record_id) - 1]";
283
284 if (type.get_type_id() == Type::Type_Id::string)
285 {
286 out << ".clear()";
287 }
288 else if (type.get_type_id() == Type::Type_Id::reference)
289 {
290 out << " = ";
291 write_type(type, false, false);
292 out << "(Record_Id(0))";
293 }
294 else if (type.get_type_id() == Type::Type_Id::blob)
295 {
296 out << " = joedb::Blob();";
297 }
298 else
299 {
300 out << " = 0";
301 }
302
303 out << ";\n";
304 }
305
306 out << " storage_of_" << tname << ".freedom_keeper.free(size_t(record_id) + 1);\n";
307 out << " }\n";
308 }
309
310 out << '\n';
311 for (const auto &[tid, tname]: tables)
312 {
313 out << " void internal_insert_" << tname << "(Record_Id record_id)\n";
314 out << " {\n";
315
316 for (const auto &index: options.get_indices())
317 if (index.table_id == tid)
318 {
319 out << " storage_of_" << tname;
320 out << ".iterator_over_" << index.name << "[size_t(record_id) - 1] = ";
321 out << "index_of_" << index.name << ".end();\n";
322 }
323
324 out << " storage_of_" << tname << ".freedom_keeper.use(size_t(record_id) + 1);\n";
325
326 out << " }\n\n";
327
328 out << " void internal_vector_insert_" << tname << "(Record_Id record_id, size_t size)\n";
329 out << " {\n";
330 out << " storage_of_" << tname << ".freedom_keeper.use_vector(size_t(record_id) + 1, size);\n";
331
332 for (const auto &index: options.get_indices())
333 if (index.table_id == tid)
334 {
335 out << " std::fill_n\n";
336 out << " (\n";
337 out << " &storage_of_" << tname << ".iterator_over_" << index.name << "[size_t(record_id) - 1],\n";
338 out << " size,\n";
339 out << " index_of_" << index.name << ".end()\n";
340 out << " );\n";
341 }
342
343 out << " }\n";
344 }
345
346 out << '\n';
347 for (const auto &[tid, tname]: tables)
348 {
349 for (const auto &[fid, fname]: db.get_fields(tid))
350 {
351 const Type &type = db.get_field_type(tid, fid);
352
353 out << " void internal_update_" << tname << "__" << fname;
354 out << "\n (\n Record_Id record_id,\n ";
355 write_type(type, true, false);
356 out << " field_value_of_" << fname << "\n )\n";
357 out << " {\n";
358 out << " JOEDB_ASSERT(is_valid_record_id_for_" << tname << "(record_id));\n";
359 out << " storage_of_" << tname << ".field_value_of_" << fname;
360 out << "[size_t(record_id) - 1] = field_value_of_" << fname;
361 out << ";\n";
362
363 for (const auto &index: options.get_indices())
364 {
365 if (index.is_trigger(tid, fid))
366 {
367 out << " remove_index_of_" << index.name << "(record_id);\n";
368 out << " add_index_of_" << index.name << "(record_id);\n";
369 }
370 }
371
372 out << " }\n\n";
373
374 out << " void internal_update_vector_" << tname << "__" << fname << '\n';
375 out << " (\n";
376 out << " Record_Id record_id,\n";
377 out << " size_t size,\n";
378 out << " const ";
379 write_type(type, false, false);
380 out << " *value\n";
381 out << " )\n";
382 out << " {\n";
383 out << " for (size_t i = 0; i < size; i++)\n";
384 out << " JOEDB_ASSERT(is_valid_record_id_for_" << tname << "(record_id + i));\n";
385 out << " ";
386 write_type(type, false, false);
387 out << " *target = &storage_of_" << tname;
388 out << ".field_value_of_" << fname << "[size_t(record_id) - 1];\n";
389 out << " if (target != value)\n";
390 out << " std::copy_n(value, size, target);\n";
391
392 for (const auto &index: options.get_indices())
393 {
394 if (index.is_trigger(tid, fid))
395 {
396 out << " for (size_t i = 0; i < size; i++)\n";
397 out << " remove_index_of_" << index.name << "(record_id + i);\n";
398 out << " for (size_t i = 0; i < size; i++)\n";
399 out << " add_index_of_" << index.name << "(record_id + i);\n";
400 }
401 }
402
403 out << " }\n\n";
404 }
405 }
406
407 //
408 // delete_from writable function
409 //
410 out << '\n';
411 out << " void delete_from(Table_Id table_id, Record_Id record_id) final\n";
412 out << " {\n";
413 {
414 bool first = true;
415 for (const auto &[tid, tname]: tables)
416 {
417 out << " ";
418 if (first)
419 first = false;
420 else
421 out << "else ";
422
423 out << "if (table_id == Table_Id(" << tid << "))\n";
424 out << " internal_delete_" << tname << "(record_id);\n";
425 }
426 }
427 out << " }\n";
428
429 //
430 // insert_into
431 //
432 out << '\n';
433 out << " void insert_into(Table_Id table_id, Record_Id record_id) final\n";
434 out << " {\n";
435 out << " if (size_t(record_id) <= 0 || (max_record_id && size_t(record_id) > max_record_id))\n";
436 out << " throw_exception(\"insert_into: too big\");\n";
437 {
438 bool first = true;
439 for (const auto &[tid, tname]: tables)
440 {
441 out << " ";
442 if (first)
443 first = false;
444 else
445 out << "else ";
446
447 out << "if (table_id == Table_Id(" << tid << "))\n";
448 out << " {\n";
449 out << " if (is_valid_record_id_for_" << tname << "(record_id))\n";
450 out << " throw_exception(\"Duplicate insert into table " << tname << "\");\n";
451 out << " if (storage_of_" << tname << ".size() < size_t(record_id))\n";
452 out << " storage_of_" << tname << ".resize(size_t(record_id));\n";
453 out << " internal_insert_" << tname << "(record_id);\n";
454 out << " }\n";
455 }
456 }
457 out << " }\n";
458
459 //
460 // insert_vector
461 //
462 out << R"RRR(
463
464 void insert_vector
465 (
466 Table_Id table_id,
467 Record_Id record_id,
468 size_t size
469 ) final
470 {
471 if
472 (
473 size_t(record_id) <= 0 ||
474 (max_record_id && (size_t(record_id) > max_record_id || size > max_record_id))
475 )
476 {
477 throw_exception("insert_vector: null record_id, or too big");
478 }
479)RRR";
480
481 {
482 bool first = true;
483 for (const auto &[tid, tname]: tables)
484 {
485 out << " ";
486 if (first)
487 first = false;
488 else
489 out << "else ";
490
491 out << "if (table_id == Table_Id(" << tid << "))\n";
492 out << " {\n";
493 out << " if (storage_of_" << tname << ".size() < size_t(record_id) + size - 1)\n";
494 out << " storage_of_" << tname << ".resize(size_t(record_id) + size - 1);\n";
495 out << " internal_vector_insert_" << tname << "(record_id, size);\n";
496 out << " }\n";
497 }
498 }
499 out << " }\n";
500
501 //
502 // set of existing types in the database
503 //
504 std::set<Type::Type_Id> db_types;
505
506 for (const auto &[tid, tname]: tables)
507 for (const auto &[fid, fname]: db.get_fields(tid))
508 db_types.insert(db.get_field_type(tid, fid).get_type_id());
509
510 //
511 // update
512 //
513 {
514 for (int type_index = 1; type_index < int(Type::type_ids); type_index++)
515 {
516 const Type::Type_Id type_id = Type::Type_Id(type_index);
517 if (db_types.find(type_id) == db_types.end())
518 continue;
519
520 out << '\n';
521 out << " void update_" << get_type_string(type_id) << '\n';
522 out << " (\n";
523 out << " Table_Id table_id,\n";
524 out << " Record_Id record_id,\n";
525 out << " Field_Id field_id,\n";
526 out << " " << get_cpp_type_string(type_id) << " value\n";
527 out << " )\n";
528 out << " final\n";
529 out << " {\n";
530
531 for (const auto &[tid, tname]: tables)
532 {
533 bool has_typed_field = false;
534
535 for (const auto &[fid, fname]: db.get_fields(tid))
536 {
537 const Type &type = db.get_field_type(tid, fid);
538 if (type.get_type_id() == type_id)
539 {
540 has_typed_field = true;
541 break;
542 }
543 }
544
545 if (has_typed_field)
546 {
547 out << " if (table_id == Table_Id(" << tid << "))\n";
548 out << " {\n";
549
550 for (const auto &[fid, fname]: db.get_fields(tid))
551 {
552 const Type &type = db.get_field_type(tid, fid);
553 if (type.get_type_id() == type_id)
554 {
555 out << " if (field_id == Field_Id(" << fid << "))\n";
556 out << " {\n";
557 out << " internal_update_" << tname;
558 out << "__" << fname << "(record_id, ";
559 if (type.get_type_id() != Type::Type_Id::reference)
560 out << "value";
561 else
562 {
563 out << "id_of_" << db.get_table_name(type.get_table_id());
564 out << "(value)";
565 }
566 out << ");\n";
567 out << " return;\n";
568 out << " }\n";
569 }
570 }
571
572 out << " return;\n";
573 out << " }\n";
574 }
575 }
576
577 out << " }\n";
578 }
579 }
580
581 //
582 // update_vector
583 //
584 {
585 for (int type_index = 1; type_index < int(Type::type_ids); type_index++)
586 {
587 const auto type_id = Type::Type_Id(type_index);
588 if (db_types.find(Type::Type_Id(type_id)) == db_types.end())
589 continue;
590
591 out << '\n';
592 out << " void update_vector_" << get_type_string(type_id) << '\n';
593 out << " (\n";
594 out << " Table_Id table_id,\n";
595 out << " Record_Id record_id,\n";
596 out << " Field_Id field_id,\n";
597 out << " size_t size,\n";
598 out << " const " << get_storage_type_string(type_id) << " *value\n";
599 out << " )\n";
600 out << " final\n";
601 out << " {\n";
602
603 for (const auto &[tid, tname]: tables)
604 {
605 bool has_typed_field = false;
606
607 for (const auto &[fid, fname]: db.get_fields(tid))
608 {
609 const Type &type = db.get_field_type(tid, fid);
610 if (type.get_type_id() == type_id)
611 {
612 has_typed_field = true;
613 break;
614 }
615 }
616
617 if (has_typed_field)
618 {
619 out << " if (table_id == Table_Id(" << tid << "))\n";
620 out << " {\n";
621
622 for (const auto &[fid, fname]: db.get_fields(tid))
623 {
624 const Type &type = db.get_field_type(tid, fid);
625 if (type.get_type_id() == type_id)
626 {
627 out << " if (field_id == Field_Id(" << fid << "))\n";
628 out << " {\n";
629 out << " internal_update_vector_" << tname;
630 out << "__" << fname << "(record_id, size, ";
631
632 if (type_id != joedb::Type::Type_Id::reference)
633 out << "value";
634 else
635 {
636 out << "reinterpret_cast<const ";
637 write_type(type, false, false);
638 out << "*>(value)";
639 }
640
641 out << ");\n";
642 out << " return;\n";
643 out << " }\n";
644 }
645 }
646
647 out << " return;\n";
648 out << " }\n";
649 }
650 }
651
652 out << " }\n";
653 }
654 }
655
656 //
657 // get_own_storage
658 //
659 {
660 for (int type_index = 1; type_index < int(Type::type_ids); type_index++)
661 {
662 const Type::Type_Id type_id = Type::Type_Id(type_index);
663 if (db_types.find(Type::Type_Id(type_id)) == db_types.end())
664 continue;
665
666 out << '\n';
667 out << " " << get_storage_type_string(type_id);
668 out << " *get_own_" << get_type_string(type_id) << "_storage\n";
669 out << " (\n";
670 out << " Table_Id table_id,\n";
671 out << " Record_Id record_id,\n";
672 out << " Field_Id field_id,\n";
673 out << " size_t &capacity\n";
674 out << " )\n";
675 out << " final\n";
676 out << " {\n";
677
678 for (const auto &[tid, tname]: tables)
679 {
680 bool has_typed_field = false;
681
682 for (const auto &[fid, fname]: db.get_fields(tid))
683 {
684 const Type &type = db.get_field_type(tid, fid);
685 if (type.get_type_id() == type_id)
686 {
687 has_typed_field = true;
688 break;
689 }
690 }
691
692 if (has_typed_field)
693 {
694 out << " if (table_id == Table_Id(" << tid << "))\n";
695 out << " {\n";
696 out << " capacity = size_t(storage_of_" << tname << ".freedom_keeper.size());\n";
697
698 for (const auto &[fid, fname]: db.get_fields(tid))
699 {
700 const Type &type = db.get_field_type(tid, fid);
701 if (type.get_type_id() == type_id)
702 {
703 out << " if (field_id == Field_Id(" << fid << "))\n"
704 << " {\n"
705 << " return ";
706
707 if (type_id == Type::Type_Id::reference)
708 out << "reinterpret_cast<Record_Id *>";
709
710 out << "(storage_of_" << tname;
711 out << ".field_value_of_" << fname << ".data() + size_t(record_id) - 1);\n"
712 << " }\n";
713 }
714 }
715
716 out << " return nullptr;\n";
717 out << " }\n";
718 }
719 }
720
721 out << " return nullptr;\n";
722 out << " }\n";
723 }
724 }
725
726 //
727 // Informative events are ignored
728 //
729 out << R"RRR(
730 void comment(const std::string &comment) override {}
731 void timestamp(int64_t timestamp) override {}
732 void valid_data() final {}
733)RRR";
734
735 //
736 // Schema changes are forwarded to the schema string
737 //
738 out << R"RRR(
739 bool upgrading_schema = false;
740 joedb::Memory_File schema_file;
741 joedb::Writable_Journal schema_journal;
742
743 bool requires_schema_upgrade() const
744 {
745 return schema_file.get_data().size() < detail::schema_string_size;
746 }
747
748 void check_schema()
749 {
750 constexpr size_t pos = size_t(joedb::Writable_Journal::header_size);
751 const size_t schema_file_size = schema_file.get_data().size();
752
753 if
754 (
755 schema_file_size < pos ||
756 schema_file_size > detail::schema_string_size ||
757 std::memcmp
758 (
759 schema_file.get_data().data() + pos,
760 detail::schema_string + pos,
761 schema_file_size - pos
762 ) != 0
763 )
764 {
765 throw_exception("Trying to open a file with incompatible schema");
766 }
767 }
768
769 void create_table(const std::string &name) override
770 {
771 ++current_table_id;
772 schema_journal.create_table(name);
773 schema_journal.default_checkpoint();
774 }
775
776 void drop_table(Table_Id table_id) final
777 {
778 schema_journal.drop_table(table_id);
779 schema_journal.default_checkpoint();
780 }
781
782 void rename_table
783 (
784 Table_Id table_id,
785 const std::string &name
786 ) final
787 {
788 schema_journal.rename_table(table_id, name);
789 schema_journal.default_checkpoint();
790 }
791
792 void add_field
793 (
794 Table_Id table_id,
795 const std::string &name,
796 joedb::Type type
797 ) override
798 {
799 schema_journal.add_field(table_id, name, type);
800 schema_journal.default_checkpoint();
801 }
802
803 void drop_field(Table_Id table_id, Field_Id field_id) final
804 {
805 schema_journal.drop_field(table_id, field_id);
806 schema_journal.default_checkpoint();
807 }
808
809 void rename_field
810 (
811 Table_Id table_id,
812 Field_Id field_id,
813 const std::string &name
814 ) final
815 {
816 schema_journal.rename_field(table_id, field_id, name);
817 schema_journal.default_checkpoint();
818 }
819
820 void custom(const std::string &name) override
821 {
822 schema_journal.custom(name);
823 schema_journal.default_checkpoint();
824 }
825)RRR";
826
827 //
828 // Public stuff
829 //
830 out << R"RRR(
831 public:
832 Database():
833 max_record_id(0),
834 schema_journal(schema_file)
835 {}
836
837 int64_t get_schema_checkpoint() const
838 {
839 return schema_journal.get_checkpoint_position();
840 }
841
842 void initialize_with_readonly_journal(joedb::Readonly_Journal &journal)
843 {
844 max_record_id = size_t(journal.get_checkpoint_position());
845 journal.replay_log(*this);
846 max_record_id = 0;
847
848 check_schema();
849
850 if (requires_schema_upgrade())
851 throw_exception<joedb::Out_Of_Date>("Schema is out of date. Can't upgrade a read-only database.");
852 }
853)RRR";
854
855 for (const auto &[tid, tname]: tables)
856 {
857 out << '\n';
858 const bool single_row = options.get_table_options(tid).single_row;
859
860 //
861 // Declaration of container access
862 //
863 out << " container_of_" << tname << " get_" << tname << "_table() const;\n\n";
864
865 out << " id_of_" << tname << " next(id_of_" << tname << " id) const\n";
866 out << " {\n";
867 out << " return id_of_" << tname << "\n (\n Record_Id(storage_of_" << tname << ".freedom_keeper.get_next(id.get_id() + 1) - 1)\n );\n";
868 out << " }\n\n";
869
870 out << " id_of_" << tname << " previous(id_of_" << tname << " id) const\n";
871 out << " {\n";
872 out << " return id_of_" << tname << "\n (\n Record_Id(storage_of_" << tname << ".freedom_keeper.get_previous(id.get_id() + 1) - 1)\n );\n";
873 out << " }\n\n";
874
875 out << " template<class Comparator>\n";
876 out << " std::vector<id_of_" << tname << "> sorted_" << tname;
877 out << "(Comparator comparator) const;\n\n";
878
879 //
880 // Easy access to null
881 //
882 out << " static id_of_" << tname << " null_" << tname << "()\n";
883 out << " {\n";
884 out << " return id_of_" << tname << "();\n";
885 out << " }\n";
886
887 //
888 // the_<table>
889 //
890 if (single_row)
891 {
892 out << " static constexpr id_of_" << tname << " the_" << tname << "()\n";
893 out << " {\n";
894 out << " return id_of_" << tname << "{1};\n";
895 out << " }\n";
896 }
897
898 //
899 // Loop over fields
900 //
901 for (const auto &[fid, fname]: db.get_fields(tid))
902 {
903 const Type &type = db.get_field_type(tid, fid);
904
905 out << '\n';
906
907 //
908 // Getter
909 //
910 out << " ";
911 write_type(type, true, false);
912 out << " get_" << fname << "(id_of_" << tname << " record";
913 if (single_row)
914 out << "= id_of_" << tname << "{1}";
915 out << ") const\n";
916 out << " {\n";
917 out << " JOEDB_ASSERT(is_valid_record_id_for_" << tname << "(record.get_record_id()));\n";
918 out << " return (";
919 write_type(type, true, false);
920 out << ")(storage_of_" << tname;
921 out << ".field_value_of_" << fname << "[record.get_id() - 1]);\n";
922 out << " }\n";
923 }
924 }
925
926 //
927 // get_index_of_X
928 //
929 for (const auto &index: options.get_indices())
930 {
931 out << '\n';
932 out << " const ";
933 write_index_type(index);
934 out << " &get_index_of_" << index.name << "()\n";
935 out << " {\n";
936 out << " return index_of_" << index.name << ";\n";
937 out << " }\n";
938 }
939
940 //
941 // find_index
942 //
943 for (const auto &index: options.get_indices())
944 if (index.unique)
945 {
946 const std::string &tname = db.get_table_name(index.table_id);
947 out << '\n';
948
949 out << " id_of_" << tname << " next_" << index.name << '(';
950 out << "id_of_" << tname << " id)\n";
951 out << " {\n";
952 out << " JOEDB_ASSERT(is_valid_record_id_for_" << tname << "(id.get_record_id()));\n";
953 out << " auto iterator = storage_of_" << tname << ".iterator_over_" << index.name << "[id.get_id() - 1];\n";
954 out << " ++iterator;\n";
955 out << " if (iterator != index_of_" << index.name << ".end())\n";
956 out << " return iterator->second;\n";
957 out << " else\n";
958 out << " return id_of_" << tname << "();\n";
959 out << " }\n";
960
961 out << " id_of_" << tname << " previous_" << index.name << '(';
962 out << "id_of_" << tname << " id)\n";
963 out << " {\n";
964 out << " JOEDB_ASSERT(is_valid_record_id_for_" << tname << "(id.get_record_id()));\n";
965 out << " auto iterator = storage_of_" << tname << ".iterator_over_" << index.name << "[id.get_id() - 1];\n";
966 out << " if (iterator != index_of_" << index.name << ".begin())\n";
967 out << " return (--iterator)->second;\n";
968 out << " else\n";
969 out << " return id_of_" << tname << "();\n";
970 out << " }\n";
971
972 out << " id_of_" << tname << " find_" << index.name << '(';
973 for (size_t i = 0; i < index.field_ids.size(); i++)
974 {
975 if (i > 0)
976 out << ", ";
977 const Type &type = db.get_field_type(index.table_id, index.field_ids[i]);
978 write_type(type, true, false);
979 out << " field_value_of_";
980 out << db.get_field_name(index.table_id, index.field_ids[i]);
981 }
982 out << ") const\n";
983 out << " {\n";
984 out << " const auto i = index_of_" << index.name << ".find(";
985 write_tuple_type(index);
986 out << '(';
987 for (size_t i = 0; i < index.field_ids.size(); i++)
988 {
989 if (i > 0)
990 out << ", ";
991 out << "field_value_of_";
992 out << db.get_field_name(index.table_id, index.field_ids[i]);
993 }
994 out << "));\n";
995 out << " if (i == index_of_" << index.name << ".end())\n";
996 out << " return id_of_" << tname << "();\n";
997 out << " else\n";
998 out << " return i->second;\n";
999 out << " }\n";
1000 }
1001 else
1002 {
1003 out << " range_of_" << index.name << " find_" << index.name << '(';
1004 for (size_t i = 0; i < index.field_ids.size(); i++)
1005 {
1006 if (i > 0)
1007 out << ", ";
1008 const Type &type = db.get_field_type(index.table_id, index.field_ids[i]);
1009 write_type(type, true, false);
1010 out << " field_value_of_";
1011 out << db.get_field_name(index.table_id, index.field_ids[i]);
1012 }
1013 out << ") const;\n";
1014 }
1015
1016 out << " };\n";
1017
1018 //
1019 // Plain iteration over tables
1020 //
1021 for (const auto &[tid, tname]: tables)
1022 {
1023 out << " /// returned by @ref Database::get_" << tname << "_table\n";
1024 out << " class container_of_" << tname << "\n";
1025 out << " {\n";
1026 out << " friend class Database;\n";
1027 out << '\n';
1028 out << " private:\n";
1029 out << " const Database &db;\n";
1030 out << " container_of_" << tname << "(const Database &db): db(db) {}\n";
1031 out << '\n';
1032 out << " public:\n";
1033 out << " class iterator\n";
1034 out << " {\n";
1035 out << " friend class container_of_" << tname << ";\n";
1036 out << " private:\n";
1037
1038
1039 out << " const joedb::Compact_Freedom_Keeper *fk;\n"; // must use pointer for copy constructor
1040 out << " size_t index;\n";
1041 out << " iterator(const detail::data_of_" << tname << " &data): fk(&data.freedom_keeper), index(0) {}\n";
1042 out << " public:\n";
1043 out << " typedef std::forward_iterator_tag iterator_category;\n";
1044 out << " typedef id_of_" << tname << " value_type;\n";
1045 out << " typedef std::ptrdiff_t difference_type;\n";
1046 out << " typedef value_type* pointer;\n";
1047 out << " typedef value_type& reference;\n";
1048 out << '\n';
1049 out << " bool operator==(const iterator &i) const {return index == i.index;}\n";
1050 out << " bool operator!=(const iterator &i) const {return index != i.index;}\n";
1051 out << " iterator &operator++() {index = fk->get_next(index); return *this;}\n";
1052 out << " iterator operator++(int) {auto copy = *this; index = fk->get_next(index); return copy;}\n";
1053 out << " iterator &operator--() {index = fk->get_previous(index); return *this;}\n";
1054 out << " iterator operator--(int) {auto copy = *this; index = fk->get_previous(index); return copy;}\n";
1055 out << " id_of_" << tname << " operator*() const {return id_of_";
1056 out << tname << "(Record_Id(index - 1));}\n";
1057 out << " };\n";
1058 out << '\n';
1059 out << " iterator begin() const {return ++iterator(db.storage_of_" << tname << ");}\n";
1060 out << " iterator end() const {return iterator(db.storage_of_" << tname << ");}\n";
1061 out << " bool is_empty() const {return db.storage_of_" << tname
1062 << ".freedom_keeper.is_empty();}\n";
1063 out << " size_t get_size() const {return db.storage_of_" << tname << ".freedom_keeper.get_used_count();}\n";
1064 out << " static id_of_" << tname << " get_at(size_t i) {return id_of_"
1065 << tname << "(Record_Id(i));}\n";
1066 out << " bool is_valid_at(size_t i) {return db.storage_of_" << tname << ".freedom_keeper.is_used(i + 1);}\n";
1067
1068 out << " id_of_" << tname << " first() const {return *begin();}\n";
1069 out << " id_of_" << tname << " last() const {return *--end();}\n";
1070 out << " id_of_" << tname << " get_end() const {return *end();}\n";
1071
1072 out << " };\n";
1073 out << '\n';
1074
1075 out << " inline container_of_" << tname << " Database::get_" << tname << "_table() const\n";
1076 out << " {\n";
1077 out << " return container_of_" << tname << "(*this);\n";
1078 out << " }\n";
1079 out << '\n';
1080
1081 out << " template<class Comparator>\n";
1082 out << " std::vector<id_of_" << tname << "> Database::sorted_" << tname;
1083 out << "(Comparator comparator) const\n";
1084 out << " {\n";
1085 out << " std::vector<id_of_" << tname << "> result;\n";
1086 out << " for (auto x: get_" << tname << "_table())\n";
1087 out << " result.emplace_back(x);\n";
1088 out << " std::sort(result.begin(), result.end(), comparator);\n";
1089 out << " return result;\n";
1090 out << " }\n";
1091 }
1092
1093 //
1094 // Index ranges for indexes that are not unique
1095 //
1096 for (const auto &index: options.get_indices())
1097 {
1098 if (!index.unique)
1099 {
1100 out << " /// returned by @ref Database::find_" << index.name << '\n';
1101 out << " class range_of_" << index.name << "\n";
1102 out << " {\n";
1103 out << " friend class Database;\n";
1104 out << " private:\n";
1105 out << " std::pair<";
1106 write_index_type(index);
1107 out << "::const_iterator, ";
1108 write_index_type(index);
1109 out << "::const_iterator> range;\n";
1110 out << " range_of_" << index.name << "(const Database &db";
1111 for (size_t i = 0; i < index.field_ids.size(); i++)
1112 {
1113 out << ", ";
1114 const Type &type = db.get_field_type(index.table_id, index.field_ids[i]);
1115 write_type(type, true, false);
1116 out << ' ' << db.get_field_name(index.table_id, index.field_ids[i]);
1117 }
1118 out << ")\n";
1119 out << " {\n";
1120 out << " range = db.index_of_" << index.name << ".equal_range(";
1121 write_tuple_type(index);
1122 out << '(';
1123 for (size_t i = 0; i < index.field_ids.size(); i++)
1124 {
1125 if (i > 0)
1126 out << ", ";
1127 out << db.get_field_name(index.table_id, index.field_ids[i]);
1128 }
1129 out << "));\n";
1130 out << " }\n";
1131 out << " public:\n";
1132 out << " class iterator\n";
1133 out << " {\n";
1134 out << " friend class range_of_" << index.name << ";\n";
1135 out << " private:\n";
1136 out << " ";
1137 write_index_type(index);
1138 out << "::const_iterator map_iterator;\n";
1139 out << " iterator(";
1140 write_index_type(index);
1141 out << "::const_iterator map_iterator): map_iterator(map_iterator) {}\n"
1142 << " public:\n"
1143 << " bool operator !=(const iterator &i) const\n"
1144 << " {\n"
1145 << " return map_iterator != i.map_iterator;\n"
1146 << " }\n"
1147 << " iterator &operator++() {map_iterator++; return *this;}\n"
1148 << " id_of_" << db.get_table_name(index.table_id)
1149 << " operator*() const {return map_iterator->second;}\n"
1150 << " };\n"
1151 << " iterator begin() const {return range.first;}\n"
1152 << " iterator end() const {return range.second;}\n"
1153 << " bool empty() const {return range.first == range.second;}\n"
1154 << " size_t size() const {return size_t(std::distance(range.first, range.second));}\n"
1155 << " };\n\n";
1156
1157 out << " inline range_of_" << index.name << " Database::find_" << index.name << '(';
1158 for (size_t i = 0; i < index.field_ids.size(); i++)
1159 {
1160 if (i > 0)
1161 out << ", ";
1162 const Type &type = db.get_field_type(index.table_id, index.field_ids[i]);
1163 write_type(type, true, false);
1164 out << " field_value_of_";
1165 out << db.get_field_name(index.table_id, index.field_ids[i]);
1166 }
1167 out << ") const\n";
1168 out << " {\n";
1169 out << " return range_of_" << index.name << "(*this";
1170 for (size_t i = 0; i < index.field_ids.size(); i++)
1171 {
1172 out << ", ";
1173 out << "field_value_of_";
1174 out << db.get_field_name(index.table_id, index.field_ids[i]);
1175 }
1176 out << ");\n";
1177 out << " }\n";
1178 }
1179 }
1180
1182 out << "\n#endif\n";
1183 }
1184}
const std::vector< std::string > & get_name_space() const
const std::vector< Index > & get_indices() const
const Table_Options & get_table_options(Table_Id table_id) const
const Database & get_db() const
const Compact_Freedom_Keeper & get_freedom(Table_Id table_id) const override
const std::map< Table_Id, std::string > & get_tables() const override
const Type & get_field_type(Table_Id table_id, Field_Id field_id) const override
const std::map< Field_Id, std::string > & get_fields(Table_Id table_id) const override
int64_t get_size() const override
Definition Memory_File.h:24
const std::string & get_field_name(Table_Id table_id, Field_Id field_id) const
Definition Readable.cpp:54
const std::string & get_table_name(Table_Id table_id) const
Definition Readable.cpp:38
Table_Id get_table_id() const
Definition Type.h:41
Type_Id get_type_id() const
Definition Type.h:40
@ type_ids
Definition Type.h:24
Database_h(const Compiler_Options &options)
void write_index_type(const Compiler_Options::Index &index)
static const char * get_storage_type_string(Type type)
static const char * get_type_string(Type type)
void write_tuple_type(const Compiler_Options::Index &index)
Definition Generator.cpp:71
void write_type(Type type, bool return_type, bool setter_type)
Definition Generator.cpp:42
static const char * get_cpp_type_string(Type type)
const Compiler_Options & options
Definition Generator.h:14
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(std::ostream &out, const char *name, const std::vector< std::string > &n)
std::string namespace_string(const std::vector< std::string > &n, const char *delimiter)
One code generator for each of the file generated by joedbc.
Definition Client_h.cpp:5
constexpr const char * get_version()
Definition get_version.h:6