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 | |