Joedb 9.1.4
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 default_checkpoint();
68 }
69)RRR";
70
71
72 if (!options.get_custom_names().empty())
73 {
74 out << R"RRR(
75 void custom(const std::string &name) final
76 {
77 Database::custom(name);
78
79 if (upgrading_schema)
80 {
81)RRR";
82 for (const auto &name: options.get_custom_names())
83 {
84 out << " if (name == \"" << name << "\")\n";
85 out << " " << name << "(*this);\n";
86 }
87 out << " }\n";
88 out << " }\n";
89
90 out << '\n';
91 out << " public:\n";
92 for (const auto &name: options.get_custom_names())
93 out << " static void " << name << "(Writable_Database &db);\n";
94 out << "\n private:";
95 }
96
97 if (db_has_values())
98 {
99 out << R"RRR(
100 void add_field
101 (
102 Table_Id table_id,
103 const std::string &name,
104 joedb::Type type
105 ) override;
106)RRR";
107 }
108
110 {
111 out <<"\n void create_table(const std::string &name) override;\n";
112 }
113
114 out << R"RRR(
115 Writable_Database
116 (
117 joedb::Buffered_File &file,
118 bool perform_initialization,
119 joedb::Readonly_Journal::Check check,
120 joedb::Commit_Level commit_level
121 );
122
123 public:
124 Writable_Database
125 (
126 joedb::Buffered_File &file,
127 joedb::Readonly_Journal::Check check = joedb::Readonly_Journal::Check::all,
128 joedb::Commit_Level commit_level = joedb::Commit_Level::no_commit
129 );
130
131 const joedb::Readonly_Journal &get_journal() const {return journal;}
132
133 std::string read_blob_data(joedb::Blob blob) const
134 {
135 return journal.get_file().read_blob_data(blob);
136 }
137
138 joedb::Blob write_blob_data(const std::string &data) final
139 {
140 return journal.write_blob_data(data);
141 }
142
143 int64_t ahead_of_checkpoint() const
144 {
145 return journal.ahead_of_checkpoint();
146 }
147
148 void checkpoint_no_commit()
149 {
150 journal.checkpoint(joedb::Commit_Level::no_commit);
151 }
152
153 void checkpoint_half_commit()
154 {
155 journal.checkpoint(joedb::Commit_Level::half_commit);
156 }
157
158 void checkpoint_full_commit()
159 {
160 journal.checkpoint(joedb::Commit_Level::full_commit);
161 }
162
163 void checkpoint()
164 {
165 journal.default_checkpoint();
166 }
167
168 void checkpoint(joedb::Commit_Level commit_level) final
169 {
170 journal.checkpoint(commit_level);
171 }
172
173 void write_comment(const std::string &comment);
174 void write_timestamp();
175 void write_timestamp(int64_t timestamp);
176 void write_valid_data();
177 void flush() override {journal.flush();}
178)RRR";
179
180 for (const auto &[tid, tname]: tables)
181 {
182 out << '\n';
183 const bool single_row = options.get_table_options(tid).single_row;
184
185 //
186 // Erase all elements of the table
187 //
188 if (!single_row)
189 {
190 out << " void clear_" << tname << "_table();\n";
191 out << '\n';
192 }
193
194 if (single_row)
195 out << " private:\n";
196
197 //
198 // Uninitialized new
199 //
200 out << " id_of_" << tname << " new_" << tname << "()\n";
201 out << " {\n";
202
203 out << " id_of_" << tname << " result(Record_Id(storage_of_" << tname << ".freedom_keeper.get_free_record() - 1));\n";
204 out << " storage_of_" << tname << ".resize(storage_of_" << tname << ".freedom_keeper.size());\n";
205 out << " internal_insert_" << tname << "(result.get_record_id());\n\n";
206 out << " journal.insert_into(Table_Id(" << tid << "), result.get_record_id());\n";
207 out << " return result;\n";
208 out << " }\n";
209 out << '\n';
210
211 //
212 // new uninitialized vector
213 //
214 if (!single_row)
215 {
216 out << " id_of_" << tname << " new_vector_of_" << tname << "(size_t size)\n";
217 out << " {\n";
218 out << " id_of_" << tname << " result(Record_Id(storage_of_" << tname;
219 out << ".size() + 1));\n";
220 out << " storage_of_" << tname << ".resize(storage_of_";
221 out << tname << ".size() + size);\n";
222 out << " internal_vector_insert_" << tname << "(result.get_record_id(), size);\n";
223 out << " journal.insert_vector(Table_Id(" << tid;
224 out << "), result.get_record_id(), size);\n";
225 out << " return result;\n";
226 out << " }\n";
227 out << '\n';
228 }
229
230 //
231 // new with all fields
232 //
233 if (!db.get_fields(tid).empty())
234 {
235 out << " id_of_" << tname << " new_" << tname << '\n';
236 out << " (\n ";
237 {
238 bool first = true;
239
240 for (const auto &[fid, fname]: db.get_fields(tid))
241 {
242 if (first)
243 first = false;
244 else
245 out << ",\n ";
246
247 const Type &type = db.get_field_type(tid, fid);
248 write_type(type, false, true);
249 out << " field_value_of_" << fname;
250 }
251
252 out << '\n';
253 }
254 out << " )\n";
255 out << " {\n";
256 out << " auto result = new_" << tname << "();\n";
257
258 for (const auto &[fid, fname]: db.get_fields(tid))
259 out << " set_" << fname << "(result, field_value_of_" << fname << ");\n";
260
261 out << " return result;\n";
262 out << " }\n\n";
263 }
264
265 if (single_row)
266 out << " public:\n";
267
268 //
269 // Delete
270 //
271 if (!single_row)
272 {
273 out << " void delete_" << tname << "(id_of_" << tname << " record)\n";
274 out << " {\n";
275 out << " internal_delete_" << tname << "(record.get_record_id());\n";
276 out << " journal.delete_from(Table_Id(" << tid << "), record.get_record_id());\n";
277 out << " }\n\n";
278
279 out << " void delete_vector_of_" << tname << "(id_of_" << tname << " v, size_t size)\n";
280 out << " {\n";
281 out << " for (size_t i = size; i > 0;)\n";
282 out << " delete_" << tname << "(v[--i]);\n";
283 out << " }\n\n";
284 }
285
286 //
287 // Loop over fields
288 //
289 for (const auto &[fid, fname]: db.get_fields(tid))
290 {
291 const Type &type = db.get_field_type(tid, fid);
292
293 //
294 // Setter
295 //
296 out << " void set_" << fname;
297 out << "(id_of_" << tname << " record, ";
298 write_type(type, false, true);
299 out << " field_value_of_" << fname << ")\n";
300 out << " {\n";
301 out << " internal_update_" << tname << "__" << fname;
302
303 out << "(record.get_record_id(), ";
304 out << "field_value_of_" << fname << ");\n";
305 out << " journal.update_";
306 out << get_type_string(type);
307 out << "(Table_Id(" << tid << "), record.get_record_id(), Field_Id(" << fid << "), ";
308 out << "field_value_of_" << fname;
309 if (type.get_type_id() == Type::Type_Id::reference)
310 out << ".get_record_id()";
311 out << ");\n";
312
313 out << " }\n\n";
314
315 //
316 // Vector update
317 // Note: write even if exception, to keep memory and file in sync
318 //
319 out << " template<typename F> void update_vector_of_" << fname;
320 out << "(id_of_" << tname << " record, size_t size, F f)\n";
321 out << " {\n";
322 out << " std::exception_ptr exception;\n";
323 out << " joedb::Span<";
324 write_type(type, false, false);
325 out << "> span(&storage_of_" << tname;
326 out << ".field_value_of_" << fname << "[record.get_id() - 1], size);\n";
327 out << " try {f(span);}\n";
328 out << " catch (...) {exception = std::current_exception();}\n";
329 out << " internal_update_vector_" << tname << "__" << fname << "(record.get_record_id(), size, span.begin());\n";
330 out << " journal.update_vector_" << get_type_string(type) << "(Table_Id(" << tid << "), record.get_record_id(), Field_Id(" << fid << "), size, ";
331
332 if (type.get_type_id() == Type::Type_Id::reference)
333 out << "reinterpret_cast<Record_Id *>";
334
335 out << "(span.begin()));\n";
336 out << " if (exception)\n";
337 out << " std::rethrow_exception(exception);\n";
338 out << " }\n\n";
339 }
340 }
341
342 out << "\n };";
343
345 out << "\n#endif\n";
346 }
347}
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:40
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