5#include "backend/WebAssembly.hpp"
29 std::istringstream in(str);
50 std::istringstream in(str);
75 while (parser.
token()) {
79 auto ast = parser.
parse();
83 using namespace std::chrono;
84 for (
const auto &M : timer) {
86 std::cout << M.name <<
": " << duration_cast<microseconds>(M.duration()).count() / 1e3 <<
'\n';
101 std::istringstream in(str);
116 auto timer = C.
timer();
118 if (is<const ast::SelectStmt>(stmt)) {
123 query_graph->dot(dot.
stream());
124 dot.
show(
"graph", is_stdin,
"fdp");
127 query_graph->sql(std::cout);
131 std::unique_ptr<Producer> optree;
135 "Compute the logical query plan",
138 optree = std::move(res.first);
140 std::filesystem::path JSON_path(
Options::Get().output_partial_plans_file);
142 std::ofstream JSON_file(JSON_path);
143 if (not JSON_file or errno) {
144 const auto errsv = errno;
146 diag.
err() <<
"Failed to open output file for partial plans " << JSON_path <<
": "
147 << strerror(errsv) << std::endl;
149 diag.
err() <<
"Failed to open output file for partial plans " << JSON_path << std::endl;
158 optree =
M_TIME_EXPR(Opt(*query_graph),
"Compute the logical query plan", timer);
160 M_insist(
bool(optree),
"optree must have been computed");
164 optree->dot(dot.
stream());
165 dot.
show(
"logical_plan", is_stdin);
168 std::unique_ptr<Consumer> logical_plan;
170 logical_plan = std::make_unique<NoOpOperator>(std::cout);
172 logical_plan = std::make_unique<PrintOperator>(std::cout);
173 logical_plan->add_child(optree.release());
175 static thread_local std::unique_ptr<Backend> backend;
180 backend->register_operators(PhysOpt);
181 M_TIME_EXPR(PhysOpt.
cover(*logical_plan),
"Compute the physical query plan", timer);
185 physical_plan->dump(std::cout);
188 M_TIME_EXPR(backend->execute(*physical_plan),
"Execute query", timer);
189 }
else if (
auto I = cast<const ast::InsertStmt>(&stmt)) {
191 auto &
T = DB.get_table(I->table_name.text.assert_not_none());
192 auto &store =
T.store();
198 for (
auto &t : I->tuples) {
200 for (std::size_t i = 0; i != t.size(); ++i) {
204 get_tuple.emit_St_Tup_Null(0, i);
212 get_tuple.emit(*v.second);
213 get_tuple.emit_Cast(S[i].type, v.second->type());
214 get_tuple.emit_St_Tup(0, i, S[i].type);
222 }
else if (
auto S = cast<const ast::CreateDatabaseStmt>(&stmt)) {
223 C.
add_database(S->database_name.text.assert_not_none());
224 }
else if (
auto S = cast<const ast::DropDatabaseStmt>(&stmt)) {
226 }
else if (
auto S = cast<const ast::UseDatabaseStmt>(&stmt)) {
227 auto &DB = C.
get_database(S->database_name.text.assert_not_none());
229 }
else if (
auto S = cast<const ast::CreateTableStmt>(&stmt)) {
231 auto &
T = DB.add_table(S->table_name.text.assert_not_none());
233 for (
auto &attr : S->attributes) {
234 const PrimitiveType *ty = cast<const PrimitiveType>(attr->type);
235 auto attribute_name = attr->name.text.assert_not_none();
238 for (
auto &c : attr->constraints) {
241 T.add_primary_key(attribute_name);
244 T.at(attribute_name).unique =
true;
247 T.at(attribute_name).not_nullable =
true;
250 auto &ref_table = DB.get_table(ref.table_name.text.assert_not_none());
251 auto &ref_attr = ref_table.at(ref.attr_name.text.assert_not_none());
252 T.at(attribute_name).reference = &ref_attr;
261 }
else if (
auto S = cast<const ast::DropTableStmt>(&stmt)) {
263 }
else if (
auto S = cast<const ast::DSVImportStmt>(&stmt)) {
265 auto &
T = DB.get_table(S->table_name.text.assert_not_none());
268 if (S->rows) cfg.
num_rows = strtol(*S->rows.text,
nullptr, 10);
278 std::string filename(*S->path.text, 1, strlen(*S->path.text) - 2);
280 std::ifstream file(filename);
282 const auto errsv = errno;
283 diag.
e(S->path.pos) <<
"Could not open file '" << S->path.text <<
'\'';
285 diag.
err() <<
": " << strerror(errsv);
286 diag.
err() << std::endl;
288 M_TIME_EXPR(R(file, *S->path.text),
"Read DSV file", timer);
291 diag.
err() <<
"Error reading DSV file: " << e.
what() <<
"\n";
296 using namespace std::chrono;
297 for (
const auto &M : timer) {
299 std::cout << M.name <<
": " << duration_cast<microseconds>(M.duration()).count() / 1e3 <<
'\n';
317 }
catch (
const std::exception &e) {
318 diag.
e(instruction.
tok.
pos) <<
"Instruction " << instruction.
name <<
" does not exist.\n";
329 auto optree =
M_TIME_EXPR(Opt(*query_graph),
"Compute the logical query plan", C.
timer());
331 consumer->add_child(optree.release());
339 static thread_local std::unique_ptr<Backend> backend;
341 backend =
M_TIME_EXPR(C.create_backend(),
"Create backend", C.timer());
357 static thread_local std::unique_ptr<Backend> backend;
359 backend =
M_TIME_EXPR(C.create_backend(),
"Create backend", C.timer());
371 static thread_local std::unique_ptr<Backend> backend;
373 backend =
M_TIME_EXPR(C.create_backend(),
"Create backend", C.timer());
386 bool has_header,
bool skip_header)
390 cfg.num_rows = num_rows;
391 cfg.has_header = has_header;
392 cfg.skip_header = skip_header;
393 DSVReader R(table, std::move(cfg), diag);
396 std::ifstream file(path);
398 diag.
e(
Position(path.c_str())) <<
"Could not open file '" << path <<
'\'';
400 diag.
err() <<
": " << strerror(errno);
401 diag.
err() << std::endl;
403 R(file, path.c_str());
416 std::ifstream in(path);
419 std::cerr <<
"Could not open '" << path <<
"'";
421 std::cerr <<
": " << std::strerror(errsv);
422 std::cerr << std::endl;
426 Lexer lexer(diag, C.get_pool(), path.c_str(), in);
430 while (parser.
token()) {
431 std::unique_ptr<Command> command(parser.
parse());
433 if (
auto inst = cast<Instruction>(command)) {
436 auto stmt = as<Stmt>(std::move(command));
451 if (layout_ != &store_.table().layout()) {
452 layout_ = &store_.table().layout();
454 S, store_.num_rows() - 1));
#define M_TIME_EXPR(EXPR, DESCR, TIMER)
#define M_unreachable(MSG)
M_EXPORT const version_info & get()
void M_EXPORT load_from_CSV(Diagnostic &diag, Table &table, const std::filesystem::path &path, std::size_t num_rows=std::numeric_limits< std::size_t >::max(), bool has_header=false, bool skip_header=false)
Loads a CSV file into a Table.
std::unique_ptr< Consumer > M_EXPORT logical_plan_from_statement(Diagnostic &diag, const ast::SelectStmt &stmt, std::unique_ptr< Consumer > consumer)
Optimizes the given SelectStmt.
void M_EXPORT process_stream(std::istream &in, const char *filename, Diagnostic diag)
Extracts and executes statements from given stream.
std::unique_ptr< DatabaseCommand > M_EXPORT command_from_string(Diagnostic &diag, const std::string &str)
Create a DatabaseCommand from str.
void M_EXPORT execute_statement(Diagnostic &diag, const ast::Stmt &stmt, bool is_stdin=false)
Optimizes and executes the given Stmt.
std::unique_ptr< ast::Instruction > M_EXPORT instruction_from_string(Diagnostic &diag, const std::string &str)
Use lexer and parser to create an Instruction from str.
bool streq(const char *first, const char *second)
std::string M_EXPORT unescape(const std::string &str, char esc='\\', char quote='"')
void M_EXPORT execute_instruction(Diagnostic &diag, const ast::Instruction &instruction)
Executes the given Instruction.
void M_EXPORT execute_physical_plan(Diagnostic &diag, const MatchBase &physical_plan)
Executes the given physical plan.
void M_EXPORT execute_file(Diagnostic &diag, const std::filesystem::path &path)
Execute the SQL file at path.
std::unique_ptr< ast::Stmt > M_EXPORT statement_from_string(Diagnostic &diag, const std::string &str)
Use lexer, parser, and semantic analysis to create a Stmt from str.
void M_EXPORT execute_query(Diagnostic &diag, const ast::SelectStmt &stmt, std::unique_ptr< Consumer > consumer)
Optimizes and executes the given SelectStmt.
bool M_EXPORT init(void)
Initializes the mu*t*able library.
auto visit(Callable &&callable, Base &obj, m::tag< Callable > &&=m::tag< Callable >())
Generic implementation to visit a class hierarchy, with similar syntax as std::visit.
std::unique_ptr< MatchBase > M_EXPORT physical_plan_from_logical_plan(Diagnostic &diag, const Consumer &logical_plan)
Computes a physical plan from the given logical plan.
Defines the interface of all execution Backends.
virtual void register_operators(PhysicalOptimizer &phys_opt) const =0
Registers all physical operators of this Backend in phys_opt.
virtual void execute(const MatchBase &plan) const =0
Executes the already computed physical covering represented by plan using this Backend.
The catalog contains all Databases and keeps track of all meta information of the database system.
CostFunction & cost_function() const
Returns a reference to the default CostFunction.
ThreadSafeStringPool & get_pool()
Returns a reference to the StringPool.
Database & get_database_in_use()
Returns a reference to the Database that is currently in use, if any.
Database & get_database(const ThreadSafePooledString &name) const
Returns the Database with the given name.
std::unique_ptr< Store > create_store(const Table &tbl) const
Creates a new Store for the given Table tbl.
Database & add_database(ThreadSafePooledString name)
Creates a new Database with the given name.
static Catalog & Get()
Return a reference to the single Catalog instance.
std::unique_ptr< DatabaseInstruction > create_instruction(const ThreadSafePooledString &name, const std::vector< std::string > &args) const
Returns a reference to the DatabaseInstruction with the given name.
Timer & timer()
Returns the global Timer instance.
Scheduler & scheduler() const
Returns a reference to the default Scheduler.
void set_database_in_use(Database &db)
Sets the Database db as the Database that is currently in use.
storage::DataLayoutFactory & data_layout() const
Returns a reference to the default DataLayoutFactory.
pe::PlanEnumerator & plan_enumerator() const
Returns a reference to the default PlanEnumerator.
std::unique_ptr< Backend > create_backend() const
Returns a new Backend.
A Consumer is an Operator that can be evaluated on a sequence of tuples.
Configuration parameters for importing a DSV file.
static Config CSV()
Creates a Config for CSV files, with delimiter, escape, and quote set accordingly to RFC 4180 (see ht...
char delimiter
the delimiter separating cells
char quote
the quotation mark for strings
bool skip_header
whether to ignore the headline (requires has_header = true)
char escape
the character to escape special characters within strings, e.g. \n
bool has_header
whether the first line of the file is a headline describing the columns
std::size_t num_rows
the maximum number of rows to read from the file (may exceed actual number of rows)
A reader for delimiter separated value (DSV) files.
std::ostream & e(const Position pos)
void clear()
Resets the error counter.
unsigned num_errors() const
Returns the number of errors emitted since the last call to clear().
static StackMachine compile_store(const Schema &tuple_schema, void *address, const storage::DataLayout &layout, const Schema &layout_schema, std::size_t row_id=0, std::size_t tuple_id=0)
Compile a StackMachine to store a tuple of Schema tuple_schema using a given memory address and a giv...
std::pair< std::unique_ptr< Producer >, PlanTable > optimize_with_plantable(QueryGraph &G) const
Recursively computes and constructs an optimal logical plan for the given query graph G,...
static Options & Get()
Return a reference to the single Options instance.
A partial plan is a set of (potentially incomplete) pairwise disjoint plans.
void for_each_complete_partial_plan(const PlanTable &PT, callback_type callback)
Given a PlanTable with a final plan, enumerate all complete partial plans of this final plan and invo...
void write_partial_plans_JSON(std::ostream &out, const QueryGraph &G, const PlanTable &PT, std::function< void(callback_type)> for_each_partial_plan)
std::function< void(const partial_plan_type &)> callback_type
Concrete PhysicalOptimizer implementation using a concrete statically-typed.
void cover(const Operator &plan) override
Finds an optimal physical operator covering for the logical plan rooted in plan.
std::unique_ptr< MatchBase > extract_plan() override
Extracts the found physical operator covering by moving it out of the underlying physical plan table.
This table represents all explored plans with their sub-plans, estimated size, cost,...
PrimitiveTypes represent Types of values.
virtual const PrimitiveType * as_vectorial() const =0
Convert this PrimitiveType to its vectorial equivalent.
static std::unique_ptr< QueryGraph > Build(const ast::Stmt &stmt)
bool autocommit(std::unique_ptr< ast::Command > command, Diagnostic &diag)
Schedule a ast::Command for execution and automatically commits its changes.
A Schema represents a sequence of identifiers, optionally with a prefix, and their associated types.
A stack machine that evaluates an expression.
This class provides direct write access to the contents of a Store.
void append(const Tuple &tup) const
Appends tup to the store.
const Schema & schema() const
Returns the Schema of Tuples to write.
StoreWriter(Store &store)
Defines a generic store interface.
A table is a sorted set of attributes.
Collect timings of events.
Token tok
the token of the Instruction; starts with \
ThreadSafePooledString name
the name of the Instruction (without leading \)
std::vector< std::string > args
the arguments to the Instruction; may be empty
std::unique_ptr< Stmt > parse_Stmt()
std::unique_ptr< Command > parse()
std::unique_ptr< Instruction > parse_Instruction()
std::unique_ptr< DatabaseCommand > analyze(std::unique_ptr< ast::Command > ast)
Perform semantic analysis of an ast::Command.
const char * what() const noexcept override
Signals that an argument to a function of method was invalid.
Signals a runtime error that mu*t*able is not responsible for and that mu*t*able was not able to reco...