LCOV - code coverage report
Current view: top level - src - mutable.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 112 334 33.5 %
Date: 2025-03-25 01:19:55 Functions: 19 46 41.3 %
Branches: 117 843 13.9 %

           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 : }

Generated by: LCOV version 1.16