ClickHouse/dbms/src/Interpreters/evaluateMissingDefaults.cpp

102 lines
3.5 KiB
C++
Raw Normal View History

#include "evaluateMissingDefaults.h"
#include <Core/Block.h>
#include <Storages/ColumnDefault.h>
#include <Interpreters/SyntaxAnalyzer.h>
#include <Interpreters/ExpressionAnalyzer.h>
#include <Interpreters/ExpressionActions.h>
#include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTWithAlias.h>
2016-01-13 00:32:59 +00:00
#include <utility>
#include <DataTypes/DataTypesNumber.h>
2016-01-13 00:32:59 +00:00
namespace DB
{
static ASTPtr requiredExpressions(Block & block, const NamesAndTypesList & required_columns, const ColumnDefaults & column_defaults)
2016-01-13 00:32:59 +00:00
{
ASTPtr default_expr_list = std::make_shared<ASTExpressionList>();
2016-01-13 00:32:59 +00:00
for (const auto & column : required_columns)
{
if (block.has(column.name))
continue;
2016-01-13 00:32:59 +00:00
const auto it = column_defaults.find(column.name);
2016-01-13 00:32:59 +00:00
/// expressions must be cloned to prevent modification by the ExpressionAnalyzer
if (it != column_defaults.end())
default_expr_list->children.emplace_back(
setAlias(it->second.expression->clone(), it->first));
}
2016-01-13 00:32:59 +00:00
if (default_expr_list->children.empty())
return nullptr;
return default_expr_list;
}
void evaluateMissingDefaults(Block & block,
const NamesAndTypesList & required_columns,
const ColumnDefaults & column_defaults,
const Context & context, bool save_unneeded_columns)
{
if (column_defaults.empty())
return;
ASTPtr default_expr_list = requiredExpressions(block, required_columns, column_defaults);
if (!default_expr_list)
return;
2016-01-13 00:32:59 +00:00
if (!save_unneeded_columns)
{
2019-01-09 16:16:59 +00:00
auto syntax_result = SyntaxAnalyzer(context).analyze(default_expr_list, block.getNamesAndTypesList());
ExpressionAnalyzer{default_expr_list, syntax_result, context}.getActions(true)->execute(block);
return;
}
/** ExpressionAnalyzer eliminates "unused" columns, in order to ensure their safety
* we are going to operate on a copy instead of the original block */
Block copy_block{block};
2019-01-09 16:16:59 +00:00
auto syntax_result = SyntaxAnalyzer(context).analyze(default_expr_list, block.getNamesAndTypesList());
auto expression_analyzer = ExpressionAnalyzer{default_expr_list, syntax_result, context};
auto required_source_columns = expression_analyzer.getRequiredSourceColumns();
auto rows_was = copy_block.rows();
// Delete all not needed columns in DEFAULT expression.
// They can intersect with columns added in PREWHERE
// test 00950_default_prewhere
// CLICKHOUSE-4523
for (const auto & delete_column : copy_block.getNamesAndTypesList())
{
if (std::find(required_source_columns.begin(), required_source_columns.end(), delete_column.name) == required_source_columns.end())
{
copy_block.erase(delete_column.name);
}
}
if (copy_block.columns() == 0)
{
// Add column to indicate block size in execute()
copy_block.insert({DataTypeUInt8().createColumnConst(rows_was, 0u), std::make_shared<DataTypeUInt8>(), "__dummy"});
}
expression_analyzer.getActions(true)->execute(copy_block);
2016-01-13 00:32:59 +00:00
/// move evaluated columns to the original block, materializing them at the same time
size_t pos = 0;
for (auto col = required_columns.begin(); col != required_columns.end(); ++col, ++pos)
{
if (copy_block.has(col->name))
{
auto evaluated_col = copy_block.getByName(col->name);
evaluated_col.column = evaluated_col.column->convertToFullColumnIfConst();
2016-01-13 00:32:59 +00:00
block.insert(pos, std::move(evaluated_col));
}
}
2016-01-13 00:32:59 +00:00
}
}