| 1 | #include "evaluateMissingDefaults.h" |
| 2 | |
| 3 | #include <Core/Block.h> |
| 4 | #include <Storages/ColumnDefault.h> |
| 5 | #include <Interpreters/SyntaxAnalyzer.h> |
| 6 | #include <Interpreters/ExpressionAnalyzer.h> |
| 7 | #include <Interpreters/ExpressionActions.h> |
| 8 | #include <Parsers/ASTExpressionList.h> |
| 9 | #include <Parsers/ASTWithAlias.h> |
| 10 | #include <utility> |
| 11 | #include <DataTypes/DataTypesNumber.h> |
| 12 | |
| 13 | |
| 14 | namespace DB |
| 15 | { |
| 16 | |
| 17 | static ASTPtr requiredExpressions(Block & block, const NamesAndTypesList & required_columns, const ColumnDefaults & column_defaults) |
| 18 | { |
| 19 | ASTPtr default_expr_list = std::make_shared<ASTExpressionList>(); |
| 20 | |
| 21 | for (const auto & column : required_columns) |
| 22 | { |
| 23 | if (block.has(column.name)) |
| 24 | continue; |
| 25 | |
| 26 | const auto it = column_defaults.find(column.name); |
| 27 | |
| 28 | /// expressions must be cloned to prevent modification by the ExpressionAnalyzer |
| 29 | if (it != column_defaults.end()) |
| 30 | default_expr_list->children.emplace_back( |
| 31 | setAlias(it->second.expression->clone(), it->first)); |
| 32 | } |
| 33 | |
| 34 | if (default_expr_list->children.empty()) |
| 35 | return nullptr; |
| 36 | return default_expr_list; |
| 37 | } |
| 38 | |
| 39 | void evaluateMissingDefaults(Block & block, |
| 40 | const NamesAndTypesList & required_columns, |
| 41 | const ColumnDefaults & column_defaults, |
| 42 | const Context & context, bool save_unneeded_columns) |
| 43 | { |
| 44 | if (column_defaults.empty()) |
| 45 | return; |
| 46 | |
| 47 | ASTPtr default_expr_list = requiredExpressions(block, required_columns, column_defaults); |
| 48 | if (!default_expr_list) |
| 49 | return; |
| 50 | |
| 51 | if (!save_unneeded_columns) |
| 52 | { |
| 53 | auto syntax_result = SyntaxAnalyzer(context).analyze(default_expr_list, block.getNamesAndTypesList()); |
| 54 | ExpressionAnalyzer{default_expr_list, syntax_result, context}.getActions(true)->execute(block); |
| 55 | return; |
| 56 | } |
| 57 | |
| 58 | /** ExpressionAnalyzer eliminates "unused" columns, in order to ensure their safety |
| 59 | * we are going to operate on a copy instead of the original block */ |
| 60 | Block copy_block{block}; |
| 61 | |
| 62 | auto syntax_result = SyntaxAnalyzer(context).analyze(default_expr_list, block.getNamesAndTypesList()); |
| 63 | auto expression_analyzer = ExpressionAnalyzer{default_expr_list, syntax_result, context}; |
| 64 | auto required_source_columns = syntax_result->requiredSourceColumns(); |
| 65 | auto rows_was = copy_block.rows(); |
| 66 | |
| 67 | // Delete all not needed columns in DEFAULT expression. |
| 68 | // They can intersect with columns added in PREWHERE |
| 69 | // test 00950_default_prewhere |
| 70 | // CLICKHOUSE-4523 |
| 71 | for (const auto & delete_column : copy_block.getNamesAndTypesList()) |
| 72 | { |
| 73 | if (std::find(required_source_columns.begin(), required_source_columns.end(), delete_column.name) == required_source_columns.end()) |
| 74 | { |
| 75 | copy_block.erase(delete_column.name); |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | if (copy_block.columns() == 0) |
| 80 | { |
| 81 | // Add column to indicate block size in execute() |
| 82 | copy_block.insert({DataTypeUInt8().createColumnConst(rows_was, 0u), std::make_shared<DataTypeUInt8>(), "__dummy" }); |
| 83 | } |
| 84 | |
| 85 | expression_analyzer.getActions(true)->execute(copy_block); |
| 86 | |
| 87 | /// move evaluated columns to the original block, materializing them at the same time |
| 88 | size_t pos = 0; |
| 89 | for (auto col = required_columns.begin(); col != required_columns.end(); ++col, ++pos) |
| 90 | { |
| 91 | if (copy_block.has(col->name)) |
| 92 | { |
| 93 | auto evaluated_col = copy_block.getByName(col->name); |
| 94 | evaluated_col.column = evaluated_col.column->convertToFullColumnIfConst(); |
| 95 | |
| 96 | block.insert(pos, std::move(evaluated_col)); |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | } |
| 102 | |