diff --git a/dbms/include/DB/Core/Block.h b/dbms/include/DB/Core/Block.h index 05a8d5a47de..cf9e96d2d41 100644 --- a/dbms/include/DB/Core/Block.h +++ b/dbms/include/DB/Core/Block.h @@ -66,9 +66,6 @@ public: void erase(const String & name); /// Добавляет в блок недостающие столбцы со значениями по-умолчанию void addDefaults(const NamesAndTypesList & required_columns); - void addDefaults(const NamesAndTypesList & required_columns, - const ColumnDefaults & column_defaults, - const Context & context); ColumnWithNameAndType & getByPosition(size_t position); const ColumnWithNameAndType & getByPosition(size_t position) const; diff --git a/dbms/include/DB/DataStreams/AddingDefaultBlockInputStream.h b/dbms/include/DB/DataStreams/AddingDefaultBlockInputStream.h index 76b10b7d0e1..92928a4167a 100644 --- a/dbms/include/DB/DataStreams/AddingDefaultBlockInputStream.h +++ b/dbms/include/DB/DataStreams/AddingDefaultBlockInputStream.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -54,7 +55,8 @@ protected: Block res = children.back()->read(); if (!res) return res; - res.addDefaults(*required_columns, column_defaults, context); + evaluateMissingDefaults(res, *required_columns, column_defaults, context); + res.addDefaults(*required_columns); return res; } diff --git a/dbms/include/DB/DataStreams/AddingDefaultBlockOutputStream.h b/dbms/include/DB/DataStreams/AddingDefaultBlockOutputStream.h index 3d2fd157f65..efdcb0f36fa 100644 --- a/dbms/include/DB/DataStreams/AddingDefaultBlockOutputStream.h +++ b/dbms/include/DB/DataStreams/AddingDefaultBlockOutputStream.h @@ -7,6 +7,7 @@ #include #include +#include namespace DB @@ -38,7 +39,8 @@ public: void write(const Block & block) override { Block res = block; - res.addDefaults(*required_columns, column_defaults, context); + evaluateMissingDefaults(res, *required_columns, column_defaults, context); + res.addDefaults(*required_columns); output->write(res); } diff --git a/dbms/include/DB/Interpreters/evaluateMissingDefaults.h b/dbms/include/DB/Interpreters/evaluateMissingDefaults.h new file mode 100644 index 00000000000..ec695da4dbe --- /dev/null +++ b/dbms/include/DB/Interpreters/evaluateMissingDefaults.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include + +namespace DB +{ + +inline void evaluateMissingDefaults(Block & block, + const NamesAndTypesList & required_columns, + const ColumnDefaults & column_defaults, + const Context & context) +{ + if (column_defaults.empty()) + return; + + ASTPtr default_expr_list{stdext::make_unique().release()}; + + for (const auto & column : required_columns) + { + if (block.has(column.name)) + continue; + + const auto it = column_defaults.find(column.name); + + /// 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)); + } + + /// nothing to evaluate + if (default_expr_list->children.empty()) + 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}; + /// evaluate default values for defaulted columns + ExpressionAnalyzer{default_expr_list, context, required_columns}.getActions(true)->execute(copy_block); + + /// move evaluated columns to the original block + for (auto & column_name_type : copy_block.getColumns()) + block.insert(std::move(column_name_type)); +} + +} diff --git a/dbms/include/DB/Storages/ColumnDefault.h b/dbms/include/DB/Storages/ColumnDefault.h index f58bf75a11f..b6a0b7a763b 100644 --- a/dbms/include/DB/Storages/ColumnDefault.h +++ b/dbms/include/DB/Storages/ColumnDefault.h @@ -4,7 +4,6 @@ #include #include #include -#include #include namespace DB diff --git a/dbms/include/DB/Storages/MergeTree/MergeTreeReader.h b/dbms/include/DB/Storages/MergeTree/MergeTreeReader.h index a72086c1f4d..7b7d62a9127 100644 --- a/dbms/include/DB/Storages/MergeTree/MergeTreeReader.h +++ b/dbms/include/DB/Storages/MergeTree/MergeTreeReader.h @@ -10,6 +10,7 @@ #include #include #include +#include namespace DB @@ -195,7 +196,7 @@ public: } /// evaluate defaulted columns - res.addDefaults(columns, storage.column_defaults, storage.context); + evaluateMissingDefaults(res, columns, storage.column_defaults, storage.context); } catch (const Exception & e) { diff --git a/dbms/include/DB/Storages/StorageLog.h b/dbms/include/DB/Storages/StorageLog.h index 824b3adff17..8cfef75522e 100644 --- a/dbms/include/DB/Storages/StorageLog.h +++ b/dbms/include/DB/Storages/StorageLog.h @@ -148,6 +148,12 @@ public: const ColumnDefaults & column_defaults_, size_t max_compress_block_size_ = DEFAULT_MAX_COMPRESS_BLOCK_SIZE); + static StoragePtr create( + const std::string & path_, + const std::string & name_, + NamesAndTypesListPtr columns_, + size_t max_compress_block_size_ = DEFAULT_MAX_COMPRESS_BLOCK_SIZE); + std::string getName() const { return "Log"; } std::string getTableName() const { return name; } diff --git a/dbms/src/Core/Block.cpp b/dbms/src/Core/Block.cpp index 47f3da4165e..ca46b28cd59 100644 --- a/dbms/src/Core/Block.cpp +++ b/dbms/src/Core/Block.cpp @@ -34,42 +34,6 @@ void Block::addDefaults(const NamesAndTypesList & required_columns) insertDefault(column.name, column.type); } -void Block::addDefaults(const NamesAndTypesList & required_columns, - const ColumnDefaults & column_defaults, - const Context & context) -{ - ASTPtr default_expr_list{stdext::make_unique().release()}; - - for (const auto & column : required_columns) - { - if (has(column.name)) - continue; - - const auto it = column_defaults.find(column.name); - - /// expressions must be cloned to prevent modification by the ExpressionAnalyzer - if (it == column_defaults.end()) - insertDefault(column.name, column.type); - else - default_expr_list->children.emplace_back( - setAlias(it->second.expression->clone(), it->first)); - } - - /// nothing to evaluate - if (default_expr_list->children.empty()) - 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{*this}; - /// evaluate default values for defaulted columns - ExpressionAnalyzer{default_expr_list, context, required_columns}.getActions(true)->execute(copy_block); - - /// move evaluated columns to the original block - for (auto & column_name_type : copy_block.getColumns()) - insert(std::move(column_name_type)); -} - Block & Block::operator= (const Block & other) { data = other.data; diff --git a/dbms/src/Storages/StorageLog.cpp b/dbms/src/Storages/StorageLog.cpp index 049540736bb..9a1732ef16d 100644 --- a/dbms/src/Storages/StorageLog.cpp +++ b/dbms/src/Storages/StorageLog.cpp @@ -450,6 +450,19 @@ StoragePtr StorageLog::create( })->thisPtr(); } +StoragePtr StorageLog::create( + const std::string & path_, + const std::string & name_, + NamesAndTypesListPtr columns_, + size_t max_compress_block_size_) +{ + return (new StorageLog{ + path_, name_, columns_, + {}, {}, {}, + max_compress_block_size_ + })->thisPtr(); +} + void StorageLog::addFile(const String & column_name, const IDataType & type, size_t level) {