mutable
A Database System for Research and Fast Prototyping
Loading...
Searching...
No Matches
DatabaseCommand.cpp
Go to the documentation of this file.
2
7#include <mutable/mutable.hpp>
8#include <mutable/Options.hpp>
11
12
13using namespace m;
14
15
16void EmptyCommand::execute(Diagnostic &diag) { /* Nothing to be done. */ }
17
18
19/*======================================================================================================================
20 * Instructions
21 *====================================================================================================================*/
22
24{
25 auto &C = Catalog::Get();
26 if (not C.has_database_in_use()) { diag.err() << "No database selected.\n"; return; }
27
28 auto &DB = C.get_database_in_use();
29 if (DB.size() == 0) { diag.err() << "There are no tables in the database.\n"; return; }
30
31 auto CE = C.create_cardinality_estimator(C.pool("Spn"), DB.name);
32 auto spn_estimator = cast<SpnEstimator>(CE.get());
33 spn_estimator->learn_spns();
34 DB.cardinality_estimator(std::move(CE));
35
36 if (not Options::Get().quiet) { diag.out() << "Learned SPN on every table in " << DB.name << ".\n"; }
37}
38
39__attribute__((constructor(201)))
40static void register_instructions()
41{
42 Catalog &C = Catalog::Get();
43#define REGISTER(NAME, DESCRIPTION) \
44 C.register_instruction<NAME>(C.pool(#NAME), DESCRIPTION)
45 REGISTER(learn_spns, "create an SPN for every table in the database");
46#undef REGISTER
47}
48
49/*======================================================================================================================
50 * Data Manipulation Language (DML)
51 *====================================================================================================================*/
52
54{
55 Catalog &C = Catalog::Get();
56
57 if (auto stmt = cast<ast::Stmt>(&ast())) {
58 if (Options::Get().ast)
59 stmt->dump(diag.out());
60 if (Options::Get().astdot) {
61 DotTool dot(diag);
62 stmt->dot(dot.stream());
63 dot.show("ast", false, "dot");
64 }
65 }
66
67 auto graph_construction = C.timer().create_timing("Construct the query graph");
68 graph_ = QueryGraph::Build(ast<ast::SelectStmt>());
69 graph_->transaction(this->transaction());
70 for (auto &pre_opt : C.pre_optimizations())
71 (*pre_opt.second).operator()(*graph_);
72 graph_construction.stop();
73
74 if (Options::Get().graph)
75 graph_->dump(std::cout);
76 if (Options::Get().graphdot) {
77 DotTool dot(diag);
78 graph_->dot(dot.stream());
79 dot.show("graph", false, "fdp");
80 }
81 if (Options::Get().graph2sql) {
82 graph_->sql(std::cout);
83 std::cout.flush();
84 }
85
86 auto logical_plan_computation = C.timer().create_timing("Compute the logical query plan");
88 std::unique_ptr<Producer> producer = Opt(*graph_);
89 for (auto &post_opt : C.logical_post_optimizations())
90 producer = (*post_opt.second).operator()(std::move(producer));
91 logical_plan_computation.stop();
92 M_insist(bool(producer), "logical plan must have been computed");
93
94 if (Options::Get().plan)
95 producer->dump(diag.out());
96 if (Options::Get().plandot) {
97 DotTool dot(diag);
98 producer->dot(dot.stream());
99 dot.show("logical_plan", false, "dot");
100 }
101
102 if (Options::Get().benchmark)
103 logical_plan_ = std::make_unique<NoOpOperator>(std::cout);
104 else
105 logical_plan_ = std::make_unique<PrintOperator>(std::cout);
106 logical_plan_->add_child(producer.release());
107
108 static thread_local std::unique_ptr<Backend> backend;
109 if (not backend)
110 backend = M_TIME_EXPR(C.create_backend(), "Create backend", C.timer());
111
112 auto physical_plan_computation = C.timer().create_timing("Compute the physical query plan");
114 backend->register_operators(PhysOpt);
115 PhysOpt.cover(*logical_plan_);
116 physical_plan_ = PhysOpt.extract_plan();
117 for (auto &post_opt : C.physical_post_optimizations())
118 physical_plan_ = (*post_opt.second).operator()(std::move(physical_plan_));
119 physical_plan_computation.stop();
120
122 physical_plan_->dump(std::cout);
123
124 if (not Options::Get().dryrun)
125 M_TIME_EXPR(backend->execute(*physical_plan_), "Execute query", C.timer());
126}
127
129{
130 Catalog &C = Catalog::Get();
131 auto &DB = C.get_database_in_use();
132
133 auto &I = ast<ast::InsertStmt>();
134 auto &T = DB.get_table(I.table_name.text.assert_not_none());
135 auto &store = T.store();
136 StoreWriter W(store);
137 auto &S = W.schema();
138 Tuple tup(S);
139
140 /* Find timestamp attributes */
141 auto ts_begin = std::find_if(T.cbegin_hidden(), T.end_hidden(),
142 [&](const Attribute & attr) {
143 return attr.name == C.pool("$ts_begin");
144 });
145 auto ts_end = std::find_if(T.cbegin_hidden(), T.end_hidden(),
146 [&](const Attribute & attr) {
147 return attr.name == C.pool("$ts_end");
148 });
149
150 /* Write all tuples to the store. */
151 for (auto &t : I.tuples) {
152 StackMachine get_tuple(Schema{});
153 for (std::size_t i = 0; i != t.size(); ++i) {
154 auto attr_id = T.convert_id(i); // hidden attributes change the actual id of the attribute
155 auto &v = t[i];
156 switch (v.first) {
158 get_tuple.emit_St_Tup_Null(0, i);
159 break;
160
162 /* nothing to be done, Tuples are initialized to default values */
163 break;
164
166 get_tuple.emit(*v.second);
167 get_tuple.emit_Cast(S[attr_id].type, v.second->type());
168 get_tuple.emit_St_Tup(0, attr_id, S[attr_id].type);
169 break;
170 }
171 }
172 Tuple *args[] = { &tup };
173 get_tuple(args);
174
175 /*----- set timestamps if available. -----*/
176 if (ts_begin != T.end_hidden()) {
177 tup.set(ts_begin->id, Value(transaction()->start_time()));
178 /* Set $ts_end to -1. It is a special value representing infinity. */
179 M_insist(ts_end != T.end_hidden());
180 tup.set(ts_end->id, Value(-1));
181 }
182
183 W.append(tup);
184 }
185 /* Invalidate all indexes on the table. */
186 DB.invalidate_indexes(T.name());
187}
188
190{
191 M_unreachable("not yet implemented");
192}
193
195{
196 M_unreachable("not yet implemented");
197}
198
200{
201 Catalog &C = Catalog::Get();
202 try {
203 DSVReader R(table_, cfg_, diag, transaction());
204
205 errno = 0;
206 std::ifstream file(path_);
207 if (not file) {
208 const auto errsv = errno;
209 diag.err() << "Could not open file " << path_;
210 if (errsv)
211 diag.err() << ": " << strerror(errsv);
212 diag.err() << std::endl;
213 } else {
214 M_TIME_EXPR(R(file, path_.c_str()), "Read DSV file", C.timer());
215 }
216 } catch (m::invalid_argument e) {
217 diag.err() << "Error reading DSV file: " << e.what() << "\n";
218 }
219}
220
221
222/*======================================================================================================================
223 * Data Definition Language
224 *====================================================================================================================*/
225
227{
228 try {
230 if (not Options::Get().quiet)
231 diag.out() << "Created database " << db_name_ << ".\n";
232 } catch (std::invalid_argument) {
233 diag.err() << "Database " << db_name_ << " already exists.\n";
234 }
235}
236
238{
239 try {
241 if (not Options::Get().quiet)
242 diag.out() << "Dropped database " << db_name_ << ".\n";
243 } catch (std::invalid_argument) {
244 diag.err() << "Database " << db_name_ << " does not exist.\n";
245 }
246}
247
249{
250 auto &C = Catalog::Get();
251 try {
252 auto &DB = C.get_database(db_name_);
253 C.set_database_in_use(DB);
254 if (not Options::Get().quiet)
255 diag.out() << "Using database " << db_name_ << ".\n";
256 } catch (std::out_of_range) {
257 diag.err() << "Database " << db_name_ << " does not exist.\n";
258 }
259}
260
262{
263 auto &C = Catalog::Get();
264 auto &DB = C.get_database_in_use();
265 ThreadSafePooledString table_name = table_->name();
266 Table *table = nullptr;
267 try {
268 table = &DB.add(std::move(table_));
269 } catch (std::invalid_argument) {
270 diag.err() << "Table " << table_name << " already exists in database " << DB.name << ".\n";
271 }
272
273 table->layout(C.data_layout());
274 table->store(C.create_store(*table));
275
276 if (not Options::Get().quiet)
277 diag.out() << "Created table " << table->name() << ".\n";
278}
279
281{
282 auto &C = Catalog::Get();
283 auto &DB = C.get_database_in_use();
284
285 for (auto &table_name : table_names_) {
286 try {
287 DB.drop_table(table_name);
288 if (not Options::Get().quiet)
289 diag.out() << "Dropped table " << table_name << ".\n";
290 } catch (std::invalid_argument) {
291 diag.err() << "Table " << table_name << " does not exist in Database " << DB.name << ".\n";
292 }
293 }
294}
295
297{
298 auto &C = Catalog::Get();
299 auto &DB = C.get_database_in_use();
300 const auto &table = DB.get_table(table_name_);
301
302 /* Compute bulkloading schema from attribute name. */
303 Schema schema;
304 for (auto &entry : table.schema()) {
305 if (entry.id.name == attribute_name_) {
306 schema.add(entry);
307 break; // only one-dimensional indexes are supported
308 }
309 }
310
311 /* Bulkload index. */
312 try {
313 M_TIME_EXPR(index_->bulkload(table, schema), "Bulkload index", C.timer());
314 } catch (invalid_argument) {
315 diag.err() << "Could not bulkload index." << '\n';
316 }
317
318 /* Add index to database. */
319 try {
320 DB.add_index(std::move(index_), table_name_, attribute_name_, index_name_);
321 if (not Options::Get().quiet)
322 diag.out() << "Created index " << index_name_ << ".\n";
323 } catch (std::out_of_range) {
324 diag.err() << "Table " << table_name_ << " or Attribute " << attribute_name_ << " does not exist in Database "
325 << DB.name << ".\n";
326 } catch (invalid_argument) {
327 diag.err() << "Index " << index_name_ << " already exists in Database " << DB.name << ".\n";
328 }
329}
330
332{
333 auto &C = Catalog::Get();
334 auto &DB = C.get_database_in_use();
335
336 for (auto &index_name : index_names_) {
337 try {
338 DB.drop_index(index_name);
339 if (not Options::Get().quiet)
340 diag.out() << "Dropped index " << index_name << ".\n";
341 } catch (invalid_argument) {
342 diag.err() << "Index " << index_name << " does not exist in Database " << DB.name << ".\n";
343 }
344 }
345}
346
347#define ACCEPT(CLASS) \
348 void CLASS::accept(DatabaseCommandVisitor &v) { v(*this); } \
349 void CLASS::accept(ConstDatabaseCommandVisitor &v) const { v(*this); }
351#undef ACCEPT
#define M_DATABASE_COMMAND_LIST(X)
#define ACCEPT(CLASS)
#define REGISTER(CLASS)
__attribute__((constructor(202))) static void register_interpreter()
#define M_TIME_EXPR(EXPR, DESCR, TIMER)
Definition: Timer.hpp:177
struct @5 args
#define M_unreachable(MSG)
Definition: macro.hpp:146
#define M_insist(...)
Definition: macro.hpp:129
‍mutable namespace
Definition: Backend.hpp:10
T(x)
An attribute of a table.
Definition: Schema.hpp:289
The catalog contains all Databases and keeps track of all meta information of the database system.
Definition: Catalog.hpp:215
CostFunction & cost_function() const
Returns a reference to the default CostFunction.
Definition: Catalog.hpp:502
auto logical_post_optimizations()
Definition: Catalog.hpp:644
Database & get_database_in_use()
Returns a reference to the Database that is currently in use, if any.
Definition: Catalog.hpp:295
Database & add_database(ThreadSafePooledString name)
Creates a new Database with the given name.
Definition: Catalog.cpp:58
static Catalog & Get()
Return a reference to the single Catalog instance.
auto pre_optimizations()
Definition: Catalog.hpp:622
void drop_database(const ThreadSafePooledString &name)
Drops the Database with the name.
Definition: Catalog.cpp:66
Timer & timer()
Returns the global Timer instance.
Definition: Catalog.hpp:264
auto physical_post_optimizations()
Definition: Catalog.hpp:668
pe::PlanEnumerator & plan_enumerator() const
Returns a reference to the default PlanEnumerator.
Definition: Catalog.hpp:441
std::unique_ptr< Backend > create_backend() const
Returns a new Backend.
Definition: Catalog.hpp:477
void execute(Diagnostic &diag) override
Executes the command.
ThreadSafePooledString db_name_
ThreadSafePooledString table_name_
ThreadSafePooledString index_name_
void execute(Diagnostic &diag) override
Executes the command.
ThreadSafePooledString attribute_name_
std::unique_ptr< idx::IndexBase > index_
void execute(Diagnostic &diag) override
Executes the command.
std::unique_ptr< Table > table_
A reader for delimiter separated value (DSV) files.
Definition: Reader.hpp:30
Scheduler::Transaction * transaction()
void execute(Diagnostic &diag) override
Executes the command.
std::ostream & out() const
Definition: Diagnostic.hpp:52
std::ostream & err()
Definition: Diagnostic.hpp:53
This class enables direct rendering of dot output (e.g.
Definition: DotTool.hpp:14
std::ostream & stream()
Definition: DotTool.hpp:27
void show(const char *name, bool interactive, const char *algo=DEFAULT_LAYOUT_ALGORITHM)
Present the graph to the user.
Definition: DotTool.cpp:84
void execute(Diagnostic &diag) override
Executes the command.
ThreadSafePooledString db_name_
std::vector< ThreadSafePooledString > index_names_
void execute(Diagnostic &diag) override
Executes the command.
void execute(Diagnostic &diag) override
Executes the command.
std::vector< ThreadSafePooledString > table_names_
void execute(Diagnostic &diag) override
Executes the command.
const Table & table_
std::filesystem::path path_
void execute(Diagnostic &diag) override
Executes the command.
void execute(Diagnostic &diag) override
Executes the command.
The optimizer interface.
Definition: Optimizer.hpp:19
bool dryrun
If true, do not pass the query to the backend for execution.
Definition: Options.hpp:51
static Options & Get()
Return a reference to the single Options instance.
Definition: Options.cpp:9
bool physplan
Definition: Options.hpp:48
bool graph
Definition: Options.hpp:43
bool graphdot
Definition: Options.hpp:44
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.
A data type representing a pooled (or internalized) object.
Definition: Pool.hpp:168
std::unique_ptr< Consumer > logical_plan_
std::unique_ptr< MatchBase > physical_plan_
std::unique_ptr< QueryGraph > graph_
void execute(Diagnostic &diag) override
Executes the command.
static std::unique_ptr< QueryGraph > Build(const ast::Stmt &stmt)
A Schema represents a sequence of identifiers, optionally with a prefix, and their associated types.
Definition: Schema.hpp:39
void add(entry_type e)
Adds the entry e to this Schema.
Definition: Schema.hpp:181
A stack machine that evaluates an expression.
This class provides direct write access to the contents of a Store.
Definition: mutable.hpp:116
void append(const Tuple &tup) const
Appends tup to the store.
Definition: mutable.cpp:448
const Schema & schema() const
Returns the Schema of Tuples to write.
Definition: mutable.hpp:128
A table is a sorted set of attributes.
Definition: Schema.hpp:388
virtual const storage::DataLayout & layout() const =0
Returns a reference to the physical data layout.
virtual const ThreadSafePooledString & name() const =0
Returns the name of the Table.
virtual Store & store() const =0
Returns a reference to the backing store.
TimingProcess create_timing(std::string name)
Creates a new TimingProcess with the given name.
Definition: Timer.hpp:152
void set(std::size_t idx, Value val)
Assigns the Value val to this Tuple at index idx and clears the respective NULL bit.
Definition: Tuple.hpp:240
void execute(Diagnostic &diag) override
Executes the command.
void execute(Diagnostic &diag) override
Executes the command.
ThreadSafePooledString db_name_
This class holds a SQL attribute value.
Definition: Tuple.hpp:19
const char * what() const noexcept override
Definition: exception.hpp:17
Signals that an argument to a function of method was invalid.
Definition: exception.hpp:37
Learn an SPN on every table in the database that is currently in use.
void execute(Diagnostic &diag) override
Executes the command.