Branch data Line data Source code
1 : : #include <mutable/mutable.hpp>
2 : :
3 : : #include "backend/Interpreter.hpp"
4 : : #include "backend/StackMachine.hpp"
5 : : #include "backend/WebAssembly.hpp"
6 : : #include "IR/PartialPlanGenerator.hpp"
7 : : #include "lex/Lexer.hpp"
8 : : #include "parse/Parser.hpp"
9 : : #include "parse/Sema.hpp"
10 : : #include <cerrno>
11 : : #include <fstream>
12 : : #include <mutable/catalog/DatabaseCommand.hpp>
13 : : #include <mutable/io/Reader.hpp>
14 : : #include <mutable/IR/Tuple.hpp>
15 : : #include <mutable/Options.hpp>
16 : : #include <mutable/util/Diagnostic.hpp>
17 : :
18 : :
19 : : using namespace m;
20 : : using namespace m::ast;
21 : :
22 : :
23 : 0 : bool m::init() { return streq(m::version::GIT_REV, m::version::get().GIT_REV); }
24 : :
25 : 1137 : std::unique_ptr<Stmt> m::statement_from_string(Diagnostic &diag, const std::string &str)
26 : : {
27 : 1137 : Catalog &C = Catalog::Get();
28 : :
29 : 1137 : std::istringstream in(str);
30 [ + - + - ]: 1137 : Lexer lexer(diag, C.get_pool(), "-", in);
31 [ + - ]: 1137 : Parser parser(lexer);
32 [ + - + - : 2274 : auto stmt = M_TIME_EXPR(std::unique_ptr<Stmt>(parser.parse_Stmt()), "Parse the statement", C.timer());
+ - - + ]
33 [ + - + - ]: 1137 : if (diag.num_errors() != 0)
34 [ # # # # : 0 : throw frontend_exception("syntactic error in statement");
# # ]
35 [ + - + - ]: 1137 : M_insist(diag.num_errors() == 0);
36 : :
37 [ + - ]: 1137 : Sema sema(diag);
38 [ + - + - : 2274 : M_TIME_EXPR(sema(*stmt), "Semantic analysis", C.timer());
+ - - + ]
39 [ + - + - ]: 1137 : if (diag.num_errors() != 0)
40 [ # # # # : 0 : throw frontend_exception("semantic error in statement");
# # ]
41 [ + - + - ]: 1137 : M_insist(diag.num_errors() == 0);
42 : :
43 : 1137 : return stmt;
44 [ + - ]: 1137 : }
45 : :
46 : 0 : std::unique_ptr<DatabaseCommand> m::command_from_string(Diagnostic &diag, const std::string &str)
47 : : {
48 : 0 : Catalog &C = Catalog::Get();
49 : :
50 : 0 : std::istringstream in(str);
51 [ # # # # ]: 0 : Lexer lexer(diag, C.get_pool(), "-", in);
52 [ # # ]: 0 : Parser parser(lexer);
53 [ # # # # : 0 : auto stmt = M_TIME_EXPR(std::unique_ptr<Stmt>(parser.parse_Stmt()), "Parse the statement", C.timer());
# # # # ]
54 [ # # # # ]: 0 : if (diag.num_errors() != 0)
55 [ # # # # : 0 : throw frontend_exception("syntactic error in statement");
# # ]
56 [ # # # # ]: 0 : M_insist(diag.num_errors() == 0);
57 : :
58 [ # # ]: 0 : Sema sema(diag);
59 [ # # # # : 0 : auto cmd = M_TIME_EXPR(sema.analyze(std::move(stmt)), "Semantic analysis", C.timer());
# # # # ]
60 [ # # # # ]: 0 : if (diag.num_errors() != 0)
61 [ # # # # : 0 : throw frontend_exception("semantic error in statement");
# # ]
62 [ # # # # ]: 0 : M_insist(diag.num_errors() == 0);
63 : :
64 : 0 : return cmd;
65 [ # # ]: 0 : }
66 : :
67 : 0 : void m::process_stream(std::istream &in, const char *filename, Diagnostic diag)
68 : : {
69 : 0 : Catalog &C = Catalog::Get();
70 : :
71 : : /*----- Process the input stream. --------------------------------------------------------------------------------*/
72 : 0 : ast::Lexer lexer(diag, C.get_pool(), filename, in);
73 [ # # ]: 0 : ast::Parser parser(lexer);
74 : 1 :
75 [ # # # # : 0 : while (parser.token()) {
# # ]
76 : 0 : bool err = false;
77 [ # # ]: 0 : diag.clear();
78 [ # # ]: 0 : Timer &timer = C.timer();
79 [ # # ]: 0 : auto ast = parser.parse();
80 [ # # # # ]: 0 : C.scheduler().autocommit(std::move(ast), diag);
81 : :
82 [ # # # # ]: 0 : if (Options::Get().times) {
83 : : using namespace std::chrono;
84 [ # # # # : 0 : for (const auto &M : timer) {
# # ]
85 [ # # # # ]: 0 : if (M.is_finished())
86 [ # # # # : 0 : std::cout << M.name << ": " << duration_cast<microseconds>(M.duration()).count() / 1e3 << '\n';
# # # # #
# # # #
# ]
87 : : }
88 [ # # ]: 0 : std::cout.flush();
89 [ # # ]: 0 : timer.clear();
90 : 0 : }
91 : 0 : }
92 : :
93 [ # # ]: 0 : std::cout.flush();
94 [ # # ]: 0 : std::cerr.flush();
95 : 0 : }
96 : :
97 : 0 : std::unique_ptr<Instruction> m::instruction_from_string(Diagnostic &diag, const std::string &str)
98 : : {
99 : 0 : Catalog &C = Catalog::Get();
100 : :
101 : 0 : std::istringstream in(str);
102 [ # # # # ]: 0 : Lexer lexer(diag, C.get_pool(), "-", in);
103 [ # # ]: 0 : Parser parser(lexer);
104 [ # # # # : 0 : auto instruction = M_TIME_EXPR(parser.parse_Instruction(), "Parse the instruction", C.timer());
# # # # ]
105 [ # # # # ]: 0 : if (diag.num_errors() != 0)
106 [ # # # # : 0 : throw frontend_exception("syntactic error in instruction");
# # # # ]
107 [ # # # # ]: 0 : M_insist(diag.num_errors() == 0);
108 : :
109 : 0 : return instruction;
110 [ # # ]: 0 : }
111 : :
112 : 771 : void m::execute_statement(Diagnostic &diag, const ast::Stmt &stmt, const bool is_stdin)
113 : : {
114 : 771 : diag.clear();
115 : 771 : Catalog &C = Catalog::Get();
116 : 771 : auto timer = C.timer();
117 : :
118 [ + - - + ]: 771 : if (is<const ast::SelectStmt>(stmt)) {
119 [ # # # # : 0 : auto query_graph = M_TIME_EXPR(QueryGraph::Build(stmt), "Construct the query graph", timer);
# # # # ]
120 [ # # # # : 0 : if (Options::Get().graph) query_graph->dump(std::cout);
# # ]
121 [ # # # # ]: 759 : if (Options::Get().graphdot) {
122 [ # # ]: 0 : DotTool dot(diag);
123 [ # # # # ]: 0 : query_graph->dot(dot.stream());
124 [ # # ]: 0 : dot.show("graph", is_stdin, "fdp");
125 : 0 : }
126 [ # # # # ]: 0 : if (Options::Get().graph2sql) {
127 [ # # ]: 0 : query_graph->sql(std::cout);
128 [ # # ]: 0 : std::cout.flush();
129 : 0 : }
130 [ # # # # : 0 : Optimizer Opt(C.plan_enumerator(), C.cost_function());
# # ]
131 : 0 : std::unique_ptr<Producer> optree;
132 [ # # # # ]: 0 : if (Options::Get().output_partial_plans_file) {
133 [ # # # # : 0 : auto res = M_TIME_EXPR(
# # # # ]
134 : : Opt.optimize_with_plantable<PlanTableLargeAndSparse>(*query_graph),
135 : : "Compute the logical query plan",
136 : : timer
137 : : );
138 : 0 : optree = std::move(res.first);
139 : :
140 [ # # # # ]: 0 : std::filesystem::path JSON_path(Options::Get().output_partial_plans_file);
141 : 0 : errno = 0;
142 [ # # ]: 0 : std::ofstream JSON_file(JSON_path);
143 [ # # # # : 0 : if (not JSON_file or errno) {
# # ]
144 : 0 : const auto errsv = errno;
145 [ # # ]: 0 : if (errsv) {
146 [ # # # # : 0 : diag.err() << "Failed to open output file for partial plans " << JSON_path << ": "
# # # # ]
147 [ # # # # ]: 0 : << strerror(errsv) << std::endl;
148 : 0 : } else {
149 [ # # # # : 0 : diag.err() << "Failed to open output file for partial plans " << JSON_path << std::endl;
# # # # ]
150 : : }
151 : 0 : } else {
152 : 0 : auto for_each = [&res](PartialPlanGenerator::callback_type callback) {
153 [ # # ]: 0 : PartialPlanGenerator{}.for_each_complete_partial_plan(res.second, callback);
154 : 0 : };
155 [ # # ]: 0 : PartialPlanGenerator{}.write_partial_plans_JSON(JSON_file, *query_graph, res.second, for_each);
156 : : }
157 : 0 : } else {
158 [ # # # # : 0 : optree = M_TIME_EXPR(Opt(*query_graph), "Compute the logical query plan", timer);
# # # # ]
159 : : }
160 [ # # ]: 0 : M_insist(bool(optree), "optree must have been computed");
161 [ # # # # : 0 : if (Options::Get().plan) optree->dump(std::cout);
# # ]
162 [ # # # # ]: 0 : if (Options::Get().plandot) {
163 [ # # ]: 0 : DotTool dot(diag);
164 [ # # # # ]: 0 : optree->dot(dot.stream());
165 [ # # ]: 0 : dot.show("logical_plan", is_stdin);
166 : 0 : }
167 : :
168 : 0 : std::unique_ptr<Consumer> logical_plan;
169 [ # # # # ]: 0 : if (Options::Get().benchmark)
170 [ # # ]: 0 : logical_plan = std::make_unique<NoOpOperator>(std::cout);
171 : : else
172 [ # # ]: 0 : logical_plan = std::make_unique<PrintOperator>(std::cout);
173 [ # # ]: 0 : logical_plan->add_child(optree.release());
174 : :
175 [ # # ]: 0 : static thread_local std::unique_ptr<Backend> backend;
176 [ # # ]: 0 : if (not backend)
177 [ # # # # : 0 : backend = M_TIME_EXPR(C.create_backend(), "Create backend", timer);
# # # # ]
178 : :
179 [ # # ]: 0 : PhysicalOptimizerImpl<ConcretePhysicalPlanTable> PhysOpt;
180 [ # # ]: 0 : backend->register_operators(PhysOpt);
181 [ # # # # : 0 : M_TIME_EXPR(PhysOpt.cover(*logical_plan), "Compute the physical query plan", timer);
# # # # ]
182 [ # # ]: 0 : auto physical_plan = PhysOpt.extract_plan();
183 : :
184 [ # # # # ]: 0 : if (Options::Get().physplan)
185 [ # # ]: 0 : physical_plan->dump(std::cout);
186 : :
187 [ # # # # ]: 0 : if (not Options::Get().dryrun)
188 [ # # # # : 0 : M_TIME_EXPR(backend->execute(*physical_plan), "Execute query", timer);
# # # # ]
189 [ + - + + ]: 771 : } else if (auto I = cast<const ast::InsertStmt>(&stmt)) {
190 [ + - ]: 759 : auto &DB = C.get_database_in_use();
191 [ + - + - ]: 759 : auto &T = DB.get_table(I->table_name.text.assert_not_none());
192 [ + - ]: 759 : auto &store = T.store();
193 [ + - ]: 759 : StoreWriter W(store);
194 [ + - ]: 759 : auto &S = W.schema();
195 [ + - ]: 759 : Tuple tup(S);
196 : :
197 : : /* Write all tuples to the store. */
198 [ + + ]: 1596 : for (auto &t : I->tuples) {
199 [ + - ]: 837 : StackMachine get_tuple(Schema{});
200 [ + + ]: 4218 : for (std::size_t i = 0; i != t.size(); ++i) {
201 : 3381 : auto &v = t[i];
202 [ - + + ]: 3381 : switch (v.first) {
203 : : case ast::InsertStmt::I_Null:
204 [ + - ]: 180 : get_tuple.emit_St_Tup_Null(0, i);
205 : 180 : break;
206 : :
207 : : case ast::InsertStmt::I_Default:
208 : : /* nothing to be done, Tuples are initialized to default values */
209 : 0 : break;
210 : :
211 : : case ast::InsertStmt::I_Expr:
212 [ + - ]: 3201 : get_tuple.emit(*v.second);
213 [ + - + - : 3201 : get_tuple.emit_Cast(S[i].type, v.second->type());
+ - ]
214 [ + - + - ]: 3201 : get_tuple.emit_St_Tup(0, i, S[i].type);
215 : 3201 : break;
216 : : }
217 : 3381 : }
218 : 837 : Tuple *args[] = { &tup };
219 [ + - ]: 837 : get_tuple(args);
220 [ + - ]: 837 : W.append(tup);
221 : 837 : }
222 [ + - - + ]: 771 : } else if (auto S = cast<const ast::CreateDatabaseStmt>(&stmt)) {
223 [ # # # # ]: 0 : C.add_database(S->database_name.text.assert_not_none());
224 [ + - - + ]: 12 : } else if (auto S = cast<const ast::DropDatabaseStmt>(&stmt)) {
225 [ # # ]: 0 : M_unreachable("not implemented");
226 [ + - - + ]: 12 : } else if (auto S = cast<const ast::UseDatabaseStmt>(&stmt)) {
227 [ # # # # ]: 0 : auto &DB = C.get_database(S->database_name.text.assert_not_none());
228 [ # # ]: 0 : C.set_database_in_use(DB);
229 [ + - + - ]: 12 : } else if (auto S = cast<const ast::CreateTableStmt>(&stmt)) {
230 [ + - ]: 12 : auto &DB = C.get_database_in_use();
231 [ + - + - ]: 12 : auto &T = DB.add_table(S->table_name.text.assert_not_none());
232 : :
233 [ + + ]: 54 : for (auto &attr : S->attributes) {
234 [ + - ]: 42 : const PrimitiveType *ty = cast<const PrimitiveType>(attr->type);
235 [ + - ]: 42 : auto attribute_name = attr->name.text.assert_not_none();
236 : :
237 [ + - + - : 42 : T.push_back(attribute_name, ty->as_vectorial());
+ - ]
238 [ + + ]: 54 : for (auto &c : attr->constraints) {
239 [ + - + - : 48 : visit(overloaded {
+ - + - ]
240 : 24 : [&](const PrimaryKeyConstraint&) {
241 : 12 : T.add_primary_key(attribute_name);
242 : 12 : },
243 : 12 : [&](const UniqueConstraint&) {
244 : 0 : T.at(attribute_name).unique = true;
245 : 0 : },
246 : 12 : [&](const NotNullConstraint&) {
247 : 0 : T.at(attribute_name).not_nullable = true;
248 : 0 : },
249 : 12 : [&](const ReferenceConstraint &ref) {
250 [ # # ]: 0 : auto &ref_table = DB.get_table(ref.table_name.text.assert_not_none());
251 [ # # ]: 0 : auto &ref_attr = ref_table.at(ref.attr_name.text.assert_not_none());
252 : 0 : T.at(attribute_name).reference = &ref_attr;
253 : 0 : },
254 : 0 : [](auto&&) { M_unreachable("constraint not implemented"); },
255 : 12 : }, *c, tag<ConstASTConstraintVisitor>{});
256 : : }
257 : 42 : }
258 : :
259 [ + - + - ]: 12 : T.layout(C.data_layout());
260 [ + - + - ]: 12 : T.store(C.create_store(T));
261 [ # # # # ]: 12 : } else if (auto S = cast<const ast::DropTableStmt>(&stmt)) {
262 [ # # ]: 0 : M_unreachable("not implemented");
263 [ # # # # ]: 0 : } else if (auto S = cast<const ast::DSVImportStmt>(&stmt)) {
264 [ # # ]: 0 : auto &DB = C.get_database_in_use();
265 [ # # # # ]: 0 : auto &T = DB.get_table(S->table_name.text.assert_not_none());
266 : :
267 : 0 : DSVReader::Config cfg;
268 [ # # # # : 0 : if (S->rows) cfg.num_rows = strtol(*S->rows.text, nullptr, 10);
# # ]
269 [ # # # # : 0 : if (S->delimiter) cfg.delimiter = unescape(*S->delimiter.text)[1];
# # # # #
# # # ]
270 [ # # # # : 0 : if (S->escape) cfg.escape = unescape(*S->escape.text)[1];
# # # # #
# # # ]
271 [ # # # # : 0 : if (S->quote) cfg.quote = unescape(*S->quote.text)[1];
# # # # #
# # # ]
272 : 0 : cfg.has_header = S->has_header;
273 : 0 : cfg.skip_header = S->skip_header;
274 : :
275 : : try {
276 [ # # ]: 0 : DSVReader R(T, std::move(cfg), diag);
277 : :
278 [ # # # # : 0 : std::string filename(*S->path.text, 1, strlen(*S->path.text) - 2);
# # ]
279 : 0 : errno = 0;
280 [ # # ]: 0 : std::ifstream file(filename);
281 [ # # # # ]: 0 : if (not file) {
282 : 0 : const auto errsv = errno;
283 [ # # # # : 0 : diag.e(S->path.pos) << "Could not open file '" << S->path.text << '\'';
# # # # ]
284 [ # # ]: 0 : if (errsv)
285 [ # # # # : 0 : diag.err() << ": " << strerror(errsv);
# # ]
286 [ # # # # ]: 0 : diag.err() << std::endl;
287 : 0 : } else {
288 [ # # # # : 0 : M_TIME_EXPR(R(file, *S->path.text), "Read DSV file", timer);
# # # # #
# ]
289 : : }
290 [ # # # # ]: 0 : } catch (m::invalid_argument e) {
291 [ # # # # : 0 : diag.err() << "Error reading DSV file: " << e.what() << "\n";
# # # # ]
292 [ # # # # ]: 0 : }
293 : 0 : }
294 : :
295 [ + - - + ]: 771 : if (Options::Get().times) {
296 : : using namespace std::chrono;
297 [ # # # # : 0 : for (const auto &M : timer) {
# # ]
298 [ # # # # ]: 0 : if (M.is_finished())
299 [ # # # # : 0 : std::cout << M.name << ": " << duration_cast<microseconds>(M.duration()).count() / 1e3 << '\n';
# # # # #
# # # #
# ]
300 : : }
301 [ # # ]: 0 : std::cout.flush();
302 [ # # ]: 0 : timer.clear();
303 : 0 : }
304 : :
305 [ + - ]: 771 : std::cout.flush();
306 [ + - ]: 771 : std::cerr.flush();
307 : 771 : }
308 : :
309 : 0 : void m::execute_instruction(Diagnostic &diag, const Instruction &instruction)
310 : : {
311 : 0 : diag.clear();
312 : 0 : Catalog &C = Catalog::Get();
313 : :
314 : : try {
315 [ # # ]: 0 : auto I = C.create_instruction(instruction.name, instruction.args);
316 [ # # ]: 0 : I->execute(diag);
317 [ # # ]: 0 : } catch (const std::exception &e) {
318 [ # # # # : 0 : diag.e(instruction.tok.pos) << "Instruction " << instruction.name << " does not exist.\n";
# # # # ]
319 [ # # ]: 0 : }
320 : 0 : }
321 : :
322 : 81 : std::unique_ptr<Consumer> m::logical_plan_from_statement(Diagnostic&, const SelectStmt &stmt,
323 : : std::unique_ptr<Consumer> consumer)
324 : : {
325 : 81 : Catalog &C = Catalog::Get();
326 [ + - + - : 162 : auto query_graph = M_TIME_EXPR(QueryGraph::Build(stmt), "Construct the query graph", C.timer());
- + ]
327 : :
328 [ + - + - : 81 : Optimizer Opt(C.plan_enumerator(), C.cost_function());
+ - ]
329 [ + - + - : 162 : auto optree = M_TIME_EXPR(Opt(*query_graph), "Compute the logical query plan", C.timer());
+ - - + ]
330 : :
331 [ - + ]: 81 : consumer->add_child(optree.release());
332 : :
333 : 81 : return consumer;
334 : 81 : }
335 : :
336 : 0 : std::unique_ptr<MatchBase> m::physical_plan_from_logical_plan(Diagnostic &diag, const Consumer &logical_plan)
337 : : {
338 : 0 : auto &C = Catalog::Get();
339 [ # # ]: 0 : static thread_local std::unique_ptr<Backend> backend;
340 [ # # ]: 0 : if (not backend)
341 [ # # # # : 0 : backend = M_TIME_EXPR(C.create_backend(), "Create backend", C.timer());
# # ]
342 : 0 : return physical_plan_from_logical_plan(diag, logical_plan, *backend);
343 : : }
344 : :
345 : 81 : std::unique_ptr<MatchBase> m::physical_plan_from_logical_plan(Diagnostic&, const Consumer &logical_plan,
346 : : const Backend &backend)
347 : : {
348 : 81 : PhysicalOptimizerImpl<ConcretePhysicalPlanTable> PhysOpt;
349 [ + - ]: 81 : backend.register_operators(PhysOpt);
350 [ + - + - : 162 : M_TIME_EXPR(PhysOpt.cover(logical_plan), "Compute the physical query plan", Catalog::Get().timer());
+ - - + ]
351 [ + - ]: 81 : return PhysOpt.extract_plan();
352 : 81 : }
353 : :
354 : 0 : void m::execute_physical_plan(Diagnostic &diag, const MatchBase &physical_plan)
355 : : {
356 : 0 : auto &C = Catalog::Get();
357 [ # # ]: 0 : static thread_local std::unique_ptr<Backend> backend;
358 [ # # ]: 0 : if (not backend)
359 [ # # # # : 0 : backend = M_TIME_EXPR(C.create_backend(), "Create backend", C.timer());
# # ]
360 : 0 : execute_physical_plan(diag, physical_plan, *backend);
361 : 0 : }
362 : :
363 : 81 : void m::execute_physical_plan(Diagnostic&, const MatchBase &physical_plan, const Backend &backend)
364 : : {
365 [ + - + - : 162 : M_TIME_EXPR(backend.execute(physical_plan), "Execute query", Catalog::Get().timer());
- + ]
366 : 81 : }
367 : :
368 : 75 : void m::execute_query(Diagnostic &diag, const SelectStmt &stmt, std::unique_ptr<Consumer> consumer)
369 : : {
370 : 75 : auto &C = Catalog::Get();
371 [ + + ]: 75 : static thread_local std::unique_ptr<Backend> backend;
372 [ + + ]: 75 : if (not backend)
373 [ + - + - : 2 : backend = M_TIME_EXPR(C.create_backend(), "Create backend", C.timer());
- + ]
374 [ + - ]: 75 : execute_query(diag, stmt, std::move(consumer), *backend);
375 : 75 : }
376 : :
377 : 81 : void m::execute_query(Diagnostic &diag, const SelectStmt &stmt, std::unique_ptr<Consumer> consumer,
378 : : const Backend &backend)
379 : : {
380 [ + - ]: 81 : auto logical_plan = logical_plan_from_statement(diag, stmt, std::move(consumer));
381 [ + - ]: 81 : auto physical_plan = physical_plan_from_logical_plan(diag, *logical_plan, backend);
382 [ - + ]: 81 : execute_physical_plan(diag, *physical_plan, backend);
383 : 81 : }
384 : :
385 : 0 : void m::load_from_CSV(Diagnostic &diag, Table &table, const std::filesystem::path &path, std::size_t num_rows,
386 : : bool has_header, bool skip_header)
387 : : {
388 : 0 : diag.clear();
389 : 0 : auto cfg = DSVReader::Config::CSV();
390 : 0 : cfg.num_rows = num_rows;
391 : 0 : cfg.has_header = has_header;
392 : 0 : cfg.skip_header = skip_header;
393 : 0 : DSVReader R(table, std::move(cfg), diag);
394 : :
395 : 0 : errno = 0;
396 [ # # ]: 0 : std::ifstream file(path);
397 [ # # # # ]: 0 : if (not file) {
398 [ # # # # : 0 : diag.e(Position(path.c_str())) << "Could not open file '" << path << '\'';
# # # # #
# ]
399 [ # # ]: 0 : if (errno)
400 [ # # # # : 0 : diag.err() << ": " << strerror(errno);
# # ]
401 [ # # # # ]: 0 : diag.err() << std::endl;
402 : 0 : } else {
403 [ # # ]: 0 : R(file, path.c_str()); // read the file
404 : : }
405 : :
406 [ # # # # ]: 0 : if (diag.num_errors() != 0)
407 [ # # # # : 0 : throw runtime_error("error while reading CSV file");
# # # # ]
408 : 0 : }
409 : :
410 : 0 : void m::execute_file(Diagnostic &diag, const std::filesystem::path &path)
411 : : {
412 : 0 : diag.clear();
413 : 0 : auto &C = Catalog::Get();
414 : :
415 : 0 : errno = 0;
416 : 0 : std::ifstream in(path);
417 [ # # # # ]: 0 : if (not in) {
418 : 0 : auto errsv = errno;
419 [ # # # # : 0 : std::cerr << "Could not open '" << path << "'";
# # ]
420 [ # # ]: 0 : if (errno)
421 [ # # # # ]: 0 : std::cerr << ": " << std::strerror(errsv);
422 [ # # ]: 0 : std::cerr << std::endl;
423 : 0 : exit(EXIT_FAILURE);
424 : : }
425 : :
426 [ # # # # ]: 0 : Lexer lexer(diag, C.get_pool(), path.c_str(), in);
427 [ # # ]: 0 : Parser parser(lexer);
428 [ # # ]: 0 : Sema sema(diag);
429 : :
430 [ # # # # : 0 : while (parser.token()) {
# # ]
431 [ # # ]: 0 : std::unique_ptr<Command> command(parser.parse());
432 [ # # # # ]: 0 : if (diag.num_errors()) return;
433 [ # # # # : 0 : if (auto inst = cast<Instruction>(command)) {
# # ]
434 [ # # ]: 0 : execute_instruction(diag, *inst);
435 : 0 : } else {
436 [ # # ]: 0 : auto stmt = as<Stmt>(std::move(command));
437 [ # # ]: 0 : sema(*stmt);
438 [ # # # # ]: 0 : if (diag.num_errors()) return;
439 [ # # ]: 0 : execute_statement(diag, *stmt);
440 [ # # ]: 0 : }
441 [ # # ]: 0 : }
442 [ # # ]: 0 : }
443 : :
444 [ + - ]: 759 : m::StoreWriter::StoreWriter(Store &store) : store_(store), S(store.table().schema()) { }
445 : :
446 : 759 : m::StoreWriter::~StoreWriter() { }
447 : :
448 : 837 : void m::StoreWriter::append(const Tuple &tup) const
449 : : {
450 : 837 : store_.append();
451 [ + + ]: 837 : if (layout_ != &store_.table().layout()) {
452 : 759 : layout_ = &store_.table().layout();
453 [ + - + - ]: 1518 : writer_ = std::make_unique<m::StackMachine>(m::Interpreter::compile_store(S, store_.memory().addr(), *layout_,
454 : 759 : S, store_.num_rows() - 1));
455 : 759 : }
456 : :
457 : 837 : Tuple *args[] = { const_cast<Tuple*>(&tup) };
458 : 837 : (*writer_)(args);
459 : 837 : }
|