Joedb 9.5.0
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Writable_Database_h.cpp
Go to the documentation of this file.
3#include "joedb/ui/type_io.h"
4
5namespace joedb::generator
6{
7 ////////////////////////////////////////////////////////////////////////////
9 ////////////////////////////////////////////////////////////////////////////
10 (
11 const Compiler_Options &options
12 ):
13 Generator(".", "Writable_Database.h", options)
14 {
15 }
16
17 ////////////////////////////////////////////////////////////////////////////
19 ////////////////////////////////////////////////////////////////////////////
20 {
21 const Database &db = options.get_db();
22 auto tables = db.get_tables();
23
24 namespace_include_guard(out, "Writable_Database", options.get_name_space());
25
26 out << R"RRR(
27#include "Database.h"
28#include "joedb/Span.h"
29
30)RRR";
31
33
34 //
35 // Writable_Database
36 //
37 out << R"RRR(
38 namespace detail
39 {
40 class Client_Data;
41 }
42
43 class Client;
44 class Multiplexer;
45
46 /// A writable @ref Database constructed from a writable @ref joedb::Buffered_File
47 class Writable_Database: public Database
48 {
49 friend class detail::Client_Data;
50 friend class Client;
51 friend class Multiplexer;
52
53 private:
54 joedb::Writable_Journal journal;
55 bool ready_to_write;
56
57 void play_journal();
58 void auto_upgrade();
59 void check_single_row();
60
61 void initialize()
62 {
63 play_journal();
64 check_schema();
65 auto_upgrade();
66 check_single_row();
67 }
68)RRR";
69
70
71 if (!options.get_custom_names().empty())
72 {
73 out << R"RRR(
74 void custom(const std::string &name) final
75 {
76 Database::custom(name);
77
78 if (upgrading_schema)
79 {
80)RRR";
81 for (const auto &name: options.get_custom_names())
82 {
83 out << " if (name == \"" << name << "\")\n";
84 out << " " << name << "(*this);\n";
85 }
86 out << " }\n";
87 out << " }\n";
88
89 out << '\n';
90 out << " public:\n";
91 for (const auto &name: options.get_custom_names())
92 out << " static void " << name << "(Writable_Database &db);\n";
93 out << "\n private:";
94 }
95
96 if (db_has_values())
97 {
98 out << R"RRR(
99 void add_field
100 (
101 Table_Id table_id,
102 const std::string &name,
103 joedb::Type type
104 ) override;
105)RRR";
106 }
107
109 {
110 out <<"\n void create_table(const std::string &name) override;\n";
111 }
112
113 out << R"RRR(
114 Writable_Database
115 (
116 joedb::Buffered_File &file,
117 bool perform_initialization
118 );
119
120 public:
121 Writable_Database(joedb::Buffered_File &file);
122
123 const joedb::Readonly_Journal &get_journal() const {return journal;}
124
125 std::string read_blob(joedb::Blob blob) const
126 {
127 return journal.get_file().read_blob(blob);
128 }
129
130 joedb::Blob write_blob(const std::string &data) final
131 {
132 return journal.write_blob(data);
133 }
134
135 int64_t ahead_of_checkpoint() const
136 {
137 return journal.ahead_of_checkpoint();
138 }
139
140 void soft_checkpoint()
141 {
142 journal.soft_checkpoint();
143 }
144
145 void hard_checkpoint()
146 {
147 journal.hard_checkpoint();
148 }
149
150 void write_comment(const std::string &comment);
151 void write_timestamp();
152 void write_timestamp(int64_t timestamp);
153 void write_valid_data();
154 void flush() override {journal.flush();}
155)RRR";
156
157 for (const auto &[tid, tname]: tables)
158 {
159 out << '\n';
160 const bool single_row = options.get_table_options(tid).single_row;
161
162 //
163 // Erase all elements of the table
164 //
165 if (!single_row)
166 {
167 out << " void clear_" << tname << "_table();\n";
168 out << '\n';
169 }
170
171 if (single_row)
172 out << " private:\n";
173
174 //
175 // Uninitialized new
176 //
177 out << " id_of_" << tname << " new_" << tname << "()\n";
178 out << " {\n";
179
180 out << " id_of_" << tname << " result(Record_Id(storage_of_" << tname << ".freedom_keeper.get_free_record() - 1));\n";
181 out << " storage_of_" << tname << ".resize(storage_of_" << tname << ".freedom_keeper.size());\n";
182 out << " internal_insert_" << tname << "(result.get_record_id());\n\n";
183 out << " journal.insert_into(Table_Id(" << tid << "), result.get_record_id());\n";
184 out << " return result;\n";
185 out << " }\n";
186 out << '\n';
187
188 //
189 // new uninitialized vector
190 //
191 if (!single_row)
192 {
193 out << " id_of_" << tname << " new_vector_of_" << tname << "(size_t size)\n";
194 out << " {\n";
195 out << " id_of_" << tname << " result(Record_Id(storage_of_" << tname;
196 out << ".size() + 1));\n";
197 out << " storage_of_" << tname << ".resize(storage_of_";
198 out << tname << ".size() + size);\n";
199 out << " internal_vector_insert_" << tname << "(result.get_record_id(), size);\n";
200 out << " journal.insert_vector(Table_Id(" << tid;
201 out << "), result.get_record_id(), size);\n";
202 out << " return result;\n";
203 out << " }\n";
204 out << '\n';
205 }
206
207 //
208 // new with all fields
209 //
210 if (!db.get_fields(tid).empty())
211 {
212 out << " id_of_" << tname << " new_" << tname << '\n';
213 out << " (\n ";
214 {
215 bool first = true;
216
217 for (const auto &[fid, fname]: db.get_fields(tid))
218 {
219 if (first)
220 first = false;
221 else
222 out << ",\n ";
223
224 const Type &type = db.get_field_type(tid, fid);
225 write_type(type, false, true);
226 out << " field_value_of_" << fname;
227 }
228
229 out << '\n';
230 }
231 out << " )\n";
232 out << " {\n";
233 out << " auto result = new_" << tname << "();\n";
234
235 for (const auto &[fid, fname]: db.get_fields(tid))
236 out << " set_" << fname << "(result, field_value_of_" << fname << ");\n";
237
238 out << " return result;\n";
239 out << " }\n\n";
240 }
241
242 if (single_row)
243 out << " public:\n";
244
245 //
246 // Delete
247 //
248 if (!single_row)
249 {
250 out << " void delete_" << tname << "(id_of_" << tname << " record)\n";
251 out << " {\n";
252 out << " internal_delete_" << tname << "(record.get_record_id());\n";
253 out << " journal.delete_from(Table_Id(" << tid << "), record.get_record_id());\n";
254 out << " }\n\n";
255
256 out << " void delete_vector_of_" << tname << "(id_of_" << tname << " v, size_t size)\n";
257 out << " {\n";
258 out << " for (size_t i = size; i > 0;)\n";
259 out << " internal_delete_" << tname << "(v[--i].get_record_id());\n";
260 out << " journal.delete_vector(Table_Id(" << tid << "), v.get_record_id(), size);\n";
261 out << " }\n\n";
262 }
263
264 //
265 // Loop over fields
266 //
267 for (const auto &[fid, fname]: db.get_fields(tid))
268 {
269 const Type &type = db.get_field_type(tid, fid);
270
271 //
272 // Setter
273 //
274 out << " void set_" << fname;
275 out << "(id_of_" << tname << " record, ";
276 write_type(type, false, true);
277 out << " field_value_of_" << fname << ")\n";
278 out << " {\n";
279 out << " internal_update_" << tname << "__" << fname;
280
281 out << "(record.get_record_id(), ";
282 out << "field_value_of_" << fname << ");\n";
283 out << " journal.update_";
284 out << get_type_string(type);
285 out << "(Table_Id(" << tid << "), record.get_record_id(), Field_Id(" << fid << "), ";
286 out << "field_value_of_" << fname;
287 if (type.get_type_id() == Type::Type_Id::reference)
288 out << ".get_record_id()";
289 out << ");\n";
290
291 out << " }\n\n";
292
293 //
294 // Vector update
295 // Note: write even if exception, to keep memory and file in sync
296 //
297 out << " template<typename F> void update_vector_of_" << fname;
298 out << "(id_of_" << tname << " record, size_t size, F f)\n";
299 out << " {\n";
300 out << " std::exception_ptr exception;\n";
301 out << " joedb::Span<";
302 write_type(type, false, false);
303 out << "> span(&storage_of_" << tname;
304 out << ".field_value_of_" << fname << "[record.get_id() - 1], size);\n";
305 out << " try {f(span);}\n";
306 out << " catch (...) {exception = std::current_exception();}\n";
307 out << " internal_update_vector_" << tname << "__" << fname << "(record.get_record_id(), size, span.begin());\n";
308 out << " journal.update_vector_" << get_type_string(type) << "(Table_Id(" << tid << "), record.get_record_id(), Field_Id(" << fid << "), size, ";
309
310 if (type.get_type_id() == Type::Type_Id::reference)
311 out << "reinterpret_cast<Record_Id *>";
312
313 out << "(span.begin()));\n";
314 out << " if (exception)\n";
315 out << " std::rethrow_exception(exception);\n";
316 out << " }\n\n";
317 }
318 }
319
320 out << "\n };";
321
323 out << "\n#endif\n";
324 }
325}
const std::vector< std::string > & get_custom_names() const
const std::vector< std::string > & get_name_space() const
const Table_Options & get_table_options(Table_Id table_id) const
const Database & get_db() const
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
Type_Id get_type_id() const
Definition Type.h:41
static const char * get_type_string(Type type)
void write_type(Type type, bool return_type, bool setter_type)
Definition Generator.cpp:42
const Compiler_Options & options
Definition Generator.h:14
Writable_Database_h(const Compiler_Options &options)
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)
One code generator for each of the file generated by joedbc.
Definition Client_h.cpp:5