mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-10 01:25:21 +00:00
Client interactive suggest (extract info from CREATE queries)
This will parse CREATE queries and add the following things to completion list for clickhouse-client/clickhouse-local: - table - database - columns
This commit is contained in:
parent
02146a11d8
commit
36c4fc054c
@ -65,6 +65,27 @@ std::optional<LineReader::Suggest::WordsRange> LineReader::Suggest::getCompletio
|
||||
});
|
||||
}
|
||||
|
||||
void LineReader::Suggest::addWords(const std::vector<std::string> & new_words)
|
||||
{
|
||||
for (const auto & new_word : new_words)
|
||||
{
|
||||
if (std::binary_search(words.begin(), words.end(), new_word))
|
||||
continue;
|
||||
|
||||
words.push_back(new_word);
|
||||
words_no_case.push_back(new_word);
|
||||
}
|
||||
|
||||
std::sort(words.begin(), words.end());
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
LineReader::LineReader(const String & history_file_path_, bool multiline_, Patterns extenders_, Patterns delimiters_)
|
||||
: history_file_path(history_file_path_), multiline(multiline_), extenders(std::move(extenders_)), delimiters(std::move(delimiters_))
|
||||
{
|
||||
|
@ -20,6 +20,7 @@ public:
|
||||
|
||||
/// Get iterators for the matched range of words if any.
|
||||
std::optional<WordsRange> getCompletions(const String & prefix, size_t prefix_length) const;
|
||||
void addWords(const std::vector<std::string> & new_words);
|
||||
};
|
||||
|
||||
using Patterns = std::vector<const char *>;
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <Parsers/ASTQueryWithOutput.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTIdentifier.h>
|
||||
#include <Parsers/ASTColumnDeclaration.h>
|
||||
|
||||
#include <Processors/Formats/Impl/NullFormat.h>
|
||||
#include <Processors/Formats/IInputFormat.h>
|
||||
@ -552,6 +553,25 @@ void ClientBase::initLogsOutputStream()
|
||||
}
|
||||
}
|
||||
|
||||
void ClientBase::updateSuggest(const ASTCreateQuery & ast_create)
|
||||
{
|
||||
std::vector<std::string> new_words;
|
||||
|
||||
if (ast_create.database)
|
||||
new_words.push_back(ast_create.getDatabase());
|
||||
new_words.push_back(ast_create.getTable());
|
||||
|
||||
if (ast_create.columns_list && ast_create.columns_list->columns)
|
||||
{
|
||||
for (const auto & elem : ast_create.columns_list->columns->children)
|
||||
{
|
||||
if (const auto * column = elem->as<ASTColumnDeclaration>())
|
||||
new_words.push_back(column->name);
|
||||
}
|
||||
}
|
||||
|
||||
suggest->addWords(new_words);
|
||||
}
|
||||
|
||||
void ClientBase::processTextAsSingleQuery(const String & full_query)
|
||||
{
|
||||
@ -565,6 +585,18 @@ void ClientBase::processTextAsSingleQuery(const String & full_query)
|
||||
|
||||
String query_to_execute;
|
||||
|
||||
/// Query will be parsed before checking the result because error does not
|
||||
/// always means a problem, i.e. if table already exists, and it is no a
|
||||
/// huge problem if suggestion will be added even on error, since this is
|
||||
/// just suggestion.
|
||||
if (auto * create = parsed_query->as<ASTCreateQuery>())
|
||||
{
|
||||
/// Do not update suggest, until suggestion will be ready
|
||||
/// (this will avoid extra complexity)
|
||||
if (suggest && suggest->ready)
|
||||
updateSuggest(*create);
|
||||
}
|
||||
|
||||
// An INSERT query may have the data that follow query text. Remove the
|
||||
/// Send part of query without data, because data will be sent separately.
|
||||
auto * insert = parsed_query->as<ASTInsertQuery>();
|
||||
@ -1463,7 +1495,6 @@ void ClientBase::runInteractive()
|
||||
/// Initialize DateLUT here to avoid counting time spent here as query execution time.
|
||||
const auto local_tz = DateLUT::instance().getTimeZone();
|
||||
|
||||
std::optional<Suggest> suggest;
|
||||
suggest.emplace();
|
||||
if (load_suggestions)
|
||||
{
|
||||
|
@ -136,6 +136,8 @@ private:
|
||||
void readArguments(int argc, char ** argv, Arguments & common_arguments, std::vector<Arguments> & external_tables_arguments);
|
||||
void parseAndCheckOptions(OptionsDescription & options_description, po::variables_map & options, Arguments & arguments);
|
||||
|
||||
void updateSuggest(const ASTCreateQuery & ast_create);
|
||||
|
||||
protected:
|
||||
bool is_interactive = false; /// Use either interactive line editing interface or batch mode.
|
||||
bool is_multiquery = false;
|
||||
@ -144,6 +146,8 @@ protected:
|
||||
bool echo_queries = false; /// Print queries before execution in batch mode.
|
||||
bool ignore_error = false; /// In case of errors, don't print error message, continue to next query. Only applicable for non-interactive mode.
|
||||
bool print_time_to_stderr = false; /// Output execution time to stderr in batch mode.
|
||||
|
||||
std::optional<Suggest> suggest;
|
||||
bool load_suggestions = false;
|
||||
|
||||
std::vector<String> queries_files; /// If not empty, queries will be read from these files
|
||||
|
@ -38,6 +38,8 @@ private:
|
||||
|
||||
/// Words are fetched asynchronously.
|
||||
std::thread loading_thread;
|
||||
|
||||
Words new_words;
|
||||
};
|
||||
|
||||
}
|
||||
|
89
tests/queries/0_stateless/02160_client_autocomplete_parse_query.expect
Executable file
89
tests/queries/0_stateless/02160_client_autocomplete_parse_query.expect
Executable file
@ -0,0 +1,89 @@
|
||||
#!/usr/bin/expect -f
|
||||
|
||||
log_user 0
|
||||
set timeout 60
|
||||
set uuid ""
|
||||
match_max 100000
|
||||
# A default timeout action is to do nothing, change it to fail
|
||||
expect_after {
|
||||
timeout {
|
||||
send_user "FAILED (uuid=$uuid)\n"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
set basedir [file dirname $argv0]
|
||||
spawn bash -c "source $basedir/../shell_config.sh ; \$CLICKHOUSE_CLIENT_BINARY \$CLICKHOUSE_CLIENT_OPT"
|
||||
expect ":) "
|
||||
|
||||
# Make a query
|
||||
send -- "set max_distributed"
|
||||
expect "set max_distributed"
|
||||
|
||||
# Wait for suggestions to load, they are loaded in background
|
||||
set is_done 0
|
||||
set timeout 1
|
||||
while {$is_done == 0} {
|
||||
send -- "\t"
|
||||
expect {
|
||||
"_" {
|
||||
set is_done 1
|
||||
}
|
||||
default {
|
||||
# Reset the expect_after
|
||||
}
|
||||
}
|
||||
}
|
||||
set timeout 60
|
||||
send -- ""
|
||||
expect ":) "
|
||||
send_user "Completion loaded\n"
|
||||
|
||||
# Generate UIUD to avoid matching old database/tables/columns from previous test runs.
|
||||
send -- "select 'begin-' || replace(toString(generateUUIDv4()), '-', '') || '-end' format TSV\r"
|
||||
expect -re TSV.*TSV.*begin-(.*)-end.*
|
||||
set uuid $expect_out(1,string)
|
||||
expect ":) "
|
||||
send_user "UUID generated\n"
|
||||
|
||||
# Create
|
||||
send -- "create database new_${uuid}_database\r"
|
||||
expect ":) "
|
||||
send -- "create table new_${uuid}_table (new_${uuid}_column Int) engine=Null()\r"
|
||||
expect ":) "
|
||||
send_user "Structure created\n"
|
||||
|
||||
# Check completion
|
||||
send -- "new_${uuid}_data"
|
||||
expect "new_${uuid}_data"
|
||||
send -- "\t"
|
||||
expect "base"
|
||||
send -- ""
|
||||
expect ":) "
|
||||
send_user "Database completion works\n"
|
||||
|
||||
send -- "new_${uuid}_ta"
|
||||
expect "new_${uuid}_ta"
|
||||
send -- "\t"
|
||||
expect "ble"
|
||||
send -- ""
|
||||
expect ":) "
|
||||
send_user "Table completion works\n"
|
||||
|
||||
send -- "new_${uuid}_col"
|
||||
expect "new_${uuid}_col"
|
||||
send -- "\t"
|
||||
expect "umn"
|
||||
send -- ""
|
||||
expect ":) "
|
||||
send_user "Column completion works\n"
|
||||
|
||||
# Cleanup
|
||||
send -- "drop database new_${uuid}_database\r"
|
||||
expect ":) "
|
||||
send -- "drop table new_${uuid}_table\r"
|
||||
expect ":) "
|
||||
send_user "Cleanup\n"
|
||||
|
||||
send -- ""
|
||||
expect eof
|
@ -0,0 +1,7 @@
|
||||
Completion loaded
|
||||
UUID generated
|
||||
Structure created
|
||||
Database completion works
|
||||
Table completion works
|
||||
Column completion works
|
||||
Cleanup
|
Loading…
Reference in New Issue
Block a user