| 448 | } |
| 449 | |
| 450 | bool KeeperClient::processQueryText(const String & text, bool is_interactive) |
| 451 | { |
| 452 | if (exit_strings.contains(text)) |
| 453 | return false; |
| 454 | |
| 455 | static constexpr size_t total_retries = 10; |
| 456 | std::chrono::milliseconds current_sleep{100}; |
| 457 | size_t i = 0; |
| 458 | |
| 459 | auto component_guard = Coordination::setCurrentComponent("KeeperClient::processQueryText"); |
| 460 | while (true) |
| 461 | { |
| 462 | try |
| 463 | { |
| 464 | if (i > 0) |
| 465 | connectToKeeper(); |
| 466 | |
| 467 | if (waiting_confirmation) |
| 468 | { |
| 469 | waiting_confirmation = false; |
| 470 | if (text.size() == 1 && (text == "y" || text == "Y")) |
| 471 | confirmation_callback(); |
| 472 | return true; |
| 473 | } |
| 474 | |
| 475 | const char * begin = text.data(); |
| 476 | const char * end = begin + text.size(); |
| 477 | |
| 478 | /// Tokenize once for the entire input. We use skip_insignificant=false |
| 479 | /// so that whitespace tokens are explicit — needed for `\ ` (escaped space) |
| 480 | /// handling in parseKeeperArg. We avoid tryParseQuery because it rejects |
| 481 | /// Error tokens (like `\`) during its lookahead scan. |
| 482 | Tokens tokens(begin, end, 0, false); |
| 483 | IParser::Pos pos(tokens, DBMS_DEFAULT_MAX_PARSER_DEPTH, DBMS_DEFAULT_MAX_PARSER_BACKTRACKS); |
| 484 | |
| 485 | while (!pos->isEnd()) |
| 486 | { |
| 487 | /// Skip leading whitespace and semicolons (to support multi statements). |
| 488 | while (!pos->isEnd() && (pos->type == TokenType::Whitespace || pos->type == TokenType::Semicolon)) |
| 489 | ++pos; |
| 490 | |
| 491 | if (pos->isEnd()) |
| 492 | break; |
| 493 | |
| 494 | KeeperParser parser; |
| 495 | ASTPtr res; |
| 496 | Expected expected; |
| 497 | bool parsed = parser.parse(pos, res, expected); |
| 498 | |
| 499 | if (!parsed || !res) |
| 500 | { |
| 501 | std::cerr << "Syntax error at position " << (pos->begin - begin) << "\n"; |
| 502 | return true; |
| 503 | } |
| 504 | |
| 505 | /// Skip trailing whitespace after the parsed command. |
| 506 | while (!pos->isEnd() && pos->type == TokenType::Whitespace) |
| 507 | ++pos; |
nothing calls this directly
no test coverage detected