mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 15:42:02 +00:00
Allow null to default convertion only if column has default
This commit is contained in:
parent
55d2627a27
commit
54a7a6ef0d
@ -10,10 +10,11 @@ AddingDefaultBlockOutputStream::AddingDefaultBlockOutputStream(
|
||||
const BlockOutputStreamPtr & output_,
|
||||
const Block & header_,
|
||||
const ColumnsDescription & columns_,
|
||||
ContextPtr context_)
|
||||
ContextPtr context_,
|
||||
bool null_as_default_)
|
||||
: output(output_), header(header_)
|
||||
{
|
||||
auto dag = addMissingDefaults(header_, output->getHeader().getNamesAndTypesList(), columns_, context_);
|
||||
auto dag = addMissingDefaults(header_, output->getHeader().getNamesAndTypesList(), columns_, context_, null_as_default_);
|
||||
adding_defaults_actions = std::make_shared<ExpressionActions>(std::move(dag), ExpressionActionsSettings::fromContext(context_));
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,8 @@ public:
|
||||
const BlockOutputStreamPtr & output_,
|
||||
const Block & header_,
|
||||
const ColumnsDescription & columns_,
|
||||
ContextPtr context_);
|
||||
ContextPtr context_,
|
||||
bool null_as_default_ = false);
|
||||
|
||||
Block getHeader() const override { return header; }
|
||||
void write(const Block & block) override;
|
||||
|
@ -242,11 +242,12 @@ BlockIO InterpreterInsertQuery::execute()
|
||||
|
||||
const auto & input_columns = res.pipeline.getHeader().getColumns();
|
||||
const auto & query_columns = query_sample_block.getColumns();
|
||||
const auto & output_columns = metadata_snapshot->getColumns();
|
||||
|
||||
size_t col_idx = 0;
|
||||
for (const auto & column : query_columns_names_and_types)
|
||||
{
|
||||
if (input_columns[col_idx]->isNullable() && !query_columns[col_idx]->isNullable())
|
||||
if (input_columns[col_idx]->isNullable() && !query_columns[col_idx]->isNullable() && output_columns.hasDefault(column.name))
|
||||
{
|
||||
auto nullable_column = ColumnNullable::create(query_columns[col_idx], ColumnUInt8::create(query_columns[col_idx]->size(), 0));
|
||||
ColumnWithTypeAndName new_column(std::move(nullable_column), std::make_shared<DataTypeNullable>(column.type), column.name);
|
||||
@ -282,10 +283,12 @@ BlockIO InterpreterInsertQuery::execute()
|
||||
out = std::make_shared<CheckConstraintsBlockOutputStream>(
|
||||
query.table_id, out, out->getHeader(), metadata_snapshot->getConstraints(), getContext());
|
||||
|
||||
bool null_as_default = query.select && getContext()->getSettingsRef().insert_null_as_default;
|
||||
|
||||
/// Actually we don't know structure of input blocks from query/table,
|
||||
/// because some clients break insertion protocol (columns != header)
|
||||
out = std::make_shared<AddingDefaultBlockOutputStream>(
|
||||
out, query_sample_block, metadata_snapshot->getColumns(), getContext());
|
||||
out, query_sample_block, metadata_snapshot->getColumns(), getContext(), null_as_default);
|
||||
|
||||
/// It's important to squash blocks as early as possible (before other transforms),
|
||||
/// because other transforms may work inefficient if block size is small.
|
||||
|
@ -19,7 +19,8 @@ ActionsDAGPtr addMissingDefaults(
|
||||
const Block & header,
|
||||
const NamesAndTypesList & required_columns,
|
||||
const ColumnsDescription & columns,
|
||||
ContextPtr context)
|
||||
ContextPtr context,
|
||||
bool null_as_default)
|
||||
{
|
||||
auto actions = std::make_shared<ActionsDAG>(header.getColumnsWithTypeAndName());
|
||||
auto & index = actions->getIndex();
|
||||
@ -80,7 +81,7 @@ ActionsDAGPtr addMissingDefaults(
|
||||
}
|
||||
|
||||
/// Computes explicitly specified values by default and materialized columns.
|
||||
if (auto dag = evaluateMissingDefaults(actions->getResultColumns(), required_columns, columns, context))
|
||||
if (auto dag = evaluateMissingDefaults(actions->getResultColumns(), required_columns, columns, context, true, null_as_default))
|
||||
actions = ActionsDAG::merge(std::move(*actions), std::move(*dag));
|
||||
else
|
||||
/// Removes unused columns and reorders result.
|
||||
|
@ -24,5 +24,6 @@ using ActionsDAGPtr = std::shared_ptr<ActionsDAG>;
|
||||
* All three types of columns are materialized (not constants).
|
||||
*/
|
||||
ActionsDAGPtr addMissingDefaults(
|
||||
const Block & header, const NamesAndTypesList & required_columns, const ColumnsDescription & columns, ContextPtr context);
|
||||
const Block & header, const NamesAndTypesList & required_columns,
|
||||
const ColumnsDescription & columns, ContextPtr context, bool null_as_default = false);
|
||||
}
|
||||
|
@ -24,17 +24,19 @@ namespace
|
||||
{
|
||||
|
||||
/// Add all required expressions for missing columns calculation
|
||||
void addDefaultRequiredExpressionsRecursively(const Block & block, const String & required_column_name, DataTypePtr required_column_type, const ColumnsDescription & columns, ASTPtr default_expr_list_accum, NameSet & added_columns)
|
||||
void addDefaultRequiredExpressionsRecursively(
|
||||
const Block & block, const String & required_column_name, DataTypePtr required_column_type,
|
||||
const ColumnsDescription & columns, ASTPtr default_expr_list_accum, NameSet & added_columns, bool null_as_default)
|
||||
{
|
||||
checkStackSize();
|
||||
|
||||
bool is_column_in_query = block.has(required_column_name);
|
||||
bool from_nullable_to_non_nullable = false;
|
||||
bool convert_null_to_default = false;
|
||||
|
||||
if (is_column_in_query)
|
||||
from_nullable_to_non_nullable = block.findByName(required_column_name)->type->isNullable() && !required_column_type->isNullable();
|
||||
convert_null_to_default = null_as_default && block.findByName(required_column_name)->type->isNullable() && !required_column_type->isNullable();
|
||||
|
||||
if ((is_column_in_query && !from_nullable_to_non_nullable) || added_columns.count(required_column_name))
|
||||
if ((is_column_in_query && !convert_null_to_default) || added_columns.count(required_column_name))
|
||||
return;
|
||||
|
||||
auto column_default = columns.getDefault(required_column_name);
|
||||
@ -50,10 +52,10 @@ void addDefaultRequiredExpressionsRecursively(const Block & block, const String
|
||||
RequiredSourceColumnsVisitor(columns_context).visit(column_default_expr);
|
||||
NameSet required_columns_names = columns_context.requiredColumns();
|
||||
|
||||
if (is_column_in_query && from_nullable_to_non_nullable)
|
||||
if (is_column_in_query && convert_null_to_default)
|
||||
{
|
||||
auto null_as_default_func = makeASTFunction("ifNull", std::make_shared<ASTIdentifier>(required_column_name), column_default_expr);
|
||||
default_expr_list_accum->children.emplace_back(setAlias(null_as_default_func, required_column_name));
|
||||
auto null_as_default_expr = makeASTFunction("ifNull", std::make_shared<ASTIdentifier>(required_column_name), column_default_expr);
|
||||
default_expr_list_accum->children.emplace_back(setAlias(null_as_default_expr, required_column_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -64,17 +66,17 @@ void addDefaultRequiredExpressionsRecursively(const Block & block, const String
|
||||
added_columns.emplace(required_column_name);
|
||||
|
||||
for (const auto & next_required_column_name : required_columns_names)
|
||||
addDefaultRequiredExpressionsRecursively(block, next_required_column_name, required_column_type, columns, default_expr_list_accum, added_columns);
|
||||
addDefaultRequiredExpressionsRecursively(block, next_required_column_name, required_column_type, columns, default_expr_list_accum, added_columns, null_as_default);
|
||||
}
|
||||
}
|
||||
|
||||
ASTPtr defaultRequiredExpressions(const Block & block, const NamesAndTypesList & required_columns, const ColumnsDescription & columns)
|
||||
ASTPtr defaultRequiredExpressions(const Block & block, const NamesAndTypesList & required_columns, const ColumnsDescription & columns, bool null_as_default)
|
||||
{
|
||||
ASTPtr default_expr_list = std::make_shared<ASTExpressionList>();
|
||||
|
||||
NameSet added_columns;
|
||||
for (const auto & column : required_columns)
|
||||
addDefaultRequiredExpressionsRecursively(block, column.name, column.type, columns, default_expr_list, added_columns);
|
||||
addDefaultRequiredExpressionsRecursively(block, column.name, column.type, columns, default_expr_list, added_columns, null_as_default);
|
||||
|
||||
if (default_expr_list->children.empty())
|
||||
return nullptr;
|
||||
@ -147,12 +149,14 @@ ActionsDAGPtr evaluateMissingDefaults(
|
||||
const Block & header,
|
||||
const NamesAndTypesList & required_columns,
|
||||
const ColumnsDescription & columns,
|
||||
ContextPtr context, bool save_unneeded_columns)
|
||||
ContextPtr context,
|
||||
bool save_unneeded_columns,
|
||||
bool null_as_default)
|
||||
{
|
||||
if (!columns.hasDefaults())
|
||||
return nullptr;
|
||||
|
||||
ASTPtr expr_list = defaultRequiredExpressions(header, required_columns, columns);
|
||||
ASTPtr expr_list = defaultRequiredExpressions(header, required_columns, columns, null_as_default);
|
||||
return createExpressions(header, expr_list, save_unneeded_columns, required_columns, context);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,9 @@ ActionsDAGPtr evaluateMissingDefaults(
|
||||
const Block & header,
|
||||
const NamesAndTypesList & required_columns,
|
||||
const ColumnsDescription & columns,
|
||||
ContextPtr context, bool save_unneeded_columns = true);
|
||||
ContextPtr context,
|
||||
bool save_unneeded_columns = true,
|
||||
bool null_as_default = false);
|
||||
|
||||
/// Tries to convert columns in block to required_columns
|
||||
void performRequiredConversions(Block & block, const NamesAndTypesList & required_columns, ContextPtr context);
|
||||
|
Loading…
Reference in New Issue
Block a user