| 77 | } |
| 78 | |
| 79 | void TableFunctionExplain::parseArguments(const ASTPtr & ast_function, ContextPtr context) |
| 80 | { |
| 81 | const auto * function = ast_function->as<ASTFunction>(); |
| 82 | if (!function || !function->arguments) |
| 83 | throw Exception(ErrorCodes::BAD_ARGUMENTS, |
| 84 | "Table function '{}' cannot be called directly, use `SELECT * FROM (EXPLAIN ...)` syntax", getName()); |
| 85 | |
| 86 | size_t num_args = function->arguments->children.size(); |
| 87 | if (num_args != 2 && num_args != 3) |
| 88 | throw Exception(ErrorCodes::BAD_ARGUMENTS, |
| 89 | "Table function '{}' requires 2 or 3 arguments, got {}", getName(), num_args); |
| 90 | |
| 91 | const auto & kind_arg = function->arguments->children[0]; |
| 92 | const auto * kind_literal = kind_arg->as<ASTLiteral>(); |
| 93 | if (!kind_literal || kind_literal->value.getType() != Field::Types::String) |
| 94 | throw Exception(ErrorCodes::BAD_ARGUMENTS, |
| 95 | "Table function '{}' requires a String argument for EXPLAIN kind, got '{}'", |
| 96 | getName(), kind_arg->formatForErrorMessage()); |
| 97 | |
| 98 | ASTExplainQuery::ExplainKind kind = ASTExplainQuery::fromString(kind_literal->value.safeGet<String>()); |
| 99 | auto explain_query = make_intrusive<ASTExplainQuery>(kind); |
| 100 | |
| 101 | const auto * settings_arg = function->arguments->children[1]->as<ASTLiteral>(); |
| 102 | if (!settings_arg || settings_arg->value.getType() != Field::Types::String) |
| 103 | throw Exception(ErrorCodes::BAD_ARGUMENTS, |
| 104 | "Table function '{}' requires a serialized string settings argument, got '{}'", |
| 105 | getName(), function->arguments->children[1]->formatForErrorMessage()); |
| 106 | |
| 107 | const auto & settings_str = settings_arg->value.safeGet<String>(); |
| 108 | if (!settings_str.empty()) |
| 109 | { |
| 110 | const Settings & settings = context->getSettingsRef(); |
| 111 | |
| 112 | /// parse_only_internals_ = true - we don't want to parse `SET` keyword |
| 113 | ParserSetQuery settings_parser(/* parse_only_internals_ = */ true); |
| 114 | ASTPtr settings_ast = parseQuery( |
| 115 | settings_parser, settings_str, settings[Setting::max_query_size], settings[Setting::max_parser_depth], settings[Setting::max_parser_backtracks]); |
| 116 | explain_query->setSettings(std::move(settings_ast)); |
| 117 | } |
| 118 | |
| 119 | if (function->arguments->children.size() > 2) |
| 120 | { |
| 121 | const auto & subquery_arg = function->arguments->children[2]; |
| 122 | const auto * subquery = subquery_arg->as<ASTSubquery>(); |
| 123 | |
| 124 | if (!subquery) |
| 125 | throw Exception(ErrorCodes::BAD_ARGUMENTS, |
| 126 | "Table function '{}' requires a subquery argument, got '{}'", |
| 127 | getName(), subquery_arg->formatForErrorMessage()); |
| 128 | |
| 129 | if (subquery->children.empty()) |
| 130 | throw Exception(ErrorCodes::UNEXPECTED_AST_STRUCTURE, |
| 131 | "A subquery AST element must have a child"); |
| 132 | |
| 133 | const auto & query_arg = subquery->children[0]; |
| 134 | |
| 135 | if (!query_arg->as<ASTSelectWithUnionQuery>()) |
| 136 | throw Exception(ErrorCodes::BAD_ARGUMENTS, |
nothing calls this directly
no test coverage detected