| 454 | |
| 455 | |
| 456 | std::pair<const char *, bool> splitMultipartQuery( |
| 457 | const std::string & queries, |
| 458 | std::vector<std::string> & queries_list, |
| 459 | size_t max_query_size, |
| 460 | size_t max_parser_depth, |
| 461 | size_t max_parser_backtracks, |
| 462 | bool allow_settings_after_format_in_insert, |
| 463 | bool implicit_select) |
| 464 | { |
| 465 | ASTPtr ast; |
| 466 | |
| 467 | const char * begin = queries.data(); /// begin of current query |
| 468 | const char * pos = begin; /// parser moves pos from begin to the end of current query |
| 469 | const char * end = begin + queries.size(); |
| 470 | |
| 471 | ParserQuery parser(end, allow_settings_after_format_in_insert, implicit_select); |
| 472 | |
| 473 | queries_list.clear(); |
| 474 | |
| 475 | while (pos < end) |
| 476 | { |
| 477 | begin = pos; |
| 478 | |
| 479 | ast = parseQueryAndMovePosition(parser, pos, end, "", true, max_query_size, max_parser_depth, max_parser_backtracks); |
| 480 | |
| 481 | bool is_insert_with_data = false; |
| 482 | if (ASTInsertQuery * insert = getInsertAST(ast); insert && insert->data) |
| 483 | { |
| 484 | /// Data for INSERT is broken on the new line |
| 485 | pos = insert->data; |
| 486 | while (*pos && *pos != '\n') |
| 487 | ++pos; |
| 488 | insert->end = pos; |
| 489 | is_insert_with_data = true; |
| 490 | } |
| 491 | |
| 492 | /// `pos` now points at the end of the current query. For an INSERT with inline data this is the |
| 493 | /// boundary of the data line and must not be extended further, otherwise a trailing comment would |
| 494 | /// be handed to the format reader as input data. |
| 495 | const char * query_end = pos; |
| 496 | |
| 497 | /// Skip trailing whitespace and semicolons before the next query. |
| 498 | while (isWhitespaceASCII(*pos) || *pos == ';') |
| 499 | ++pos; |
| 500 | |
| 501 | /// If only whitespace and/or comments remain, there is no further query to parse. Consume the rest |
| 502 | /// so the trailing comment is not handed to the parser as a separate, comment-only `Empty query`. |
| 503 | Tokens tokens(pos, end, max_query_size, true); |
| 504 | IParser::Pos token_iterator(tokens, static_cast<uint32_t>(max_parser_depth), static_cast<uint32_t>(max_parser_backtracks)); |
| 505 | |
| 506 | if (token_iterator->isEnd()) |
| 507 | { |
| 508 | pos = end; |
| 509 | /// For a non-INSERT query fold the trailing comment into the returned fragment (it is harmless); |
| 510 | /// for an INSERT keep the boundary at the data line so the tail is dropped rather than parsed as data. |
| 511 | if (!is_insert_with_data) |
| 512 | query_end = end; |
| 513 | } |