| 57 | namespace |
| 58 | { |
| 59 | void validateCreateQuery(const ASTCreateQuery & query, const VirtualColumnsDescription & virtuals, ContextPtr context) |
| 60 | { |
| 61 | /// First validate that the query can be parsed |
| 62 | const auto serialized_query = query.formatWithSecretsOneLine(); |
| 63 | ParserCreateQuery parser; |
| 64 | ASTPtr new_query_raw = parseQuery( |
| 65 | parser, |
| 66 | serialized_query.data(), |
| 67 | serialized_query.data() + serialized_query.size(), |
| 68 | "after altering table ", |
| 69 | 0, |
| 70 | context->getSettingsRef()[Setting::max_parser_depth], |
| 71 | context->getSettingsRef()[Setting::max_parser_backtracks]); |
| 72 | const auto & new_query = new_query_raw->as<const ASTCreateQuery &>(); |
| 73 | /// If there are no columns, then there is nothing much we can do |
| 74 | if (!new_query.columns_list || !new_query.columns_list->columns) |
| 75 | return; |
| 76 | |
| 77 | const auto & columns = *new_query.columns_list; |
| 78 | /// Do some basic sanity checks. We cannot do the same strict checks as on create, because context might not have the same settings if it is not called directly from an alter query. |
| 79 | /// SECONDARY_CREATE should check most of the important things. |
| 80 | const auto columns_desc |
| 81 | = InterpreterCreateQuery::getColumnsDescription(*columns.columns, context, LoadingStrictnessLevel::SECONDARY_CREATE, false); |
| 82 | |
| 83 | if (columns_desc.getInsertable().empty()) |
| 84 | throw Exception(ErrorCodes::EMPTY_LIST_OF_COLUMNS_PASSED, "Cannot CREATE table without insertable columns"); |
| 85 | |
| 86 | /// Default expressions are only validated in level CREATE, so let's check them now |
| 87 | DefaultExpressionsInfo default_expr_info{make_intrusive<ASTExpressionList>()}; |
| 88 | |
| 89 | for (const auto & ast : columns.columns->children) |
| 90 | { |
| 91 | const auto & col_decl = ast->as<ASTColumnDeclaration &>(); |
| 92 | /// There might be some special columns for which `columns_desc.get` would throw, e.g. Nested column when flatten_nested is enabled. |
| 93 | /// At the time of writing I am not aware of anything else, but my knowledge is limited and new types might be added, so let's be safe. |
| 94 | if (!col_decl.getDefaultExpression()) |
| 95 | continue; |
| 96 | |
| 97 | /// If no column description for the name, let's skip the validation of default expressions, but let's log the fact that something went wrong |
| 98 | if (const auto * maybe_column_desc = columns_desc.tryGet(col_decl.name); maybe_column_desc) |
| 99 | getDefaultExpressionInfoInto(col_decl, maybe_column_desc->type, default_expr_info); |
| 100 | else |
| 101 | LOG_WARNING(getLogger("validateCreateQuery"), "Couldn't get column description for column {}", col_decl.name); |
| 102 | } |
| 103 | |
| 104 | if (default_expr_info.expr_list) |
| 105 | validateColumnsDefaultsAndGetSampleBlock(default_expr_info.expr_list, columns_desc.getAll(), context); |
| 106 | |
| 107 | constexpr bool escape_index_filenames = true; /// We don't care, we are only doing validation and discarding the result |
| 108 | bool is_implicitly_created = false; /// Same |
| 109 | if (columns.indices) |
| 110 | { |
| 111 | for (const auto & child : columns.indices->children) |
| 112 | IndexDescription::getIndexFromAST(child, columns_desc, is_implicitly_created, escape_index_filenames, context); |
| 113 | } |
| 114 | if (columns.constraints) |
| 115 | { |
| 116 | InterpreterCreateQuery::getConstraintsDescription(columns.constraints, columns_desc, context); |
no test coverage detected