diff --git a/dbms/include/DB/Columns/ColumnNullable.h b/dbms/include/DB/Columns/ColumnNullable.h index b9d0e02dc8b..d96aae80e8f 100644 --- a/dbms/include/DB/Columns/ColumnNullable.h +++ b/dbms/include/DB/Columns/ColumnNullable.h @@ -19,7 +19,6 @@ public: bool isFixed() const override; bool isNullable() const override; ColumnPtr cloneResized(size_t size) const override; - ColumnPtr cloneEmpty() const override; size_t size() const override; bool isNullAt(size_t n) const; Field operator[](size_t n) const override; @@ -35,7 +34,7 @@ public: void popBack(size_t n) override; ColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override; ColumnPtr permute(const Permutation & perm, size_t limit) const override; - int compareAt(size_t n, size_t m, const IColumn & rhs_, int nan_direction_hint) const override; + int compareAt(size_t n, size_t m, const IColumn & rhs_, int null_direction_hint) const override; void getPermutation(bool reverse, size_t limit, Permutation & res) const override; void reserve(size_t n) override; size_t byteSize() const override; diff --git a/dbms/include/DB/Columns/ColumnVector.h b/dbms/include/DB/Columns/ColumnVector.h index 5b91dc4d44c..6b7bd51fcc1 100644 --- a/dbms/include/DB/Columns/ColumnVector.h +++ b/dbms/include/DB/Columns/ColumnVector.h @@ -250,9 +250,23 @@ public: std::string getName() const override { return "ColumnVector<" + TypeName::get() + ">"; } - ColumnPtr cloneEmpty() const override + ColumnPtr cloneResized(size_t size) const override { - return std::make_shared>(); + ColumnPtr new_col_holder = std::make_shared(); + + if (size > 0) + { + auto & new_col = static_cast(*new_col_holder); + new_col.data.resize(size); + + size_t count = std::min(this->size(), size); + memcpy(&new_col.data[0], &data[0], count * sizeof(data[0])); + + if (size > count) + memset(&new_col.data[count], value_type(), size - count); + } + + return new_col_holder; } Field operator[](size_t n) const override @@ -401,14 +415,6 @@ public: } void getExtremes(Field & min, Field & max) const override - { - getExtremesFromNullableContent(min, max, nullptr); - } - - /// The following method implements a slightly more general version of getExtremes(). - /// It takes into account the possible presence of nullable values if a non-null pointer - /// to a null byte map is specified. - void getExtremesFromNullableContent(Field & min, Field & max, const PaddedPODArray * null_map_) const { size_t size = data.size(); @@ -419,54 +425,16 @@ public: return; } - size_t min_i = 0; - if (null_map_ != nullptr) + T cur_min = data[0]; + T cur_max = data[0]; + + for (size_t i = 1; i < size; ++i) { - const auto & null_map_ref = *null_map_; + if (data[i] < cur_min) + cur_min = data[i]; - for (; min_i < size; ++min_i) - { - if (null_map_ref[min_i] == 0) - break; - } - - if (min_i == size) - { - min = Field{}; - max = Field{}; - return; - } - } - - T cur_min = data[min_i]; - T cur_max = data[min_i]; - - if (null_map_ != nullptr) - { - const auto & null_map_ref = *null_map_; - - for (size_t i = min_i + 1; i < size; ++i) - { - if (null_map_ref[i] != 0) - continue; - - if (data[i] < cur_min) - cur_min = data[i]; - - if (data[i] > cur_max) - cur_max = data[i]; - } - } - else - { - for (size_t i = min_i + 1; i < size; ++i) - { - if (data[i] < cur_min) - cur_min = data[i]; - - if (data[i] > cur_max) - cur_max = data[i]; - } + if (data[i] > cur_max) + cur_max = data[i]; } min = typename NearestFieldType::Type(cur_min); diff --git a/dbms/src/Columns/ColumnNullable.cpp b/dbms/src/Columns/ColumnNullable.cpp index dc56f3d2425..a6eca488a2e 100644 --- a/dbms/src/Columns/ColumnNullable.cpp +++ b/dbms/src/Columns/ColumnNullable.cpp @@ -75,8 +75,6 @@ ColumnPtr ColumnNullable::convertToFullColumnIfConst() const } } } - else - new_col_holder = {}; return new_col_holder; } @@ -100,21 +98,7 @@ ColumnPtr ColumnNullable::cloneResized(size_t size) const { ColumnPtr new_col_holder = std::make_shared(nested_column->cloneResized(size)); auto & new_col = static_cast(*new_col_holder); - - /// Create a new null byte map for the cloned column. - /// Resize it if required. - new_col.null_map = null_map->clone(); - if (size != this->size()) - new_col.getNullMapContent().getData().resize_fill(size, 0); - - return new_col_holder; -} - -ColumnPtr ColumnNullable::cloneEmpty() const -{ - ColumnPtr new_col_holder = std::make_shared(nested_column->cloneEmpty()); - auto & new_col = static_cast(*new_col_holder); - new_col.null_map = null_map->cloneEmpty(); + new_col.null_map = getNullMapContent().cloneResized(size); return new_col_holder; } @@ -144,7 +128,7 @@ void ColumnNullable::get(size_t n, Field & res) const UInt64 ColumnNullable::get64(size_t n) const { - throw Exception{"Method get64 is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED}; + return nested_column->get64(n); } StringRef ColumnNullable::getDataAt(size_t n) const @@ -194,20 +178,9 @@ const char * ColumnNullable::deserializeAndInsertFromArena(const char * pos) void ColumnNullable::insertRangeFrom(const IColumn & src, size_t start, size_t length) { - if (length == 0) - return; - - const ColumnNullable & concrete_src = static_cast(src); - - if (start > (std::numeric_limits::max() - length)) - throw Exception{"ColumnNullable: overflow", ErrorCodes::LOGICAL_ERROR}; - - if ((start + length) > concrete_src.size()) - throw Exception{"Parameter out of bound in ColumNullable::insertRangeFrom method.", - ErrorCodes::PARAMETER_OUT_OF_BOUND}; - - getNullMapContent().insertRangeFrom(*concrete_src.null_map, start, length); - nested_column->insertRangeFrom(*concrete_src.nested_column, start, length); + const ColumnNullable & nullable_col = static_cast(src); + getNullMapContent().insertRangeFrom(*nullable_col.null_map, start, length); + nested_column->insertRangeFrom(*nullable_col.nested_column, start, length); } void ColumnNullable::insert(const Field & x) @@ -254,7 +227,7 @@ ColumnPtr ColumnNullable::permute(const Permutation & perm, size_t limit) const return permuted_col_holder; } -int ColumnNullable::compareAt(size_t n, size_t m, const IColumn & rhs_, int nan_direction_hint) const +int ColumnNullable::compareAt(size_t n, size_t m, const IColumn & rhs_, int null_direction_hint) const { const ColumnNullable & nullable_rhs = static_cast(rhs_); @@ -272,7 +245,7 @@ int ColumnNullable::compareAt(size_t n, size_t m, const IColumn & rhs_, int nan_ return 1; const IColumn & nested_rhs = *(nullable_rhs.getNestedColumn()); - return nested_column->compareAt(n, m, nested_rhs, nan_direction_hint); + return nested_column->compareAt(n, m, nested_rhs, null_direction_hint); } void ColumnNullable::getPermutation(bool reverse, size_t limit, Permutation & res) const @@ -351,28 +324,83 @@ size_t ColumnNullable::byteSize() const return nested_column->byteSize() + getNullMapContent().byteSize(); } +namespace +{ + +/// The following function implements a slightly more general version +/// of getExtremes() than the implementation from ColumnVector. +/// It takes into account the possible presence of nullable values. +template +void getExtremesFromNullableContent(const ColumnVector & col, const NullValuesByteMap & null_map, Field & min, Field & max) +{ + const auto & data = col.getData(); + size_t size = data.size(); + + if (size == 0) + { + min = typename NearestFieldType::Type(0); + max = typename NearestFieldType::Type(0); + return; + } + + size_t min_i = 0; + + for (; min_i < size; ++min_i) + { + if (null_map[min_i] == 0) + break; + } + + if (min_i == size) + { + min = Field{}; + max = Field{}; + return; + } + + T cur_min = data[min_i]; + T cur_max = data[min_i]; + + for (size_t i = min_i + 1; i < size; ++i) + { + if (null_map[i] != 0) + continue; + + if (data[i] < cur_min) + cur_min = data[i]; + + if (data[i] > cur_max) + cur_max = data[i]; + } + + min = typename NearestFieldType::Type(cur_min); + max = typename NearestFieldType::Type(cur_max); +} + +} + void ColumnNullable::getExtremes(Field & min, Field & max) const { - if (auto col = typeid_cast(nested_column.get())) - col->getExtremesFromNullableContent(min, max, &getNullMapContent().getData()); - else if (auto col = typeid_cast(nested_column.get())) - col->getExtremesFromNullableContent(min, max, &getNullMapContent().getData()); - else if (auto col = typeid_cast(nested_column.get())) - col->getExtremesFromNullableContent(min, max, &getNullMapContent().getData()); - else if (auto col = typeid_cast(nested_column.get())) - col->getExtremesFromNullableContent(min, max, &getNullMapContent().getData()); - else if (auto col = typeid_cast(nested_column.get())) - col->getExtremesFromNullableContent(min, max, &getNullMapContent().getData()); - else if (auto col = typeid_cast(nested_column.get())) - col->getExtremesFromNullableContent(min, max, &getNullMapContent().getData()); - else if (auto col = typeid_cast(nested_column.get())) - col->getExtremesFromNullableContent(min, max, &getNullMapContent().getData()); - else if (auto col = typeid_cast(nested_column.get())) - col->getExtremesFromNullableContent(min, max, &getNullMapContent().getData()); - else if (auto col = typeid_cast(nested_column.get())) - col->getExtremesFromNullableContent(min, max, &getNullMapContent().getData()); - else if (auto col = typeid_cast(nested_column.get())) - col->getExtremesFromNullableContent(min, max, &getNullMapContent().getData()); + if (const auto col = typeid_cast(nested_column.get())) + getExtremesFromNullableContent(*col, getNullMapContent().getData(), min, max); + else if (const auto col = typeid_cast(nested_column.get())) + getExtremesFromNullableContent(*col, getNullMapContent().getData(), min, max); + else if (const auto col = typeid_cast(nested_column.get())) + getExtremesFromNullableContent(*col, getNullMapContent().getData(), min, max); + else if (const auto col = typeid_cast(nested_column.get())) + getExtremesFromNullableContent(*col, getNullMapContent().getData(), min, max); + else if (const auto col = typeid_cast(nested_column.get())) + getExtremesFromNullableContent(*col, getNullMapContent().getData(), min, max); + else if (const auto col = typeid_cast(nested_column.get())) + getExtremesFromNullableContent(*col, getNullMapContent().getData(), min, max); + else if (const auto col = typeid_cast(nested_column.get())) + getExtremesFromNullableContent(*col, getNullMapContent().getData(), min, max); + else if (const auto col = typeid_cast(nested_column.get())) + getExtremesFromNullableContent(*col, getNullMapContent().getData(), min, max); + else if (const auto col = typeid_cast(nested_column.get())) + getExtremesFromNullableContent(*col, getNullMapContent().getData(), min, max); + else if (const auto col = typeid_cast(nested_column.get())) + getExtremesFromNullableContent(*col, getNullMapContent().getData(), min, max); else nested_column->getExtremes(min, max); }