38void usage(std::ostream &out,
const char *name)
40 out <<
"An interactive shell to communicate with the database system.\n"
41 <<
"USAGE:\n\t" << name <<
" [<FILE>...]"
47 std::string delimiter =
",";
49 size_t next = list.find(delimiter, last);
50 std::filesystem::path cwd(
".");
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;
56 std::cerr <<
"loading plugin " << path_to_shared <<
"\n";
57 void *handle = dlopen(path_to_shared.c_str(), RTLD_NOW);
59 std::cerr <<
"WARNING: Failed to load " << path_to_shared <<
": " << dlerror() <<
'\n';
60 if (next == std::string::npos)
63 next = list.find(delimiter, last);
74 const auto ms = std::chrono::duration_cast<std::chrono::microseconds>(dur).count() / 1e3;
78 << std::fixed << std::setprecision(2) << ms <<
" ms ";
88 if (C.has_database_in_use()) {
89 auto &DB = C.get_database_in_use();
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 ) {
110 else if (( c & m3 ) == m3)
112 else if (( c & m2 ) == m2)
115 return codepoint_len;
121 auto it = prefix.rbegin();
122 for (; it != prefix.rend(); ++it) {
127 return it - prefix.rbegin();
133 static constexpr const char *KW[] = {
134#define M_KEYWORD(tt, name) #name,
135#include <mutable/tables/Keywords.tbl>
139 Replxx::completions_t completions;
140 Replxx::Color color = Replxx::Color::DEFAULT;
142 std::string context = prefix.substr(prefix.size() -
context_len);
143 for (
auto const &kw : KW) {
145 completions.emplace_back(kw, color);
153 std::vector<std::pair<std::string, Replxx::Color>> regex_color = {
155#define M_KEYWORD(tt, name)\
156 { #name, Replxx::Color::BROWN },
157#include <mutable/tables/Keywords.tbl>
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},
174 {
"[\\-|+]{0,1}[0-9]+", Replxx::Color::BLUE},
175 {
"[\\-|+]{0,1}[0-9]*\\.[0-9]+", Replxx::Color::BLUE},
176 {
"\"([^\\\\\"]|\\\\\")*\"", Replxx::Color::BRIGHTMAGENTA},
178 for (
const auto &e : regex_color) {
180 std::string str = context;
183 while (std::regex_search(str, match, std::regex(e.first))) {
184 std::string c = match[0];
185 std::string prefix = match.prefix().str();
189 for (
int i = 0; i < len; ++i)
190 colors.at(pos + i) = e.second;
193 str = match.suffix();
201 static constexpr const char *KW[] = {
202#define M_KEYWORD(tt, name) #name,
203#include <mutable/tables/Keywords.tbl>
207 Replxx::hints_t hints;
209 std::string context = prefix.substr(prefix.size() -
context_len);
210 if (context.size() >= 2) {
211 for (
auto const &kw : KW) {
213 hints.emplace_back(kw);
216 if (hints.size() == 1)
217 color = Replxx::Color::GREEN;
221int main(
int argc,
const char **argv)
228 bool show_any_help =
false;
232#define ADD(TYPE, VAR, INIT, SHORT, LONG, DESCR, CALLBACK)\
235 AP.add<TYPE>(SHORT, LONG, DESCR, CALLBACK);\
240 "prints this help message",
242 show_any_help =
true;
246 nullptr,
"--version",
247 "shows version information",
256 nullptr,
"--noprompt",
261 "work in quiet mode",
266 "report exact timings",
269 "-s",
"--statistics",
270 "show some statistics",
278 "print the AST of statements",
282 "dot the AST of statements",
286 "print the computed query graph",
289 nullptr,
"--graphdot",
290 "dot the computed query graph",
293 nullptr,
"--graph2sql",
294 "translate the computed query graph into SQL",
298 "emit the chosen execution plan",
301 nullptr,
"--plandot",
302 "dot the chosen operator tree",
305 nullptr,
"--physplan",
306 "emit the chosen physical execution covering",
310 "don't actually execute the query",
313 nullptr,
"--benchmark",
314 "run queries in benchmark mode",
317 nullptr,
"--output-partial-plans-file",
318 "specify file to output all partial plans of the final plan",
322 nullptr,
"--plan-table-sod",
323 "use the plan table optimized for small or dense query graphs",
326 nullptr,
"--plan-table-las",
327 "use the plan table optimized for large and sparse query graphs",
331 nullptr,
"--list-data-layouts",
332 "list all available data layouts",
335 show_any_help =
true;
339 nullptr,
"--list-cardinality-estimators",
340 "list all available cardinality estimators",
343 show_any_help =
true;
348 nullptr,
"--list-plan-enumerators",
349 "list all available plan enumerators",
352 show_any_help =
true;
356 nullptr,
"--list-backends",
357 "list all available backends",
360 show_any_help =
true;
364 nullptr,
"--list-schedulers",
365 "list all available schedulers",
368 show_any_help =
true;
372 nullptr,
"--list-table-properties",
373 "list all available table properties",
376 show_any_help =
true;
380 nullptr,
"--list-cost-functions",
381 "list all available cost functions",
384 show_any_help =
true;
389 nullptr,
"--train-cost-models",
390 "train cost models (may take a couple of minutes)",
395 nullptr,
"--plugins",
396 "A comma separated list of libraries that are loaded dynamically.",
407 std::cout <<
"mutable";
408 std::cout <<
"\n© 2023, Saarland University";
410 std::cout <<
"\nversion " << v.GIT_REV;
411 if (not
streq(v.GIT_BRANCH,
""))
412 std::cout <<
" (" << v.GIT_BRANCH <<
')';
413 std::cout <<
"\nAuthors: \
424 std::cout << std::endl;
425 std::exit(EXIT_SUCCESS);
429 usage(std::cout, argv[0]);
430 std::cout <<
"WHERE\n" << AP;
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();
443 std::cout << std::endl;
447 std::cout <<
"List of available cardinality estimators:";
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();
456 std::cout << std::endl;
460 std::cout <<
"List of available plan enumerators:";
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();
469 std::cout << std::endl;
473 std::cout <<
"List of available backends:";
474 std::size_t max_len = 0;
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();
482 std::cout << std::endl;
486 std::cout <<
"List of available cost functions:";
487 std::size_t max_len = 0;
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();
495 std::cout <<
"\n (Use --train-cost-models to train a cost function on your specific hardware)";
496 std::cout << std::endl;
500 std::cout <<
"List of available schedulers:";
501 std::size_t max_len = 0;
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();
509 std::cout << std::endl;
513 std::cout <<
"List of available table properties:";
514 std::size_t max_len = 0;
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();
522 std::cout << std::endl;
530#if __linux || __APPLE__
531 std::cout <<
' ' << getpid();
533 std::cout << std::endl;
537 std::ios_base::sync_with_stdio(
false);
546 "cost models trained on current hardware using linear regression");
552 rx.install_window_change_handler();
556 rx.history_load(history_file);
557 rx.set_max_history_size(1024);
558 rx.set_unique_history(
false);
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);
571 KEY_BIND(HOME, MOVE_CURSOR_TO_BEGINING_OF_LINE);
572 KEY_BIND(END, MOVE_CURSOR_TO_END_OF_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);
579 KEY_BIND(control(
'L'), CLEAR_SCREEN);
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);
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);
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);
605 rx.set_highlighter_callback(std::bind(&
hook_highlighter, std::placeholders::_1, std::placeholders::_2));
609 rx.set_word_break_characters(
" \t.,-%!;:=*~^'\"/?<>|[](){}");
617 for (
auto filename :
args) {
619 if (
streq(
"-", filename)) {
620 const char *cinput =
nullptr;
621 std::stringstream ss;
625 while ((cinput ==
nullptr)
and (errno == EAGAIN));
629 if (cinput ==
nullptr) {
631 std::cout << std::endl;
637 auto len = strlen(cinput);
638 if (not
isspace(cinput, len)) {
639 ss.write(cinput, len);
640 rx.history_add(cinput);
641 if (cinput[len - 1] ==
';') {
648 rx.history_save(history_file);
651 std::ifstream in(filename);
653 const auto errsv = errno;
654 diag.
err() <<
"Could not open file '" << filename <<
'\'';
656 diag.
err() <<
": " << strerror(errsv);
657 diag.
err() <<
". Aborting." << std::endl;
667 std::exit(diag.
num_errors() ? EXIT_FAILURE : EXIT_SUCCESS);
bool show_help
whether to show a help message
A parser for command line arguments.
void parse_args(int argc, const char **argv)
Parses the arguments from argv.
const std::vector< const char * > & args() const
Returns all positional arguments.
constexpr auto CLOCK_FAST
constexpr const char * ITALIC
constexpr const char * BOLD
constexpr const char * RESET
constexpr const char * FG_WHITE
Color bg(unsigned color)
Create a background color to be printed in a terminal.
bool M_EXPORT has_color()
Returns true if the terminal is known to support colors, false otherwise.
Color fg(unsigned color)
Create a foreground color to be printed in a terminal.
constexpr const char * BG_DEFAULT
M_EXPORT const version_info & get()
void M_EXPORT process_stream(std::istream &in, const char *filename, Diagnostic diag)
Extracts and executes statements from given stream.
bool isspace(const char *s, std::size_t len)
Returns true iff the character sequence only consists of white spaces.
bool streq(const char *first, const char *second)
bool strneq(const char *first, const char *second, std::size_t n)
std::filesystem::path get_home_path()
Returns path of the user's home directory.
void hook_highlighter(const std::string &context, Replxx::colors_t &colors)
std::string prompt(bool is_editing, Timer::duration dur=Timer::duration())
int context_len(const std::string &prefix)
Determines the amount of chars after a word breaker (i.e.
int utf8str_codepoint_len(const char *s, int utf8_len)
Determine codepoint length of utf-8 string.
void load_plugins(std::string list)
#define KEY_BIND(BUTTON, RESULT)
Replxx::hints_t hook_hint(const std::string &prefix, int &context_len, Replxx::Color &color)
void usage(std::ostream &out, const char *name)
#define ADD(TYPE, VAR, INIT, SHORT, LONG, DESCR, CALLBACK)
Replxx::completions_t hook_completion(const std::string &prefix, int &context_len)
The catalog contains all Databases and keeps track of all meta information of the database system.
auto plan_enumerators_cend() const
auto schedulers_cbegin() const
auto cost_functions_cbegin() const
auto cardinality_estimators_cend() const
auto data_layouts_cbegin() const
void default_cost_function(const ThreadSafePooledString &name)
Sets the default CostFunction to use.
ThreadSafePooledString pool(const char *str) const
Creates an internalized copy of the string str by adding it to the internal StringPool.
static Catalog & Get()
Return a reference to the single Catalog instance.
auto cardinality_estimators_cbegin() const
auto data_layouts_cend() const
auto backends_cend() const
auto plan_enumerators_cbegin() const
auto schedulers_cend() const
auto backends_cbegin() const
auto table_properties_cend() const
auto cost_functions_cend() const
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.
auto table_properties_cbegin() const
m::ArgParser & arg_parser()
static std::unique_ptr< CostFunction > get_cost_function()
Generates a CostFunction containing CostModels for cost estimation.
unsigned num_errors() const
Returns the number of errors emitted since the last call to clear().
bool list_cardinality_estimators
bool dryrun
If true, do not pass the query to the backend for execution.
bool train_cost_models
If true, run the procedure to train cost models for query building blocks at startup.
static Options & Get()
Return a reference to the single Options instance.
const char * output_partial_plans_file
bool list_table_properties
bool list_plan_enumerators
bool benchmark
If true, the results of queries are dropped and not passed back to the user.
PlanTableType plan_table_type
The type of plan table to use for query optimization.