mutable
A Database System for Research and Fast Prototyping
Loading...
Searching...
No Matches
shell.cpp
Go to the documentation of this file.
1#include "util/glyphs.hpp"
2#include <cerrno>
3#include <cstdlib>
4#include <dlfcn.h>
5#include <filesystem>
6#include <fstream>
7#include <functional>
8#include <iomanip>
9#include <iostream>
11#include <mutable/mutable.hpp>
12#include <mutable/Options.hpp>
14#include <regex>
15#include <replxx.hxx>
16#include <vector>
17
18#if __linux
19#include <unistd.h>
20
21#elif __APPLE__
22#include <unistd.h>
23#endif
24
25
26/* forward declarations */
27namespace m {
28
29struct PlanTable;
30
31}
32
33
34using namespace m;
35using Replxx = replxx::Replxx;
36
37
38void usage(std::ostream &out, const char *name)
39{
40 out << "An interactive shell to communicate with the database system.\n"
41 << "USAGE:\n\t" << name << " [<FILE>...]"
42 << std::endl;
43}
44
45void load_plugins(std::string list)
46{
47 std::string delimiter = ",";
48 size_t last = 0;
49 size_t next = list.find(delimiter, last);
50 std::filesystem::path cwd(".");
51 for (;;) {
52 std::filesystem::path path_to_shared = list.substr(last, next - last);
53 if (path_to_shared.is_relative() and path_to_shared.string().find("./") != 0)
54 path_to_shared = cwd / path_to_shared; // prepend './'
55 if (not Options::Get().quiet)
56 std::cerr << "loading plugin " << path_to_shared << "\n";
57 void *handle = dlopen(path_to_shared.c_str(), RTLD_NOW);
58 if (not handle)
59 std::cerr << "WARNING: Failed to load " << path_to_shared << ": " << dlerror() << '\n';
60 if (next == std::string::npos)
61 break;
62 last = next + 1;
63 next = list.find(delimiter, last);
64 }
65}
66
67std::string prompt(bool is_editing, Timer::duration dur = Timer::duration())
68{
69 unsigned bg = 242;
70 std::ostringstream prompt;
71
72 if (not is_editing) {
73 if (dur != Timer::duration()) {
74 const auto ms = std::chrono::duration_cast<std::chrono::microseconds>(dur).count() / 1e3;
75 bg = 242;
77 << term::fg(220) << term::bg(bg) << ' '
78 << std::fixed << std::setprecision(2) << ms << " ms ";
79 bg = 238;
80 prompt << term::bg(bg) << term::fg(242) << glyphs::RIGHT << ' ';
81 }
82
83 bg = 238;
84 static auto &C = Catalog::Get();
85 prompt << term::bg(bg) << term::FG_WHITE << " mu"
86 << term::ITALIC << term::fg(30) << 't' << term::RESET
87 << term::bg(bg) << term::FG_WHITE << "able ";
88 if (C.has_database_in_use()) {
89 auto &DB = C.get_database_in_use();
90 prompt << term::fg(bg);
91 bg = 242;
93 << ' ' << glyphs::DATABASE << ' ' << DB.name << ' ';
94 }
95 }
97 return prompt.str();
98}
99
101int utf8str_codepoint_len(const char *s, int utf8_len) {
102 int codepoint_len = 0;
103 unsigned char m4 = 128 + 64 + 32 + 16;
104 unsigned char m3 = 128 + 64 + 32;
105 unsigned char m2 = 128 + 64;
106 for (int i = 0; i < utf8_len; ++i, ++codepoint_len ) {
107 char c = s[i];
108 if ((c & m4) == m4)
109 i += 3;
110 else if (( c & m3 ) == m3)
111 i += 2;
112 else if (( c & m2 ) == m2)
113 i += 1;
114 }
115 return codepoint_len;
116}
117
119int context_len(const std::string &prefix)
120{
121 auto it = prefix.rbegin();
122 for (; it != prefix.rend(); ++it) {
123 if (not is_alnum(*it))
124 break;
125 }
126
127 return it - prefix.rbegin();
128}
129
130/* Completion */
131Replxx::completions_t hook_completion(const std::string &prefix, int &context_len)
132{
133 static constexpr const char *KW[] = {
134#define M_KEYWORD(tt, name) #name,
135#include <mutable/tables/Keywords.tbl>
136#undef M_KEYWORD
137 };
138
139 Replxx::completions_t completions;
140 Replxx::Color color = Replxx::Color::DEFAULT;
141 context_len = ::context_len(prefix);
142 std::string context = prefix.substr(prefix.size() - context_len);
143 for (auto const &kw : KW) {
144 if (strneq(kw, context.c_str(), context_len))
145 completions.emplace_back(kw, color);
146 }
147 return completions;
148}
149
150/* Highlighter */
151void hook_highlighter(const std::string &context, Replxx::colors_t &colors)
152{
153 std::vector<std::pair<std::string, Replxx::Color>> regex_color = {
154 /* Keywords */
155#define M_KEYWORD(tt, name)\
156 { #name, Replxx::Color::BROWN },
157#include <mutable/tables/Keywords.tbl>
158#undef M_KEYWORD
159 /* Operators */
160 { "\\(", Replxx::Color::LIGHTGRAY},
161 { "\\)", Replxx::Color::LIGHTGRAY},
162 { "\\~", Replxx::Color::LIGHTGRAY},
163 { "\\+", Replxx::Color::LIGHTGRAY},
164 { "\\-", Replxx::Color::LIGHTGRAY},
165 { "\\*", Replxx::Color::LIGHTGRAY},
166 { "\\/", Replxx::Color::LIGHTGRAY},
167 { "\\%", Replxx::Color::LIGHTGRAY},
168 { "\\.", Replxx::Color::LIGHTGRAY},
169 { "\\=", Replxx::Color::LIGHTGRAY},
170 { "\\!=", Replxx::Color::LIGHTGRAY},
171 { "\\<", Replxx::Color::LIGHTGRAY},
172 { "\\>", Replxx::Color::LIGHTGRAY},
173 /* Constants */
174 {"[\\-|+]{0,1}[0-9]+", Replxx::Color::BLUE}, // integral numbers
175 {"[\\-|+]{0,1}[0-9]*\\.[0-9]+", Replxx::Color::BLUE}, // fixed-point and floating-point numbers
176 {"\"([^\\\\\"]|\\\\\")*\"", Replxx::Color::BRIGHTMAGENTA}, // double quoted strings
177 };
178 for (const auto &e : regex_color) {
179 std::size_t pos = 0;
180 std::string str = context; // string that is yet to be searched
181 std::smatch match;
182
183 while (std::regex_search(str, match, std::regex(e.first))) {
184 std::string c = match[0]; // first match for regex
185 std::string prefix = match.prefix().str(); // substring until first match
186 pos += utf8str_codepoint_len(prefix.c_str(), prefix.size());
187 int len = utf8str_codepoint_len(c.c_str(), c.size());
188
189 for (int i = 0; i < len; ++i)
190 colors.at(pos + i) = e.second; // set colors according to match
191
192 pos += len; // search for regex from pos onward
193 str = match.suffix();
194 }
195 }
196}
197
198/* Hints */
199Replxx::hints_t hook_hint(const std::string &prefix, int &context_len, Replxx::Color &color)
200{
201 static constexpr const char *KW[] = {
202#define M_KEYWORD(tt, name) #name,
203#include <mutable/tables/Keywords.tbl>
204#undef M_KEYWORD
205 };
206
207 Replxx::hints_t hints;
208 context_len = ::context_len(prefix);
209 std::string context = prefix.substr(prefix.size() - context_len);
210 if (context.size() >= 2) {
211 for (auto const &kw : KW) {
212 if (strneq(kw, context.c_str(), context_len))
213 hints.emplace_back(kw);
214 }
215 }
216 if (hints.size() == 1)
217 color = Replxx::Color::GREEN;
218 return hints;
219}
220
221int main(int argc, const char **argv)
222{
223 Catalog &C = Catalog::Get();
224
225 /* Identify whether the terminal supports colors. */
226 const bool term_has_color = term::has_color();
227
228 bool show_any_help = false;
229
230 /*----- Parse command line arguments. ----------------------------------------------------------------------------*/
231 ArgParser &AP = C.arg_parser();
232#define ADD(TYPE, VAR, INIT, SHORT, LONG, DESCR, CALLBACK)\
233 VAR = INIT;\
234 {\
235 AP.add<TYPE>(SHORT, LONG, DESCR, CALLBACK);\
236 }
237 /*----- Help message ---------------------------------------------------------------------------------------------*/
238 ADD(bool, Options::Get().show_help, false, /* Type, Var, Init */
239 "-h", "--help", /* Short, Long */
240 "prints this help message", /* Description */
241 [&](bool) { /* Callback */
242 show_any_help = true;
243 Options::Get().show_help = true;
244 });
245 ADD(bool, Options::Get().show_version, false, /* Type, Var, Init */
246 nullptr, "--version", /* Short, Long */
247 "shows version information", /* Description */
248 [&](bool) { Options::Get().show_version = true; }); /* Callback */
249 /* Shell configuration */
250 /*----- Shell configuration --------------------------------------------------------------------------------------*/
251 ADD(bool, Options::Get().has_color, false, /* Type, Var, Init */
252 nullptr, "--color", /* Short, Long */
253 "use colors", /* Description */
254 [&](bool) { Options::Get().has_color = true; }); /* Callback */
255 ADD(bool, Options::Get().show_prompt, true, /* Type, Var, Init */
256 nullptr, "--noprompt", /* Short, Long */
257 "disable prompt", /* Description */
258 [&](bool) { Options::Get().show_prompt = false; }); /* Callback */
259 ADD(bool, Options::Get().quiet, false, /* Type, Var, Init */
260 "-q", "--quiet", /* Short, Long */
261 "work in quiet mode", /* Description */
262 [&](bool) { Options::Get().quiet = true; }); /* Callback */
263 /* Additional output */
264 ADD(bool, Options::Get().times, false, /* Type, Var, Init */
265 "-t", "--times", /* Short, Long */
266 "report exact timings", /* Description */
267 [&](bool) { Options::Get().times = true; }); /* Callback */
268 ADD(bool, Options::Get().statistics, false, /* Type, Var, Init */
269 "-s", "--statistics", /* Short, Long */
270 "show some statistics", /* Description */
271 [&](bool) { Options::Get().statistics = true; }); /* Callback */
272 ADD(bool, Options::Get().echo, false, /* Type, Var, Init */
273 nullptr, "--echo", /* Short, Long */
274 "echo statements", /* Description */
275 [&](bool) { Options::Get().echo = true; }); /* Callback */
276 ADD(bool, Options::Get().ast, false, /* Type, Var, Init */
277 nullptr, "--ast", /* Short, Long */
278 "print the AST of statements", /* Description */
279 [&](bool) { Options::Get().ast = true; }); /* Callback */
280 ADD(bool, Options::Get().astdot, false, /* Type, Var, Init */
281 nullptr, "--astdot", /* Short, Long */
282 "dot the AST of statements", /* Description */
283 [&](bool) { Options::Get().astdot = true; }); /* Callback */
284 ADD(bool, Options::Get().graph, false, /* Type, Var, Init */
285 nullptr, "--graph", /* Short, Long */
286 "print the computed query graph", /* Description */
287 [&](bool) { Options::Get().graph = true; }); /* Callback */
288 ADD(bool, Options::Get().graphdot, false, /* Type, Var, Init */
289 nullptr, "--graphdot", /* Short, Long */
290 "dot the computed query graph", /* Description */
291 [&](bool) { Options::Get().graphdot = true; }); /* Callback */
292 ADD(bool, Options::Get().graph2sql, false, /* Type, Var, Init */
293 nullptr, "--graph2sql", /* Short, Long */
294 "translate the computed query graph into SQL", /* Description */
295 [&](bool) { Options::Get().graph2sql = true; }); /* Callback */
296 ADD(bool, Options::Get().plan, false, /* Type, Var, Init */
297 nullptr, "--plan", /* Short, Long */
298 "emit the chosen execution plan", /* Description */
299 [&](bool) { Options::Get().plan = true; }); /* Callback */
300 ADD(bool, Options::Get().plandot, false, /* Type, Var, Init */
301 nullptr, "--plandot", /* Short, Long */
302 "dot the chosen operator tree", /* Description */
303 [&](bool) { Options::Get().plandot = true; }); /* Callback */
304 ADD(bool, Options::Get().physplan, false, /* Type, Var, Init */
305 nullptr, "--physplan", /* Short, Long */
306 "emit the chosen physical execution covering", /* Description */
307 [&](bool) { Options::Get().physplan = true; }); /* Callback */
308 ADD(bool, Options::Get().dryrun, false, /* Type, Var, Init */
309 nullptr, "--dryrun", /* Short, Long */
310 "don't actually execute the query", /* Description */
311 [&](bool) { Options::Get().dryrun = true; }); /* Callback */
312 ADD(bool, Options::Get().benchmark, false, /* Type, Var, Init */
313 nullptr, "--benchmark", /* Short, Long */
314 "run queries in benchmark mode", /* Description */
315 [&](bool) { Options::Get().benchmark = true; }); /* Callback */
316 ADD(const char*, Options::Get().output_partial_plans_file, nullptr, /* Type, Var, Init */
317 nullptr, "--output-partial-plans-file", /* Short, Long */
318 "specify file to output all partial plans of the final plan", /* Description */
319 [&](const char *str) { Options::Get().output_partial_plans_file = str; }); /* Callback */
320 /*----- Select type of plan table to use -------------------------------------------------------------------------*/
321 ADD(bool, Options::Get().plan_table_type, Options::PT_auto, /* Type, Var, Init */
322 nullptr, "--plan-table-sod", /* Short, Long */
323 "use the plan table optimized for small or dense query graphs", /* Description */
324 [&](bool) { Options::Get().plan_table_type = Options::PT_SmallOrDense; }); /* Callback */
325 ADD(bool, Options::Get().plan_table_type, Options::PT_auto, /* Type, Var, Init */
326 nullptr, "--plan-table-las", /* Short, Long */
327 "use the plan table optimized for large and sparse query graphs", /* Description */
328 [&](bool) { Options::Get().plan_table_type = Options::PT_LargeAndSparse; }); /* Callback */
329
330 ADD(bool, Options::Get().list_data_layouts, false, /* Type, Var, Init */
331 nullptr, "--list-data-layouts", /* Short, Long */
332 "list all available data layouts", /* Description */
333 [&](bool) { /* Callback */
335 show_any_help = true;
336 }
337 );
338 ADD(bool, Options::Get().list_cardinality_estimators, false, /* Type, Var, Init */
339 nullptr, "--list-cardinality-estimators", /* Short, Long */
340 "list all available cardinality estimators", /* Description */
341 [&](bool) { /* Callback */
343 show_any_help = true;
344 }
345 );
346
347 ADD(bool, Options::Get().list_plan_enumerators, false, /* Type, Var, Init */
348 nullptr, "--list-plan-enumerators", /* Short, Long */
349 "list all available plan enumerators", /* Description */
350 [&](bool) { /* Callback */
352 show_any_help = true;
353 }
354 );
355 ADD(bool, Options::Get().list_backends, false, /* Type, Var, Init */
356 nullptr, "--list-backends", /* Short, Long */
357 "list all available backends", /* Description */
358 [&](bool) { /* Callback */
360 show_any_help = true;
361 }
362 );
363 ADD(bool, Options::Get().list_schedulers, false, /* Type, Var, Init */
364 nullptr, "--list-schedulers", /* Short, Long */
365 "list all available schedulers", /* Description */
366 [&](bool) { /* Callback */
368 show_any_help = true;
369 }
370 );
371 ADD(bool, Options::Get().list_table_properties, false, /* Type, Var, Init */
372 nullptr, "--list-table-properties", /* Short, Long */
373 "list all available table properties", /* Description */
374 [&](bool) { /* Callback */
376 show_any_help = true;
377 }
378 );
379 ADD(bool, Options::Get().list_cost_functions, false, /* Type, Var, Init */
380 nullptr, "--list-cost-functions", /* Short, Long */
381 "list all available cost functions", /* Description */
382 [&](bool) { /* Callback */
384 show_any_help = true;
385 }
386 );
387 /*------ Cost Model Generation -----------------------------------------------------------------------------------*/
388 ADD(bool, Options::Get().train_cost_models, false, /* Type, Var, Init */
389 nullptr, "--train-cost-models", /* Short, Long */
390 "train cost models (may take a couple of minutes)", /* Description */
391 [&](bool) { Options::Get().train_cost_models = true; } /* Callback */
392 );
393 /*------ Plugins -------------------------------------------------------------------------------------------------*/
394 ADD(const char*, Options::Get().plugins, nullptr, /* Type, Var, Init */
395 nullptr, "--plugins", /* Short, Long */
396 "A comma separated list of libraries that are loaded dynamically.", /* Description */
397 [&](const char *str) { load_plugins(str); }); /* Callback */
398#undef ADD
399 AP.parse_args(argc, argv);
400
402 if (term_has_color)
403 std::cout << term::FG_WHITE << "mu"
404 << term::ITALIC << term::fg(30) << 't' << term::RESET
405 << term::FG_WHITE << "able" << term::RESET;
406 else
407 std::cout << "mutable";
408 std::cout << "\n© 2023, Saarland University";
409 auto &v = version::get();
410 std::cout << "\nversion " << v.GIT_REV;
411 if (not streq(v.GIT_BRANCH, ""))
412 std::cout << " (" << v.GIT_BRANCH << ')';
413 std::cout << "\nAuthors: \
414Immanuel Haffner\
415, Joris Nix\
416, Marcel Maltry\
417, Luca Gretscher\
418, Tobias Kopp\
419, Jonas Lauermann\
420, Felix Brinkmann\
421, Til Roth\
422, Alireza Kheradmand\
423";
424 std::cout << std::endl;
425 std::exit(EXIT_SUCCESS);
426 }
427
428 if (Options::Get().show_help) {
429 usage(std::cout, argv[0]);
430 std::cout << "WHERE\n" << AP;
431 }
432
433 if (Options::Get().list_data_layouts) {
434 std::cout << "List of available data layouts:";
436 std::size_t max_len = 0;
437 for (auto &layout : layouts) max_len = std::max(max_len, strlen(*layout.first));
438 for (auto &layout : layouts) {
439 std::cout << "\n " << layout.first << std::setw(max_len - strlen(*layout.first)) << "";
440 if (layout.second.description())
441 std::cout << " - " << layout.second.description();
442 }
443 std::cout << std::endl;
444 }
445
446 if (Options::Get().list_cardinality_estimators) {
447 std::cout << "List of available cardinality estimators:";
448 range cardinality_estimators(C.cardinality_estimators_cbegin(), C.cardinality_estimators_cend());
449 std::size_t max_len = 0;
450 for (auto &ce : cardinality_estimators) max_len = std::max(max_len, strlen(*ce.first));
451 for (auto &ce : cardinality_estimators) {
452 std::cout << "\n " << ce.first << std::setw(max_len - strlen(*ce.first)) << "";;
453 if (ce.second.description())
454 std::cout << " - " << ce.second.description();
455 }
456 std::cout << std::endl;
457 }
458
459 if (Options::Get().list_plan_enumerators) {
460 std::cout << "List of available plan enumerators:";
461 range plan_enumerators(C.plan_enumerators_cbegin(), C.plan_enumerators_cend());
462 std::size_t max_len = 0;
463 for (auto &pe : plan_enumerators) max_len = std::max(max_len, strlen(*pe.first));
464 for (auto &pe : plan_enumerators) {
465 std::cout << "\n " << pe.first << std::setw(max_len - strlen(*pe.first)) << "";;
466 if (pe.second.description())
467 std::cout << " - " << pe.second.description();
468 }
469 std::cout << std::endl;
470 }
471
472 if (Options::Get().list_backends) {
473 std::cout << "List of available backends:";
474 std::size_t max_len = 0;
475 range backends(C.backends_cbegin(), C.backends_cend());
476 for (auto &backend : backends) max_len = std::max(max_len, strlen(*backend.first));
477 for (auto &backend : backends) {
478 std::cout << "\n " << backend.first << std::setw(max_len - strlen(*backend.first)) << "";;
479 if (backend.second.description())
480 std::cout << " - " << backend.second.description();
481 }
482 std::cout << std::endl;
483 }
484
485 if (Options::Get().list_cost_functions) {
486 std::cout << "List of available cost functions:";
487 std::size_t max_len = 0;
488 range cost_functions(C.cost_functions_cbegin(), C.cost_functions_cend());
489 for (auto &cf : cost_functions) max_len = std::max(max_len, strlen(*cf.first));
490 for (auto &cf : cost_functions) {
491 std::cout << "\n " << cf.first << std::setw(max_len - strlen(*cf.first)) << "";;
492 if (cf.second.description())
493 std::cout << " - " << cf.second.description();
494 }
495 std::cout << "\n (Use --train-cost-models to train a cost function on your specific hardware)";
496 std::cout << std::endl;
497 }
498
499 if (Options::Get().list_schedulers) {
500 std::cout << "List of available schedulers:";
501 std::size_t max_len = 0;
502 range schedulers(C.schedulers_cbegin(), C.schedulers_cend());
503 for (auto &scheduler : schedulers) max_len = std::max(max_len, strlen(*scheduler.first));
504 for (auto &scheduler : schedulers) {
505 std::cout << "\n " << scheduler.first << std::setw(max_len - strlen(*scheduler.first)) << "";;
506 if (scheduler.second.description())
507 std::cout << " - " << scheduler.second.description();
508 }
509 std::cout << std::endl;
510 }
511
512 if (Options::Get().list_table_properties) {
513 std::cout << "List of available table properties:";
514 std::size_t max_len = 0;
515 range table_factories(C.table_properties_cbegin(), C.table_properties_cend());
516 for (auto &table_factory : table_factories) max_len = std::max(max_len, strlen(*table_factory.first));
517 for (auto &table_factory : table_factories) {
518 std::cout << "\n " << table_factory.first << std::setw(max_len - strlen(*table_factory.first)) << "";;
519 if (table_factory.second.description())
520 std::cout << " - " << table_factory.second.description();
521 }
522 std::cout << std::endl;
523 }
524
525 if (show_any_help)
526 exit(EXIT_SUCCESS);
527
528 if (not Options::Get().quiet) {
529 std::cout << "PID";
530#if __linux || __APPLE__
531 std::cout << ' ' << getpid();
532#endif
533 std::cout << std::endl;
534 }
535
536 /* Disable synchronisation between C and C++ I/O (e.g. stdin vs std::cin). */
537 std::ios_base::sync_with_stdio(false);
538
539 /* Create the diagnostics object. */
540 Diagnostic diag(Options::Get().has_color, std::cout, std::cerr);
541
542 /* ----- Cost model training -------------------------------------------------------------------------------------*/
543 if (Options::Get().train_cost_models) {
545 C.register_cost_function(C.pool("TrainedCostFunction"), std::move(CF),
546 "cost models trained on current hardware using linear regression");
547 C.default_cost_function(C.pool("TrainedCostFunction"));
548 }
549
550 /* ----- Replxx configuration ------------------------------------------------------------------------------------*/
551 Replxx rx;
552 rx.install_window_change_handler();
553
554 /* History setup */
555 auto history_file = get_home_path() / ".mutable_history";
556 rx.history_load(history_file);
557 rx.set_max_history_size(1024);
558 rx.set_unique_history(false);
559
560 /* Key bindings */
561#define KEY_BIND(BUTTON, RESULT)\
562 rx.bind_key(Replxx::KEY::BUTTON, std::bind(&Replxx::invoke, &rx, Replxx::ACTION::RESULT, std::placeholders::_1));
563 KEY_BIND(BACKSPACE, DELETE_CHARACTER_LEFT_OF_CURSOR);
564 KEY_BIND(DELETE, DELETE_CHARACTER_UNDER_CURSOR);
565 KEY_BIND(LEFT, MOVE_CURSOR_LEFT);
566 KEY_BIND(RIGHT, MOVE_CURSOR_RIGHT);
567 KEY_BIND(UP, HISTORY_PREVIOUS);
568 KEY_BIND(DOWN, HISTORY_NEXT);
569 KEY_BIND(PAGE_UP, HISTORY_FIRST);
570 KEY_BIND(PAGE_DOWN, HISTORY_LAST);
571 KEY_BIND(HOME, MOVE_CURSOR_TO_BEGINING_OF_LINE);
572 KEY_BIND(END, MOVE_CURSOR_TO_END_OF_LINE);
573 KEY_BIND(TAB, COMPLETE_LINE);
574 KEY_BIND(control('R'), HISTORY_INCREMENTAL_SEARCH);
575 KEY_BIND(control('W'), KILL_TO_BEGINING_OF_WORD);
576 KEY_BIND(control('U'), KILL_TO_BEGINING_OF_LINE);
577 KEY_BIND(control('K'), KILL_TO_END_OF_LINE);
578 KEY_BIND(control('Y'), YANK);
579 KEY_BIND(control('L'), CLEAR_SCREEN);
580 KEY_BIND(control('D'), SEND_EOF);
581 KEY_BIND(control('Z'), SUSPEND);
582 KEY_BIND(control(Replxx::KEY::ENTER), COMMIT_LINE);
583 KEY_BIND(control(Replxx::KEY::LEFT), MOVE_CURSOR_ONE_WORD_LEFT);
584 KEY_BIND(control(Replxx::KEY::RIGHT), MOVE_CURSOR_ONE_WORD_RIGHT);
585 KEY_BIND(control(Replxx::KEY::UP), HINT_PREVIOUS);
586 KEY_BIND(control(Replxx::KEY::DOWN), HINT_NEXT);
587 KEY_BIND(meta('p'), HISTORY_COMMON_PREFIX_SEARCH);
588 KEY_BIND(meta(Replxx::KEY::BACKSPACE),KILL_TO_BEGINING_OF_WORD);
589#undef KEY_BIND
590
591 if (Options::Get().show_prompt) {
592 /* Completion */
593 rx.set_completion_callback(std::bind(&hook_completion, std::placeholders::_1, std::placeholders::_2));
594 rx.set_completion_count_cutoff(128);
595 rx.set_double_tab_completion(false);
596 rx.set_complete_on_empty(false);
597 rx.set_beep_on_ambiguous_completion(false);
598
599 /* Hints */
600 rx.set_hint_callback(std::bind(&hook_hint, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
601 rx.set_max_hint_rows(3);
602 rx.set_hint_delay(500);
603
604 /* Highlighter */
605 rx.set_highlighter_callback(std::bind(&hook_highlighter, std::placeholders::_1, std::placeholders::_2));
606 }
607
608 /* Other options */
609 rx.set_word_break_characters(" \t.,-%!;:=*~^'\"/?<>|[](){}");
610 rx.set_no_color(not Options::Get().show_prompt);
611
612 auto args = AP.args();
613 if (args.empty())
614 args.push_back("-"); // start in interactive mode
615
616 /* Process all the inputs. */
617 for (auto filename : args) {
618 /*----- Open the input stream. -------------------------------------------------------------------------------*/
619 if (streq("-", filename)) {
620 const char *cinput = nullptr;
621 std::stringstream ss;
622 for (;;) {
623 do
624 cinput = rx.input(Options::Get().show_prompt ? prompt(ss.str().size() != 0) : ""); // Read one line of input
625 while ((cinput == nullptr) and (errno == EAGAIN));
626 M_insist(errno != EAGAIN);
627
628 /* User sent EOF */
629 if (cinput == nullptr) {
630 if (Options::Get().show_prompt)
631 std::cout << std::endl;
632 break;
633 }
634 M_insist(cinput);
635
636 /* User sent input */
637 auto len = strlen(cinput);
638 if (not isspace(cinput, len)) {
639 ss.write(cinput, len); // append replxx line to stream
640 rx.history_add(cinput);
641 if (cinput[len - 1] == ';') {
642 process_stream(ss, filename, diag);
643 ss.str(""); // empty the stream
644 ss.clear(); // and clear EOF bit
645 } else
646 ss.put('\n');
647 }
648 rx.history_save(history_file);
649 }
650 } else {
651 std::ifstream in(filename);
652 if (not in) {
653 const auto errsv = errno;
654 diag.err() << "Could not open file '" << filename << '\'';
655 if (errsv)
656 diag.err() << ": " << strerror(errsv);
657 diag.err() << ". Aborting." << std::endl;
658 break;
659 }
660 process_stream(in, filename, diag);
661 }
662 }
663
664 /* Explicitly destroy the `Catalog` to dispose of all held resources. This is particularly important as the address
665 * sanitizer scans for leaked allocations *before* any `__attribute((destructor))__` annotated functions are run. */
667 std::exit(diag.num_errors() ? EXIT_FAILURE : EXIT_SUCCESS);
668}
int main(void)
bool show_help
‍whether to show a help message
struct @5 args
A parser for command line arguments.
Definition: ArgParser.hpp:20
void parse_args(int argc, const char **argv)
Parses the arguments from argv.
Definition: ArgParser.cpp:186
const std::vector< const char * > & args() const
Returns all positional arguments.
Definition: ArgParser.hpp:143
#define M_insist(...)
Definition: macro.hpp:129
constexpr auto CLOCK_FAST
Definition: glyphs.hpp:13
constexpr auto DATABASE
Definition: glyphs.hpp:8
constexpr auto RIGHT
Definition: glyphs.hpp:11
constexpr const char * ITALIC
Definition: terminal.hpp:18
constexpr const char * BOLD
Definition: terminal.hpp:14
constexpr const char * RESET
Definition: terminal.hpp:12
constexpr const char * FG_WHITE
Definition: terminal.hpp:51
Color bg(unsigned color)
Create a background color to be printed in a terminal.
Definition: terminal.hpp:90
bool M_EXPORT has_color()
Returns true if the terminal is known to support colors, false otherwise.
Definition: terminal.cpp:7
Color fg(unsigned color)
Create a foreground color to be printed in a terminal.
Definition: terminal.hpp:88
constexpr const char * BG_DEFAULT
Definition: terminal.hpp:69
M_EXPORT const version_info & get()
Definition: version.cpp:4
‍mutable namespace
Definition: Backend.hpp:10
void M_EXPORT process_stream(std::istream &in, const char *filename, Diagnostic diag)
Extracts and executes statements from given stream.
Definition: mutable.cpp:67
bool isspace(const char *s, std::size_t len)
Returns true iff the character sequence only consists of white spaces.
Definition: fn.hpp:622
bool streq(const char *first, const char *second)
Definition: fn.hpp:29
bool strneq(const char *first, const char *second, std::size_t n)
Definition: fn.hpp:30
bool is_alnum(int c)
Definition: fn.hpp:594
std::filesystem::path get_home_path()
Returns path of the user's home directory.
Definition: fn.hpp:597
and
Definition: enum_ops.hpp:12
void hook_highlighter(const std::string &context, Replxx::colors_t &colors)
Definition: shell.cpp:151
std::string prompt(bool is_editing, Timer::duration dur=Timer::duration())
Definition: shell.cpp:67
int context_len(const std::string &prefix)
Determines the amount of chars after a word breaker (i.e.
Definition: shell.cpp:119
replxx::Replxx Replxx
Definition: shell.cpp:35
int utf8str_codepoint_len(const char *s, int utf8_len)
Determine codepoint length of utf-8 string.
Definition: shell.cpp:101
void load_plugins(std::string list)
Definition: shell.cpp:45
#define KEY_BIND(BUTTON, RESULT)
Replxx::hints_t hook_hint(const std::string &prefix, int &context_len, Replxx::Color &color)
Definition: shell.cpp:199
void usage(std::ostream &out, const char *name)
Definition: shell.cpp:38
#define ADD(TYPE, VAR, INIT, SHORT, LONG, DESCR, CALLBACK)
Replxx::completions_t hook_completion(const std::string &prefix, int &context_len)
Definition: shell.cpp:131
The catalog contains all Databases and keeps track of all meta information of the database system.
Definition: Catalog.hpp:215
auto plan_enumerators_cend() const
Definition: Catalog.hpp:452
auto schedulers_cbegin() const
Definition: Catalog.hpp:563
auto cost_functions_cbegin() const
Definition: Catalog.hpp:512
auto cardinality_estimators_cend() const
Definition: Catalog.hpp:427
auto data_layouts_cbegin() const
Definition: Catalog.hpp:389
void default_cost_function(const ThreadSafePooledString &name)
Sets the default CostFunction to use.
Definition: Catalog.hpp:498
ThreadSafePooledString pool(const char *str) const
Creates an internalized copy of the string str by adding it to the internal StringPool.
Definition: Catalog.hpp:274
static Catalog & Get()
Return a reference to the single Catalog instance.
auto cardinality_estimators_cbegin() const
Definition: Catalog.hpp:426
auto data_layouts_cend() const
Definition: Catalog.hpp:390
auto backends_cend() const
Definition: Catalog.hpp:488
auto plan_enumerators_cbegin() const
Definition: Catalog.hpp:451
auto schedulers_cend() const
Definition: Catalog.hpp:564
auto backends_cbegin() const
Definition: Catalog.hpp:487
auto table_properties_cend() const
Definition: Catalog.hpp:606
auto cost_functions_cend() const
Definition: Catalog.hpp:513
static void Destroy()
Destroys the current Catalog instance.
void register_cost_function(ThreadSafePooledString name, std::unique_ptr< CostFunction > CF, const char *description=nullptr)
Registers a new CostFunction with the given name.
Definition: Catalog.hpp:492
auto table_properties_cbegin() const
Definition: Catalog.hpp:605
m::ArgParser & arg_parser()
Definition: Catalog.hpp:253
static std::unique_ptr< CostFunction > get_cost_function()
Generates a CostFunction containing CostModels for cost estimation.
Definition: CostModel.cpp:588
unsigned num_errors() const
Returns the number of errors emitted since the last call to clear().
Definition: Diagnostic.hpp:48
std::ostream & err()
Definition: Diagnostic.hpp:53
bool astdot
Definition: Options.hpp:42
bool list_cardinality_estimators
Definition: Options.hpp:25
bool list_schedulers
Definition: Options.hpp:29
bool dryrun
If true, do not pass the query to the backend for execution.
Definition: Options.hpp:51
bool times
Definition: Options.hpp:38
bool plan
Definition: Options.hpp:46
bool train_cost_models
If true, run the procedure to train cost models for query building blocks at startup.
Definition: Options.hpp:64
bool list_data_layouts
Definition: Options.hpp:24
bool statistics
Definition: Options.hpp:39
static Options & Get()
Return a reference to the single Options instance.
Definition: Options.cpp:9
bool plandot
Definition: Options.hpp:47
bool echo
Definition: Options.hpp:40
bool show_version
Definition: Options.hpp:23
const char * output_partial_plans_file
Definition: Options.hpp:61
bool list_backends
Definition: Options.hpp:27
bool show_help
Definition: Options.hpp:22
bool list_table_properties
Definition: Options.hpp:30
bool physplan
Definition: Options.hpp:48
bool has_color
Definition: Options.hpp:33
bool list_plan_enumerators
Definition: Options.hpp:26
bool list_cost_functions
Definition: Options.hpp:28
bool benchmark
If true, the results of queries are dropped and not passed back to the user.
Definition: Options.hpp:54
PlanTableType plan_table_type
The type of plan table to use for query optimization.
Definition: Options.hpp:57
@ PT_LargeAndSparse
Definition: Options.hpp:18
@ PT_SmallOrDense
Definition: Options.hpp:17
bool show_prompt
Definition: Options.hpp:34
bool graph
Definition: Options.hpp:43
bool graphdot
Definition: Options.hpp:44
bool quiet
Definition: Options.hpp:35
bool ast
Definition: Options.hpp:41
bool graph2sql
Definition: Options.hpp:45
clock::duration duration
Definition: Timer.hpp:40