diff options
author | Bulat Gayazov <brgayazov@yandex-team.ru> | 2023-10-10 18:14:59 +0300 |
---|---|---|
committer | brgayazov <bulat@ydb.tech> | 2023-10-10 19:14:49 +0300 |
commit | 927f78bc5e24e809ad7bed12a9c5edb075c81482 (patch) | |
tree | 3c13c76b5743de7960cd6e172f286836cf48a55e | |
parent | 2f0e1eed795f5e18b50fe0fe0ede0999d816dc4b (diff) | |
download | ydb-927f78bc5e24e809ad7bed12a9c5edb075c81482.tar.gz |
Added interactive CLI "SET stats" command validation
Added interactive CLI "SET stats" command validation
Pull Request resolved: https://github.com/ydb-platform/ydb/pull/386
-rw-r--r-- | ydb/public/lib/ydb_cli/commands/interactive/interactive_cli.cpp | 102 |
1 files changed, 39 insertions, 63 deletions
diff --git a/ydb/public/lib/ydb_cli/commands/interactive/interactive_cli.cpp b/ydb/public/lib/ydb_cli/commands/interactive/interactive_cli.cpp index 2e3db32865..79e4268b22 100644 --- a/ydb/public/lib/ydb_cli/commands/interactive/interactive_cli.cpp +++ b/ydb/public/lib/ydb_cli/commands/interactive/interactive_cli.cpp @@ -29,36 +29,6 @@ std::string ToLower(std::string_view value) { return result; } -template <typename Predicate> -void TrimRight(std::string & value, Predicate predicate) { - while (!value.empty() && predicate(value.back())) - value.pop_back(); -} - -template <typename Predicate> -void TrimLeft(std::string & value, Predicate predicate) { - size_t value_size = value.size(); - size_t i = 0; - - for (; i < value_size; ++i) { - if (!predicate(value[i])) { - break; - } - } - - if (i != 0) { - value = value.substr(i); - } -} - -void TrimSpacesRight(std::string & value) { - TrimRight(value, [](char character) { return std::isspace(character); }); -} - -void TrimSpacesLeft(std::string & value) { - TrimLeft(value, [](char character) { return std::isspace(character); }); -} - struct Token { std::string_view data; }; @@ -69,6 +39,8 @@ public: std::optional<Token> GetNextToken(); + static bool IsSeparatedTokenSymbol(char c); + private: std::string_view Input; const char * Position = nullptr; @@ -89,16 +61,22 @@ std::optional<Token> Lexer::GetNextToken() { } const char * tokenStart = Position; - ++Position; - - while (Position < Input.end() && !std::isspace(*Position)) { + if (IsSeparatedTokenSymbol(*Position)) { ++Position; + } else { + while (Position < Input.end() && !std::isspace(*Position) && !IsSeparatedTokenSymbol(*Position)) { + ++Position; + } } std::string_view TokenData(tokenStart, Position); return Token{TokenData}; } +bool Lexer::IsSeparatedTokenSymbol(char c) { + return c == '=' || c == ';'; +} + std::vector<Token> Tokenize(std::string_view input) { std::vector<Token> tokens; Lexer lexer(input); @@ -116,39 +94,33 @@ struct InteractiveCLIState { std::optional<NTable::ECollectQueryStatsMode> TryParseCollectStatsMode(const std::vector<Token> & tokens) { size_t tokensSize = tokens.size(); - if (tokensSize < 2) { - return {}; - } - if (ToLower(tokens[0].data) != "set") { + if (tokensSize > 4) { + Cerr << "Variable value for \"SET stats\" special command should contain exactly one token." << Endl; return {}; } - std::string setQuery; - for (size_t i = 1; i < tokensSize; ++i) { - setQuery += tokens[i].data; - } - - auto position = setQuery.find_first_of('='); - if (position == std::string::npos) { - return {}; + auto statsMode = NTable::ParseQueryStatsMode(tokens[3].data); + if (!statsMode) { + Cerr << "Unknown stats collection mode: \"" << tokens[3].data << "\"." << Endl; } + return statsMode; +} - std::string name = setQuery.substr(0, position); - std::string value = setQuery.substr(position + 1); - - TrimSpacesLeft(name); - TrimSpacesRight(name); - if (ToLower(name) != "stats") { - return {}; +void ParseSetCommand(const std::vector<Token> & tokens, InteractiveCLIState & interactiveCLIState) { + if (tokens.size() == 1) { + Cerr << "Missing variable name for \"SET\" special command." << Endl; + } else if (tokens.size() == 2 || tokens[2].data != "=") { + Cerr << "Missing \"=\" symbol for \"SET\" special command." << Endl; + } else if (tokens.size() == 3) { + Cerr << "Missing variable value for \"SET\" special command." << Endl; + } else if (ToLower(tokens[1].data) == "stats") { + if (auto statsMode = TryParseCollectStatsMode(tokens)) { + interactiveCLIState.CollectStatsMode = *statsMode; + } + } else { + Cerr << "Unknown variable name \"" << tokens[1].data << "\" for \"SET\" special command." << Endl; } - - TrimSpacesLeft(value); - TrimRight(value, [](char character) { - return std::isspace(character) || character == ';'; - }); - - return NTable::ParseQueryStatsMode(value); } } @@ -159,7 +131,8 @@ TInteractiveCLI::TInteractiveCLI(TClientCommand::TConfig & config, std::string p {} void TInteractiveCLI::Run() { - std::vector<std::string> SQLWords = {"SELECT", "FROM", "WHERE", "GROUP", "ORDER" , "BY", "LIMIT", "OFFSET", "EXPLAIN", "AST"}; + std::vector<std::string> SQLWords = {"SELECT", "FROM", "WHERE", "GROUP", "ORDER", "BY", "LIMIT", "OFFSET", + "EXPLAIN", "AST", "SET"}; std::vector<std::string> Words; for (auto & word : SQLWords) { Words.push_back(word); @@ -182,13 +155,16 @@ void TInteractiveCLI::Run() { try { auto tokens = Tokenize(line); size_t tokensSize = tokens.size(); + if (tokens.empty()) { + continue; + } - if (auto collectStatsMode = TryParseCollectStatsMode(tokens)) { - interactiveCLIState.CollectStatsMode = *collectStatsMode; + if (ToLower(tokens[0].data) == "set") { + ParseSetCommand(tokens, interactiveCLIState); continue; } - if (!tokens.empty() && ToLower(tokens.front().data) == "explain") { + if (ToLower(tokens[0].data) == "explain") { bool printAst = tokensSize >= 2 && ToLower(tokens[1].data) == "ast"; size_t skipTokens = 1 + printAst; TString explainQuery; |