From 3982031215936e7813ae37ba6bb2f61ffe992bfd Mon Sep 17 00:00:00 2001 From: kssenii Date: Sun, 1 Aug 2021 23:28:39 +0300 Subject: [PATCH] Completion for clickhouse-local --- programs/local/LocalServer.cpp | 18 +++++++++++++ programs/local/LocalServer.h | 2 ++ src/Client/ClientBase.h | 2 +- src/Client/Suggest.cpp | 46 +++++++++++++++++++++++++++++++--- src/Client/Suggest.h | 12 ++++++++- 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/programs/local/LocalServer.cpp b/programs/local/LocalServer.cpp index e9fe163edc7..d3f6b7bb937 100644 --- a/programs/local/LocalServer.cpp +++ b/programs/local/LocalServer.cpp @@ -217,6 +217,15 @@ std::string LocalServer::getInitialCreateTableQuery() } +void LocalServer::loadSuggestionData(Suggest & suggest) +{ + if (!config().getBool("disable_suggestion", false)) + { + suggest.load(query_context, config().getInt("suggestion_limit")); + } +} + + void LocalServer::executeSingleQuery(const String & query_to_execute, ASTPtr /* parsed_query */) { ReadBufferFromString read_buf(query_to_execute); @@ -636,6 +645,10 @@ void LocalServer::addAndCheckOptions(OptionsDescription & options_description, p ("multiline,m", "multiline") ("multiquery,n", "multiquery") ("highlight", po::value()->default_value(true), "enable or disable basic syntax highlight in interactive command line") + + ("disable_suggestion,A", "Disable loading suggestion data. Note that suggestion data is loaded asynchronously through a second connection to ClickHouse server. Also it is reasonable to disable suggestion if you want to paste a query with TAB characters. Shorthand option -A is for those who get used to mysql client.") + ("suggestion_limit", po::value()->default_value(10000), + "Suggestion limit for how many databases, tables and columns to fetch.") ; cmd_settings.addProgramOptions(options_description.main_description.value()); @@ -715,6 +728,11 @@ void LocalServer::processOptions(const OptionsDescription &, const CommandLineOp config().setBool("multiline", true); if (options.count("multiquery")) config().setBool("multiquery", true); + + if (options.count("disable_suggestion")) + config().setBool("disable_suggestion", true); + if (options.count("suggestion_limit")) + config().setInt("suggestion_limit", options["suggestion_limit"].as()); } } diff --git a/programs/local/LocalServer.h b/programs/local/LocalServer.h index 5f46d75484f..dc03c74e8e1 100644 --- a/programs/local/LocalServer.h +++ b/programs/local/LocalServer.h @@ -44,6 +44,8 @@ protected: String getQueryTextPrefix() override; + void loadSuggestionData(Suggest &) override; + void readArguments(int argc, char ** argv, Arguments & common_arguments, std::vector &) override; diff --git a/src/Client/ClientBase.h b/src/Client/ClientBase.h index 85c774b0f8a..7bb6bcb691f 100644 --- a/src/Client/ClientBase.h +++ b/src/Client/ClientBase.h @@ -95,7 +95,7 @@ protected: /// For non-interactive multi-query mode get queries text prefix. virtual String getQueryTextPrefix() { return ""; } - virtual void loadSuggestionData(Suggest &) {} + virtual void loadSuggestionData(Suggest &) = 0; void resetOutput(); diff --git a/src/Client/Suggest.cpp b/src/Client/Suggest.cpp index d4db49a1598..ac6cf588ddc 100644 --- a/src/Client/Suggest.cpp +++ b/src/Client/Suggest.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -70,6 +71,37 @@ void Suggest::load(const ConnectionParameters & connection_parameters, size_t su }); } +void Suggest::load(ContextMutablePtr context, size_t suggestion_limit) +{ + loading_thread = std::thread([context, suggestion_limit, this] + { + try + { + ThreadStatus thread_status; + CurrentThread::QueryScope query_scope_holder(context); + loadImpl(context, suggestion_limit); + } + catch (...) + { + std::cerr << "Cannot load data for command line suggestions: " << getCurrentExceptionMessage(false, true) << "\n"; + } + + /// Note that keyword suggestions are available even if we cannot load data from server. + + std::sort(words.begin(), words.end()); + words_no_case = words; + std::sort(words_no_case.begin(), words_no_case.end(), [](const std::string & str1, const std::string & str2) + { + return std::lexicographical_compare(begin(str1), end(str1), begin(str2), end(str2), [](const char char1, const char char2) + { + return std::tolower(char1) < std::tolower(char2); + }); + }); + + ready = true; + }); +} + Suggest::Suggest() { /// Keywords may be not up to date with ClickHouse parser. @@ -88,11 +120,10 @@ Suggest::Suggest() "INTERVAL", "LIMITS", "ONLY", "TRACKING", "IP", "REGEXP", "ILIKE"}; } -void Suggest::loadImpl(Connection & connection, const ConnectionTimeouts & timeouts, size_t suggestion_limit) +static String getLoadSuggestionQuery(size_t suggestion_limit) { /// NOTE: Once you will update the completion list, /// do not forget to update 01676_clickhouse_client_autocomplete.sh - WriteBufferFromOwnString query; query << "SELECT DISTINCT arrayJoin(extractAll(name, '[\\\\w_]{2,}')) AS res FROM (" "SELECT name FROM system.functions" @@ -133,8 +164,17 @@ void Suggest::loadImpl(Connection & connection, const ConnectionTimeouts & timeo } query << ") WHERE notEmpty(res)"; + return query.str(); +} - fetch(connection, timeouts, query.str()); +void Suggest::loadImpl(Connection & connection, const ConnectionTimeouts & timeouts, size_t suggestion_limit) +{ + fetch(connection, timeouts, getLoadSuggestionQuery(suggestion_limit)); +} + +void Suggest::loadImpl(ContextMutablePtr context, size_t suggestion_limit) +{ + executeQuery(getLoadSuggestionQuery(suggestion_limit), context); } void Suggest::fetch(Connection & connection, const ConnectionTimeouts & timeouts, const std::string & query) diff --git a/src/Client/Suggest.h b/src/Client/Suggest.h index 03332088cbe..fe18b8165a3 100644 --- a/src/Client/Suggest.h +++ b/src/Client/Suggest.h @@ -19,21 +19,31 @@ class Suggest : public LineReader::Suggest, boost::noncopyable { public: Suggest(); + ~Suggest() { if (loading_thread.joinable()) loading_thread.join(); } + /// Load suggestions for clickhouse-client. void load(const ConnectionParameters & connection_parameters, size_t suggestion_limit); + /// Load suggestions for clickhouse-local. + void load(ContextMutablePtr context, size_t suggestion_limit); + /// Older server versions cannot execute the query above. static constexpr int MIN_SERVER_REVISION = 54406; private: - void loadImpl(Connection & connection, const ConnectionTimeouts & timeouts, size_t suggestion_limit); + + void loadImpl(ContextMutablePtr context, size_t suggestion_limit); + void fetch(Connection & connection, const ConnectionTimeouts & timeouts, const std::string & query); + + void fetch(ContextMutablePtr context, const std::string & query); + void fillWordsFromBlock(const Block & block); /// Words are fetched asynchronously.