diff --git a/dbms/include/DB/Columns/ColumnArray.h b/dbms/include/DB/Columns/ColumnArray.h index ae4aa9d8c86..3950488d3a7 100644 --- a/dbms/include/DB/Columns/ColumnArray.h +++ b/dbms/include/DB/Columns/ColumnArray.h @@ -386,6 +386,10 @@ private: 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(); @@ -430,6 +434,10 @@ private: 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 ColumnString & cur_string = typeid_cast(*data); diff --git a/dbms/include/DB/Columns/ColumnConst.h b/dbms/include/DB/Columns/ColumnConst.h index c44300537d6..a0031c7070e 100644 --- a/dbms/include/DB/Columns/ColumnConst.h +++ b/dbms/include/DB/Columns/ColumnConst.h @@ -87,7 +87,8 @@ public: if (s != offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); - return new ColumnConst(offsets.back(), data, data_type); + size_t replicated_size = 0 == s ? 0 : offsets.back(); + return new ColumnConst(replicated_size, data, data_type); } size_t byteSize() const { return sizeof(data) + sizeof(s); } diff --git a/dbms/include/DB/Columns/ColumnFixedString.h b/dbms/include/DB/Columns/ColumnFixedString.h index c9a3ff45d94..c18af6e21da 100644 --- a/dbms/include/DB/Columns/ColumnFixedString.h +++ b/dbms/include/DB/Columns/ColumnFixedString.h @@ -48,12 +48,12 @@ public: { return true; } - + size_t byteSize() const { return chars.size() + sizeof(n); } - + Field operator[](size_t index) const { return String(reinterpret_cast(&chars[n * index]), n); @@ -75,7 +75,7 @@ public: if (s.size() > n) throw Exception("Too large string '" + s + "' for FixedString column", ErrorCodes::TOO_LARGE_STRING_SIZE); - + size_t old_size = chars.size(); chars.resize_fill(old_size + n); memcpy(&chars[old_size], s.data(), s.size()); @@ -222,7 +222,10 @@ public: ColumnFixedString * res_ = new ColumnFixedString(n); ColumnPtr res = res_; - + + if (0 == col_size) + return res; + Chars_t & res_chars = res_->chars; res_chars.reserve(n * offsets.back()); diff --git a/dbms/include/DB/Columns/ColumnString.h b/dbms/include/DB/Columns/ColumnString.h index 1d7253a1479..210444c24cc 100644 --- a/dbms/include/DB/Columns/ColumnString.h +++ b/dbms/include/DB/Columns/ColumnString.h @@ -31,8 +31,8 @@ private: /// Размер, включая завершающий нулевой байт. size_t __attribute__((__always_inline__)) sizeAt(size_t i) const { return i == 0 ? offsets[0] : (offsets[i] - offsets[i - 1]); } - -public: + +public: /** Создать пустой столбец строк */ ColumnString() {} @@ -78,7 +78,7 @@ public: const String & s = DB::get(x); size_t old_size = chars.size(); size_t size_to_append = s.size() + 1; - + chars.resize(old_size + size_to_append); memcpy(&chars[old_size], s.c_str(), size_to_append); offsets.push_back((offsets.size() == 0 ? 0 : offsets.back()) + size_to_append); @@ -90,7 +90,7 @@ public: size_t old_size = chars.size(); size_t size_to_append = src.sizeAt(n); size_t offset = src.offsetAt(n); - + chars.resize(old_size + size_to_append); memcpy(&chars[old_size], &src.chars[offset], size_to_append); offsets.push_back((offsets.size() == 0 ? 0 : offsets.back()) + size_to_append); @@ -132,7 +132,7 @@ public: res_->chars.resize(nested_length); memcpy(&res_->chars[0], &chars[nested_offset], nested_length); - + Offsets_t & res_offsets = res_->offsets; if (start == 0) @@ -173,7 +173,7 @@ public: { if (!filt[i]) continue; - + size_t string_offset = i == 0 ? 0 : offsets[i - 1]; size_t string_size = offsets[i] - string_offset; @@ -248,12 +248,12 @@ public: reinterpret_cast(&chars[offsetAt(n)]), reinterpret_cast(&rhs.chars[rhs.offsetAt(m)])); } - + /// Версия compareAt для locale-sensitive сравнения строк int compareAtWithCollation(size_t n, size_t m, const IColumn & rhs_, const Collator & collator) const { const ColumnString & rhs = static_cast(rhs_); - + return collator.compare( reinterpret_cast(&chars[offsetAt(n)]), sizeAt(n), reinterpret_cast(&rhs.chars[rhs.offsetAt(m)]), rhs.sizeAt(m)); @@ -305,9 +305,9 @@ public: { const ColumnString & parent; const Collator & collator; - + lessWithCollation(const ColumnString & parent_, const Collator & collator_) : parent(parent_), collator(collator_) {} - + bool operator()(size_t lhs, size_t rhs) const { int res = collator.compare( @@ -354,6 +354,9 @@ public: ColumnString * res_ = new ColumnString; ColumnPtr res = res_; + if (0 == col_size) + return res; + Chars_t & res_chars = res_->chars; Offsets_t & res_offsets = res_->offsets; res_chars.reserve(chars.size() / col_size * replicate_offsets.back()); diff --git a/dbms/include/DB/Columns/ColumnVector.h b/dbms/include/DB/Columns/ColumnVector.h index 02d6fd96e89..e6473d4a6a1 100644 --- a/dbms/include/DB/Columns/ColumnVector.h +++ b/dbms/include/DB/Columns/ColumnVector.h @@ -296,6 +296,9 @@ public: if (size != offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); + if (0 == size) + return new Self; + Self * res_ = new Self; ColumnPtr res = res_; typename Self::Container_t & res_data = res_->getData(); diff --git a/dbms/include/DB/Columns/IColumnDummy.h b/dbms/include/DB/Columns/IColumnDummy.h index ffa6a8742c5..1ab49024fc8 100644 --- a/dbms/include/DB/Columns/IColumnDummy.h +++ b/dbms/include/DB/Columns/IColumnDummy.h @@ -6,7 +6,7 @@ namespace DB { - + /** Базовый класс для столбцов-констант, содержащих значение, не входящее в Field. * Не является полноценым столбцом и используется особым образом. */ @@ -14,16 +14,16 @@ class IColumnDummy : public IColumn { public: IColumnDummy(size_t s_) : s(s_) {} - + virtual ColumnPtr cloneDummy(size_t s_) const = 0; - + ColumnPtr cloneResized(size_t s_) const { return cloneDummy(s_); } bool isConst() const { return true; } size_t size() const { return s; } void insertDefault() { ++s; } size_t byteSize() const { return 0; } int compareAt(size_t n, size_t m, const IColumn & rhs_, int nan_direction_hint) const { return 0; } - + Field operator[](size_t n) const { throw Exception("Cannot get value from " + getName(), ErrorCodes::NOT_IMPLEMENTED); } void get(size_t n, Field & res) const { throw Exception("Cannot get value from " + getName(), ErrorCodes::NOT_IMPLEMENTED); }; void insert(const Field & x) { throw Exception("Cannot insert element into " + getName(), ErrorCodes::NOT_IMPLEMENTED); } @@ -39,42 +39,42 @@ public: { return cloneDummy(length); } - + ColumnPtr filter(const Filter & filt) const { size_t new_size = 0; for (Filter::const_iterator it = filt.begin(); it != filt.end(); ++it) if (*it) ++new_size; - + return cloneDummy(new_size); } - + ColumnPtr permute(const Permutation & perm, size_t limit) const { if (s != perm.size()) throw Exception("Size of permutation doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); - + return cloneDummy(limit ? std::min(s, limit) : s); } - + void getPermutation(bool reverse, size_t limit, Permutation & res) const { res.resize(s); for (size_t i = 0; i < s; ++i) res[i] = i; } - + ColumnPtr replicate(const Offsets_t & offsets) const { if (s != offsets.size()) throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH); - - return cloneDummy(offsets.back()); + + return cloneDummy(s == 0 ? 0 : offsets.back()); } - + private: size_t s; }; - + } diff --git a/dbms/include/DB/Functions/FunctionsCoding.h b/dbms/include/DB/Functions/FunctionsCoding.h index 05494c80bab..84056adc3ee 100644 --- a/dbms/include/DB/Functions/FunctionsCoding.h +++ b/dbms/include/DB/Functions/FunctionsCoding.h @@ -375,7 +375,7 @@ public: prev_offset = new_offset; } - if (out_offsets.back() != out_vec.size()) + if (!out_offsets.empty() && out_offsets.back() != out_vec.size()) throw Exception("Column size mismatch (internal logical error)", ErrorCodes::LOGICAL_ERROR); return true; @@ -436,7 +436,7 @@ public: prev_offset = new_offset; } - if (out_offsets.back() != out_vec.size()) + if (!out_offsets.empty() && out_offsets.back() != out_vec.size()) throw Exception("Column size mismatch (internal logical error)", ErrorCodes::LOGICAL_ERROR); return true; @@ -742,7 +742,7 @@ public: } out_vec.resize(pos - begin); - if (out_offsets.back() != out_vec.size()) + if (!out_offsets.empty() && out_offsets.back() != out_vec.size()) throw Exception("Column size mismatch (internal logical error)", ErrorCodes::LOGICAL_ERROR); return true; @@ -797,7 +797,7 @@ public: } out_vec.resize(pos - begin); - if (out_offsets.back() != out_vec.size()) + if (!out_offsets.empty() && out_offsets.back() != out_vec.size()) throw Exception("Column size mismatch (internal logical error)", ErrorCodes::LOGICAL_ERROR); return true; diff --git a/dbms/tests/queries/0_stateless/00067_replicate_segfault.reference b/dbms/tests/queries/0_stateless/00067_replicate_segfault.reference new file mode 100644 index 00000000000..c8711199d90 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00067_replicate_segfault.reference @@ -0,0 +1,2 @@ +[] 1 +[] 1 diff --git a/dbms/tests/queries/0_stateless/00067_replicate_segfault.sql b/dbms/tests/queries/0_stateless/00067_replicate_segfault.sql new file mode 100644 index 00000000000..bf1a756d887 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00067_replicate_segfault.sql @@ -0,0 +1,2 @@ +SELECT arrayFilter(x -> materialize(0), materialize([0])) AS p, arrayAll(y -> arrayExists(x -> y != x, p), p) AS test; +SELECT arrayFilter(x -> materialize(0), materialize([''])) AS p, arrayAll(y -> arrayExists(x -> y != x, p), p) AS test;