diff --git a/dbms/include/DB/Columns/ColumnArray.h b/dbms/include/DB/Columns/ColumnArray.h index 42fae9fbc3c..170dafce004 100644 --- a/dbms/include/DB/Columns/ColumnArray.h +++ b/dbms/include/DB/Columns/ColumnArray.h @@ -119,38 +119,7 @@ public: getOffsets().push_back((getOffsets().size() == 0 ? 0 : getOffsets().back()) + elems); } - ColumnPtr cut(size_t start, size_t length) const override - { - if (length == 0) - return new ColumnArray(data); - - if (start + length > getOffsets().size()) - throw Exception("Parameter out of bound in IColumnArray::cut() method.", - ErrorCodes::PARAMETER_OUT_OF_BOUND); - - size_t nested_offset = offsetAt(start); - size_t nested_length = getOffsets()[start + length - 1] - nested_offset; - - ColumnArray * res_ = new ColumnArray(data); - ColumnPtr res = res_; - - res_->data = data->cut(nested_offset, nested_length); - Offsets_t & res_offsets = res_->getOffsets(); - - if (start == 0) - { - res_offsets.assign(getOffsets().begin(), getOffsets().begin() + length); - } - else - { - res_offsets.resize(length); - - for (size_t i = 0; i < length; ++i) - res_offsets[i] = getOffsets()[start + i] - nested_offset; - } - - return res; - } + ColumnPtr cut(size_t start, size_t length) const override; void insert(const Field & x) override { @@ -178,82 +147,9 @@ public: getOffsets().push_back(getOffsets().size() == 0 ? 0 : getOffsets().back()); } - ColumnPtr filter(const Filter & filt) const override - { - size_t size = getOffsets().size(); - if (size != filt.size()) - throw Exception("Size of filter doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); + ColumnPtr filter(const Filter & filt) const override; - if (size == 0) - return new ColumnArray(data); - - /// Не слишком оптимально. Можно сделать специализацию для массивов известных типов. - Filter nested_filt(getOffsets().back()); - for (size_t i = 0; i < size; ++i) - { - if (filt[i]) - memset(&nested_filt[offsetAt(i)], 1, sizeAt(i)); - else - memset(&nested_filt[offsetAt(i)], 0, sizeAt(i)); - } - - ColumnArray * res_ = new ColumnArray(data); - ColumnPtr res = res_; - res_->data = data->filter(nested_filt); - - Offsets_t & res_offsets = res_->getOffsets(); - res_offsets.reserve(size); - - size_t current_offset = 0; - for (size_t i = 0; i < size; ++i) - { - if (filt[i]) - { - current_offset += sizeAt(i); - res_offsets.push_back(current_offset); - } - } - - return res; - } - - ColumnPtr permute(const Permutation & perm, size_t limit) const override - { - size_t size = getOffsets().size(); - - if (limit == 0) - limit = size; - else - limit = std::min(size, limit); - - if (perm.size() < limit) - throw Exception("Size of permutation is less than required.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); - - if (limit == 0) - return new ColumnArray(data); - - Permutation nested_perm(getOffsets().back()); - - ColumnArray * res_ = new ColumnArray(data->cloneEmpty()); - ColumnPtr res = res_; - - Offsets_t & res_offsets = res_->getOffsets(); - res_offsets.resize(limit); - size_t current_offset = 0; - - for (size_t i = 0; i < limit; ++i) - { - for (size_t j = 0; j < sizeAt(perm[i]); ++j) - nested_perm[current_offset + j] = offsetAt(perm[i]) + j; - current_offset += sizeAt(perm[i]); - res_offsets[i] = current_offset; - } - - if (current_offset != 0) - res_->data = data->permute(nested_perm, current_offset); - - return res; - } + 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 { @@ -290,31 +186,7 @@ public: } }; - void getPermutation(bool reverse, size_t limit, Permutation & res) const override - { - size_t s = size(); - if (limit >= s) - limit = 0; - - res.resize(s); - for (size_t i = 0; i < s; ++i) - res[i] = i; - - if (limit) - { - if (reverse) - std::partial_sort(res.begin(), res.begin() + limit, res.end(), less(*this)); - else - std::partial_sort(res.begin(), res.begin() + limit, res.end(), less(*this)); - } - else - { - if (reverse) - std::sort(res.begin(), res.end(), less(*this)); - else - std::sort(res.begin(), res.end(), less(*this)); - } - } + void getPermutation(bool reverse, size_t limit, Permutation & res) const override; void reserve(size_t n) override { @@ -364,24 +236,7 @@ public: const ColumnPtr & getOffsetsColumn() const { return offsets; } - ColumnPtr replicate(const Offsets_t & replicate_offsets) const override - { - /// Не получается реализовать в общем случае. - - if (typeid_cast(&*data)) return replicate(replicate_offsets); - if (typeid_cast(&*data)) return replicate(replicate_offsets); - if (typeid_cast(&*data)) return replicate(replicate_offsets); - if (typeid_cast(&*data)) return replicate(replicate_offsets); - if (typeid_cast(&*data)) return replicate(replicate_offsets); - if (typeid_cast(&*data)) return replicate(replicate_offsets); - if (typeid_cast(&*data)) return replicate(replicate_offsets); - if (typeid_cast(&*data)) return replicate(replicate_offsets); - if (typeid_cast(&*data)) return replicate(replicate_offsets); - if (typeid_cast(&*data)) return replicate(replicate_offsets); - if (typeid_cast(&*data)) return replicateString(replicate_offsets); - - throw Exception("Replication of column " + getName() + " is not implemented.", ErrorCodes::NOT_IMPLEMENTED); - } + ColumnPtr replicate(const Offsets_t & replicate_offsets) const override; private: ColumnPtr data; @@ -393,129 +248,17 @@ private: /// Размножить значения, если вложенный столбец - ColumnArray. template - ColumnPtr replicate(const Offsets_t & replicate_offsets) const - { - size_t col_size = size(); - if (col_size != replicate_offsets.size()) - throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); - - ColumnPtr res = cloneEmpty(); - - if (0 == col_size) - return res; - - ColumnArray & res_ = typeid_cast(*res); - - const typename ColumnVector::Container_t & cur_data = typeid_cast &>(*data).getData(); - const Offsets_t & cur_offsets = getOffsets(); - - typename ColumnVector::Container_t & res_data = typeid_cast &>(res_.getData()).getData(); - Offsets_t & res_offsets = res_.getOffsets(); - - res_data.reserve(data->size() / col_size * replicate_offsets.back()); - res_offsets.reserve(replicate_offsets.back()); - - Offset_t prev_replicate_offset = 0; - Offset_t prev_data_offset = 0; - Offset_t current_new_offset = 0; - - for (size_t i = 0; i < col_size; ++i) - { - size_t size_to_replicate = replicate_offsets[i] - prev_replicate_offset; - size_t value_size = cur_offsets[i] - prev_data_offset; - - for (size_t j = 0; j < size_to_replicate; ++j) - { - current_new_offset += value_size; - res_offsets.push_back(current_new_offset); - - res_data.resize(res_data.size() + value_size); - memcpy(&res_data[res_data.size() - value_size], &cur_data[prev_data_offset], value_size * sizeof(T)); - } - - prev_replicate_offset = replicate_offsets[i]; - prev_data_offset = cur_offsets[i]; - } - - return res; - } + ColumnPtr replicate(const Offsets_t & replicate_offsets) const; /// Размножить значения, если вложенный столбец - ColumnString. Код слишком сложный. - ColumnPtr replicateString(const Offsets_t & replicate_offsets) const - { - size_t col_size = size(); - if (col_size != replicate_offsets.size()) - throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); + ColumnPtr replicateString(const Offsets_t & replicate_offsets) const; - ColumnPtr res = cloneEmpty(); - - if (0 == col_size) - return res; - - ColumnArray & res_ = typeid_cast(*res); - - const ColumnString & cur_string = typeid_cast(*data); - const ColumnString::Chars_t & cur_chars = cur_string.getChars(); - const Offsets_t & cur_string_offsets = cur_string.getOffsets(); - const Offsets_t & cur_offsets = getOffsets(); - - ColumnString::Chars_t & res_chars = typeid_cast(res_.getData()).getChars(); - Offsets_t & res_string_offsets = typeid_cast(res_.getData()).getOffsets(); - Offsets_t & res_offsets = res_.getOffsets(); - - res_chars.reserve(cur_chars.size() / col_size * replicate_offsets.back()); - res_string_offsets.reserve(cur_string_offsets.size() / col_size * replicate_offsets.back()); - res_offsets.reserve(replicate_offsets.back()); - - Offset_t prev_replicate_offset = 0; - - Offset_t prev_cur_offset = 0; - Offset_t prev_cur_string_offset = 0; - - Offset_t current_res_offset = 0; - Offset_t current_res_string_offset = 0; - - for (size_t i = 0; i < col_size; ++i) - { - /// Насколько размножить массив. - size_t size_to_replicate = replicate_offsets[i] - prev_replicate_offset; - /// Количество строк в массиве. - size_t value_size = cur_offsets[i] - prev_cur_offset; - - size_t sum_chars_size = 0; - - for (size_t j = 0; j < size_to_replicate; ++j) - { - current_res_offset += value_size; - res_offsets.push_back(current_res_offset); - - sum_chars_size = 0; - - size_t prev_cur_string_offset_local = prev_cur_string_offset; - for (size_t k = 0; k < value_size; ++k) - { - /// Размер одной строки. - size_t chars_size = cur_string_offsets[k + prev_cur_offset] - prev_cur_string_offset_local; - - current_res_string_offset += chars_size; - res_string_offsets.push_back(current_res_string_offset); - - /// Копирование символов одной строки. - res_chars.resize(res_chars.size() + chars_size); - memcpy(&res_chars[res_chars.size() - chars_size], &cur_chars[prev_cur_string_offset_local], chars_size); - - sum_chars_size += chars_size; - prev_cur_string_offset_local += chars_size; - } - } - - prev_replicate_offset = replicate_offsets[i]; - prev_cur_offset = cur_offsets[i]; - prev_cur_string_offset += sum_chars_size; - } - - return res; - } + /** Неконстантные массивы константных значений - довольно редкое явление. + * Большинство функций не умеет с ними работать, и не создаёт такие столбцы в качестве результата. + * Исключение - функция replicate (см. FunctionsMiscellaneous.h), которая имеет служебное значение для реализации лямбда-функций. + * Только ради неё сделана реализация метода replicate для ColumnArray(ColumnConst). + */ + ColumnPtr replicateConst(const Offsets_t & replicate_offsets) const; }; diff --git a/dbms/include/DB/Functions/FunctionsArithmetic.h b/dbms/include/DB/Functions/FunctionsArithmetic.h index b00b31a1158..d468b260e63 100644 --- a/dbms/include/DB/Functions/FunctionsArithmetic.h +++ b/dbms/include/DB/Functions/FunctionsArithmetic.h @@ -262,6 +262,32 @@ struct BitShiftRightImpl } }; + +template +struct LeastImpl +{ + typedef typename NumberTraits::ResultOfIf::Type ResultType; + + template + static inline Result apply(A a, B b) + { + /** gcc 4.9.2 успешно векторизует цикл из этой функции. */ + return static_cast(a) < static_cast(b) ? static_cast(a) : static_cast(b); + } +}; + +template +struct GreatestImpl +{ + typedef typename NumberTraits::ResultOfIf::Type ResultType; + + template + static inline Result apply(A a, B b) + { + return static_cast(a) > static_cast(b) ? static_cast(a) : static_cast(b); + } +}; + template struct NegateImpl { @@ -319,6 +345,12 @@ template using Else = T; /// Used to indicate undefined operation struct InvalidType; +template <> +struct DataTypeFromFieldType +{ + using Type = InvalidType; +}; + template struct IsIntegral { static constexpr auto value = false; }; template <> struct IsIntegral { static constexpr auto value = true; }; template <> struct IsIntegral { static constexpr auto value = true; }; @@ -342,11 +374,13 @@ template struct IsDateOrDateTime { static constexpr auto val template <> struct IsDateOrDateTime { static constexpr auto value = true; }; template <> struct IsDateOrDateTime { static constexpr auto value = true; }; -/** Returns appropriate result type for binary operator on dates: +/** Returns appropriate result type for binary operator on dates (or datetimes): * Date + Integral -> Date * Integral + Date -> Date * Date - Date -> Int32 * Date - Integral -> Date + * least(Date, Date) -> Date + * greatest(Date, Date) -> Date * All other operations are not defined and return InvalidType, operations on * distinct date types are also undefined (e.g. DataTypeDate - DataTypeDateTime) */ template