mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 07:31:57 +00:00
Merge branch 'master' into ks1322-master
This commit is contained in:
commit
1a6f38b27f
2
contrib/poco
vendored
2
contrib/poco
vendored
@ -1 +1 @@
|
||||
Subproject commit bcf9ebad48b2162d25f5fc432b176d74a09f498d
|
||||
Subproject commit 81d4fdfcb887f89b0f7b1e9b503cbe63e6d8366b
|
@ -54,7 +54,8 @@ done
|
||||
# Копируем больше заголовочных файлов с интринсиками, так как на серверах, куда будут устанавливаться
|
||||
# заголовочные файлы, будет использоваться опция -march=native.
|
||||
|
||||
for i in $(ls -1 $($CLANG -v -xc++ - <<<'' 2>&1 | grep '^ /' | grep 'include' | grep '/lib/clang/')/*.h | grep -vE 'arm|altivec|Intrin');
|
||||
for i in $(ls -1 $($CLANG -v -xc++ - <<<'' 2>&1 | grep '^ /' | grep 'include' | grep -E '/lib/clang/|/include/clang/')/*.h | grep -vE 'arm|altivec|Intrin');
|
||||
do
|
||||
mkdir -p "$DST/$(echo $i | sed -r -e 's/\/[^/]*$/\//')";
|
||||
cp "$i" "$DST/$i";
|
||||
done
|
||||
|
@ -10,6 +10,11 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
|
||||
}
|
||||
|
||||
|
||||
/** Not an aggregate function, but an adapter of aggregate functions,
|
||||
* which any aggregate function `agg(x)` makes an aggregate function of the form `aggArray(x)`.
|
||||
@ -92,11 +97,21 @@ public:
|
||||
nested[i] = &static_cast<const ColumnArray &>(*columns[i]).getData();
|
||||
|
||||
const ColumnArray & first_array_column = static_cast<const ColumnArray &>(*columns[0]);
|
||||
const IColumn::Offsets_t & offsets = first_array_column.getOffsets();
|
||||
const IColumn::Offsets & offsets = first_array_column.getOffsets();
|
||||
|
||||
size_t begin = row_num == 0 ? 0 : offsets[row_num - 1];
|
||||
size_t end = offsets[row_num];
|
||||
|
||||
/// Sanity check. NOTE We can implement specialization for a case with single argument, if the check will hurt performance.
|
||||
for (size_t i = 1; i < num_agruments; ++i)
|
||||
{
|
||||
const ColumnArray & ith_column = static_cast<const ColumnArray &>(*columns[i]);
|
||||
const IColumn::Offsets & ith_offsets = ith_column.getOffsets();
|
||||
|
||||
if (ith_offsets[row_num] != end || (row_num != 0 && ith_offsets[row_num - 1] != begin))
|
||||
throw Exception("Arrays passed to " + getName() + " aggregate function have different sizes", ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH);
|
||||
}
|
||||
|
||||
for (size_t i = begin; i < end; ++i)
|
||||
nested_func->add(place, nested, i, arena);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace DB
|
||||
class Context;
|
||||
class IDataType;
|
||||
|
||||
using DataTypePtr = std::shared_ptr<IDataType>;
|
||||
using DataTypePtr = std::shared_ptr<const IDataType>;
|
||||
using DataTypes = std::vector<DataTypePtr>;
|
||||
|
||||
|
||||
|
@ -152,7 +152,7 @@ public:
|
||||
void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena * arena) const override
|
||||
{
|
||||
const ColumnArray & first_array_column = static_cast<const ColumnArray &>(*columns[0]);
|
||||
const IColumn::Offsets_t & offsets = first_array_column.getOffsets();
|
||||
const IColumn::Offsets & offsets = first_array_column.getOffsets();
|
||||
const IColumn * array_data = &first_array_column.getData();
|
||||
size_t begin = row_num == 0 ? 0 : offsets[row_num - 1];
|
||||
size_t end = offsets[row_num];
|
||||
@ -221,7 +221,7 @@ public:
|
||||
const AggregateFunctionForEachData & state = data(place);
|
||||
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
IColumn & elems_to = arr_to.getData();
|
||||
|
||||
const char * nested_state = state.array_of_aggregate_datas;
|
||||
|
@ -125,11 +125,11 @@ public:
|
||||
size_t size = value.size();
|
||||
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + size);
|
||||
|
||||
typename ColumnVector<T>::Container_t & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
typename ColumnVector<T>::Container & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
data_to.insert(this->data(place).value.begin(), this->data(place).value.end());
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ public:
|
||||
|
||||
void setArgumentsImpl(const DataTypes & arguments)
|
||||
{
|
||||
if (!arguments.at(1)->canBeUsedAsNonNegativeArrayIndex())
|
||||
if (!arguments.at(1)->isUnsignedInteger())
|
||||
throw Exception("Second argument of aggregate function " + getName() + " must be integer.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
|
||||
type = arguments.front();
|
||||
@ -184,7 +184,7 @@ public:
|
||||
{
|
||||
ColumnArray & to_array = static_cast<ColumnArray &>(to);
|
||||
IColumn & to_data = to_array.getData();
|
||||
ColumnArray::Offsets_t & to_offsets = to_array.getOffsets();
|
||||
ColumnArray::Offsets & to_offsets = to_array.getOffsets();
|
||||
|
||||
const Array & arr = data(place).value;
|
||||
|
||||
|
@ -83,14 +83,14 @@ public:
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
const typename State::Set & set = this->data(place).value;
|
||||
size_t size = set.size();
|
||||
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + size);
|
||||
|
||||
typename ColumnVector<T>::Container_t & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
typename ColumnVector<T>::Container & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
size_t old_size = data_to.size();
|
||||
data_to.resize(old_size + size);
|
||||
|
||||
@ -138,7 +138,7 @@ public:
|
||||
|
||||
DataTypePtr getReturnType() const override
|
||||
{
|
||||
return std::make_shared<DataTypeArray>(input_data_type->clone());
|
||||
return std::make_shared<DataTypeArray>(input_data_type);
|
||||
}
|
||||
|
||||
bool allocatesMemoryInArena() const override
|
||||
@ -210,7 +210,7 @@ public:
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
IColumn & data_to = arr_to.getData();
|
||||
|
||||
auto & set = this->data(place).value;
|
||||
|
@ -151,8 +151,8 @@ public:
|
||||
ColumnNullable & to_concrete = static_cast<ColumnNullable &>(to);
|
||||
if (getFlag(place))
|
||||
{
|
||||
nested_function->insertResultInto(nestedPlace(place), *to_concrete.getNestedColumn());
|
||||
to_concrete.getNullMap().push_back(0);
|
||||
nested_function->insertResultInto(nestedPlace(place), to_concrete.getNestedColumn());
|
||||
to_concrete.getNullMapData().push_back(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -205,7 +205,7 @@ public:
|
||||
if (!column->isNullAt(row_num))
|
||||
{
|
||||
this->setFlag(place);
|
||||
const IColumn * nested_column = column->getNestedColumn().get();
|
||||
const IColumn * nested_column = &column->getNestedColumn();
|
||||
this->nested_function->add(this->nestedPlace(place), &nested_column, row_num, arena);
|
||||
}
|
||||
}
|
||||
@ -268,7 +268,7 @@ public:
|
||||
/// we don't process this row.
|
||||
return;
|
||||
}
|
||||
nested_columns[i] = nullable_col.getNestedColumn().get();
|
||||
nested_columns[i] = &nullable_col.getNestedColumn();
|
||||
}
|
||||
else
|
||||
nested_columns[i] = columns[i];
|
||||
|
@ -174,21 +174,21 @@ public:
|
||||
Sample & sample = const_cast<Sample &>(this->data(place).sample);
|
||||
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
size_t size = levels.size();
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + size);
|
||||
|
||||
if (returns_float)
|
||||
{
|
||||
ColumnFloat64::Container_t & data_to = static_cast<ColumnFloat64 &>(arr_to.getData()).getData();
|
||||
ColumnFloat64::Container & data_to = static_cast<ColumnFloat64 &>(arr_to.getData()).getData();
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
data_to.push_back(sample.quantileInterpolated(levels[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
typename ColumnVector<ArgumentFieldType>::Container_t & data_to = static_cast<ColumnVector<ArgumentFieldType> &>(arr_to.getData()).getData();
|
||||
typename ColumnVector<ArgumentFieldType>::Container & data_to = static_cast<ColumnVector<ArgumentFieldType> &>(arr_to.getData()).getData();
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
data_to.push_back(sample.quantileInterpolated(levels[i]));
|
||||
|
@ -186,21 +186,21 @@ public:
|
||||
Sample & sample = const_cast<Sample &>(this->data(place).sample);
|
||||
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
size_t size = levels.size();
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + size);
|
||||
|
||||
if (returns_float)
|
||||
{
|
||||
ColumnFloat64::Container_t & data_to = static_cast<ColumnFloat64 &>(arr_to.getData()).getData();
|
||||
ColumnFloat64::Container & data_to = static_cast<ColumnFloat64 &>(arr_to.getData()).getData();
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
data_to.push_back(sample.quantileInterpolated(levels[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
typename ColumnVector<ArgumentFieldType>::Container_t & data_to = static_cast<ColumnVector<ArgumentFieldType> &>(arr_to.getData()).getData();
|
||||
typename ColumnVector<ArgumentFieldType>::Container & data_to = static_cast<ColumnVector<ArgumentFieldType> &>(arr_to.getData()).getData();
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
data_to.push_back(sample.quantileInterpolated(levels[i]));
|
||||
|
@ -187,12 +187,12 @@ public:
|
||||
auto & array = const_cast<typename AggregateFunctionQuantileExactData<T>::Array &>(this->data(place).array);
|
||||
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
size_t num_levels = levels.size();
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + num_levels);
|
||||
|
||||
typename ColumnVector<T>::Container_t & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
typename ColumnVector<T>::Container & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
size_t old_size = data_to.size();
|
||||
data_to.resize(old_size + num_levels);
|
||||
|
||||
|
@ -230,7 +230,7 @@ public:
|
||||
size_t size = map.size();
|
||||
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
size_t num_levels = levels.size();
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + num_levels);
|
||||
@ -238,7 +238,7 @@ public:
|
||||
if (!num_levels)
|
||||
return;
|
||||
|
||||
typename ColumnVector<ValueType>::Container_t & data_to = static_cast<ColumnVector<ValueType> &>(arr_to.getData()).getData();
|
||||
typename ColumnVector<ValueType>::Container & data_to = static_cast<ColumnVector<ValueType> &>(arr_to.getData()).getData();
|
||||
|
||||
size_t old_size = data_to.size();
|
||||
data_to.resize(old_size + num_levels);
|
||||
|
@ -540,7 +540,7 @@ public:
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
size_t size = levels.size();
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + size);
|
||||
@ -550,7 +550,7 @@ public:
|
||||
|
||||
if (returns_float)
|
||||
{
|
||||
typename ColumnFloat32::Container_t & data_to = static_cast<ColumnFloat32 &>(arr_to.getData()).getData();
|
||||
typename ColumnFloat32::Container & data_to = static_cast<ColumnFloat32 &>(arr_to.getData()).getData();
|
||||
size_t old_size = data_to.size();
|
||||
data_to.resize(data_to.size() + size);
|
||||
|
||||
@ -559,7 +559,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
typename ColumnVector<T>::Container_t & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
typename ColumnVector<T>::Container & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
size_t old_size = data_to.size();
|
||||
data_to.resize(data_to.size() + size);
|
||||
|
||||
@ -627,7 +627,7 @@ public:
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
size_t size = levels.size();
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + size);
|
||||
@ -637,7 +637,7 @@ public:
|
||||
|
||||
if (returns_float)
|
||||
{
|
||||
typename ColumnFloat32::Container_t & data_to = static_cast<ColumnFloat32 &>(arr_to.getData()).getData();
|
||||
typename ColumnFloat32::Container & data_to = static_cast<ColumnFloat32 &>(arr_to.getData()).getData();
|
||||
size_t old_size = data_to.size();
|
||||
data_to.resize(data_to.size() + size);
|
||||
|
||||
@ -646,7 +646,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
typename ColumnVector<T>::Container_t & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
typename ColumnVector<T>::Container & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
size_t old_size = data_to.size();
|
||||
data_to.resize(data_to.size() + size);
|
||||
|
||||
|
@ -961,7 +961,7 @@ public:
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
size_t size = levels.size();
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + size);
|
||||
@ -969,7 +969,7 @@ public:
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
typename ColumnFloat32::Container_t & data_to = static_cast<ColumnFloat32 &>(arr_to.getData()).getData();
|
||||
typename ColumnFloat32::Container & data_to = static_cast<ColumnFloat32 &>(arr_to.getData()).getData();
|
||||
size_t old_size = data_to.size();
|
||||
data_to.resize(data_to.size() + size);
|
||||
|
||||
@ -1029,7 +1029,7 @@ public:
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
size_t size = levels.size();
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + size);
|
||||
@ -1037,7 +1037,7 @@ public:
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
typename ColumnFloat32::Container_t & data_to = static_cast<ColumnFloat32 &>(arr_to.getData()).getData();
|
||||
typename ColumnFloat32::Container & data_to = static_cast<ColumnFloat32 &>(arr_to.getData()).getData();
|
||||
size_t old_size = data_to.size();
|
||||
data_to.resize(data_to.size() + size);
|
||||
|
||||
|
@ -102,7 +102,7 @@ public:
|
||||
{
|
||||
// Column 0 contains array of keys of known type
|
||||
const ColumnArray & array_column = static_cast<const ColumnArray &>(*columns[0]);
|
||||
const IColumn::Offsets_t & offsets = array_column.getOffsets();
|
||||
const IColumn::Offsets & offsets = array_column.getOffsets();
|
||||
const auto & keys_vec = static_cast<const ColumnVector<T> &>(array_column.getData());
|
||||
const size_t keys_vec_offset = row_num == 0 ? 0 : offsets[row_num - 1];
|
||||
const size_t keys_vec_size = (offsets[row_num] - keys_vec_offset);
|
||||
@ -113,7 +113,7 @@ public:
|
||||
{
|
||||
Field value;
|
||||
const ColumnArray & array_column = static_cast<const ColumnArray &>(*columns[col + 1]);
|
||||
const IColumn::Offsets_t & offsets = array_column.getOffsets();
|
||||
const IColumn::Offsets & offsets = array_column.getOffsets();
|
||||
const size_t values_vec_offset = row_num == 0 ? 0 : offsets[row_num - 1];
|
||||
const size_t values_vec_size = (offsets[row_num] - values_vec_offset);
|
||||
|
||||
@ -221,8 +221,8 @@ public:
|
||||
|
||||
size_t size = merged_maps.size();
|
||||
|
||||
auto & to_cols = static_cast<ColumnTuple &>(to).getColumns();
|
||||
auto & to_keys_arr = static_cast<ColumnArray &>(*to_cols[0]);
|
||||
auto & to_tuple = static_cast<ColumnTuple &>(to);
|
||||
auto & to_keys_arr = static_cast<ColumnArray &>(to_tuple.getColumn(0));
|
||||
auto & to_keys_col = to_keys_arr.getData();
|
||||
|
||||
// Advance column offsets
|
||||
@ -232,7 +232,7 @@ public:
|
||||
|
||||
for (size_t col = 0; col < values_types.size(); ++col)
|
||||
{
|
||||
auto & to_values_arr = static_cast<ColumnArray &>(*to_cols[col + 1]);
|
||||
auto & to_values_arr = static_cast<ColumnArray &>(to_tuple.getColumn(col + 1));
|
||||
auto & to_values_offsets = to_values_arr.getOffsets();
|
||||
to_values_offsets.push_back((to_values_offsets.empty() ? 0 : to_values_offsets.back()) + size);
|
||||
to_values_arr.getData().reserve(size);
|
||||
@ -247,7 +247,7 @@ public:
|
||||
// Write 0..n arrays of values
|
||||
for (size_t col = 0; col < values_types.size(); ++col)
|
||||
{
|
||||
auto & to_values_col = static_cast<ColumnArray &>(*to_cols[col + 1]).getData();
|
||||
auto & to_values_col = static_cast<ColumnArray &>(to_tuple.getColumn(col + 1)).getData();
|
||||
to_values_col.insert(elem.second[col]);
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ public:
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
|
||||
const typename State::Set & set = this->data(place).value;
|
||||
auto result_vec = set.topK(threshold);
|
||||
@ -116,7 +116,7 @@ public:
|
||||
|
||||
offsets_to.push_back((offsets_to.size() == 0 ? 0 : offsets_to.back()) + size);
|
||||
|
||||
typename ColumnVector<T>::Container_t & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
typename ColumnVector<T>::Container & data_to = static_cast<ColumnVector<T> &>(arr_to.getData()).getData();
|
||||
size_t old_size = data_to.size();
|
||||
data_to.resize(old_size + size);
|
||||
|
||||
@ -182,7 +182,7 @@ public:
|
||||
|
||||
DataTypePtr getReturnType() const override
|
||||
{
|
||||
return std::make_shared<DataTypeArray>(input_data_type->clone());
|
||||
return std::make_shared<DataTypeArray>(input_data_type);
|
||||
}
|
||||
|
||||
bool allocatesMemoryInArena() const override
|
||||
@ -217,7 +217,7 @@ public:
|
||||
set.readAlphaMap(buf);
|
||||
}
|
||||
|
||||
void addImpl(AggregateDataPtr place, const IColumn & column, size_t row_num, Arena *) const
|
||||
void addImpl(AggregateDataPtr place, const IColumn & column, size_t row_num, Arena * arena) const
|
||||
{
|
||||
auto & set = this->data(place).value;
|
||||
if (set.capacity() != reserved)
|
||||
@ -225,8 +225,10 @@ public:
|
||||
set.resize(reserved);
|
||||
}
|
||||
|
||||
StringRef str_serialized = column.getDataAt(row_num);
|
||||
const char * begin = nullptr;
|
||||
StringRef str_serialized = column.serializeValueIntoArena(row_num, *arena, begin);
|
||||
set.insert(str_serialized);
|
||||
arena->rollback(str_serialized.size);
|
||||
}
|
||||
|
||||
void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena *) const override
|
||||
@ -237,7 +239,7 @@ public:
|
||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||
{
|
||||
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
||||
ColumnArray::Offsets_t & offsets_to = arr_to.getOffsets();
|
||||
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
||||
IColumn & data_to = arr_to.getData();
|
||||
|
||||
auto result_vec = this->data(place).value.topK(threshold);
|
||||
|
@ -19,7 +19,7 @@ class WriteBuffer;
|
||||
class IColumn;
|
||||
class IDataType;
|
||||
|
||||
using DataTypePtr = std::shared_ptr<IDataType>;
|
||||
using DataTypePtr = std::shared_ptr<const IDataType>;
|
||||
using DataTypes = std::vector<DataTypePtr>;
|
||||
|
||||
using AggregateDataPtr = char *;
|
||||
|
@ -26,10 +26,9 @@ void ColumnAggregateFunction::addArena(ArenaPtr arena_)
|
||||
arenas.push_back(arena_);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnAggregateFunction::convertToValues() const
|
||||
MutableColumnPtr ColumnAggregateFunction::convertToValues() const
|
||||
{
|
||||
const IAggregateFunction * function = func.get();
|
||||
ColumnPtr res = function->getReturnType()->createColumn();
|
||||
|
||||
/** If the aggregate function returns an unfinalized/unfinished state,
|
||||
* then you just need to copy pointers to it and also shared ownership of data.
|
||||
@ -63,17 +62,18 @@ ColumnPtr ColumnAggregateFunction::convertToValues() const
|
||||
*/
|
||||
if (const AggregateFunctionState * function_state = typeid_cast<const AggregateFunctionState *>(function))
|
||||
{
|
||||
std::shared_ptr<ColumnAggregateFunction> res = std::make_shared<ColumnAggregateFunction>(*this);
|
||||
auto res = createView();
|
||||
res->set(function_state->getNestedFunction());
|
||||
res->getData().assign(getData().begin(), getData().end());
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
IColumn & column = *res;
|
||||
|
||||
MutableColumnPtr res = function->getReturnType()->createColumn();
|
||||
res->reserve(getData().size());
|
||||
|
||||
for (auto val : getData())
|
||||
function->insertResultInto(val, column);
|
||||
function->insertResultInto(val, *res);
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -104,7 +104,7 @@ void ColumnAggregateFunction::insertRangeFrom(const IColumn & from, size_t start
|
||||
else
|
||||
{
|
||||
/// Keep shared ownership of aggregation states.
|
||||
src = from_concrete.shared_from_this();
|
||||
src = from_concrete.getPtr();
|
||||
|
||||
auto & data = getData();
|
||||
size_t old_size = data.size();
|
||||
@ -114,17 +114,16 @@ void ColumnAggregateFunction::insertRangeFrom(const IColumn & from, size_t start
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnAggregateFunction::filter(const Filter & filter, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnAggregateFunction::filter(const Filter & filter, ssize_t result_size_hint) const
|
||||
{
|
||||
size_t size = getData().size();
|
||||
if (size != filter.size())
|
||||
throw Exception("Size of filter doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
std::shared_ptr<ColumnAggregateFunction> res = std::make_shared<ColumnAggregateFunction>(*this);
|
||||
|
||||
if (size == 0)
|
||||
return res;
|
||||
return cloneEmpty();
|
||||
|
||||
auto res = createView();
|
||||
auto & res_data = res->getData();
|
||||
|
||||
if (result_size_hint)
|
||||
@ -136,13 +135,13 @@ ColumnPtr ColumnAggregateFunction::filter(const Filter & filter, ssize_t result_
|
||||
|
||||
/// To save RAM in case of too strong filtering.
|
||||
if (res_data.size() * 2 < res_data.capacity())
|
||||
res_data = Container_t(res_data.cbegin(), res_data.cend());
|
||||
res_data = Container(res_data.cbegin(), res_data.cend());
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnAggregateFunction::permute(const Permutation & perm, size_t limit) const
|
||||
MutableColumnPtr ColumnAggregateFunction::permute(const Permutation & perm, size_t limit) const
|
||||
{
|
||||
size_t size = getData().size();
|
||||
|
||||
@ -154,13 +153,13 @@ ColumnPtr ColumnAggregateFunction::permute(const Permutation & perm, size_t limi
|
||||
if (perm.size() < limit)
|
||||
throw Exception("Size of permutation is less than required.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
std::shared_ptr<ColumnAggregateFunction> res = std::make_shared<ColumnAggregateFunction>(*this);
|
||||
auto res = createView();
|
||||
|
||||
res->getData().resize(limit);
|
||||
for (size_t i = 0; i < limit; ++i)
|
||||
res->getData()[i] = getData()[perm[i]];
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
/// Is required to support operations with Set
|
||||
@ -194,9 +193,9 @@ size_t ColumnAggregateFunction::allocatedBytes() const
|
||||
return res;
|
||||
}
|
||||
|
||||
ColumnPtr ColumnAggregateFunction::cloneEmpty() const
|
||||
MutableColumnPtr ColumnAggregateFunction::cloneEmpty() const
|
||||
{
|
||||
return std::make_shared<ColumnAggregateFunction>(func, Arenas(1, std::make_shared<Arena>()));
|
||||
return create(func, Arenas(1, std::make_shared<Arena>()));
|
||||
}
|
||||
|
||||
Field ColumnAggregateFunction::operator[](size_t n) const
|
||||
@ -327,21 +326,20 @@ void ColumnAggregateFunction::popBack(size_t n)
|
||||
data.resize_assume_reserved(new_size);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnAggregateFunction::replicate(const IColumn::Offsets_t & offsets) const
|
||||
MutableColumnPtr ColumnAggregateFunction::replicate(const IColumn::Offsets & offsets) const
|
||||
{
|
||||
size_t size = data.size();
|
||||
if (size != offsets.size())
|
||||
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
std::shared_ptr<ColumnAggregateFunction> res = std::make_shared<ColumnAggregateFunction>(*this);
|
||||
|
||||
if (size == 0)
|
||||
return res;
|
||||
return cloneEmpty();
|
||||
|
||||
auto res = createView();
|
||||
auto & res_data = res->getData();
|
||||
res_data.reserve(offsets.back());
|
||||
|
||||
IColumn::Offset_t prev_offset = 0;
|
||||
IColumn::Offset prev_offset = 0;
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
size_t size_to_replicate = offsets[i] - prev_offset;
|
||||
@ -351,15 +349,15 @@ ColumnPtr ColumnAggregateFunction::replicate(const IColumn::Offsets_t & offsets)
|
||||
res_data.push_back(data[i]);
|
||||
}
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
Columns ColumnAggregateFunction::scatter(IColumn::ColumnIndex num_columns, const IColumn::Selector & selector) const
|
||||
MutableColumns ColumnAggregateFunction::scatter(IColumn::ColumnIndex num_columns, const IColumn::Selector & selector) const
|
||||
{
|
||||
/// Columns with scattered values will point to this column as the owner of values.
|
||||
Columns columns(num_columns);
|
||||
MutableColumns columns(num_columns);
|
||||
for (auto & column : columns)
|
||||
column = std::make_shared<ColumnAggregateFunction>(*this);
|
||||
column = createView();
|
||||
|
||||
size_t num_rows = size();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <Common/Arena.h>
|
||||
|
||||
@ -17,8 +17,7 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
|
||||
/** State column of aggregate functions.
|
||||
/** Column of states of aggregate functions.
|
||||
* Presented as an array of pointers to the states of aggregate functions (data).
|
||||
* The states themselves are stored in one of the pools (arenas).
|
||||
*
|
||||
@ -42,12 +41,14 @@ namespace DB
|
||||
* specifying which individual values should be destroyed and which ones should not.
|
||||
* Clearly, this method would have a substantially non-zero price.
|
||||
*/
|
||||
class ColumnAggregateFunction final : public IColumn, public std::enable_shared_from_this<ColumnAggregateFunction>
|
||||
class ColumnAggregateFunction final : public COWPtrHelper<IColumn, ColumnAggregateFunction>
|
||||
{
|
||||
public:
|
||||
using Container_t = PaddedPODArray<AggregateDataPtr>;
|
||||
using Container = PaddedPODArray<AggregateDataPtr>;
|
||||
|
||||
private:
|
||||
friend class COWPtrHelper<IColumn, ColumnAggregateFunction>;
|
||||
|
||||
/// Memory pools. Aggregate states are allocated from them.
|
||||
Arenas arenas;
|
||||
|
||||
@ -56,17 +57,19 @@ private:
|
||||
|
||||
/// Source column. Used (holds source from destruction),
|
||||
/// if this column has been constructed from another and uses all or part of its values.
|
||||
std::shared_ptr<const ColumnAggregateFunction> src;
|
||||
ColumnPtr src;
|
||||
|
||||
/// Array of pointers to aggregation states, that are placed in arenas.
|
||||
Container_t data;
|
||||
Container data;
|
||||
|
||||
ColumnAggregateFunction() {}
|
||||
|
||||
public:
|
||||
/// Create a new column that has another column as a source.
|
||||
ColumnAggregateFunction(const ColumnAggregateFunction & other)
|
||||
: std::enable_shared_from_this<ColumnAggregateFunction>(other),
|
||||
arenas(other.arenas), func(other.func), src(other.shared_from_this())
|
||||
MutablePtr createView() const
|
||||
{
|
||||
MutablePtr res = create(func, arenas);
|
||||
res->src = getPtr();
|
||||
return res;
|
||||
}
|
||||
|
||||
ColumnAggregateFunction(const AggregateFunctionPtr & func_)
|
||||
@ -79,6 +82,12 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
ColumnAggregateFunction(const ColumnAggregateFunction & src_)
|
||||
: arenas(src_.arenas), func(src_.func), src(src_.getPtr())
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
~ColumnAggregateFunction();
|
||||
|
||||
void set(const AggregateFunctionPtr & func_)
|
||||
@ -94,7 +103,7 @@ public:
|
||||
|
||||
/** Transform column with states of aggregate functions to column with final result values.
|
||||
*/
|
||||
ColumnPtr convertToValues() const;
|
||||
MutableColumnPtr convertToValues() const;
|
||||
|
||||
std::string getName() const override { return "AggregateFunction(" + func->getName() + ")"; }
|
||||
const char * getFamilyName() const override { return "AggregateFunction"; }
|
||||
@ -104,7 +113,7 @@ public:
|
||||
return getData().size();
|
||||
}
|
||||
|
||||
ColumnPtr cloneEmpty() const override;;
|
||||
MutableColumnPtr cloneEmpty() const override;
|
||||
|
||||
Field operator[](size_t n) const override;
|
||||
|
||||
@ -143,13 +152,13 @@ public:
|
||||
|
||||
void popBack(size_t n) override;
|
||||
|
||||
ColumnPtr filter(const Filter & filter, ssize_t result_size_hint) const override;
|
||||
MutableColumnPtr filter(const Filter & filter, ssize_t result_size_hint) const override;
|
||||
|
||||
ColumnPtr permute(const Permutation & perm, size_t limit) const override;
|
||||
MutableColumnPtr permute(const Permutation & perm, size_t limit) const override;
|
||||
|
||||
ColumnPtr replicate(const Offsets_t & offsets) const override;
|
||||
MutableColumnPtr replicate(const Offsets & offsets) const override;
|
||||
|
||||
Columns scatter(ColumnIndex num_columns, const Selector & selector) const override;
|
||||
MutableColumns scatter(ColumnIndex num_columns, const Selector & selector) const override;
|
||||
|
||||
void gather(ColumnGathererStream & gatherer_stream) override;
|
||||
|
||||
@ -161,12 +170,12 @@ public:
|
||||
void getPermutation(bool reverse, size_t limit, int nan_direction_hint, Permutation & res) const override;
|
||||
|
||||
/** More efficient manipulation methods */
|
||||
Container_t & getData()
|
||||
Container & getData()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
const Container_t & getData() const
|
||||
const Container & getData() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
@ -31,18 +31,11 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
ColumnArray::ColumnArray(ColumnPtr nested_column, ColumnPtr offsets_column)
|
||||
ColumnArray::ColumnArray(const ColumnPtr & nested_column, const ColumnPtr & offsets_column)
|
||||
: data(nested_column), offsets(offsets_column)
|
||||
{
|
||||
if (!offsets_column)
|
||||
{
|
||||
offsets = std::make_shared<ColumnOffsets_t>();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!typeid_cast<ColumnOffsets_t *>(&*offsets_column))
|
||||
throw Exception("offsets_column must be a ColumnUInt64", ErrorCodes::ILLEGAL_COLUMN);
|
||||
}
|
||||
if (!typeid_cast<const ColumnOffsets *>(offsets_column.get()))
|
||||
throw Exception("offsets_column must be a ColumnUInt64", ErrorCodes::ILLEGAL_COLUMN);
|
||||
|
||||
/** NOTE
|
||||
* Arrays with constant value are possible and used in implementation of higher order functions (see FunctionReplicate).
|
||||
@ -50,16 +43,25 @@ ColumnArray::ColumnArray(ColumnPtr nested_column, ColumnPtr offsets_column)
|
||||
*/
|
||||
}
|
||||
|
||||
ColumnArray::ColumnArray(const ColumnPtr & nested_column)
|
||||
: data(nested_column)
|
||||
{
|
||||
if (!data->empty())
|
||||
throw Exception("Not empty data passed to ColumnArray, but no offsets passed", ErrorCodes::ILLEGAL_COLUMN);
|
||||
|
||||
offsets = ColumnOffsets::create();
|
||||
}
|
||||
|
||||
|
||||
std::string ColumnArray::getName() const { return "Array(" + getData().getName() + ")"; }
|
||||
|
||||
|
||||
ColumnPtr ColumnArray::cloneResized(size_t to_size) const
|
||||
MutableColumnPtr ColumnArray::cloneResized(size_t to_size) const
|
||||
{
|
||||
auto res = std::make_shared<ColumnArray>(getData().cloneEmpty());
|
||||
auto res = ColumnArray::create(getData().cloneEmpty());
|
||||
|
||||
if (to_size == 0)
|
||||
return res;
|
||||
return std::move(res);
|
||||
|
||||
size_t from_size = size();
|
||||
|
||||
@ -74,23 +76,20 @@ ColumnPtr ColumnArray::cloneResized(size_t to_size) const
|
||||
{
|
||||
/// Copy column and append empty arrays for extra elements.
|
||||
|
||||
Offset_t offset = 0;
|
||||
Offset offset = 0;
|
||||
if (from_size > 0)
|
||||
{
|
||||
res->getOffsets().assign(getOffsets().begin(), getOffsets().end());
|
||||
res->getDataPtr() = getData().clone();
|
||||
res->getData().insertRangeFrom(getData(), 0, getData().size());
|
||||
offset = getOffsets().back();
|
||||
}
|
||||
|
||||
res->getOffsets().resize(to_size);
|
||||
for (size_t i = from_size; i < to_size; ++i)
|
||||
{
|
||||
++offset;
|
||||
res->getOffsets()[i] = offset;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
|
||||
@ -151,7 +150,7 @@ void ColumnArray::insertData(const char * pos, size_t length)
|
||||
{
|
||||
/** Similarly - only for arrays of fixed length values.
|
||||
*/
|
||||
IColumn * data_ = data.get();
|
||||
IColumn * data_ = &getData();
|
||||
if (!data_->isFixedAndContiguous())
|
||||
throw Exception("Method insertData is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
|
||||
|
||||
@ -312,22 +311,22 @@ bool ColumnArray::hasEqualOffsets(const ColumnArray & other) const
|
||||
if (offsets == other.offsets)
|
||||
return true;
|
||||
|
||||
const Offsets_t & offsets1 = getOffsets();
|
||||
const Offsets_t & offsets2 = other.getOffsets();
|
||||
const Offsets & offsets1 = getOffsets();
|
||||
const Offsets & offsets2 = other.getOffsets();
|
||||
return offsets1.size() == offsets2.size() && 0 == memcmp(&offsets1[0], &offsets2[0], sizeof(offsets1[0]) * offsets1.size());
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnArray::convertToFullColumnIfConst() const
|
||||
MutableColumnPtr ColumnArray::convertToFullColumnIfConst() const
|
||||
{
|
||||
ColumnPtr new_data;
|
||||
|
||||
if (auto full_column = getData().convertToFullColumnIfConst())
|
||||
if (ColumnPtr full_column = getData().convertToFullColumnIfConst())
|
||||
new_data = full_column;
|
||||
else
|
||||
new_data = data;
|
||||
|
||||
return std::make_shared<ColumnArray>(new_data, offsets);
|
||||
return ColumnArray::create(new_data, offsets);
|
||||
}
|
||||
|
||||
|
||||
@ -371,10 +370,10 @@ void ColumnArray::insertRangeFrom(const IColumn & src, size_t start, size_t leng
|
||||
size_t nested_offset = src_concrete.offsetAt(start);
|
||||
size_t nested_length = src_concrete.getOffsets()[start + length - 1] - nested_offset;
|
||||
|
||||
data->insertRangeFrom(src_concrete.getData(), nested_offset, nested_length);
|
||||
getData().insertRangeFrom(src_concrete.getData(), nested_offset, nested_length);
|
||||
|
||||
Offsets_t & cur_offsets = getOffsets();
|
||||
const Offsets_t & src_offsets = src_concrete.getOffsets();
|
||||
Offsets & cur_offsets = getOffsets();
|
||||
const Offsets & src_offsets = src_concrete.getOffsets();
|
||||
|
||||
if (start == 0 && cur_offsets.empty())
|
||||
{
|
||||
@ -392,7 +391,7 @@ void ColumnArray::insertRangeFrom(const IColumn & src, size_t start, size_t leng
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnArray::filter(const Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnArray::filter(const Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
if (typeid_cast<const ColumnUInt8 *>(data.get())) return filterNumber<UInt8>(filt, result_size_hint);
|
||||
if (typeid_cast<const ColumnUInt16 *>(data.get())) return filterNumber<UInt16>(filt, result_size_hint);
|
||||
@ -411,39 +410,39 @@ ColumnPtr ColumnArray::filter(const Filter & filt, ssize_t result_size_hint) con
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ColumnPtr ColumnArray::filterNumber(const Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnArray::filterNumber(const Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
if (getOffsets().size() == 0)
|
||||
return std::make_shared<ColumnArray>(data);
|
||||
return ColumnArray::create(data);
|
||||
|
||||
auto res = std::make_shared<ColumnArray>(data->cloneEmpty());
|
||||
auto res = ColumnArray::create(data->cloneEmpty());
|
||||
|
||||
auto & res_elems = static_cast<ColumnVector<T> &>(res->getData()).getData();
|
||||
Offsets_t & res_offsets = res->getOffsets();
|
||||
Offsets & res_offsets = res->getOffsets();
|
||||
|
||||
filterArraysImpl<T>(static_cast<const ColumnVector<T> &>(*data).getData(), getOffsets(), res_elems, res_offsets, filt, result_size_hint);
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnArray::filterString(const Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnArray::filterString(const Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
size_t col_size = getOffsets().size();
|
||||
if (col_size != filt.size())
|
||||
throw Exception("Size of filter doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
if (0 == col_size)
|
||||
return std::make_shared<ColumnArray>(data);
|
||||
return ColumnArray::create(data);
|
||||
|
||||
auto res = std::make_shared<ColumnArray>(data->cloneEmpty());
|
||||
auto res = ColumnArray::create(data->cloneEmpty());
|
||||
|
||||
const ColumnString & src_string = typeid_cast<const ColumnString &>(*data);
|
||||
const ColumnString::Chars_t & src_chars = src_string.getChars();
|
||||
const Offsets_t & src_string_offsets = src_string.getOffsets();
|
||||
const Offsets_t & src_offsets = getOffsets();
|
||||
const Offsets & src_string_offsets = src_string.getOffsets();
|
||||
const Offsets & src_offsets = getOffsets();
|
||||
|
||||
ColumnString::Chars_t & res_chars = typeid_cast<ColumnString &>(res->getData()).getChars();
|
||||
Offsets_t & res_string_offsets = typeid_cast<ColumnString &>(res->getData()).getOffsets();
|
||||
Offsets_t & res_offsets = res->getOffsets();
|
||||
Offsets & res_string_offsets = typeid_cast<ColumnString &>(res->getData()).getOffsets();
|
||||
Offsets & res_offsets = res->getOffsets();
|
||||
|
||||
if (result_size_hint < 0) /// Other cases are not considered.
|
||||
{
|
||||
@ -452,11 +451,11 @@ ColumnPtr ColumnArray::filterString(const Filter & filt, ssize_t result_size_hin
|
||||
res_offsets.reserve(col_size);
|
||||
}
|
||||
|
||||
Offset_t prev_src_offset = 0;
|
||||
Offset_t prev_src_string_offset = 0;
|
||||
Offset prev_src_offset = 0;
|
||||
Offset prev_src_string_offset = 0;
|
||||
|
||||
Offset_t prev_res_offset = 0;
|
||||
Offset_t prev_res_string_offset = 0;
|
||||
Offset prev_res_offset = 0;
|
||||
Offset prev_res_string_offset = 0;
|
||||
|
||||
for (size_t i = 0; i < col_size; ++i)
|
||||
{
|
||||
@ -490,17 +489,17 @@ ColumnPtr ColumnArray::filterString(const Filter & filt, ssize_t result_size_hin
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnArray::filterGeneric(const Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnArray::filterGeneric(const Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
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);
|
||||
|
||||
if (size == 0)
|
||||
return std::make_shared<ColumnArray>(data);
|
||||
return ColumnArray::create(data);
|
||||
|
||||
Filter nested_filt(getOffsets().back());
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
@ -511,7 +510,7 @@ ColumnPtr ColumnArray::filterGeneric(const Filter & filt, ssize_t result_size_hi
|
||||
memset(&nested_filt[offsetAt(i)], 0, sizeAt(i));
|
||||
}
|
||||
|
||||
std::shared_ptr<ColumnArray> res = std::make_shared<ColumnArray>(data);
|
||||
auto res = ColumnArray::create(data);
|
||||
|
||||
ssize_t nested_result_size_hint = 0;
|
||||
if (result_size_hint < 0)
|
||||
@ -521,7 +520,7 @@ ColumnPtr ColumnArray::filterGeneric(const Filter & filt, ssize_t result_size_hi
|
||||
|
||||
res->data = data->filter(nested_filt, nested_result_size_hint);
|
||||
|
||||
Offsets_t & res_offsets = res->getOffsets();
|
||||
Offsets & res_offsets = res->getOffsets();
|
||||
if (result_size_hint)
|
||||
res_offsets.reserve(result_size_hint > 0 ? result_size_hint : size);
|
||||
|
||||
@ -535,36 +534,36 @@ ColumnPtr ColumnArray::filterGeneric(const Filter & filt, ssize_t result_size_hi
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnArray::filterNullable(const Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnArray::filterNullable(const Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
if (getOffsets().size() == 0)
|
||||
return std::make_shared<ColumnArray>(data);
|
||||
return ColumnArray::create(data);
|
||||
|
||||
const ColumnNullable & nullable_elems = static_cast<const ColumnNullable &>(*data);
|
||||
|
||||
auto array_of_nested = std::make_shared<ColumnArray>(nullable_elems.getNestedColumn(), offsets);
|
||||
auto array_of_nested = ColumnArray::create(nullable_elems.getNestedColumnPtr(), offsets);
|
||||
auto filtered_array_of_nested_owner = array_of_nested->filter(filt, result_size_hint);
|
||||
auto & filtered_array_of_nested = static_cast<ColumnArray &>(*filtered_array_of_nested_owner);
|
||||
auto & filtered_offsets = filtered_array_of_nested.getOffsetsColumn();
|
||||
auto & filtered_array_of_nested = static_cast<const ColumnArray &>(*filtered_array_of_nested_owner);
|
||||
auto & filtered_offsets = filtered_array_of_nested.getOffsetsPtr();
|
||||
|
||||
auto res_null_map = std::make_shared<ColumnUInt8>();
|
||||
auto res = std::make_shared<ColumnArray>(
|
||||
std::make_shared<ColumnNullable>(
|
||||
auto res_null_map = ColumnUInt8::create();
|
||||
|
||||
filterArraysImplOnlyData(nullable_elems.getNullMapData(), getOffsets(), res_null_map->getData(), filt, result_size_hint);
|
||||
|
||||
return ColumnArray::create(
|
||||
ColumnNullable::create(
|
||||
filtered_array_of_nested.getDataPtr(),
|
||||
res_null_map),
|
||||
std::move(res_null_map)),
|
||||
filtered_offsets);
|
||||
|
||||
filterArraysImplOnlyData(nullable_elems.getNullMap(), getOffsets(), res_null_map->getData(), filt, result_size_hint);
|
||||
return res;
|
||||
}
|
||||
|
||||
ColumnPtr ColumnArray::filterTuple(const Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnArray::filterTuple(const Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
if (getOffsets().size() == 0)
|
||||
return std::make_shared<ColumnArray>(data);
|
||||
return ColumnArray::create(data);
|
||||
|
||||
const ColumnTuple & tuple = static_cast<const ColumnTuple &>(*data);
|
||||
|
||||
@ -577,19 +576,19 @@ ColumnPtr ColumnArray::filterTuple(const Filter & filt, ssize_t result_size_hint
|
||||
|
||||
Columns temporary_arrays(tuple_size);
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
temporary_arrays[i] = ColumnArray(tuple.getColumns()[i], getOffsetsColumn()).filter(filt, result_size_hint);
|
||||
temporary_arrays[i] = ColumnArray(tuple.getColumns()[i], getOffsetsPtr()).filter(filt, result_size_hint);
|
||||
|
||||
Columns tuple_columns(tuple_size);
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
tuple_columns[i] = static_cast<ColumnArray &>(*temporary_arrays[i]).getDataPtr();
|
||||
tuple_columns[i] = static_cast<const ColumnArray &>(*temporary_arrays[i]).getDataPtr();
|
||||
|
||||
return std::make_shared<ColumnArray>(
|
||||
std::make_shared<ColumnTuple>(tuple_columns),
|
||||
static_cast<ColumnArray &>(*temporary_arrays.front()).getOffsetsColumn());
|
||||
return ColumnArray::create(
|
||||
ColumnTuple::create(tuple_columns),
|
||||
static_cast<const ColumnArray &>(*temporary_arrays.front()).getOffsetsPtr());
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnArray::permute(const Permutation & perm, size_t limit) const
|
||||
MutableColumnPtr ColumnArray::permute(const Permutation & perm, size_t limit) const
|
||||
{
|
||||
size_t size = getOffsets().size();
|
||||
|
||||
@ -602,13 +601,13 @@ ColumnPtr ColumnArray::permute(const Permutation & perm, size_t limit) const
|
||||
throw Exception("Size of permutation is less than required.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
if (limit == 0)
|
||||
return std::make_shared<ColumnArray>(data);
|
||||
return ColumnArray::create(data);
|
||||
|
||||
Permutation nested_perm(getOffsets().back());
|
||||
|
||||
std::shared_ptr<ColumnArray> res = std::make_shared<ColumnArray>(data->cloneEmpty());
|
||||
auto res = ColumnArray::create(data->cloneEmpty());
|
||||
|
||||
Offsets_t & res_offsets = res->getOffsets();
|
||||
Offsets & res_offsets = res->getOffsets();
|
||||
res_offsets.resize(limit);
|
||||
size_t current_offset = 0;
|
||||
|
||||
@ -623,7 +622,7 @@ ColumnPtr ColumnArray::permute(const Permutation & perm, size_t limit) const
|
||||
if (current_offset != 0)
|
||||
res->data = data->permute(nested_perm, current_offset);
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
void ColumnArray::getPermutation(bool reverse, size_t limit, int nan_direction_hint, Permutation & res) const
|
||||
@ -653,7 +652,7 @@ void ColumnArray::getPermutation(bool reverse, size_t limit, int nan_direction_h
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnArray::replicate(const Offsets_t & replicate_offsets) const
|
||||
MutableColumnPtr ColumnArray::replicate(const Offsets & replicate_offsets) const
|
||||
{
|
||||
if (typeid_cast<const ColumnUInt8 *>(data.get())) return replicateNumber<UInt8>(replicate_offsets);
|
||||
if (typeid_cast<const ColumnUInt16 *>(data.get())) return replicateNumber<UInt16>(replicate_offsets);
|
||||
@ -674,31 +673,31 @@ ColumnPtr ColumnArray::replicate(const Offsets_t & replicate_offsets) const
|
||||
|
||||
|
||||
template <typename T>
|
||||
ColumnPtr ColumnArray::replicateNumber(const Offsets_t & replicate_offsets) const
|
||||
MutableColumnPtr ColumnArray::replicateNumber(const Offsets & 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();
|
||||
MutableColumnPtr res = cloneEmpty();
|
||||
|
||||
if (0 == col_size)
|
||||
return res;
|
||||
|
||||
ColumnArray & res_ = typeid_cast<ColumnArray &>(*res);
|
||||
|
||||
const typename ColumnVector<T>::Container_t & src_data = typeid_cast<const ColumnVector<T> &>(*data).getData();
|
||||
const Offsets_t & src_offsets = getOffsets();
|
||||
const typename ColumnVector<T>::Container & src_data = typeid_cast<const ColumnVector<T> &>(*data).getData();
|
||||
const Offsets & src_offsets = getOffsets();
|
||||
|
||||
typename ColumnVector<T>::Container_t & res_data = typeid_cast<ColumnVector<T> &>(res_.getData()).getData();
|
||||
Offsets_t & res_offsets = res_.getOffsets();
|
||||
typename ColumnVector<T>::Container & res_data = typeid_cast<ColumnVector<T> &>(res_.getData()).getData();
|
||||
Offsets & 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;
|
||||
Offset prev_replicate_offset = 0;
|
||||
Offset prev_data_offset = 0;
|
||||
Offset current_new_offset = 0;
|
||||
|
||||
for (size_t i = 0; i < col_size; ++i)
|
||||
{
|
||||
@ -722,13 +721,13 @@ ColumnPtr ColumnArray::replicateNumber(const Offsets_t & replicate_offsets) cons
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnArray::replicateString(const Offsets_t & replicate_offsets) const
|
||||
MutableColumnPtr ColumnArray::replicateString(const Offsets & 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();
|
||||
MutableColumnPtr res = cloneEmpty();
|
||||
|
||||
if (0 == col_size)
|
||||
return res;
|
||||
@ -737,24 +736,24 @@ ColumnPtr ColumnArray::replicateString(const Offsets_t & replicate_offsets) cons
|
||||
|
||||
const ColumnString & src_string = typeid_cast<const ColumnString &>(*data);
|
||||
const ColumnString::Chars_t & src_chars = src_string.getChars();
|
||||
const Offsets_t & src_string_offsets = src_string.getOffsets();
|
||||
const Offsets_t & src_offsets = getOffsets();
|
||||
const Offsets & src_string_offsets = src_string.getOffsets();
|
||||
const Offsets & src_offsets = getOffsets();
|
||||
|
||||
ColumnString::Chars_t & res_chars = typeid_cast<ColumnString &>(res_.getData()).getChars();
|
||||
Offsets_t & res_string_offsets = typeid_cast<ColumnString &>(res_.getData()).getOffsets();
|
||||
Offsets_t & res_offsets = res_.getOffsets();
|
||||
Offsets & res_string_offsets = typeid_cast<ColumnString &>(res_.getData()).getOffsets();
|
||||
Offsets & res_offsets = res_.getOffsets();
|
||||
|
||||
res_chars.reserve(src_chars.size() / col_size * replicate_offsets.back());
|
||||
res_string_offsets.reserve(src_string_offsets.size() / col_size * replicate_offsets.back());
|
||||
res_offsets.reserve(replicate_offsets.back());
|
||||
|
||||
Offset_t prev_replicate_offset = 0;
|
||||
Offset prev_replicate_offset = 0;
|
||||
|
||||
Offset_t prev_src_offset = 0;
|
||||
Offset_t prev_src_string_offset = 0;
|
||||
Offset prev_src_offset = 0;
|
||||
Offset prev_src_string_offset = 0;
|
||||
|
||||
Offset_t current_res_offset = 0;
|
||||
Offset_t current_res_string_offset = 0;
|
||||
Offset current_res_offset = 0;
|
||||
Offset current_res_string_offset = 0;
|
||||
|
||||
for (size_t i = 0; i < col_size; ++i)
|
||||
{
|
||||
@ -797,7 +796,7 @@ ColumnPtr ColumnArray::replicateString(const Offsets_t & replicate_offsets) cons
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnArray::replicateConst(const Offsets_t & replicate_offsets) const
|
||||
MutableColumnPtr ColumnArray::replicateConst(const Offsets & replicate_offsets) const
|
||||
{
|
||||
size_t col_size = size();
|
||||
if (col_size != replicate_offsets.size())
|
||||
@ -806,15 +805,15 @@ ColumnPtr ColumnArray::replicateConst(const Offsets_t & replicate_offsets) const
|
||||
if (0 == col_size)
|
||||
return cloneEmpty();
|
||||
|
||||
const Offsets_t & src_offsets = getOffsets();
|
||||
const Offsets & src_offsets = getOffsets();
|
||||
|
||||
auto res_column_offsets = std::make_shared<ColumnOffsets_t>();
|
||||
Offsets_t & res_offsets = res_column_offsets->getData();
|
||||
auto res_column_offsets = ColumnOffsets::create();
|
||||
Offsets & res_offsets = res_column_offsets->getData();
|
||||
res_offsets.reserve(replicate_offsets.back());
|
||||
|
||||
Offset_t prev_replicate_offset = 0;
|
||||
Offset_t prev_data_offset = 0;
|
||||
Offset_t current_new_offset = 0;
|
||||
Offset prev_replicate_offset = 0;
|
||||
Offset prev_data_offset = 0;
|
||||
Offset current_new_offset = 0;
|
||||
|
||||
for (size_t i = 0; i < col_size; ++i)
|
||||
{
|
||||
@ -831,23 +830,23 @@ ColumnPtr ColumnArray::replicateConst(const Offsets_t & replicate_offsets) const
|
||||
prev_data_offset = src_offsets[i];
|
||||
}
|
||||
|
||||
return std::make_shared<ColumnArray>(getData().cloneResized(current_new_offset), res_column_offsets);
|
||||
return ColumnArray::create(getData().cloneResized(current_new_offset), std::move(res_column_offsets));
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnArray::replicateGeneric(const Offsets_t & replicate_offsets) const
|
||||
MutableColumnPtr ColumnArray::replicateGeneric(const Offsets & 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();
|
||||
MutableColumnPtr res = cloneEmpty();
|
||||
ColumnArray & res_concrete = static_cast<ColumnArray &>(*res);
|
||||
|
||||
if (0 == col_size)
|
||||
return res;
|
||||
|
||||
IColumn::Offset_t prev_offset = 0;
|
||||
IColumn::Offset prev_offset = 0;
|
||||
for (size_t i = 0; i < col_size; ++i)
|
||||
{
|
||||
size_t size_to_replicate = replicate_offsets[i] - prev_offset;
|
||||
@ -861,25 +860,25 @@ ColumnPtr ColumnArray::replicateGeneric(const Offsets_t & replicate_offsets) con
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnArray::replicateNullable(const Offsets_t & replicate_offsets) const
|
||||
MutableColumnPtr ColumnArray::replicateNullable(const Offsets & replicate_offsets) const
|
||||
{
|
||||
const ColumnNullable & nullable = static_cast<const ColumnNullable &>(*data);
|
||||
|
||||
/// Make temporary arrays for each components of Nullable. Then replicate them independently and collect back to result.
|
||||
/// NOTE Offsets are calculated twice and it is redundant.
|
||||
|
||||
auto array_of_nested = ColumnArray(nullable.getNestedColumn(), getOffsetsColumn()).replicate(replicate_offsets);
|
||||
auto array_of_null_map = ColumnArray(nullable.getNullMapColumn(), getOffsetsColumn()).replicate(replicate_offsets);
|
||||
auto array_of_nested = ColumnArray(nullable.getNestedColumnPtr(), getOffsetsPtr()).replicate(replicate_offsets);
|
||||
auto array_of_null_map = ColumnArray(nullable.getNullMapColumnPtr(), getOffsetsPtr()).replicate(replicate_offsets);
|
||||
|
||||
return std::make_shared<ColumnArray>(
|
||||
std::make_shared<ColumnNullable>(
|
||||
return ColumnArray::create(
|
||||
ColumnNullable::create(
|
||||
static_cast<ColumnArray &>(*array_of_nested).getDataPtr(),
|
||||
static_cast<ColumnArray &>(*array_of_null_map).getDataPtr()),
|
||||
static_cast<ColumnArray &>(*array_of_nested).getOffsetsColumn());
|
||||
static_cast<ColumnArray &>(*array_of_nested).getOffsetsPtr());
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnArray::replicateTuple(const Offsets_t & replicate_offsets) const
|
||||
MutableColumnPtr ColumnArray::replicateTuple(const Offsets & replicate_offsets) const
|
||||
{
|
||||
const ColumnTuple & tuple = static_cast<const ColumnTuple &>(*data);
|
||||
|
||||
@ -892,15 +891,15 @@ ColumnPtr ColumnArray::replicateTuple(const Offsets_t & replicate_offsets) const
|
||||
|
||||
Columns temporary_arrays(tuple_size);
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
temporary_arrays[i] = ColumnArray(tuple.getColumns()[i], getOffsetsColumn()).replicate(replicate_offsets);
|
||||
temporary_arrays[i] = ColumnArray(tuple.getColumns()[i], getOffsetsPtr()).replicate(replicate_offsets);
|
||||
|
||||
Columns tuple_columns(tuple_size);
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
tuple_columns[i] = static_cast<ColumnArray &>(*temporary_arrays[i]).getDataPtr();
|
||||
tuple_columns[i] = static_cast<const ColumnArray &>(*temporary_arrays[i]).getDataPtr();
|
||||
|
||||
return std::make_shared<ColumnArray>(
|
||||
std::make_shared<ColumnTuple>(tuple_columns),
|
||||
static_cast<ColumnArray &>(*temporary_arrays.front()).getOffsetsColumn());
|
||||
return ColumnArray::create(
|
||||
ColumnTuple::create(tuple_columns),
|
||||
static_cast<const ColumnArray &>(*temporary_arrays.front()).getOffsetsPtr());
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,18 +18,26 @@ namespace ErrorCodes
|
||||
* In memory, it is represented as one column of a nested type, whose size is equal to the sum of the sizes of all arrays,
|
||||
* and as an array of offsets in it, which allows you to get each element.
|
||||
*/
|
||||
class ColumnArray final : public IColumn
|
||||
class ColumnArray final : public COWPtrHelper<IColumn, ColumnArray>
|
||||
{
|
||||
public:
|
||||
/** On the index i there is an offset to the beginning of the i + 1 -th element. */
|
||||
using ColumnOffsets_t = ColumnVector<Offset_t>;
|
||||
private:
|
||||
friend class COWPtrHelper<IColumn, ColumnArray>;
|
||||
|
||||
/** Create an array column with specified values and offsets. */
|
||||
ColumnArray(const ColumnPtr & nested_column, const ColumnPtr & offsets_column);
|
||||
|
||||
/** Create an empty column of arrays with the type of values as in the column `nested_column` */
|
||||
explicit ColumnArray(ColumnPtr nested_column, ColumnPtr offsets_column = nullptr);
|
||||
ColumnArray(const ColumnPtr & nested_column);
|
||||
|
||||
ColumnArray(const ColumnArray &) = default;
|
||||
|
||||
public:
|
||||
/** On the index i there is an offset to the beginning of the i + 1 -th element. */
|
||||
using ColumnOffsets = ColumnVector<Offset>;
|
||||
|
||||
std::string getName() const override;
|
||||
const char * getFamilyName() const override { return "Array"; }
|
||||
ColumnPtr cloneResized(size_t size) const override;
|
||||
MutableColumnPtr cloneResized(size_t size) const override;
|
||||
size_t size() const override;
|
||||
Field operator[](size_t n) const override;
|
||||
void get(size_t n, Field & res) const override;
|
||||
@ -43,40 +51,45 @@ public:
|
||||
void insertFrom(const IColumn & src_, size_t n) override;
|
||||
void insertDefault() override;
|
||||
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;
|
||||
MutableColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override;
|
||||
MutableColumnPtr 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;
|
||||
void getPermutation(bool reverse, size_t limit, int nan_direction_hint, Permutation & res) const override;
|
||||
void reserve(size_t n) override;
|
||||
size_t byteSize() const override;
|
||||
size_t allocatedBytes() const override;
|
||||
ColumnPtr replicate(const Offsets_t & replicate_offsets) const override;
|
||||
ColumnPtr convertToFullColumnIfConst() const override;
|
||||
MutableColumnPtr replicate(const Offsets & replicate_offsets) const override;
|
||||
MutableColumnPtr convertToFullColumnIfConst() const override;
|
||||
void getExtremes(Field & min, Field & max) const override;
|
||||
|
||||
bool hasEqualOffsets(const ColumnArray & other) const;
|
||||
|
||||
/** More efficient methods of manipulation */
|
||||
IColumn & getData() { return *data.get(); }
|
||||
const IColumn & getData() const { return *data.get(); }
|
||||
IColumn & getData() { return *data->assumeMutable(); }
|
||||
const IColumn & getData() const { return *data; }
|
||||
|
||||
ColumnPtr & getDataPtr() { return data; }
|
||||
IColumn & getOffsetsColumn() { return *offsets->assumeMutable(); }
|
||||
const IColumn & getOffsetsColumn() const { return *offsets; }
|
||||
|
||||
Offsets & ALWAYS_INLINE getOffsets()
|
||||
{
|
||||
return static_cast<ColumnOffsets &>(*offsets->assumeMutable()).getData();
|
||||
}
|
||||
|
||||
const Offsets & ALWAYS_INLINE getOffsets() const
|
||||
{
|
||||
return static_cast<const ColumnOffsets &>(*offsets).getData();
|
||||
}
|
||||
|
||||
//MutableColumnPtr getDataMutablePtr() { return data->assumeMutable(); }
|
||||
const ColumnPtr & getDataPtr() const { return data; }
|
||||
ColumnPtr & getDataPtr() { return data; }
|
||||
|
||||
Offsets_t & ALWAYS_INLINE getOffsets()
|
||||
{
|
||||
return static_cast<ColumnOffsets_t &>(*offsets.get()).getData();
|
||||
}
|
||||
//MutableColumnPtr getOffsetsMutablePtr() { return offsets->assumeMutable(); }
|
||||
const ColumnPtr & getOffsetsPtr() const { return offsets; }
|
||||
ColumnPtr & getOffsetsPtr() { return offsets; }
|
||||
|
||||
const Offsets_t & ALWAYS_INLINE getOffsets() const
|
||||
{
|
||||
return static_cast<const ColumnOffsets_t &>(*offsets.get()).getData();
|
||||
}
|
||||
|
||||
ColumnPtr & getOffsetsColumn() { return offsets; }
|
||||
const ColumnPtr & getOffsetsColumn() const { return offsets; }
|
||||
|
||||
Columns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
MutableColumns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
{
|
||||
return scatterImpl<ColumnArray>(num_columns, selector);
|
||||
}
|
||||
@ -91,41 +104,41 @@ public:
|
||||
|
||||
private:
|
||||
ColumnPtr data;
|
||||
ColumnPtr offsets; /// Displacements can be shared across multiple columns - to implement nested data structures.
|
||||
ColumnPtr offsets;
|
||||
|
||||
size_t ALWAYS_INLINE offsetAt(size_t i) const { return i == 0 ? 0 : getOffsets()[i - 1]; }
|
||||
size_t ALWAYS_INLINE sizeAt(size_t i) const { return i == 0 ? getOffsets()[0] : (getOffsets()[i] - getOffsets()[i - 1]); }
|
||||
size_t ALWAYS_INLINE offsetAt(size_t i) const { return i == 0 ? 0 : getOffsets()[i - 1]; }
|
||||
size_t ALWAYS_INLINE sizeAt(size_t i) const { return i == 0 ? getOffsets()[0] : (getOffsets()[i] - getOffsets()[i - 1]); }
|
||||
|
||||
|
||||
/// Multiply values if the nested column is ColumnVector<T>.
|
||||
template <typename T>
|
||||
ColumnPtr replicateNumber(const Offsets_t & replicate_offsets) const;
|
||||
MutableColumnPtr replicateNumber(const Offsets & replicate_offsets) const;
|
||||
|
||||
/// Multiply the values if the nested column is ColumnString. The code is too complicated.
|
||||
ColumnPtr replicateString(const Offsets_t & replicate_offsets) const;
|
||||
MutableColumnPtr replicateString(const Offsets & replicate_offsets) const;
|
||||
|
||||
/** Non-constant arrays of constant values are quite rare.
|
||||
* Most functions can not work with them, and does not create such columns as a result.
|
||||
* An exception is the function `replicate`(see FunctionsMiscellaneous.h), which has service meaning for the implementation of lambda functions.
|
||||
* Only for its sake is the implementation of the `replicate` method for ColumnArray(ColumnConst).
|
||||
*/
|
||||
ColumnPtr replicateConst(const Offsets_t & replicate_offsets) const;
|
||||
MutableColumnPtr replicateConst(const Offsets & replicate_offsets) const;
|
||||
|
||||
/** The following is done by simply replicating of nested columns.
|
||||
*/
|
||||
ColumnPtr replicateTuple(const Offsets_t & replicate_offsets) const;
|
||||
ColumnPtr replicateNullable(const Offsets_t & replicate_offsets) const;
|
||||
ColumnPtr replicateGeneric(const Offsets_t & replicate_offsets) const;
|
||||
MutableColumnPtr replicateTuple(const Offsets & replicate_offsets) const;
|
||||
MutableColumnPtr replicateNullable(const Offsets & replicate_offsets) const;
|
||||
MutableColumnPtr replicateGeneric(const Offsets & replicate_offsets) const;
|
||||
|
||||
|
||||
/// Specializations for the filter function.
|
||||
template <typename T>
|
||||
ColumnPtr filterNumber(const Filter & filt, ssize_t result_size_hint) const;
|
||||
MutableColumnPtr filterNumber(const Filter & filt, ssize_t result_size_hint) const;
|
||||
|
||||
ColumnPtr filterString(const Filter & filt, ssize_t result_size_hint) const;
|
||||
ColumnPtr filterTuple(const Filter & filt, ssize_t result_size_hint) const;
|
||||
ColumnPtr filterNullable(const Filter & filt, ssize_t result_size_hint) const;
|
||||
ColumnPtr filterGeneric(const Filter & filt, ssize_t result_size_hint) const;
|
||||
MutableColumnPtr filterString(const Filter & filt, ssize_t result_size_hint) const;
|
||||
MutableColumnPtr filterTuple(const Filter & filt, ssize_t result_size_hint) const;
|
||||
MutableColumnPtr filterNullable(const Filter & filt, ssize_t result_size_hint) const;
|
||||
MutableColumnPtr filterGeneric(const Filter & filt, ssize_t result_size_hint) const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,20 +1,23 @@
|
||||
#include <IO/Operators.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
|
||||
#include <Columns/ColumnConst.h>
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Common/FieldVisitors.h>
|
||||
#include <Columns/ColumnsCommon.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
ColumnConst::ColumnConst(ColumnPtr data_, size_t s)
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int SIZES_OF_COLUMNS_DOESNT_MATCH;
|
||||
}
|
||||
|
||||
ColumnConst::ColumnConst(const ColumnPtr & data_, size_t s)
|
||||
: data(data_), s(s)
|
||||
{
|
||||
/// Squash Const of Const.
|
||||
while (ColumnConst * const_data = typeid_cast<ColumnConst *>(data.get()))
|
||||
while (const ColumnConst * const_data = typeid_cast<const ColumnConst *>(data.get()))
|
||||
data = const_data->getDataColumnPtr();
|
||||
|
||||
if (data->size() != 1)
|
||||
@ -22,9 +25,66 @@ ColumnConst::ColumnConst(ColumnPtr data_, size_t s)
|
||||
ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnConst::convertToFullColumn() const
|
||||
MutableColumnPtr ColumnConst::convertToFullColumn() const
|
||||
{
|
||||
return data->replicate(Offsets_t(1, s));
|
||||
return data->replicate(Offsets(1, s));
|
||||
}
|
||||
|
||||
MutableColumnPtr ColumnConst::filter(const Filter & filt, ssize_t /*result_size_hint*/) const
|
||||
{
|
||||
if (s != filt.size())
|
||||
throw Exception("Size of filter (" + toString(filt.size()) + ") doesn't match size of column (" + toString(s) + ")",
|
||||
ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
return ColumnConst::create(data, countBytesInFilter(filt));
|
||||
}
|
||||
|
||||
MutableColumnPtr ColumnConst::replicate(const Offsets & offsets) const
|
||||
{
|
||||
if (s != offsets.size())
|
||||
throw Exception("Size of offsets (" + toString(offsets.size()) + ") doesn't match size of column (" + toString(s) + ")",
|
||||
ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
size_t replicated_size = 0 == s ? 0 : offsets.back();
|
||||
return ColumnConst::create(data, replicated_size);
|
||||
}
|
||||
|
||||
MutableColumnPtr ColumnConst::permute(const Permutation & perm, size_t limit) const
|
||||
{
|
||||
if (limit == 0)
|
||||
limit = s;
|
||||
else
|
||||
limit = std::min(s, limit);
|
||||
|
||||
if (perm.size() < limit)
|
||||
throw Exception("Size of permutation (" + toString(perm.size()) + ") is less than required (" + toString(limit) + ")",
|
||||
ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
return ColumnConst::create(data, limit);
|
||||
}
|
||||
|
||||
MutableColumns ColumnConst::scatter(ColumnIndex num_columns, const Selector & selector) const
|
||||
{
|
||||
if (s != selector.size())
|
||||
throw Exception("Size of selector (" + toString(selector.size()) + ") doesn't match size of column (" + toString(s) + ")",
|
||||
ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
std::vector<size_t> counts(num_columns);
|
||||
for (auto idx : selector)
|
||||
++counts[idx];
|
||||
|
||||
MutableColumns res(num_columns);
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
res[i] = cloneResized(counts[i]);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void ColumnConst::getPermutation(bool /*reverse*/, size_t /*limit*/, int /*nan_direction_hint*/, Permutation & res) const
|
||||
{
|
||||
res.resize(s);
|
||||
for (size_t i = 0; i < s; ++i)
|
||||
res[i] = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <Core/Field.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Columns/IColumn.h>
|
||||
#include <Columns/ColumnsCommon.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -11,7 +10,6 @@ namespace DB
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int SIZES_OF_COLUMNS_DOESNT_MATCH;
|
||||
extern const int NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@ -19,18 +17,21 @@ namespace ErrorCodes
|
||||
/** ColumnConst contains another column with single element,
|
||||
* but looks like a column with arbitary amount of same elements.
|
||||
*/
|
||||
class ColumnConst final : public IColumn
|
||||
class ColumnConst final : public COWPtrHelper<IColumn, ColumnConst>
|
||||
{
|
||||
private:
|
||||
friend class COWPtrHelper<IColumn, ColumnConst>;
|
||||
|
||||
ColumnPtr data;
|
||||
size_t s;
|
||||
|
||||
ColumnConst(const ColumnPtr & data, size_t s);
|
||||
ColumnConst(const ColumnConst & src) = default;
|
||||
|
||||
public:
|
||||
ColumnConst(ColumnPtr data, size_t s);
|
||||
MutableColumnPtr convertToFullColumn() const;
|
||||
|
||||
ColumnPtr convertToFullColumn() const;
|
||||
|
||||
ColumnPtr convertToFullColumnIfConst() const override
|
||||
MutableColumnPtr convertToFullColumnIfConst() const override
|
||||
{
|
||||
return convertToFullColumn();
|
||||
}
|
||||
@ -45,9 +46,9 @@ public:
|
||||
return "Const";
|
||||
}
|
||||
|
||||
ColumnPtr cloneResized(size_t new_size) const override
|
||||
MutableColumnPtr cloneResized(size_t new_size) const override
|
||||
{
|
||||
return std::make_shared<ColumnConst>(data, new_size);
|
||||
return ColumnConst::create(data, new_size);
|
||||
}
|
||||
|
||||
size_t size() const override
|
||||
@ -132,8 +133,9 @@ public:
|
||||
|
||||
const char * deserializeAndInsertFromArena(const char * pos) override
|
||||
{
|
||||
auto res = data->deserializeAndInsertFromArena(pos);
|
||||
data->popBack(1);
|
||||
MutableColumnPtr mutable_data = data->assumeMutable();
|
||||
auto res = mutable_data->deserializeAndInsertFromArena(pos);
|
||||
mutable_data->popBack(1);
|
||||
++s;
|
||||
return res;
|
||||
}
|
||||
@ -143,22 +145,10 @@ public:
|
||||
data->updateHashWithValue(0, hash);
|
||||
}
|
||||
|
||||
ColumnPtr filter(const Filter & filt, ssize_t /*result_size_hint*/) const override
|
||||
{
|
||||
if (s != filt.size())
|
||||
throw Exception("Size of filter doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
return std::make_shared<ColumnConst>(data, countBytesInFilter(filt));
|
||||
}
|
||||
|
||||
ColumnPtr replicate(const Offsets_t & offsets) const override
|
||||
{
|
||||
if (s != offsets.size())
|
||||
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
size_t replicated_size = 0 == s ? 0 : offsets.back();
|
||||
return std::make_shared<ColumnConst>(data, replicated_size);
|
||||
}
|
||||
MutableColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override;
|
||||
MutableColumnPtr replicate(const Offsets & offsets) const override;
|
||||
MutableColumnPtr permute(const Permutation & perm, size_t limit) const override;
|
||||
void getPermutation(bool reverse, size_t limit, int nan_direction_hint, Permutation & res) const override;
|
||||
|
||||
size_t byteSize() const override
|
||||
{
|
||||
@ -170,46 +160,12 @@ public:
|
||||
return data->allocatedBytes() + sizeof(s);
|
||||
}
|
||||
|
||||
ColumnPtr permute(const Permutation & perm, size_t limit) const override
|
||||
{
|
||||
if (limit == 0)
|
||||
limit = s;
|
||||
else
|
||||
limit = std::min(s, limit);
|
||||
|
||||
if (perm.size() < limit)
|
||||
throw Exception("Size of permutation is less than required.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
return std::make_shared<ColumnConst>(data, limit);
|
||||
}
|
||||
|
||||
int compareAt(size_t, size_t, const IColumn & rhs, int nan_direction_hint) const override
|
||||
{
|
||||
return data->compareAt(0, 0, *static_cast<const ColumnConst &>(rhs).data, nan_direction_hint);
|
||||
}
|
||||
|
||||
void getPermutation(bool /*reverse*/, size_t /*limit*/, int /*nan_direction_hint*/, Permutation & res) const override
|
||||
{
|
||||
res.resize(s);
|
||||
for (size_t i = 0; i < s; ++i)
|
||||
res[i] = i;
|
||||
}
|
||||
|
||||
Columns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
{
|
||||
if (size() != selector.size())
|
||||
throw Exception("Size of selector doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
std::vector<size_t> counts(num_columns);
|
||||
for (auto idx : selector)
|
||||
++counts[idx];
|
||||
|
||||
Columns res(num_columns);
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
res[i] = cloneResized(counts[i]);
|
||||
|
||||
return res;
|
||||
}
|
||||
MutableColumns scatter(ColumnIndex num_columns, const Selector & selector) const override;
|
||||
|
||||
void gather(ColumnGathererStream &) override
|
||||
{
|
||||
@ -235,10 +191,11 @@ public:
|
||||
|
||||
/// Not part of the common interface.
|
||||
|
||||
IColumn & getDataColumn() { return *data; }
|
||||
IColumn & getDataColumn() { return *data->assumeMutable(); }
|
||||
const IColumn & getDataColumn() const { return *data; }
|
||||
ColumnPtr & getDataColumnPtr() { return data; }
|
||||
//MutableColumnPtr getDataColumnMutablePtr() { return data; }
|
||||
const ColumnPtr & getDataColumnPtr() const { return data; }
|
||||
//ColumnPtr & getDataColumnPtr() { return data; }
|
||||
|
||||
Field getField() const { return getDataColumn()[0]; }
|
||||
|
||||
|
@ -6,20 +6,22 @@ namespace DB
|
||||
{
|
||||
|
||||
ColumnExpression::ColumnExpression(
|
||||
size_t s_, ExpressionActionsPtr expression_, const NamesAndTypes & arguments_, DataTypePtr return_type_, std::string return_name_)
|
||||
: IColumnDummy(s_), expression(expression_), arguments(arguments_), return_type(return_type_), return_name(return_name_)
|
||||
size_t s_, const ExpressionActionsPtr & expression_, const NamesAndTypes & arguments_, const DataTypePtr & return_type_, const String & return_name_)
|
||||
: expression(expression_), arguments(arguments_), return_type(return_type_), return_name(return_name_)
|
||||
{
|
||||
s = s_;
|
||||
}
|
||||
|
||||
ColumnExpression::ColumnExpression(
|
||||
size_t s_, ExpressionActionsPtr expression_, const NamesAndTypesList & arguments_, DataTypePtr return_type_, std::string return_name_)
|
||||
: IColumnDummy(s_), expression(expression_), arguments(arguments_.begin(), arguments_.end()), return_type(return_type_), return_name(return_name_)
|
||||
size_t s_, const ExpressionActionsPtr & expression_, const NamesAndTypesList & arguments_, const DataTypePtr & return_type_, const String & return_name_)
|
||||
: expression(expression_), arguments(arguments_.begin(), arguments_.end()), return_type(return_type_), return_name(return_name_)
|
||||
{
|
||||
s = s_;
|
||||
}
|
||||
|
||||
ColumnPtr ColumnExpression::cloneDummy(size_t s_) const
|
||||
MutableColumnPtr ColumnExpression::cloneDummy(size_t s_) const
|
||||
{
|
||||
return std::make_shared<ColumnExpression>(s_, expression, arguments, return_type, return_name);
|
||||
return ColumnExpression::create(s_, expression, arguments, return_type, return_name);
|
||||
}
|
||||
|
||||
const ExpressionActionsPtr & ColumnExpression::getExpression() const { return expression; }
|
||||
|
@ -12,17 +12,21 @@ class ExpressionActions;
|
||||
/** A column containing a lambda expression.
|
||||
* Behaves like a constant-column. Contains an expression, but not input or output data.
|
||||
*/
|
||||
class ColumnExpression final : public IColumnDummy
|
||||
class ColumnExpression final : public COWPtrHelper<IColumnDummy, ColumnExpression>
|
||||
{
|
||||
private:
|
||||
friend class COWPtrHelper<IColumnDummy, ColumnExpression>;
|
||||
|
||||
using ExpressionActionsPtr = std::shared_ptr<ExpressionActions>;
|
||||
|
||||
public:
|
||||
ColumnExpression(size_t s_, ExpressionActionsPtr expression_, const NamesAndTypes & arguments_, DataTypePtr return_type_, String return_name_);
|
||||
ColumnExpression(size_t s_, ExpressionActionsPtr expression_, const NamesAndTypesList & arguments_, DataTypePtr return_type_, String return_name_);
|
||||
ColumnExpression(size_t s_, const ExpressionActionsPtr & expression_, const NamesAndTypes & arguments_, const DataTypePtr & return_type_, const String & return_name_);
|
||||
ColumnExpression(size_t s_, const ExpressionActionsPtr & expression_, const NamesAndTypesList & arguments_, const DataTypePtr & return_type_, const String & return_name_);
|
||||
|
||||
ColumnExpression(const ColumnExpression &) = default;
|
||||
|
||||
public:
|
||||
const char * getFamilyName() const override { return "Expression"; }
|
||||
ColumnPtr cloneDummy(size_t s_) const override;
|
||||
MutableColumnPtr cloneDummy(size_t s_) const override;
|
||||
|
||||
const ExpressionActionsPtr & getExpression() const;
|
||||
const DataTypePtr & getReturnType() const;
|
||||
|
@ -25,9 +25,9 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnFixedString::cloneResized(size_t size) const
|
||||
MutableColumnPtr ColumnFixedString::cloneResized(size_t size) const
|
||||
{
|
||||
ColumnPtr new_col_holder = std::make_shared<ColumnFixedString>(n);
|
||||
MutableColumnPtr new_col_holder = ColumnFixedString::create(n);
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
@ -153,13 +153,13 @@ void ColumnFixedString::insertRangeFrom(const IColumn & src, size_t start, size_
|
||||
memcpy(&chars[old_size], &src_concrete.chars[start * n], length * n);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnFixedString::filter(const IColumn::Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnFixedString::filter(const IColumn::Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
size_t col_size = size();
|
||||
if (col_size != filt.size())
|
||||
throw Exception("Size of filter doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
std::shared_ptr<ColumnFixedString> res = std::make_shared<ColumnFixedString>(n);
|
||||
auto res = ColumnFixedString::create(n);
|
||||
|
||||
if (result_size_hint)
|
||||
res->chars.reserve(result_size_hint > 0 ? result_size_hint * n : chars.size());
|
||||
@ -227,10 +227,10 @@ ColumnPtr ColumnFixedString::filter(const IColumn::Filter & filt, ssize_t result
|
||||
data_pos += n;
|
||||
}
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnFixedString::permute(const Permutation & perm, size_t limit) const
|
||||
MutableColumnPtr ColumnFixedString::permute(const Permutation & perm, size_t limit) const
|
||||
{
|
||||
size_t col_size = size();
|
||||
|
||||
@ -243,9 +243,9 @@ ColumnPtr ColumnFixedString::permute(const Permutation & perm, size_t limit) con
|
||||
throw Exception("Size of permutation is less than required.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
if (limit == 0)
|
||||
return std::make_shared<ColumnFixedString>(n);
|
||||
return ColumnFixedString::create(n);
|
||||
|
||||
std::shared_ptr<ColumnFixedString> res = std::make_shared<ColumnFixedString>(n);
|
||||
auto res = ColumnFixedString::create(n);
|
||||
|
||||
Chars_t & res_chars = res->chars;
|
||||
|
||||
@ -255,29 +255,29 @@ ColumnPtr ColumnFixedString::permute(const Permutation & perm, size_t limit) con
|
||||
for (size_t i = 0; i < limit; ++i, offset += n)
|
||||
memcpySmallAllowReadWriteOverflow15(&res_chars[offset], &chars[perm[i] * n], n);
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnFixedString::replicate(const Offsets_t & offsets) const
|
||||
MutableColumnPtr ColumnFixedString::replicate(const Offsets & offsets) const
|
||||
{
|
||||
size_t col_size = size();
|
||||
if (col_size != offsets.size())
|
||||
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
std::shared_ptr<ColumnFixedString> res = std::make_shared<ColumnFixedString>(n);
|
||||
auto res = ColumnFixedString::create(n);
|
||||
|
||||
if (0 == col_size)
|
||||
return res;
|
||||
return std::move(res);
|
||||
|
||||
Chars_t & res_chars = res->chars;
|
||||
res_chars.resize(n * offsets.back());
|
||||
|
||||
Offset_t curr_offset = 0;
|
||||
Offset curr_offset = 0;
|
||||
for (size_t i = 0; i < col_size; ++i)
|
||||
for (size_t next_offset = offsets[i]; curr_offset < next_offset; ++curr_offset)
|
||||
memcpySmallAllowReadWriteOverflow15(&res->chars[curr_offset * n], &chars[i * n], n);
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
void ColumnFixedString::gather(ColumnGathererStream & gatherer)
|
||||
|
@ -12,9 +12,11 @@ namespace DB
|
||||
/** A column of values of "fixed-length string" type.
|
||||
* If you insert a smaller string, it will be padded with zero bytes.
|
||||
*/
|
||||
class ColumnFixedString final : public IColumn
|
||||
class ColumnFixedString final : public COWPtrHelper<IColumn, ColumnFixedString>
|
||||
{
|
||||
public:
|
||||
friend class COWPtrHelper<IColumn, ColumnFixedString>;
|
||||
|
||||
using Chars_t = PaddedPODArray<UInt8>;
|
||||
|
||||
private:
|
||||
@ -29,14 +31,16 @@ private:
|
||||
template <bool positive>
|
||||
struct less;
|
||||
|
||||
public:
|
||||
/** Create an empty column of strings of fixed-length `n` */
|
||||
ColumnFixedString(size_t n_) : n(n_) {}
|
||||
|
||||
ColumnFixedString(const ColumnFixedString & src) : chars(src.chars.begin(), src.chars.end()), n(src.n) {};
|
||||
|
||||
public:
|
||||
std::string getName() const override { return "FixedString(" + std::to_string(n) + ")"; }
|
||||
const char * getFamilyName() const override { return "FixedString"; }
|
||||
|
||||
ColumnPtr cloneResized(size_t size) const override;
|
||||
MutableColumnPtr cloneResized(size_t size) const override;
|
||||
|
||||
size_t size() const override
|
||||
{
|
||||
@ -100,13 +104,13 @@ public:
|
||||
|
||||
void insertRangeFrom(const IColumn & src, size_t start, size_t length) override;
|
||||
|
||||
ColumnPtr filter(const IColumn::Filter & filt, ssize_t result_size_hint) const override;
|
||||
MutableColumnPtr filter(const IColumn::Filter & filt, ssize_t result_size_hint) const override;
|
||||
|
||||
ColumnPtr permute(const Permutation & perm, size_t limit) const override;
|
||||
MutableColumnPtr permute(const Permutation & perm, size_t limit) const override;
|
||||
|
||||
ColumnPtr replicate(const Offsets_t & offsets) const override;
|
||||
MutableColumnPtr replicate(const Offsets & offsets) const override;
|
||||
|
||||
Columns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
MutableColumns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
{
|
||||
return scatterImpl<ColumnFixedString>(num_columns, selector);
|
||||
}
|
||||
|
@ -6,13 +6,21 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
class ColumnNothing final : public IColumnDummy
|
||||
class ColumnNothing final : public COWPtrHelper<IColumnDummy, ColumnNothing>
|
||||
{
|
||||
public:
|
||||
using IColumnDummy::IColumnDummy;
|
||||
private:
|
||||
friend class COWPtrHelper<IColumnDummy, ColumnNothing>;
|
||||
|
||||
ColumnNothing(size_t s_)
|
||||
{
|
||||
s = s_;
|
||||
}
|
||||
|
||||
ColumnNothing(const ColumnNothing &) = default;
|
||||
|
||||
public:
|
||||
const char * getFamilyName() const override { return "Nothing"; }
|
||||
ColumnPtr cloneDummy(size_t s) const override { return std::make_shared<ColumnNothing>(s); };
|
||||
MutableColumnPtr cloneDummy(size_t s) const override { return ColumnNothing::create(s); };
|
||||
|
||||
bool canBeInsideNullable() const override { return true; }
|
||||
};
|
||||
|
@ -18,14 +18,14 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
ColumnNullable::ColumnNullable(ColumnPtr nested_column_, ColumnPtr null_map_)
|
||||
ColumnNullable::ColumnNullable(const ColumnPtr & nested_column_, const ColumnPtr & null_map_)
|
||||
: nested_column{nested_column_}, null_map{null_map_}
|
||||
{
|
||||
/// ColumnNullable cannot have constant nested column. But constant argument could be passed. Materialize it.
|
||||
if (auto nested_column_materialized = nested_column->convertToFullColumnIfConst())
|
||||
if (ColumnPtr nested_column_materialized = getNestedColumn().convertToFullColumnIfConst())
|
||||
nested_column = nested_column_materialized;
|
||||
|
||||
if (!nested_column->canBeInsideNullable())
|
||||
if (!getNestedColumn().canBeInsideNullable())
|
||||
throw Exception{getName() + " cannot be inside Nullable column", ErrorCodes::ILLEGAL_COLUMN};
|
||||
|
||||
if (null_map->isColumnConst())
|
||||
@ -35,43 +35,37 @@ ColumnNullable::ColumnNullable(ColumnPtr nested_column_, ColumnPtr null_map_)
|
||||
|
||||
void ColumnNullable::updateHashWithValue(size_t n, SipHash & hash) const
|
||||
{
|
||||
const auto & arr = getNullMap();
|
||||
const auto & arr = getNullMapData();
|
||||
hash.update(reinterpret_cast<const char *>(&arr[n]), sizeof(arr[0]));
|
||||
if (arr[n] == 0)
|
||||
nested_column->updateHashWithValue(n, hash);
|
||||
getNestedColumn().updateHashWithValue(n, hash);
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnNullable::cloneResized(size_t new_size) const
|
||||
MutableColumnPtr ColumnNullable::cloneResized(size_t new_size) const
|
||||
{
|
||||
ColumnPtr new_nested_col = nested_column->cloneResized(new_size);
|
||||
auto new_null_map = std::make_shared<ColumnUInt8>();
|
||||
ColumnPtr new_nested_col = getNestedColumn().cloneResized(new_size);
|
||||
auto new_null_map = ColumnUInt8::create();
|
||||
|
||||
if (new_size > 0)
|
||||
{
|
||||
new_null_map->getData().resize(new_size);
|
||||
|
||||
size_t count = std::min(size(), new_size);
|
||||
memcpy(new_null_map->getData().data(), getNullMap().data(), count * sizeof(getNullMap()[0]));
|
||||
memcpy(new_null_map->getData().data(), getNullMapData().data(), count * sizeof(getNullMapData()[0]));
|
||||
|
||||
/// If resizing to bigger one, set all new values to NULLs.
|
||||
if (new_size > count)
|
||||
memset(&new_null_map->getData()[count], 1, new_size - count);
|
||||
}
|
||||
|
||||
return std::make_shared<ColumnNullable>(new_nested_col, new_null_map);
|
||||
return ColumnNullable::create(new_nested_col, std::move(new_null_map));
|
||||
}
|
||||
|
||||
|
||||
Field ColumnNullable::operator[](size_t n) const
|
||||
{
|
||||
if (isNullAt(n))
|
||||
return Null();
|
||||
else
|
||||
{
|
||||
const IColumn & col = *nested_column;
|
||||
return col[n];
|
||||
}
|
||||
return isNullAt(n) ? Null() : getNestedColumn()[n];
|
||||
}
|
||||
|
||||
|
||||
@ -80,7 +74,7 @@ void ColumnNullable::get(size_t n, Field & res) const
|
||||
if (isNullAt(n))
|
||||
res = Null();
|
||||
else
|
||||
nested_column->get(n, res);
|
||||
getNestedColumn().get(n, res);
|
||||
}
|
||||
|
||||
StringRef ColumnNullable::getDataAt(size_t /*n*/) const
|
||||
@ -95,7 +89,7 @@ void ColumnNullable::insertData(const char * /*pos*/, size_t /*length*/)
|
||||
|
||||
StringRef ColumnNullable::serializeValueIntoArena(size_t n, Arena & arena, char const *& begin) const
|
||||
{
|
||||
const auto & arr = getNullMap();
|
||||
const auto & arr = getNullMapData();
|
||||
static constexpr auto s = sizeof(arr[0]);
|
||||
|
||||
auto pos = arena.allocContinue(s, begin);
|
||||
@ -104,7 +98,7 @@ StringRef ColumnNullable::serializeValueIntoArena(size_t n, Arena & arena, char
|
||||
size_t nested_size = 0;
|
||||
|
||||
if (arr[n] == 0)
|
||||
nested_size = nested_column->serializeValueIntoArena(n, arena, begin).size;
|
||||
nested_size = getNestedColumn().serializeValueIntoArena(n, arena, begin).size;
|
||||
|
||||
return StringRef{begin, s + nested_size};
|
||||
}
|
||||
@ -114,12 +108,12 @@ const char * ColumnNullable::deserializeAndInsertFromArena(const char * pos)
|
||||
UInt8 val = *reinterpret_cast<const UInt8 *>(pos);
|
||||
pos += sizeof(val);
|
||||
|
||||
getNullMap().push_back(val);
|
||||
getNullMapData().push_back(val);
|
||||
|
||||
if (val == 0)
|
||||
pos = nested_column->deserializeAndInsertFromArena(pos);
|
||||
pos = getNestedColumn().deserializeAndInsertFromArena(pos);
|
||||
else
|
||||
nested_column->insertDefault();
|
||||
getNestedColumn().insertDefault();
|
||||
|
||||
return pos;
|
||||
}
|
||||
@ -127,49 +121,49 @@ const char * ColumnNullable::deserializeAndInsertFromArena(const char * pos)
|
||||
void ColumnNullable::insertRangeFrom(const IColumn & src, size_t start, size_t length)
|
||||
{
|
||||
const ColumnNullable & nullable_col = static_cast<const ColumnNullable &>(src);
|
||||
getNullMapConcreteColumn().insertRangeFrom(*nullable_col.null_map, start, length);
|
||||
nested_column->insertRangeFrom(*nullable_col.nested_column, start, length);
|
||||
getNullMapColumn().insertRangeFrom(*nullable_col.null_map, start, length);
|
||||
getNestedColumn().insertRangeFrom(*nullable_col.nested_column, start, length);
|
||||
}
|
||||
|
||||
void ColumnNullable::insert(const Field & x)
|
||||
{
|
||||
if (x.isNull())
|
||||
{
|
||||
nested_column->insertDefault();
|
||||
getNullMap().push_back(1);
|
||||
getNestedColumn().insertDefault();
|
||||
getNullMapData().push_back(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
nested_column->insert(x);
|
||||
getNullMap().push_back(0);
|
||||
getNestedColumn().insert(x);
|
||||
getNullMapData().push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ColumnNullable::insertFrom(const IColumn & src, size_t n)
|
||||
{
|
||||
const ColumnNullable & src_concrete = static_cast<const ColumnNullable &>(src);
|
||||
nested_column->insertFrom(*src_concrete.getNestedColumn(), n);
|
||||
getNullMap().push_back(src_concrete.getNullMap()[n]);
|
||||
getNestedColumn().insertFrom(src_concrete.getNestedColumn(), n);
|
||||
getNullMapData().push_back(src_concrete.getNullMapData()[n]);
|
||||
}
|
||||
|
||||
void ColumnNullable::popBack(size_t n)
|
||||
{
|
||||
nested_column->popBack(n);
|
||||
getNullMapConcreteColumn().popBack(n);
|
||||
getNestedColumn().popBack(n);
|
||||
getNullMapColumn().popBack(n);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnNullable::filter(const Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnNullable::filter(const Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
ColumnPtr filtered_data = nested_column->filter(filt, result_size_hint);
|
||||
ColumnPtr filtered_null_map = getNullMapConcreteColumn().filter(filt, result_size_hint);
|
||||
return std::make_shared<ColumnNullable>(filtered_data, filtered_null_map);
|
||||
ColumnPtr filtered_data = getNestedColumn().filter(filt, result_size_hint);
|
||||
ColumnPtr filtered_null_map = getNullMapColumn().filter(filt, result_size_hint);
|
||||
return ColumnNullable::create(filtered_data, filtered_null_map);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnNullable::permute(const Permutation & perm, size_t limit) const
|
||||
MutableColumnPtr ColumnNullable::permute(const Permutation & perm, size_t limit) const
|
||||
{
|
||||
ColumnPtr permuted_data = nested_column->permute(perm, limit);
|
||||
ColumnPtr permuted_null_map = getNullMapConcreteColumn().permute(perm, limit);
|
||||
return std::make_shared<ColumnNullable>(permuted_data, permuted_null_map);
|
||||
ColumnPtr permuted_data = getNestedColumn().permute(perm, limit);
|
||||
ColumnPtr permuted_null_map = getNullMapColumn().permute(perm, limit);
|
||||
return ColumnNullable::create(permuted_data, permuted_null_map);
|
||||
}
|
||||
|
||||
int ColumnNullable::compareAt(size_t n, size_t m, const IColumn & rhs_, int null_direction_hint) const
|
||||
@ -193,14 +187,14 @@ int ColumnNullable::compareAt(size_t n, size_t m, const IColumn & rhs_, int null
|
||||
return lval_is_null ? null_direction_hint : -null_direction_hint;
|
||||
}
|
||||
|
||||
const IColumn & nested_rhs = *(nullable_rhs.getNestedColumn());
|
||||
return nested_column->compareAt(n, m, nested_rhs, null_direction_hint);
|
||||
const IColumn & nested_rhs = nullable_rhs.getNestedColumn();
|
||||
return getNestedColumn().compareAt(n, m, nested_rhs, null_direction_hint);
|
||||
}
|
||||
|
||||
void ColumnNullable::getPermutation(bool reverse, size_t limit, int null_direction_hint, Permutation & res) const
|
||||
{
|
||||
/// Cannot pass limit because of unknown amount of NULLs.
|
||||
nested_column->getPermutation(reverse, 0, null_direction_hint, res);
|
||||
getNestedColumn().getPermutation(reverse, 0, null_direction_hint, res);
|
||||
|
||||
if ((null_direction_hint > 0) != reverse)
|
||||
{
|
||||
@ -277,18 +271,18 @@ void ColumnNullable::gather(ColumnGathererStream & gatherer)
|
||||
|
||||
void ColumnNullable::reserve(size_t n)
|
||||
{
|
||||
nested_column->reserve(n);
|
||||
getNullMap().reserve(n);
|
||||
getNestedColumn().reserve(n);
|
||||
getNullMapData().reserve(n);
|
||||
}
|
||||
|
||||
size_t ColumnNullable::byteSize() const
|
||||
{
|
||||
return nested_column->byteSize() + getNullMapConcreteColumn().byteSize();
|
||||
return getNestedColumn().byteSize() + getNullMapColumn().byteSize();
|
||||
}
|
||||
|
||||
size_t ColumnNullable::allocatedBytes() const
|
||||
{
|
||||
return nested_column->allocatedBytes() + getNullMapConcreteColumn().allocatedBytes();
|
||||
return getNestedColumn().allocatedBytes() + getNullMapColumn().allocatedBytes();
|
||||
}
|
||||
|
||||
|
||||
@ -365,7 +359,7 @@ void ColumnNullable::getExtremes(Field & min, Field & max) const
|
||||
min = Null();
|
||||
max = Null();
|
||||
|
||||
const auto & null_map = getNullMap();
|
||||
const auto & null_map = getNullMapData();
|
||||
|
||||
if (const auto col = typeid_cast<const ColumnInt8 *>(nested_column.get()))
|
||||
getExtremesFromNullableContent<Int8>(*col, null_map, min, max);
|
||||
@ -390,18 +384,18 @@ void ColumnNullable::getExtremes(Field & min, Field & max) const
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnNullable::replicate(const Offsets_t & offsets) const
|
||||
MutableColumnPtr ColumnNullable::replicate(const Offsets & offsets) const
|
||||
{
|
||||
ColumnPtr replicated_data = nested_column->replicate(offsets);
|
||||
ColumnPtr replicated_null_map = getNullMapConcreteColumn().replicate(offsets);
|
||||
return std::make_shared<ColumnNullable>(replicated_data, replicated_null_map);
|
||||
ColumnPtr replicated_data = getNestedColumn().replicate(offsets);
|
||||
ColumnPtr replicated_null_map = getNullMapColumn().replicate(offsets);
|
||||
return ColumnNullable::create(replicated_data, replicated_null_map);
|
||||
}
|
||||
|
||||
|
||||
template <bool negative>
|
||||
void ColumnNullable::applyNullMapImpl(const ColumnUInt8 & map)
|
||||
{
|
||||
NullMap & arr1 = getNullMap();
|
||||
NullMap & arr1 = getNullMapData();
|
||||
const NullMap & arr2 = map.getData();
|
||||
|
||||
if (arr1.size() != arr2.size())
|
||||
@ -425,13 +419,13 @@ void ColumnNullable::applyNegatedNullMap(const ColumnUInt8 & map)
|
||||
|
||||
void ColumnNullable::applyNullMap(const ColumnNullable & other)
|
||||
{
|
||||
applyNullMap(other.getNullMapConcreteColumn());
|
||||
applyNullMap(other.getNullMapColumn());
|
||||
}
|
||||
|
||||
|
||||
void ColumnNullable::checkConsistency() const
|
||||
{
|
||||
if (null_map->size() != nested_column->size())
|
||||
if (null_map->size() != getNestedColumn().size())
|
||||
throw Exception("Logical error: Sizes of nested column and null map of Nullable column are not equal",
|
||||
ErrorCodes::SIZES_OF_NESTED_COLUMNS_ARE_INCONSISTENT);
|
||||
}
|
||||
@ -443,9 +437,9 @@ ColumnPtr makeNullable(const ColumnPtr & column)
|
||||
return column;
|
||||
|
||||
if (column->isColumnConst())
|
||||
return std::make_shared<ColumnConst>(makeNullable(static_cast<ColumnConst &>(*column).getDataColumnPtr()), column->size());
|
||||
return ColumnConst::create(makeNullable(static_cast<const ColumnConst &>(*column).getDataColumnPtr()), column->size());
|
||||
|
||||
return std::make_shared<ColumnNullable>(column, std::make_shared<ColumnUInt8>(column->size(), 0));
|
||||
return ColumnNullable::create(column, ColumnUInt8::create(column->size(), 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
using NullMap = ColumnUInt8::Container_t;
|
||||
using NullMap = ColumnUInt8::Container;
|
||||
using ConstNullMapPtr = const NullMap *;
|
||||
|
||||
/// Class that specifies nullable columns. A nullable column represents
|
||||
@ -18,13 +18,18 @@ using ConstNullMapPtr = const NullMap *;
|
||||
/// over a bitmap because columns are usually stored on disk as compressed
|
||||
/// files. In this regard, using a bitmap instead of a byte map would
|
||||
/// greatly complicate the implementation with little to no benefits.
|
||||
class ColumnNullable final : public IColumn
|
||||
class ColumnNullable final : public COWPtrHelper<IColumn, ColumnNullable>
|
||||
{
|
||||
private:
|
||||
friend class COWPtrHelper<IColumn, ColumnNullable>;
|
||||
|
||||
ColumnNullable(const ColumnPtr & nested_column_, const ColumnPtr & null_map_);
|
||||
ColumnNullable(const ColumnNullable &) = default;
|
||||
|
||||
public:
|
||||
ColumnNullable(ColumnPtr nested_column_, ColumnPtr null_map_);
|
||||
const char * getFamilyName() const override { return "Nullable"; }
|
||||
std::string getName() const override { return "Nullable(" + nested_column->getName() + ")"; }
|
||||
ColumnPtr cloneResized(size_t size) const override;
|
||||
MutableColumnPtr cloneResized(size_t size) const override;
|
||||
size_t size() const override { return nested_column->size(); }
|
||||
bool isNullAt(size_t n) const override { return static_cast<const ColumnUInt8 &>(*null_map).getData()[n] != 0;}
|
||||
Field operator[](size_t n) const override;
|
||||
@ -40,23 +45,23 @@ public:
|
||||
|
||||
void insertDefault() override
|
||||
{
|
||||
nested_column->insertDefault();
|
||||
getNullMap().push_back(1);
|
||||
getNestedColumn().insertDefault();
|
||||
getNullMapData().push_back(1);
|
||||
}
|
||||
|
||||
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;
|
||||
MutableColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override;
|
||||
MutableColumnPtr permute(const Permutation & perm, size_t limit) 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, int null_direction_hint, Permutation & res) const override;
|
||||
void reserve(size_t n) override;
|
||||
size_t byteSize() const override;
|
||||
size_t allocatedBytes() const override;
|
||||
ColumnPtr replicate(const Offsets_t & replicate_offsets) const override;
|
||||
MutableColumnPtr replicate(const Offsets & replicate_offsets) const override;
|
||||
void updateHashWithValue(size_t n, SipHash & hash) const override;
|
||||
void getExtremes(Field & min, Field & max) const override;
|
||||
|
||||
Columns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
MutableColumns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
{
|
||||
return scatterImpl<ColumnNullable>(num_columns, selector);
|
||||
}
|
||||
@ -76,18 +81,21 @@ public:
|
||||
|
||||
|
||||
/// Return the column that represents values.
|
||||
ColumnPtr & getNestedColumn() { return nested_column; }
|
||||
const ColumnPtr & getNestedColumn() const { return nested_column; }
|
||||
IColumn & getNestedColumn() { return *nested_column->assumeMutable(); }
|
||||
const IColumn & getNestedColumn() const { return *nested_column; }
|
||||
|
||||
//ColumnPtr & getNestedColumnPtr() { return nested_column->assumeMutable(); }
|
||||
const ColumnPtr & getNestedColumnPtr() const { return nested_column; }
|
||||
|
||||
/// Return the column that represents the byte map.
|
||||
ColumnPtr & getNullMapColumn() { return null_map; }
|
||||
const ColumnPtr & getNullMapColumn() const { return null_map; }
|
||||
//ColumnPtr & getNullMapColumnPtr() { return null_map; }
|
||||
const ColumnPtr & getNullMapColumnPtr() const { return null_map; }
|
||||
|
||||
ColumnUInt8 & getNullMapConcreteColumn() { return static_cast<ColumnUInt8 &>(*null_map); }
|
||||
const ColumnUInt8 & getNullMapConcreteColumn() const { return static_cast<const ColumnUInt8 &>(*null_map); }
|
||||
ColumnUInt8 & getNullMapColumn() { return static_cast<ColumnUInt8 &>(*null_map->assumeMutable()); }
|
||||
const ColumnUInt8 & getNullMapColumn() const { return static_cast<const ColumnUInt8 &>(*null_map); }
|
||||
|
||||
NullMap & getNullMap() { return getNullMapConcreteColumn().getData(); }
|
||||
const NullMap & getNullMap() const { return getNullMapConcreteColumn().getData(); }
|
||||
NullMap & getNullMapData() { return getNullMapColumn().getData(); }
|
||||
const NullMap & getNullMapData() const { return getNullMapColumn().getData(); }
|
||||
|
||||
/// Apply the null byte map of a specified nullable column onto the
|
||||
/// null byte map of the current column by performing an element-wise OR
|
||||
|
@ -14,13 +14,17 @@ using ConstSetPtr = std::shared_ptr<const Set>;
|
||||
* Behaves like a constant-column (because the set is one, not its own for each line).
|
||||
* This column has a nonstandard value, so it can not be obtained via a normal interface.
|
||||
*/
|
||||
class ColumnSet final : public IColumnDummy
|
||||
class ColumnSet final : public COWPtrHelper<IColumnDummy, ColumnSet>
|
||||
{
|
||||
public:
|
||||
ColumnSet(size_t s_, const ConstSetPtr & data_) : IColumnDummy(s_), data(data_) {}
|
||||
private:
|
||||
friend class COWPtrHelper<IColumnDummy, ColumnSet>;
|
||||
|
||||
ColumnSet(size_t s_, const ConstSetPtr & data_) : data(data_) { s = s_; }
|
||||
ColumnSet(const ColumnSet &) = default;
|
||||
|
||||
public:
|
||||
const char * getFamilyName() const override { return "Set"; }
|
||||
ColumnPtr cloneDummy(size_t s_) const override { return std::make_shared<ColumnSet>(s_, data); }
|
||||
MutableColumnPtr cloneDummy(size_t s_) const override { return ColumnSet::create(s_, data); }
|
||||
|
||||
ConstSetPtr getData() const { return data; }
|
||||
|
||||
|
@ -19,12 +19,12 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnString::cloneResized(size_t to_size) const
|
||||
MutableColumnPtr ColumnString::cloneResized(size_t to_size) const
|
||||
{
|
||||
auto res = std::make_shared<ColumnString>();
|
||||
auto res = ColumnString::create();
|
||||
|
||||
if (to_size == 0)
|
||||
return res;
|
||||
return std::move(res);
|
||||
|
||||
size_t from_size = size();
|
||||
|
||||
@ -39,7 +39,7 @@ ColumnPtr ColumnString::cloneResized(size_t to_size) const
|
||||
{
|
||||
/// Copy column and append empty strings for extra elements.
|
||||
|
||||
Offset_t offset = 0;
|
||||
Offset offset = 0;
|
||||
if (from_size > 0)
|
||||
{
|
||||
res->offsets.assign(offsets.begin(), offsets.end());
|
||||
@ -59,7 +59,7 @@ ColumnPtr ColumnString::cloneResized(size_t to_size) const
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
|
||||
@ -97,22 +97,22 @@ void ColumnString::insertRangeFrom(const IColumn & src, size_t start, size_t len
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnString::filter(const Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnString::filter(const Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
if (offsets.size() == 0)
|
||||
return std::make_shared<ColumnString>();
|
||||
return ColumnString::create();
|
||||
|
||||
auto res = std::make_shared<ColumnString>();
|
||||
auto res = ColumnString::create();
|
||||
|
||||
Chars_t & res_chars = res->chars;
|
||||
Offsets_t & res_offsets = res->offsets;
|
||||
Offsets & res_offsets = res->offsets;
|
||||
|
||||
filterArraysImpl<UInt8>(chars, offsets, res_chars, res_offsets, filt, result_size_hint);
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnString::permute(const Permutation & perm, size_t limit) const
|
||||
MutableColumnPtr ColumnString::permute(const Permutation & perm, size_t limit) const
|
||||
{
|
||||
size_t size = offsets.size();
|
||||
|
||||
@ -125,12 +125,12 @@ ColumnPtr ColumnString::permute(const Permutation & perm, size_t limit) const
|
||||
throw Exception("Size of permutation is less than required.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
if (limit == 0)
|
||||
return std::make_shared<ColumnString>();
|
||||
return ColumnString::create();
|
||||
|
||||
std::shared_ptr<ColumnString> res = std::make_shared<ColumnString>();
|
||||
auto res = ColumnString::create();
|
||||
|
||||
Chars_t & res_chars = res->chars;
|
||||
Offsets_t & res_offsets = res->offsets;
|
||||
Offsets & res_offsets = res->offsets;
|
||||
|
||||
if (limit == size)
|
||||
res_chars.resize(chars.size());
|
||||
@ -144,7 +144,7 @@ ColumnPtr ColumnString::permute(const Permutation & perm, size_t limit) const
|
||||
|
||||
res_offsets.resize(limit);
|
||||
|
||||
Offset_t current_new_offset = 0;
|
||||
Offset current_new_offset = 0;
|
||||
|
||||
for (size_t i = 0; i < limit; ++i)
|
||||
{
|
||||
@ -158,7 +158,7 @@ ColumnPtr ColumnString::permute(const Permutation & perm, size_t limit) const
|
||||
res_offsets[i] = current_new_offset;
|
||||
}
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
|
||||
@ -208,25 +208,25 @@ void ColumnString::getPermutation(bool reverse, size_t limit, int /*nan_directio
|
||||
}
|
||||
|
||||
|
||||
ColumnPtr ColumnString::replicate(const Offsets_t & replicate_offsets) const
|
||||
MutableColumnPtr ColumnString::replicate(const Offsets & 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);
|
||||
|
||||
std::shared_ptr<ColumnString> res = std::make_shared<ColumnString>();
|
||||
auto res = ColumnString::create();
|
||||
|
||||
if (0 == col_size)
|
||||
return res;
|
||||
return std::move(res);
|
||||
|
||||
Chars_t & res_chars = res->chars;
|
||||
Offsets_t & res_offsets = res->offsets;
|
||||
Offsets & res_offsets = res->offsets;
|
||||
res_chars.reserve(chars.size() / col_size * replicate_offsets.back());
|
||||
res_offsets.reserve(replicate_offsets.back());
|
||||
|
||||
Offset_t prev_replicate_offset = 0;
|
||||
Offset_t prev_string_offset = 0;
|
||||
Offset_t current_new_offset = 0;
|
||||
Offset prev_replicate_offset = 0;
|
||||
Offset prev_string_offset = 0;
|
||||
Offset current_new_offset = 0;
|
||||
|
||||
for (size_t i = 0; i < col_size; ++i)
|
||||
{
|
||||
@ -247,7 +247,7 @@ ColumnPtr ColumnString::replicate(const Offsets_t & replicate_offsets) const
|
||||
prev_string_offset = offsets[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,23 +17,25 @@ namespace DB
|
||||
|
||||
/** Column for String values.
|
||||
*/
|
||||
class ColumnString final : public IColumn
|
||||
class ColumnString final : public COWPtrHelper<IColumn, ColumnString>
|
||||
{
|
||||
public:
|
||||
using Chars_t = PaddedPODArray<UInt8>;
|
||||
|
||||
private:
|
||||
friend class COWPtrHelper<IColumn, ColumnString>;
|
||||
|
||||
/// Maps i'th position to offset to i+1'th element. Last offset maps to the end of all chars (is the size of all chars).
|
||||
Offsets_t offsets;
|
||||
Offsets offsets;
|
||||
|
||||
/// Bytes of strings, placed contiguously.
|
||||
/// For convenience, every string ends with terminating zero byte. Note that strings could contain zero bytes in the middle.
|
||||
Chars_t chars;
|
||||
|
||||
size_t __attribute__((__always_inline__)) offsetAt(size_t i) const { return i == 0 ? 0 : offsets[i - 1]; }
|
||||
size_t ALWAYS_INLINE offsetAt(size_t i) const { return i == 0 ? 0 : offsets[i - 1]; }
|
||||
|
||||
/// Size of i-th element, including terminating zero.
|
||||
size_t __attribute__((__always_inline__)) sizeAt(size_t i) const { return i == 0 ? offsets[0] : (offsets[i] - offsets[i - 1]); }
|
||||
size_t ALWAYS_INLINE sizeAt(size_t i) const { return i == 0 ? offsets[0] : (offsets[i] - offsets[i - 1]); }
|
||||
|
||||
template <bool positive>
|
||||
struct less;
|
||||
@ -41,6 +43,12 @@ private:
|
||||
template <bool positive>
|
||||
struct lessWithCollation;
|
||||
|
||||
ColumnString() = default;
|
||||
|
||||
ColumnString(const ColumnString & src)
|
||||
: offsets(src.offsets.begin(), src.offsets.end()),
|
||||
chars(src.chars.begin(), src.chars.end()) {};
|
||||
|
||||
public:
|
||||
const char * getFamilyName() const override { return "String"; }
|
||||
|
||||
@ -59,7 +67,7 @@ public:
|
||||
return chars.allocated_bytes() + offsets.allocated_bytes();
|
||||
}
|
||||
|
||||
ColumnPtr cloneResized(size_t to_size) const override;
|
||||
MutableColumnPtr cloneResized(size_t to_size) const override;
|
||||
|
||||
Field operator[](size_t n) const override
|
||||
{
|
||||
@ -198,9 +206,9 @@ public:
|
||||
|
||||
void insertRangeFrom(const IColumn & src, size_t start, size_t length) override;
|
||||
|
||||
ColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override;
|
||||
MutableColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override;
|
||||
|
||||
ColumnPtr permute(const Permutation & perm, size_t limit) const override;
|
||||
MutableColumnPtr permute(const Permutation & perm, size_t limit) const override;
|
||||
|
||||
void insertDefault() override
|
||||
{
|
||||
@ -231,9 +239,9 @@ public:
|
||||
/// Sorting with respect of collation.
|
||||
void getPermutationWithCollation(const Collator & collator, bool reverse, size_t limit, Permutation & res) const;
|
||||
|
||||
ColumnPtr replicate(const Offsets_t & replicate_offsets) const override;
|
||||
MutableColumnPtr replicate(const Offsets & replicate_offsets) const override;
|
||||
|
||||
Columns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
MutableColumns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
{
|
||||
return scatterImpl<ColumnString>(num_columns, selector);
|
||||
}
|
||||
@ -251,8 +259,8 @@ public:
|
||||
Chars_t & getChars() { return chars; }
|
||||
const Chars_t & getChars() const { return chars; }
|
||||
|
||||
Offsets_t & getOffsets() { return offsets; }
|
||||
const Offsets_t & getOffsets() const { return offsets; }
|
||||
Offsets & getOffsets() { return offsets; }
|
||||
const Offsets & getOffsets() const { return offsets; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -38,14 +38,14 @@ ColumnTuple::ColumnTuple(const Columns & columns) : columns(columns)
|
||||
throw Exception{"ColumnTuple cannot have ColumnConst as its element", ErrorCodes::ILLEGAL_COLUMN};
|
||||
}
|
||||
|
||||
ColumnPtr ColumnTuple::cloneEmpty() const
|
||||
MutableColumnPtr ColumnTuple::cloneEmpty() const
|
||||
{
|
||||
const size_t tuple_size = columns.size();
|
||||
Columns new_columns(tuple_size);
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
new_columns[i] = columns[i]->cloneEmpty();
|
||||
|
||||
return std::make_shared<ColumnTuple>(new_columns);
|
||||
return ColumnTuple::create(new_columns);
|
||||
}
|
||||
|
||||
Field ColumnTuple::operator[](size_t n) const
|
||||
@ -81,7 +81,7 @@ void ColumnTuple::insert(const Field & x)
|
||||
throw Exception("Cannot insert value of different size into tuple", ErrorCodes::CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE);
|
||||
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
columns[i]->insert(tuple[i]);
|
||||
columns[i]->assumeMutable()->insert(tuple[i]);
|
||||
}
|
||||
|
||||
void ColumnTuple::insertFrom(const IColumn & src_, size_t n)
|
||||
@ -93,19 +93,19 @@ void ColumnTuple::insertFrom(const IColumn & src_, size_t n)
|
||||
throw Exception("Cannot insert value of different size into tuple", ErrorCodes::CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE);
|
||||
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
columns[i]->insertFrom(*src.columns[i], n);
|
||||
columns[i]->assumeMutable()->insertFrom(*src.columns[i], n);
|
||||
}
|
||||
|
||||
void ColumnTuple::insertDefault()
|
||||
{
|
||||
for (auto & column : columns)
|
||||
column->insertDefault();
|
||||
column->assumeMutable()->insertDefault();
|
||||
}
|
||||
|
||||
void ColumnTuple::popBack(size_t n)
|
||||
{
|
||||
for (auto & column : columns)
|
||||
column->popBack(n);
|
||||
column->assumeMutable()->popBack(n);
|
||||
}
|
||||
|
||||
StringRef ColumnTuple::serializeValueIntoArena(size_t n, Arena & arena, char const *& begin) const
|
||||
@ -120,7 +120,7 @@ StringRef ColumnTuple::serializeValueIntoArena(size_t n, Arena & arena, char con
|
||||
const char * ColumnTuple::deserializeAndInsertFromArena(const char * pos)
|
||||
{
|
||||
for (auto & column : columns)
|
||||
pos = column->deserializeAndInsertFromArena(pos);
|
||||
pos = column->assumeMutable()->deserializeAndInsertFromArena(pos);
|
||||
|
||||
return pos;
|
||||
}
|
||||
@ -135,12 +135,12 @@ void ColumnTuple::insertRangeFrom(const IColumn & src, size_t start, size_t leng
|
||||
{
|
||||
const size_t tuple_size = columns.size();
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
columns[i]->insertRangeFrom(
|
||||
columns[i]->assumeMutable()->insertRangeFrom(
|
||||
*static_cast<const ColumnTuple &>(src).columns[i],
|
||||
start, length);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnTuple::filter(const Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnTuple::filter(const Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
const size_t tuple_size = columns.size();
|
||||
Columns new_columns(tuple_size);
|
||||
@ -148,10 +148,10 @@ ColumnPtr ColumnTuple::filter(const Filter & filt, ssize_t result_size_hint) con
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
new_columns[i] = columns[i]->filter(filt, result_size_hint);
|
||||
|
||||
return std::make_shared<ColumnTuple>(new_columns);
|
||||
return ColumnTuple::create(new_columns);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnTuple::permute(const Permutation & perm, size_t limit) const
|
||||
MutableColumnPtr ColumnTuple::permute(const Permutation & perm, size_t limit) const
|
||||
{
|
||||
const size_t tuple_size = columns.size();
|
||||
Columns new_columns(tuple_size);
|
||||
@ -159,10 +159,10 @@ ColumnPtr ColumnTuple::permute(const Permutation & perm, size_t limit) const
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
new_columns[i] = columns[i]->permute(perm, limit);
|
||||
|
||||
return std::make_shared<ColumnTuple>(new_columns);
|
||||
return ColumnTuple::create(new_columns);
|
||||
}
|
||||
|
||||
ColumnPtr ColumnTuple::replicate(const Offsets_t & offsets) const
|
||||
MutableColumnPtr ColumnTuple::replicate(const Offsets & offsets) const
|
||||
{
|
||||
const size_t tuple_size = columns.size();
|
||||
Columns new_columns(tuple_size);
|
||||
@ -170,25 +170,25 @@ ColumnPtr ColumnTuple::replicate(const Offsets_t & offsets) const
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
new_columns[i] = columns[i]->replicate(offsets);
|
||||
|
||||
return std::make_shared<ColumnTuple>(new_columns);
|
||||
return ColumnTuple::create(new_columns);
|
||||
}
|
||||
|
||||
Columns ColumnTuple::scatter(ColumnIndex num_columns, const Selector & selector) const
|
||||
MutableColumns ColumnTuple::scatter(ColumnIndex num_columns, const Selector & selector) const
|
||||
{
|
||||
const size_t tuple_size = columns.size();
|
||||
std::vector<Columns> scattered_tuple_elements(tuple_size);
|
||||
std::vector<MutableColumns> scattered_tuple_elements(tuple_size);
|
||||
|
||||
for (size_t tuple_element_idx = 0; tuple_element_idx < tuple_size; ++tuple_element_idx)
|
||||
scattered_tuple_elements[tuple_element_idx] = columns[tuple_element_idx]->scatter(num_columns, selector);
|
||||
|
||||
Columns res(num_columns);
|
||||
MutableColumns res(num_columns);
|
||||
|
||||
for (size_t scattered_idx = 0; scattered_idx < num_columns; ++scattered_idx)
|
||||
{
|
||||
Columns new_columns(tuple_size);
|
||||
for (size_t tuple_element_idx = 0; tuple_element_idx < tuple_size; ++tuple_element_idx)
|
||||
new_columns[tuple_element_idx] = scattered_tuple_elements[tuple_element_idx][scattered_idx];
|
||||
res[scattered_idx] = std::make_shared<ColumnTuple>(new_columns);
|
||||
new_columns[tuple_element_idx] = std::move(scattered_tuple_elements[tuple_element_idx][scattered_idx]);
|
||||
res[scattered_idx] = ColumnTuple::create(new_columns);
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -207,7 +207,7 @@ int ColumnTuple::compareAt(size_t n, size_t m, const IColumn & rhs, int nan_dire
|
||||
template <bool positive>
|
||||
struct ColumnTuple::Less
|
||||
{
|
||||
ConstColumnPlainPtrs plain_columns;
|
||||
ColumnRawPtrs plain_columns;
|
||||
int nan_direction_hint;
|
||||
|
||||
Less(const Columns & columns, int nan_direction_hint_)
|
||||
@ -219,7 +219,7 @@ struct ColumnTuple::Less
|
||||
|
||||
bool operator() (size_t a, size_t b) const
|
||||
{
|
||||
for (ConstColumnPlainPtrs::const_iterator it = plain_columns.begin(); it != plain_columns.end(); ++it)
|
||||
for (ColumnRawPtrs::const_iterator it = plain_columns.begin(); it != plain_columns.end(); ++it)
|
||||
{
|
||||
int res = (*it)->compareAt(a, b, **it, nan_direction_hint);
|
||||
if (res < 0)
|
||||
@ -264,8 +264,9 @@ void ColumnTuple::gather(ColumnGathererStream & gatherer)
|
||||
|
||||
void ColumnTuple::reserve(size_t n)
|
||||
{
|
||||
for (auto & column : columns)
|
||||
column->reserve(n);
|
||||
const size_t tuple_size = columns.size();
|
||||
for (size_t i = 0; i < tuple_size; ++i)
|
||||
getColumn(i).reserve(n);
|
||||
}
|
||||
|
||||
size_t ColumnTuple::byteSize() const
|
||||
|
@ -12,21 +12,24 @@ namespace DB
|
||||
* Mixed constant/non-constant columns is prohibited in tuple
|
||||
* for implementation simplicity.
|
||||
*/
|
||||
class ColumnTuple final : public IColumn
|
||||
class ColumnTuple final : public COWPtrHelper<IColumn, ColumnTuple>
|
||||
{
|
||||
private:
|
||||
friend class COWPtrHelper<IColumn, ColumnTuple>;
|
||||
|
||||
Columns columns;
|
||||
|
||||
template <bool positive>
|
||||
struct Less;
|
||||
|
||||
public:
|
||||
ColumnTuple(const Columns & columns);
|
||||
ColumnTuple(const ColumnTuple &) = default;
|
||||
|
||||
public:
|
||||
std::string getName() const override;
|
||||
const char * getFamilyName() const override { return "Tuple"; }
|
||||
|
||||
ColumnPtr cloneEmpty() const override;
|
||||
MutableColumnPtr cloneEmpty() const override;
|
||||
|
||||
size_t size() const override
|
||||
{
|
||||
@ -46,10 +49,10 @@ public:
|
||||
const char * deserializeAndInsertFromArena(const char * pos) override;
|
||||
void updateHashWithValue(size_t n, SipHash & hash) const override;
|
||||
void insertRangeFrom(const IColumn & src, size_t start, size_t length) override;
|
||||
ColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override;
|
||||
ColumnPtr permute(const Permutation & perm, size_t limit) const override;
|
||||
ColumnPtr replicate(const Offsets_t & offsets) const override;
|
||||
Columns scatter(ColumnIndex num_columns, const Selector & selector) const override;
|
||||
MutableColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override;
|
||||
MutableColumnPtr permute(const Permutation & perm, size_t limit) const override;
|
||||
MutableColumnPtr replicate(const Offsets & offsets) const override;
|
||||
MutableColumns scatter(ColumnIndex num_columns, const Selector & selector) const override;
|
||||
void gather(ColumnGathererStream & gatherer_stream) override;
|
||||
int compareAt(size_t n, size_t m, const IColumn & rhs, int nan_direction_hint) const override;
|
||||
void getExtremes(Field & min, Field & max) const override;
|
||||
@ -59,8 +62,16 @@ public:
|
||||
size_t allocatedBytes() const override;
|
||||
void forEachSubcolumn(ColumnCallback callback) override;
|
||||
|
||||
size_t tupleSize() const { return columns.size(); }
|
||||
|
||||
const IColumn & getColumn(size_t idx) const { return *columns[idx]; }
|
||||
IColumn & getColumn(size_t idx) { return *columns[idx]->assumeMutable(); }
|
||||
|
||||
const Columns & getColumns() const { return columns; }
|
||||
Columns & getColumns() { return columns; }
|
||||
|
||||
const ColumnPtr & getColumnPtr(size_t idx) const { return columns[idx]; }
|
||||
//ColumnPtr & getColumnPtr(size_t idx) { return columns[idx]; }
|
||||
//MutableColumnPtr getColumnMutablePtr(size_t idx) { return columns[idx]->assumeMutable(); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -70,7 +70,7 @@ struct ColumnVector<T>::greater
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void ColumnVector<T>::getPermutation(bool reverse, size_t limit, int nan_direction_hint, Permutation & res) const
|
||||
void ColumnVector<T>::getPermutation(bool reverse, size_t limit, int nan_direction_hint, IColumn::Permutation & res) const
|
||||
{
|
||||
size_t s = data.size();
|
||||
res.resize(s);
|
||||
@ -103,13 +103,13 @@ const char * ColumnVector<T>::getFamilyName() const
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ColumnPtr ColumnVector<T>::cloneResized(size_t size) const
|
||||
MutableColumnPtr ColumnVector<T>::cloneResized(size_t size) const
|
||||
{
|
||||
ColumnPtr new_col_holder = std::make_shared<Self>();
|
||||
auto res = this->create();
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
auto & new_col = static_cast<Self &>(*new_col_holder);
|
||||
auto & new_col = static_cast<Self &>(*res);
|
||||
new_col.data.resize(size);
|
||||
|
||||
size_t count = std::min(this->size(), size);
|
||||
@ -119,7 +119,7 @@ ColumnPtr ColumnVector<T>::cloneResized(size_t size) const
|
||||
memset(&new_col.data[count], static_cast<int>(value_type()), size - count);
|
||||
}
|
||||
|
||||
return new_col_holder;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -146,14 +146,14 @@ void ColumnVector<T>::insertRangeFrom(const IColumn & src, size_t start, size_t
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ColumnPtr ColumnVector<T>::filter(const IColumn::Filter & filt, ssize_t result_size_hint) const
|
||||
MutableColumnPtr ColumnVector<T>::filter(const IColumn::Filter & filt, ssize_t result_size_hint) const
|
||||
{
|
||||
size_t size = data.size();
|
||||
if (size != filt.size())
|
||||
throw Exception("Size of filter doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
std::shared_ptr<Self> res = std::make_shared<Self>();
|
||||
typename Self::Container_t & res_data = res->getData();
|
||||
auto res = this->create();
|
||||
Container & res_data = res->getData();
|
||||
|
||||
if (result_size_hint)
|
||||
res_data.reserve(result_size_hint > 0 ? result_size_hint : size);
|
||||
@ -206,11 +206,11 @@ ColumnPtr ColumnVector<T>::filter(const IColumn::Filter & filt, ssize_t result_s
|
||||
++data_pos;
|
||||
}
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ColumnPtr ColumnVector<T>::permute(const IColumn::Permutation & perm, size_t limit) const
|
||||
MutableColumnPtr ColumnVector<T>::permute(const IColumn::Permutation & perm, size_t limit) const
|
||||
{
|
||||
size_t size = data.size();
|
||||
|
||||
@ -222,29 +222,29 @@ ColumnPtr ColumnVector<T>::permute(const IColumn::Permutation & perm, size_t lim
|
||||
if (perm.size() < limit)
|
||||
throw Exception("Size of permutation is less than required.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
std::shared_ptr<Self> res = std::make_shared<Self>(limit);
|
||||
typename Self::Container_t & res_data = res->getData();
|
||||
auto res = this->create(limit);
|
||||
typename Self::Container & res_data = res->getData();
|
||||
for (size_t i = 0; i < limit; ++i)
|
||||
res_data[i] = data[perm[i]];
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ColumnPtr ColumnVector<T>::replicate(const IColumn::Offsets_t & offsets) const
|
||||
MutableColumnPtr ColumnVector<T>::replicate(const IColumn::Offsets & offsets) const
|
||||
{
|
||||
size_t size = data.size();
|
||||
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 std::make_shared<Self>();
|
||||
return this->create();
|
||||
|
||||
std::shared_ptr<Self> res = std::make_shared<Self>();
|
||||
typename Self::Container_t & res_data = res->getData();
|
||||
auto res = this->create();
|
||||
typename Self::Container & res_data = res->getData();
|
||||
res_data.reserve(offsets.back());
|
||||
|
||||
IColumn::Offset_t prev_offset = 0;
|
||||
IColumn::Offset prev_offset = 0;
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
size_t size_to_replicate = offsets[i] - prev_offset;
|
||||
@ -254,7 +254,7 @@ ColumnPtr ColumnVector<T>::replicate(const IColumn::Offsets_t & offsets) const
|
||||
res_data.push_back(data[i]);
|
||||
}
|
||||
|
||||
return res;
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -120,9 +120,11 @@ template <> inline UInt64 unionCastToUInt64(Float32 x)
|
||||
/** A template for columns that use a simple array to store.
|
||||
*/
|
||||
template <typename T>
|
||||
class ColumnVector final : public IColumn
|
||||
class ColumnVector final : public COWPtrHelper<IColumn, ColumnVector<T>>
|
||||
{
|
||||
private:
|
||||
friend class COWPtrHelper<IColumn, ColumnVector<T>>;
|
||||
|
||||
using Self = ColumnVector<T>;
|
||||
|
||||
struct less;
|
||||
@ -130,12 +132,18 @@ private:
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using Container_t = PaddedPODArray<value_type>;
|
||||
using Container = PaddedPODArray<value_type>;
|
||||
|
||||
private:
|
||||
ColumnVector() {}
|
||||
ColumnVector(const size_t n) : data{n} {}
|
||||
ColumnVector(const size_t n, const value_type x) : data{n, x} {}
|
||||
ColumnVector(const size_t n) : data(n) {}
|
||||
ColumnVector(const size_t n, const value_type x) : data(n, x) {}
|
||||
ColumnVector(const ColumnVector & src) : data(src.data.begin(), src.data.end()) {};
|
||||
|
||||
/// Sugar constructor.
|
||||
ColumnVector(std::initializer_list<T> il) : data{il} {}
|
||||
|
||||
public:
|
||||
bool isNumeric() const override { return IsNumber<T>; }
|
||||
|
||||
size_t size() const override
|
||||
@ -195,7 +203,7 @@ public:
|
||||
return CompareHelper<T>::compare(data[n], static_cast<const Self &>(rhs_).data[m], nan_direction_hint);
|
||||
}
|
||||
|
||||
void getPermutation(bool reverse, size_t limit, int nan_direction_hint, Permutation & res) const override;
|
||||
void getPermutation(bool reverse, size_t limit, int nan_direction_hint, IColumn::Permutation & res) const override;
|
||||
|
||||
void reserve(size_t n) override
|
||||
{
|
||||
@ -204,7 +212,7 @@ public:
|
||||
|
||||
const char * getFamilyName() const override;
|
||||
|
||||
ColumnPtr cloneResized(size_t size) const override;
|
||||
MutableColumnPtr cloneResized(size_t size) const override;
|
||||
|
||||
Field operator[](size_t n) const override
|
||||
{
|
||||
@ -235,17 +243,17 @@ public:
|
||||
|
||||
void insertRangeFrom(const IColumn & src, size_t start, size_t length) override;
|
||||
|
||||
ColumnPtr filter(const IColumn::Filter & filt, ssize_t result_size_hint) const override;
|
||||
MutableColumnPtr filter(const IColumn::Filter & filt, ssize_t result_size_hint) const override;
|
||||
|
||||
ColumnPtr permute(const IColumn::Permutation & perm, size_t limit) const override;
|
||||
MutableColumnPtr permute(const IColumn::Permutation & perm, size_t limit) const override;
|
||||
|
||||
ColumnPtr replicate(const IColumn::Offsets_t & offsets) const override;
|
||||
MutableColumnPtr replicate(const IColumn::Offsets & offsets) const override;
|
||||
|
||||
void getExtremes(Field & min, Field & max) const override;
|
||||
|
||||
Columns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
MutableColumns scatter(IColumn::ColumnIndex num_columns, const IColumn::Selector & selector) const override
|
||||
{
|
||||
return this->scatterImpl<Self>(num_columns, selector);
|
||||
return this->template scatterImpl<Self>(num_columns, selector);
|
||||
}
|
||||
|
||||
void gather(ColumnGathererStream & gatherer_stream) override;
|
||||
@ -258,12 +266,12 @@ public:
|
||||
|
||||
|
||||
/** More efficient methods of manipulation - to manipulate with data directly. */
|
||||
Container_t & getData()
|
||||
Container & getData()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
const Container_t & getData() const
|
||||
const Container & getData() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
@ -279,7 +287,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
Container_t data;
|
||||
Container data;
|
||||
};
|
||||
|
||||
|
||||
|
@ -100,10 +100,10 @@ namespace
|
||||
|
||||
struct ResultOffsetsBuilder
|
||||
{
|
||||
IColumn::Offsets_t & res_offsets;
|
||||
IColumn::Offset_t current_src_offset = 0;
|
||||
IColumn::Offsets & res_offsets;
|
||||
IColumn::Offset current_src_offset = 0;
|
||||
|
||||
explicit ResultOffsetsBuilder(IColumn::Offsets_t * res_offsets_) : res_offsets(*res_offsets_) {}
|
||||
explicit ResultOffsetsBuilder(IColumn::Offsets * res_offsets_) : res_offsets(*res_offsets_) {}
|
||||
|
||||
void reserve(ssize_t result_size_hint, size_t src_size)
|
||||
{
|
||||
@ -118,14 +118,14 @@ namespace
|
||||
|
||||
template <size_t SIMD_BYTES>
|
||||
void insertChunk(
|
||||
const IColumn::Offset_t * src_offsets_pos,
|
||||
const IColumn::Offset * src_offsets_pos,
|
||||
bool first,
|
||||
IColumn::Offset_t chunk_offset,
|
||||
IColumn::Offset chunk_offset,
|
||||
size_t chunk_size)
|
||||
{
|
||||
const auto offsets_size_old = res_offsets.size();
|
||||
res_offsets.resize(offsets_size_old + SIMD_BYTES);
|
||||
memcpy(&res_offsets[offsets_size_old], src_offsets_pos, SIMD_BYTES * sizeof(IColumn::Offset_t));
|
||||
memcpy(&res_offsets[offsets_size_old], src_offsets_pos, SIMD_BYTES * sizeof(IColumn::Offset));
|
||||
|
||||
if (!first)
|
||||
{
|
||||
@ -147,15 +147,15 @@ namespace
|
||||
|
||||
struct NoResultOffsetsBuilder
|
||||
{
|
||||
explicit NoResultOffsetsBuilder(IColumn::Offsets_t *) {}
|
||||
explicit NoResultOffsetsBuilder(IColumn::Offsets *) {}
|
||||
void reserve(ssize_t, size_t) {}
|
||||
void insertOne(size_t) {}
|
||||
|
||||
template <size_t SIMD_BYTES>
|
||||
void insertChunk(
|
||||
const IColumn::Offset_t *,
|
||||
const IColumn::Offset *,
|
||||
bool,
|
||||
IColumn::Offset_t,
|
||||
IColumn::Offset,
|
||||
size_t)
|
||||
{
|
||||
}
|
||||
@ -164,8 +164,8 @@ namespace
|
||||
|
||||
template <typename T, typename ResultOffsetsBuilder>
|
||||
void filterArraysImplGeneric(
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets_t & src_offsets,
|
||||
PaddedPODArray<T> & res_elems, IColumn::Offsets_t * res_offsets,
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets & src_offsets,
|
||||
PaddedPODArray<T> & res_elems, IColumn::Offsets * res_offsets,
|
||||
const IColumn::Filter & filt, ssize_t result_size_hint)
|
||||
{
|
||||
const size_t size = src_offsets.size();
|
||||
@ -191,7 +191,7 @@ namespace
|
||||
const auto offsets_begin = offsets_pos;
|
||||
|
||||
/// copy array ending at *end_offset_ptr
|
||||
const auto copy_array = [&] (const IColumn::Offset_t * offset_ptr)
|
||||
const auto copy_array = [&] (const IColumn::Offset * offset_ptr)
|
||||
{
|
||||
const auto offset = offset_ptr == offsets_begin ? 0 : offset_ptr[-1];
|
||||
const auto size = *offset_ptr - offset;
|
||||
@ -259,8 +259,8 @@ namespace
|
||||
|
||||
template <typename T>
|
||||
void filterArraysImpl(
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets_t & src_offsets,
|
||||
PaddedPODArray<T> & res_elems, IColumn::Offsets_t & res_offsets,
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets & src_offsets,
|
||||
PaddedPODArray<T> & res_elems, IColumn::Offsets & res_offsets,
|
||||
const IColumn::Filter & filt, ssize_t result_size_hint)
|
||||
{
|
||||
return filterArraysImplGeneric<T, ResultOffsetsBuilder>(src_elems, src_offsets, res_elems, &res_offsets, filt, result_size_hint);
|
||||
@ -268,7 +268,7 @@ void filterArraysImpl(
|
||||
|
||||
template <typename T>
|
||||
void filterArraysImplOnlyData(
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets_t & src_offsets,
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets & src_offsets,
|
||||
PaddedPODArray<T> & res_elems,
|
||||
const IColumn::Filter & filt, ssize_t result_size_hint)
|
||||
{
|
||||
@ -279,11 +279,11 @@ void filterArraysImplOnlyData(
|
||||
/// Explicit instantiations - not to place the implementation of the function above in the header file.
|
||||
#define INSTANTIATE(TYPE) \
|
||||
template void filterArraysImpl<TYPE>( \
|
||||
const PaddedPODArray<TYPE> &, const IColumn::Offsets_t &, \
|
||||
PaddedPODArray<TYPE> &, IColumn::Offsets_t &, \
|
||||
const PaddedPODArray<TYPE> &, const IColumn::Offsets &, \
|
||||
PaddedPODArray<TYPE> &, IColumn::Offsets &, \
|
||||
const IColumn::Filter &, ssize_t); \
|
||||
template void filterArraysImplOnlyData<TYPE>( \
|
||||
const PaddedPODArray<TYPE> &, const IColumn::Offsets_t &, \
|
||||
const PaddedPODArray<TYPE> &, const IColumn::Offsets &, \
|
||||
PaddedPODArray<TYPE> &, \
|
||||
const IColumn::Filter &, ssize_t);
|
||||
|
||||
|
@ -18,14 +18,14 @@ bool memoryIsZero(const void * data, size_t size);
|
||||
/// The general implementation of `filter` function for ColumnArray and ColumnString.
|
||||
template <typename T>
|
||||
void filterArraysImpl(
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets_t & src_offsets,
|
||||
PaddedPODArray<T> & res_elems, IColumn::Offsets_t & res_offsets,
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets & src_offsets,
|
||||
PaddedPODArray<T> & res_elems, IColumn::Offsets & res_offsets,
|
||||
const IColumn::Filter & filt, ssize_t result_size_hint);
|
||||
|
||||
/// Same as above, but not fills res_offsets.
|
||||
template <typename T>
|
||||
void filterArraysImplOnlyData(
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets_t & src_offsets,
|
||||
const PaddedPODArray<T> & src_elems, const IColumn::Offsets & src_offsets,
|
||||
PaddedPODArray<T> & res_elems,
|
||||
const IColumn::Filter & filt, ssize_t result_size_hint);
|
||||
|
||||
|
70
dbms/src/Columns/FilterDescription.cpp
Normal file
70
dbms/src/Columns/FilterDescription.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include <Columns/FilterDescription.h>
|
||||
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Columns/ColumnsNumber.h>
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Columns/ColumnConst.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_TYPE_OF_COLUMN_FOR_FILTER;
|
||||
}
|
||||
|
||||
|
||||
ConstantFilterDescription::ConstantFilterDescription(const IColumn & column)
|
||||
{
|
||||
if (column.onlyNull())
|
||||
{
|
||||
always_false = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (column.isColumnConst())
|
||||
{
|
||||
if (static_cast<const ColumnConst &>(column).getValue<UInt8>())
|
||||
always_true = true;
|
||||
else
|
||||
always_false = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FilterDescription::FilterDescription(const IColumn & column)
|
||||
{
|
||||
if (const ColumnUInt8 * concrete_column = typeid_cast<const ColumnUInt8 *>(&column))
|
||||
{
|
||||
data = &concrete_column->getData();
|
||||
return;
|
||||
}
|
||||
|
||||
if (const ColumnNullable * nullable_column = typeid_cast<const ColumnNullable *>(&column))
|
||||
{
|
||||
MutableColumnPtr mutable_holder = nullable_column->getNestedColumn().mutate();
|
||||
|
||||
ColumnUInt8 * concrete_column = typeid_cast<ColumnUInt8 *>(mutable_holder.get());
|
||||
if (!concrete_column)
|
||||
throw Exception("Illegal type " + column.getName() + " of column for filter. Must be UInt8 or Nullable(UInt8).",
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_COLUMN_FOR_FILTER);
|
||||
|
||||
const NullMap & null_map = nullable_column->getNullMapData();
|
||||
IColumn::Filter & res = concrete_column->getData();
|
||||
|
||||
size_t size = res.size();
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
res[i] = res[i] && !null_map[i];
|
||||
|
||||
data = &res;
|
||||
data_holder = std::move(mutable_holder);
|
||||
return;
|
||||
}
|
||||
|
||||
throw Exception("Illegal type " + column.getName() + " of column for filter. Must be UInt8 or Nullable(UInt8) or Const variants of them.",
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_COLUMN_FOR_FILTER);
|
||||
}
|
||||
|
||||
}
|
32
dbms/src/Columns/FilterDescription.h
Normal file
32
dbms/src/Columns/FilterDescription.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <Columns/IColumn.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/// Support methods for implementation of WHERE, PREWHERE and HAVING.
|
||||
|
||||
|
||||
/// Analyze if the column for filter is constant thus filter is always false or always true.
|
||||
struct ConstantFilterDescription
|
||||
{
|
||||
bool always_false = false;
|
||||
bool always_true = false;
|
||||
|
||||
ConstantFilterDescription() {}
|
||||
explicit ConstantFilterDescription(const IColumn & column);
|
||||
};
|
||||
|
||||
|
||||
/// Obtain a filter from non constant Column, that may have type: UInt8, Nullable(UInt8).
|
||||
struct FilterDescription
|
||||
{
|
||||
const IColumn::Filter * data = nullptr; /// Pointer to filter when it is not always true or always false.
|
||||
ColumnPtr data_holder; /// If new column was generated, it will be owned by holder.
|
||||
|
||||
explicit FilterDescription(const IColumn & column);
|
||||
};
|
||||
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <Core/Field.h>
|
||||
#include <Common/COWPtr.h>
|
||||
#include <Common/PODArray.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <common/StringRef.h>
|
||||
@ -22,19 +20,21 @@ namespace ErrorCodes
|
||||
extern const int SIZES_OF_COLUMNS_DOESNT_MATCH;
|
||||
}
|
||||
|
||||
class IColumn;
|
||||
|
||||
using ColumnPtr = std::shared_ptr<IColumn>;
|
||||
using Columns = std::vector<ColumnPtr>;
|
||||
using ColumnPlainPtrs = std::vector<IColumn *>;
|
||||
using ConstColumnPlainPtrs = std::vector<const IColumn *>;
|
||||
|
||||
class Arena;
|
||||
class ColumnGathererStream;
|
||||
|
||||
/// Declares interface to store columns in memory.
|
||||
class IColumn : private boost::noncopyable
|
||||
class IColumn : public COWPtr<IColumn>
|
||||
{
|
||||
private:
|
||||
friend class COWPtr<IColumn>;
|
||||
|
||||
/// Creates the same column with the same data.
|
||||
/// This is internal method to use from COWPtr.
|
||||
/// It performs shallow copy with copy-ctor and not useful from outside.
|
||||
/// If you want to copy column for modification, look at 'mutate' method.
|
||||
virtual MutablePtr clone() const = 0;
|
||||
|
||||
public:
|
||||
/// Name of a Column. It is used in info messages.
|
||||
virtual std::string getName() const { return getFamilyName(); };
|
||||
@ -45,18 +45,15 @@ public:
|
||||
/** If column isn't constant, returns nullptr (or itself).
|
||||
* If column is constant, transforms constant to full column (if column type allows such tranform) and return it.
|
||||
*/
|
||||
virtual ColumnPtr convertToFullColumnIfConst() const { return {}; }
|
||||
|
||||
/// Creates the same column with the same data.
|
||||
virtual ColumnPtr clone() const { return cut(0, size()); }
|
||||
virtual MutablePtr convertToFullColumnIfConst() const { return {}; }
|
||||
|
||||
/// Creates empty column with the same type.
|
||||
virtual ColumnPtr cloneEmpty() const { return cloneResized(0); }
|
||||
virtual MutablePtr cloneEmpty() const { return cloneResized(0); }
|
||||
|
||||
/// Creates column with the same type and specified size.
|
||||
/// If size is less current size, then data is cut.
|
||||
/// If size is greater, than default values are appended.
|
||||
virtual ColumnPtr cloneResized(size_t /*size*/) const { throw Exception("Cannot cloneResized() column " + getName(), ErrorCodes::NOT_IMPLEMENTED); }
|
||||
virtual MutablePtr cloneResized(size_t /*size*/) const { throw Exception("Cannot cloneResized() column " + getName(), ErrorCodes::NOT_IMPLEMENTED); }
|
||||
|
||||
/// Returns number of values in column.
|
||||
virtual size_t size() const = 0;
|
||||
@ -107,9 +104,9 @@ public:
|
||||
|
||||
/// Removes all elements outside of specified range.
|
||||
/// Is used in LIMIT operation, for example.
|
||||
virtual ColumnPtr cut(size_t start, size_t length) const
|
||||
virtual MutablePtr cut(size_t start, size_t length) const
|
||||
{
|
||||
ColumnPtr res = cloneEmpty();
|
||||
MutablePtr res = cloneEmpty();
|
||||
res->insertRangeFrom(*this, start, length);
|
||||
return res;
|
||||
}
|
||||
@ -174,12 +171,12 @@ public:
|
||||
* otherwise (i.e. < 0), makes reserve() using size of source column.
|
||||
*/
|
||||
using Filter = PaddedPODArray<UInt8>;
|
||||
virtual ColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const = 0;
|
||||
virtual MutablePtr filter(const Filter & filt, ssize_t result_size_hint) const = 0;
|
||||
|
||||
/// Permutes elements using specified permutation. Is used in sortings.
|
||||
/// limit - if it isn't 0, puts only first limit elements in the result.
|
||||
using Permutation = PaddedPODArray<size_t>;
|
||||
virtual ColumnPtr permute(const Permutation & perm, size_t limit) const = 0;
|
||||
virtual MutablePtr permute(const Permutation & perm, size_t limit) const = 0;
|
||||
|
||||
/** Compares (*this)[n] and rhs[m].
|
||||
* Returns negative number, 0, or positive number (*this)[n] is less, equal, greater than rhs[m] respectively.
|
||||
@ -206,9 +203,9 @@ public:
|
||||
* (i-th element should be copied offsets[i] - offsets[i - 1] times.)
|
||||
* It is necessary in ARRAY JOIN operation.
|
||||
*/
|
||||
using Offset_t = UInt64;
|
||||
using Offsets_t = PaddedPODArray<Offset_t>;
|
||||
virtual ColumnPtr replicate(const Offsets_t & offsets) const = 0;
|
||||
using Offset = UInt64;
|
||||
using Offsets = PaddedPODArray<Offset>;
|
||||
virtual MutablePtr replicate(const Offsets & offsets) const = 0;
|
||||
|
||||
/** Split column to smaller columns. Each value goes to column index, selected by corresponding element of 'selector'.
|
||||
* Selector must contain values from 0 to num_columns - 1.
|
||||
@ -216,7 +213,7 @@ public:
|
||||
*/
|
||||
using ColumnIndex = UInt64;
|
||||
using Selector = PaddedPODArray<ColumnIndex>;
|
||||
virtual Columns scatter(ColumnIndex num_columns, const Selector & selector) const = 0;
|
||||
virtual std::vector<MutablePtr> scatter(ColumnIndex num_columns, const Selector & selector) const = 0;
|
||||
|
||||
/// Insert data from several other columns according to source mask (used in vertical merge).
|
||||
/// For now it is a helper to de-virtualize calls to insert*() functions inside gather loop
|
||||
@ -246,9 +243,18 @@ public:
|
||||
|
||||
/// If the column contains subcolumns (such as Array, Nullable, etc), do callback on them.
|
||||
/// Shallow: doesn't do recursive calls; don't do call for itself.
|
||||
using ColumnCallback = std::function<void(ColumnPtr&)>;
|
||||
using ColumnCallback = std::function<void(Ptr&)>;
|
||||
virtual void forEachSubcolumn(ColumnCallback) {}
|
||||
|
||||
|
||||
MutablePtr mutate() const
|
||||
{
|
||||
MutablePtr res = COWPtr<IColumn>::mutate();
|
||||
res->forEachSubcolumn([](Ptr & subcolumn) { subcolumn = subcolumn->mutate(); });
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/** Some columns can contain another columns inside.
|
||||
* So, we have a tree of columns. But not all combinations are possible.
|
||||
* There are the following rules:
|
||||
@ -318,7 +324,7 @@ protected:
|
||||
/// Template is to devirtualize calls to insertFrom method.
|
||||
/// In derived classes (that use final keyword), implement scatter method as call to scatterImpl.
|
||||
template <typename Derived>
|
||||
Columns scatterImpl(ColumnIndex num_columns, const Selector & selector) const
|
||||
std::vector<MutablePtr> scatterImpl(ColumnIndex num_columns, const Selector & selector) const
|
||||
{
|
||||
size_t num_rows = size();
|
||||
|
||||
@ -327,7 +333,7 @@ protected:
|
||||
"Size of selector: " + std::to_string(selector.size()) + " doesn't match size of column: " + std::to_string(num_rows),
|
||||
ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
Columns columns(num_columns);
|
||||
std::vector<MutablePtr> columns(num_columns);
|
||||
for (auto & column : columns)
|
||||
column = cloneEmpty();
|
||||
|
||||
@ -346,5 +352,12 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
using ColumnPtr = IColumn::Ptr;
|
||||
using MutableColumnPtr = IColumn::MutablePtr;
|
||||
using Columns = std::vector<ColumnPtr>;
|
||||
using MutableColumns = std::vector<MutableColumnPtr>;
|
||||
|
||||
using ColumnRawPtrs = std::vector<const IColumn *>;
|
||||
//using MutableColumnRawPtrs = std::vector<IColumn *>;
|
||||
|
||||
}
|
||||
|
@ -21,11 +21,13 @@ namespace ErrorCodes
|
||||
class IColumnDummy : public IColumn
|
||||
{
|
||||
public:
|
||||
IColumnDummy() : s(0) {}
|
||||
IColumnDummy(size_t s_) : s(s_) {}
|
||||
|
||||
virtual ColumnPtr cloneDummy(size_t s_) const = 0;
|
||||
public:
|
||||
virtual MutableColumnPtr cloneDummy(size_t s_) const = 0;
|
||||
|
||||
ColumnPtr cloneResized(size_t s_) const override { return cloneDummy(s_); }
|
||||
MutableColumnPtr cloneResized(size_t s_) const override { return cloneDummy(s_); }
|
||||
size_t size() const override { return s; }
|
||||
void insertDefault() override { ++s; }
|
||||
void popBack(size_t n) override { s -= n; }
|
||||
@ -72,12 +74,12 @@ public:
|
||||
s += length;
|
||||
}
|
||||
|
||||
ColumnPtr filter(const Filter & filt, ssize_t /*result_size_hint*/) const override
|
||||
MutableColumnPtr filter(const Filter & filt, ssize_t /*result_size_hint*/) const override
|
||||
{
|
||||
return cloneDummy(countBytesInFilter(filt));
|
||||
}
|
||||
|
||||
ColumnPtr permute(const Permutation & perm, size_t limit) const override
|
||||
MutableColumnPtr permute(const Permutation & perm, size_t limit) const override
|
||||
{
|
||||
if (s != perm.size())
|
||||
throw Exception("Size of permutation doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
@ -92,7 +94,7 @@ public:
|
||||
res[i] = i;
|
||||
}
|
||||
|
||||
ColumnPtr replicate(const Offsets_t & offsets) const override
|
||||
MutableColumnPtr replicate(const Offsets & offsets) const override
|
||||
{
|
||||
if (s != offsets.size())
|
||||
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
@ -100,7 +102,7 @@ public:
|
||||
return cloneDummy(s == 0 ? 0 : offsets.back());
|
||||
}
|
||||
|
||||
Columns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
MutableColumns scatter(ColumnIndex num_columns, const Selector & selector) const override
|
||||
{
|
||||
if (s != selector.size())
|
||||
throw Exception("Size of selector doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
||||
@ -109,7 +111,7 @@ public:
|
||||
for (auto idx : selector)
|
||||
++counts[idx];
|
||||
|
||||
Columns res(num_columns);
|
||||
MutableColumns res(num_columns);
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
res[i] = cloneResized(counts[i]);
|
||||
|
||||
@ -135,7 +137,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
size_t s;
|
||||
};
|
||||
|
||||
|
240
dbms/src/Common/COWPtr.h
Normal file
240
dbms/src/Common/COWPtr.h
Normal file
@ -0,0 +1,240 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
|
||||
#include <initializer_list>
|
||||
|
||||
|
||||
/** Copy-on-write shared ptr.
|
||||
* Allows to work with shared immutable objects and sometimes unshare and mutate you own unique copy.
|
||||
*
|
||||
* Usage:
|
||||
|
||||
class Column : public COWPtr<Column>
|
||||
{
|
||||
private:
|
||||
friend class COWPtr<Column>;
|
||||
|
||||
/// Leave all constructors in private section. They will be avaliable through 'create' method.
|
||||
Column();
|
||||
|
||||
/// Provide 'clone' method. It can be virtual if you want polymorphic behaviour.
|
||||
virtual Column * clone() const;
|
||||
public:
|
||||
/// Correctly use const qualifiers in your interface.
|
||||
|
||||
virtual ~IColumn() {}
|
||||
};
|
||||
|
||||
* It will provide 'create' and 'mutate' methods.
|
||||
* And 'Ptr' and 'MutablePtr' types.
|
||||
* Ptr is refcounted pointer to immutable object.
|
||||
* MutablePtr is refcounted noncopyable pointer to mutable object.
|
||||
* MutablePtr can be assigned to Ptr through move assignment.
|
||||
*
|
||||
* 'create' method creates MutablePtr: you cannot share mutable objects.
|
||||
* To share, move-assign to immutable pointer.
|
||||
* 'mutate' method allows to create mutable noncopyable object from immutable object:
|
||||
* either by cloning or by using directly, if it is not shared.
|
||||
* These methods are thread-safe.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
/// Creating and assigning to immutable ptr.
|
||||
Column::Ptr x = Column::create(1);
|
||||
/// Sharing single immutable object in two ptrs.
|
||||
Column::Ptr y = x;
|
||||
|
||||
/// Now x and y are shared.
|
||||
|
||||
/// Change value of x.
|
||||
{
|
||||
/// Creating mutable ptr. It can clone an object under the hood if it was shared.
|
||||
Column::MutablePtr mutate_x = x->mutate();
|
||||
/// Using non-const methods of an object.
|
||||
mutate_x->set(2);
|
||||
/// Assigning pointer 'x' to mutated object.
|
||||
x = std::move(mutate_x);
|
||||
}
|
||||
|
||||
/// Now x and y are unshared and have different values.
|
||||
|
||||
* Note. You may have heard that COW is bad practice.
|
||||
* Actually it is, if your values are small or if copying is done implicitly.
|
||||
* This is the case for string implementations.
|
||||
*
|
||||
* In contrast, COWPtr is intended for the cases when you need to share states of large objects,
|
||||
* (when you usually will use std::shared_ptr) but you also want precise control over modification
|
||||
* of this shared state.
|
||||
*/
|
||||
template <typename Derived>
|
||||
class COWPtr : public boost::intrusive_ref_counter<Derived>
|
||||
{
|
||||
private:
|
||||
Derived * derived() { return static_cast<Derived *>(this); }
|
||||
const Derived * derived() const { return static_cast<const Derived *>(this); }
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
class mutable_ptr : public boost::intrusive_ptr<T>
|
||||
{
|
||||
private:
|
||||
using Base = boost::intrusive_ptr<T>;
|
||||
|
||||
template <typename> friend class COWPtr;
|
||||
template <typename, typename> friend class COWPtrHelper;
|
||||
|
||||
explicit mutable_ptr(T * ptr) : Base(ptr) {}
|
||||
|
||||
public:
|
||||
/// Copy: not possible.
|
||||
mutable_ptr(const mutable_ptr &) = delete;
|
||||
|
||||
/// Move: ok.
|
||||
mutable_ptr(mutable_ptr &&) = default;
|
||||
mutable_ptr & operator=(mutable_ptr &&) = default;
|
||||
|
||||
/// Initializing from temporary of compatible type.
|
||||
template <typename U>
|
||||
mutable_ptr(mutable_ptr<U> && other) : Base(std::move(other)) {}
|
||||
|
||||
mutable_ptr() = default;
|
||||
|
||||
mutable_ptr(const std::nullptr_t *) {}
|
||||
};
|
||||
|
||||
public:
|
||||
using MutablePtr = mutable_ptr<Derived>;
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
class immutable_ptr : public boost::intrusive_ptr<const T>
|
||||
{
|
||||
private:
|
||||
using Base = boost::intrusive_ptr<const T>;
|
||||
|
||||
template <typename> friend class COWPtr;
|
||||
template <typename, typename> friend class COWPtrHelper;
|
||||
|
||||
explicit immutable_ptr(const T * ptr) : Base(ptr) {}
|
||||
|
||||
public:
|
||||
/// Copy from immutable ptr: ok.
|
||||
immutable_ptr(const immutable_ptr &) = default;
|
||||
immutable_ptr & operator=(const immutable_ptr &) = default;
|
||||
|
||||
template <typename U>
|
||||
immutable_ptr(const immutable_ptr<U> & other) : Base(other) {}
|
||||
|
||||
/// Move: ok.
|
||||
immutable_ptr(immutable_ptr &&) = default;
|
||||
immutable_ptr & operator=(immutable_ptr &&) = default;
|
||||
|
||||
/// Initializing from temporary of compatible type.
|
||||
template <typename U>
|
||||
immutable_ptr(immutable_ptr<U> && other) : Base(std::move(other)) {}
|
||||
|
||||
/// Move from mutable ptr: ok.
|
||||
template <typename U>
|
||||
immutable_ptr(mutable_ptr<U> && other) : Base(std::move(other)) {}
|
||||
|
||||
/// Copy from mutable ptr: not possible.
|
||||
template <typename U>
|
||||
immutable_ptr(const mutable_ptr<U> &) = delete;
|
||||
|
||||
immutable_ptr() = default;
|
||||
|
||||
immutable_ptr(const std::nullptr_t *) {}
|
||||
};
|
||||
|
||||
public:
|
||||
using Ptr = immutable_ptr<Derived>;
|
||||
|
||||
template <typename... Args>
|
||||
static MutablePtr create(Args &&... args) { return MutablePtr(new Derived(std::forward<Args>(args)...)); }
|
||||
|
||||
template <typename T>
|
||||
static MutablePtr create(std::initializer_list<T> && arg) { return create(std::forward<std::initializer_list<T>>(arg)); }
|
||||
|
||||
public:
|
||||
Ptr getPtr() const { return static_cast<Ptr>(derived()); }
|
||||
MutablePtr getPtr() { return static_cast<MutablePtr>(derived()); }
|
||||
|
||||
MutablePtr mutate() const
|
||||
{
|
||||
if (this->use_count() > 1)
|
||||
return derived()->clone();
|
||||
else
|
||||
return assumeMutable();
|
||||
}
|
||||
|
||||
MutablePtr assumeMutable() const
|
||||
{
|
||||
return const_cast<COWPtr*>(this)->getPtr();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Helper class to support inheritance.
|
||||
* Example:
|
||||
*
|
||||
* class IColumn : public COWPtr<IColumn>
|
||||
* {
|
||||
* friend class COWPtr<IColumn>;
|
||||
* virtual MutablePtr clone() const = 0;
|
||||
* virtual ~IColumn() {}
|
||||
* };
|
||||
*
|
||||
* class ConcreteColumn : public COWPtrHelper<IColumn, ConcreteColumn>
|
||||
* {
|
||||
* friend class COWPtrHelper<IColumn, ConcreteColumn>;
|
||||
* };
|
||||
*
|
||||
* Here is complete inheritance diagram:
|
||||
*
|
||||
* ConcreteColumn
|
||||
* COWPtrHelper<IColumn, ConcreteColumn>
|
||||
* IColumn
|
||||
* CowPtr<IColumn>
|
||||
* boost::intrusive_ref_counter<IColumn>
|
||||
*/
|
||||
template <typename Base, typename Derived>
|
||||
class COWPtrHelper : public Base
|
||||
{
|
||||
private:
|
||||
Derived * derived() { return static_cast<Derived *>(this); }
|
||||
const Derived * derived() const { return static_cast<const Derived *>(this); }
|
||||
|
||||
public:
|
||||
using Ptr = typename Base::template immutable_ptr<Derived>;
|
||||
using MutablePtr = typename Base::template mutable_ptr<Derived>;
|
||||
|
||||
template <typename... Args>
|
||||
static MutablePtr create(Args &&... args) { return MutablePtr(new Derived(std::forward<Args>(args)...)); }
|
||||
|
||||
template <typename T>
|
||||
static MutablePtr create(std::initializer_list<T> && arg) { return create(std::forward<std::initializer_list<T>>(arg)); }
|
||||
|
||||
typename Base::MutablePtr clone() const override { return typename Base::MutablePtr(new Derived(*derived())); }
|
||||
};
|
||||
|
||||
|
||||
/** Compositions.
|
||||
*
|
||||
* Sometimes your objects contain another objects, and you have tree-like structure.
|
||||
* And you want non-const methods of your object to also modify your subobjects.
|
||||
*
|
||||
* There are the following possible solutions:
|
||||
*
|
||||
* 1. Store subobjects as immutable ptrs. Call mutate method of subobjects inside non-const methods of your objects; modify them and assign back.
|
||||
* Drawback: additional checks inside methods: CPU overhead on atomic ops.
|
||||
*
|
||||
* 2. Store subobjects as mutable ptrs. Subobjects cannot be shared in another objects.
|
||||
* Drawback: it's not possible to share subobjects.
|
||||
*
|
||||
* 3. Store subobjects as immutable ptrs. Implement copy-constructor to do shallow copy.
|
||||
* But reimplement 'mutate' method, so it will call 'mutate' of all subobjects (do deep mutate).
|
||||
* It will guarantee, that mutable object have all subobjects unshared.
|
||||
* From non-const method, you can modify subobjects with 'assumeMutable' method.
|
||||
* Drawback: it's more complex than other solutions.
|
||||
*/
|
@ -197,7 +197,7 @@ public:
|
||||
ExternalTableData data = getData(context);
|
||||
|
||||
/// Create table
|
||||
NamesAndTypesListPtr columns = std::make_shared<NamesAndTypesList>(sample_block.getColumnsList());
|
||||
NamesAndTypesListPtr columns = std::make_shared<NamesAndTypesList>(sample_block.getNamesAndTypesList());
|
||||
StoragePtr storage = StorageMemory::create(data.second, columns, NamesAndTypesList{}, NamesAndTypesList{}, ColumnDefaults{});
|
||||
storage->startup();
|
||||
context.addExternalTable(data.second, storage);
|
||||
|
@ -166,6 +166,8 @@ public:
|
||||
insert(from_begin, from_end);
|
||||
}
|
||||
|
||||
PODArray(std::initializer_list<T> il) : PODArray(std::begin(il), std::end(il)) {}
|
||||
|
||||
~PODArray()
|
||||
{
|
||||
dealloc();
|
||||
|
@ -46,7 +46,7 @@ int main(int argc, char ** argv)
|
||||
code = e.code;
|
||||
}
|
||||
|
||||
std::cout << time(0) - time0 << "s: " << zkutil::ZooKeeper::error2string(code) << std::endl;
|
||||
std::cout << time(nullptr) - time0 << "s: " << zkutil::ZooKeeper::error2string(code) << std::endl;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
@ -65,3 +65,6 @@ target_link_libraries (integer_hash_tables_and_hashes clickhouse_common_io)
|
||||
|
||||
add_executable (allocator allocator.cpp)
|
||||
target_link_libraries (allocator clickhouse_common_io)
|
||||
|
||||
add_executable (cow_columns cow_columns.cpp)
|
||||
target_link_libraries (cow_columns clickhouse_common_io)
|
||||
|
86
dbms/src/Common/tests/cow_columns.cpp
Normal file
86
dbms/src/Common/tests/cow_columns.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include <Common/COWPtr.h>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
class IColumn : public COWPtr<IColumn>
|
||||
{
|
||||
private:
|
||||
friend class COWPtr<IColumn>;
|
||||
virtual MutablePtr clone() const = 0;
|
||||
|
||||
public:
|
||||
virtual ~IColumn() {}
|
||||
|
||||
virtual int get() const = 0;
|
||||
virtual void set(int value) = 0;
|
||||
|
||||
virtual MutablePtr test() const = 0;
|
||||
};
|
||||
|
||||
using ColumnPtr = IColumn::Ptr;
|
||||
using MutableColumnPtr = IColumn::MutablePtr;
|
||||
|
||||
class ConcreteColumn : public COWPtrHelper<IColumn, ConcreteColumn>
|
||||
{
|
||||
private:
|
||||
friend class COWPtrHelper<IColumn, ConcreteColumn>;
|
||||
|
||||
int data;
|
||||
ConcreteColumn(int data) : data(data) {}
|
||||
ConcreteColumn(const ConcreteColumn &) = default;
|
||||
|
||||
MutableColumnPtr test() const override
|
||||
{
|
||||
MutableColumnPtr res = create(123);
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
int get() const override { return data; }
|
||||
void set(int value) override { data = value; }
|
||||
};
|
||||
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
ColumnPtr x = ConcreteColumn::create(1);
|
||||
ColumnPtr y = x;//x->test();
|
||||
|
||||
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
|
||||
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
|
||||
std::cerr << "addresses: " << x.get() << ", " << y.get() << "\n";
|
||||
|
||||
{
|
||||
MutableColumnPtr mut = y->mutate();
|
||||
mut->set(2);
|
||||
|
||||
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << ", " << mut->use_count() << "\n";
|
||||
std::cerr << "addresses: " << x.get() << ", " << y.get() << ", " << mut.get() << "\n";
|
||||
y = std::move(mut);
|
||||
}
|
||||
|
||||
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
|
||||
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
|
||||
std::cerr << "addresses: " << x.get() << ", " << y.get() << "\n";
|
||||
|
||||
x = ConcreteColumn::create(0);
|
||||
|
||||
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
|
||||
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
|
||||
std::cerr << "addresses: " << x.get() << ", " << y.get() << "\n";
|
||||
|
||||
{
|
||||
MutableColumnPtr mut = y->mutate();
|
||||
mut->set(3);
|
||||
|
||||
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << ", " << mut->use_count() << "\n";
|
||||
std::cerr << "addresses: " << x.get() << ", " << y.get() << ", " << mut.get() << "\n";
|
||||
y = std::move(mut);
|
||||
}
|
||||
|
||||
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
|
||||
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <Poco/Exception.h>
|
||||
#include <Common/HashTable/Hash.h>
|
||||
#include <Common/Stopwatch.h>
|
||||
#include <Core/Defines.h>
|
||||
|
||||
#include "AvalancheTest.h" /// Taken from SMHasher.
|
||||
|
||||
@ -33,7 +34,7 @@ void setAffinity()
|
||||
}
|
||||
|
||||
|
||||
static inline __attribute__((__always_inline__)) UInt64 rdtsc()
|
||||
static inline ALWAYS_INLINE UInt64 rdtsc()
|
||||
{
|
||||
#if __x86_64__
|
||||
UInt32 a, d;
|
||||
|
@ -42,7 +42,7 @@ int main(int argc, char ** argv)
|
||||
|
||||
std::vector<Key> data(n);
|
||||
|
||||
// srand(time(0));
|
||||
// srand(time(nullptr));
|
||||
|
||||
{
|
||||
Stopwatch watch;
|
||||
|
@ -18,7 +18,6 @@ namespace ErrorCodes
|
||||
extern const int POSITION_OUT_OF_BOUND;
|
||||
extern const int NOT_FOUND_COLUMN_IN_BLOCK;
|
||||
extern const int SIZES_OF_COLUMNS_DOESNT_MATCH;
|
||||
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
|
||||
}
|
||||
|
||||
|
||||
@ -300,6 +299,46 @@ Block Block::cloneEmpty() const
|
||||
}
|
||||
|
||||
|
||||
MutableColumns Block::cloneEmptyColumns() const
|
||||
{
|
||||
size_t num_columns = data.size();
|
||||
MutableColumns columns(num_columns);
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
columns[i] = data[i].column ? data[i].column->cloneEmpty() : data[i].type->createColumn();
|
||||
return columns;
|
||||
}
|
||||
|
||||
|
||||
MutableColumns Block::mutateColumns() const
|
||||
{
|
||||
size_t num_columns = data.size();
|
||||
MutableColumns columns(num_columns);
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
columns[i] = data[i].column ? data[i].column->mutate() : data[i].type->createColumn();
|
||||
return columns;
|
||||
}
|
||||
|
||||
|
||||
void Block::setColumns(MutableColumns && columns)
|
||||
{
|
||||
size_t num_columns = data.size();
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
data[i].column = std::move(columns[i]);
|
||||
}
|
||||
|
||||
|
||||
Block Block::cloneWithColumns(MutableColumns && columns) const
|
||||
{
|
||||
Block res;
|
||||
|
||||
size_t num_columns = data.size();
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
res.insert({ std::move(columns[i]), data[i].type, data[i].name });
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Block Block::sortColumns() const
|
||||
{
|
||||
Block sorted_block;
|
||||
@ -311,13 +350,13 @@ Block Block::sortColumns() const
|
||||
}
|
||||
|
||||
|
||||
ColumnsWithTypeAndName Block::getColumns() const
|
||||
const ColumnsWithTypeAndName & Block::getColumnsWithTypeAndName() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
NamesAndTypesList Block::getColumnsList() const
|
||||
NamesAndTypesList Block::getNamesAndTypesList() const
|
||||
{
|
||||
NamesAndTypesList res;
|
||||
|
||||
@ -328,6 +367,18 @@ NamesAndTypesList Block::getColumnsList() const
|
||||
}
|
||||
|
||||
|
||||
Names Block::getNames() const
|
||||
{
|
||||
Names res;
|
||||
res.reserve(columns());
|
||||
|
||||
for (const auto & elem : data)
|
||||
res.push_back(elem.name);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool blocksHaveEqualStructure(const Block & lhs, const Block & rhs)
|
||||
{
|
||||
size_t columns = lhs.columns();
|
||||
@ -428,31 +479,11 @@ void Block::swap(Block & other) noexcept
|
||||
}
|
||||
|
||||
|
||||
void Block::unshareColumns()
|
||||
{
|
||||
std::unordered_set<void*> pointers;
|
||||
|
||||
IColumn::ColumnCallback callback = [&](ColumnPtr & subcolumn)
|
||||
{
|
||||
if (!pointers.insert(subcolumn.get()).second)
|
||||
subcolumn = subcolumn->clone();
|
||||
subcolumn->forEachSubcolumn(callback);
|
||||
};
|
||||
|
||||
for (auto & elem : data)
|
||||
{
|
||||
callback(elem.column);
|
||||
elem.column->forEachSubcolumn(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void Block::updateHash(SipHash & hash) const
|
||||
{
|
||||
for (size_t row_no = 0, num_rows = rows(); row_no < num_rows; ++row_no)
|
||||
{
|
||||
for (auto & col : getColumns())
|
||||
for (const auto & col : data)
|
||||
col.column->updateHashWithValue(row_no, hash);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -76,8 +76,9 @@ public:
|
||||
|
||||
size_t getPositionByName(const std::string & name) const;
|
||||
|
||||
ColumnsWithTypeAndName getColumns() const;
|
||||
NamesAndTypesList getColumnsList() const;
|
||||
const ColumnsWithTypeAndName & getColumnsWithTypeAndName() const;
|
||||
NamesAndTypesList getNamesAndTypesList() const;
|
||||
Names getNames() const;
|
||||
|
||||
/// Returns number of rows from first column in block, not equal to nullptr. If no columns, returns 0.
|
||||
size_t rows() const;
|
||||
@ -105,19 +106,22 @@ public:
|
||||
/** Get the same block, but empty. */
|
||||
Block cloneEmpty() const;
|
||||
|
||||
/** Get empty columns with the same types as in block. */
|
||||
MutableColumns cloneEmptyColumns() const;
|
||||
|
||||
/** Get columns from block for mutation. */
|
||||
MutableColumns mutateColumns() const;
|
||||
|
||||
/** Replace columns in a block */
|
||||
void setColumns(MutableColumns && columns);
|
||||
Block cloneWithColumns(MutableColumns && columns) const;
|
||||
|
||||
/** Get a block with columns that have been rearranged in the order of their names. */
|
||||
Block sortColumns() const;
|
||||
|
||||
void clear();
|
||||
void swap(Block & other) noexcept;
|
||||
|
||||
/** Some column implementations (ColumnArray) may have shared parts between different columns
|
||||
* (common array sizes of elements of nested data structures).
|
||||
* Before doing mutating operations on such columns, you must unshare that parts.
|
||||
* Also unsharing columns, if whole columns are shared_ptrs pointing to same instances.
|
||||
*/
|
||||
void unshareColumns();
|
||||
|
||||
/** Updates SipHash of the Block, using update method of columns.
|
||||
* Returns hash for block, that could be used to differentiate blocks
|
||||
* with same structure, but different data.
|
||||
|
@ -11,8 +11,7 @@ ColumnWithTypeAndName ColumnWithTypeAndName::cloneEmpty() const
|
||||
ColumnWithTypeAndName res;
|
||||
|
||||
res.name = name;
|
||||
if (type)
|
||||
res.type = type->clone();
|
||||
res.type = type;
|
||||
if (column)
|
||||
res.column = column->cloneEmpty();
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/UInt128.h>
|
||||
#include <Core/Types.h>
|
||||
#include <Core/Defines.h>
|
||||
#include <common/strong_typedef.h>
|
||||
|
||||
|
||||
@ -197,14 +198,14 @@ public:
|
||||
template <typename T> T & get()
|
||||
{
|
||||
using TWithoutRef = typename std::remove_reference<T>::type;
|
||||
TWithoutRef * __attribute__((__may_alias__)) ptr = reinterpret_cast<TWithoutRef*>(storage);
|
||||
TWithoutRef * __attribute__((__may_alias__)) ptr = reinterpret_cast<TWithoutRef*>(&storage);
|
||||
return *ptr;
|
||||
};
|
||||
|
||||
template <typename T> const T & get() const
|
||||
{
|
||||
using TWithoutRef = typename std::remove_reference<T>::type;
|
||||
const TWithoutRef * __attribute__((__may_alias__)) ptr = reinterpret_cast<const TWithoutRef*>(storage);
|
||||
const TWithoutRef * __attribute__((__may_alias__)) ptr = reinterpret_cast<const TWithoutRef*>(&storage);
|
||||
return *ptr;
|
||||
};
|
||||
|
||||
@ -327,11 +328,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static const size_t storage_size = std::max({
|
||||
DBMS_MIN_FIELD_SIZE - sizeof(Types::Which),
|
||||
sizeof(Null), sizeof(UInt64), sizeof(UInt128), sizeof(Int64), sizeof(Float64), sizeof(String), sizeof(Array), sizeof(Tuple)});
|
||||
std::aligned_union<DBMS_MIN_FIELD_SIZE - sizeof(Types::Which),
|
||||
Null, UInt64, UInt128, Int64, Float64, String, Array, Tuple
|
||||
>::type storage;
|
||||
|
||||
char storage[storage_size] __attribute__((aligned(8)));
|
||||
Types::Which which;
|
||||
|
||||
|
||||
@ -340,7 +340,7 @@ private:
|
||||
void createConcrete(T && x)
|
||||
{
|
||||
using JustT = typename std::decay<T>::type;
|
||||
JustT * __attribute__((__may_alias__)) ptr = reinterpret_cast<JustT *>(storage);
|
||||
JustT * __attribute__((__may_alias__)) ptr = reinterpret_cast<JustT *>(&storage);
|
||||
new (ptr) JustT(std::forward<T>(x));
|
||||
which = TypeToEnum<JustT>::value;
|
||||
}
|
||||
@ -350,7 +350,7 @@ private:
|
||||
void assignConcrete(T && x)
|
||||
{
|
||||
using JustT = typename std::decay<T>::type;
|
||||
JustT * __attribute__((__may_alias__)) ptr = reinterpret_cast<JustT *>(storage);
|
||||
JustT * __attribute__((__may_alias__)) ptr = reinterpret_cast<JustT *>(&storage);
|
||||
*ptr = std::forward<T>(x);
|
||||
}
|
||||
|
||||
@ -398,7 +398,7 @@ private:
|
||||
|
||||
void create(const char * data, size_t size)
|
||||
{
|
||||
String * __attribute__((__may_alias__)) ptr = reinterpret_cast<String*>(storage);
|
||||
String * __attribute__((__may_alias__)) ptr = reinterpret_cast<String*>(&storage);
|
||||
new (ptr) String(data, size);
|
||||
which = Types::String;
|
||||
}
|
||||
@ -408,7 +408,7 @@ private:
|
||||
create(reinterpret_cast<const char *>(data), size);
|
||||
}
|
||||
|
||||
__attribute__((__always_inline__)) void destroy()
|
||||
ALWAYS_INLINE void destroy()
|
||||
{
|
||||
if (which < Types::MIN_NON_POD)
|
||||
return;
|
||||
@ -434,7 +434,7 @@ private:
|
||||
template <typename T>
|
||||
void destroy()
|
||||
{
|
||||
T * __attribute__((__may_alias__)) ptr = reinterpret_cast<T*>(storage);
|
||||
T * __attribute__((__may_alias__)) ptr = reinterpret_cast<T*>(&storage);
|
||||
ptr->~T();
|
||||
}
|
||||
};
|
||||
|
@ -16,8 +16,8 @@ namespace DB
|
||||
*/
|
||||
struct SortCursorImpl
|
||||
{
|
||||
ConstColumnPlainPtrs all_columns;
|
||||
ConstColumnPlainPtrs sort_columns;
|
||||
ColumnRawPtrs all_columns;
|
||||
ColumnRawPtrs sort_columns;
|
||||
SortDescription desc;
|
||||
size_t sort_columns_size = 0;
|
||||
size_t pos = 0;
|
||||
|
@ -33,7 +33,7 @@ std::ostream & operator<<(std::ostream & stream, const DB::NameAndTypePair & wha
|
||||
|
||||
std::ostream & operator<<(std::ostream & stream, const DB::IDataType & what)
|
||||
{
|
||||
stream << "IDataType(name = " << what.getName() << ", default = " << what.getDefault();
|
||||
stream << "IDataType(name = " << what.getName() << ", default = " << what.getDefault() << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
@ -62,22 +62,39 @@ std::ostream & operator<<(std::ostream & stream, const DB::IFunction & what)
|
||||
std::ostream & operator<<(std::ostream & stream, const DB::Block & what)
|
||||
{
|
||||
stream << "Block("
|
||||
<< "size = " << what.getColumns().size()
|
||||
<< "size = " << what.columns()
|
||||
<< "){" << what.dumpStructure() << "}";
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
#include <Common/COWPtr.h>
|
||||
|
||||
template <typename T>
|
||||
std::ostream & printCOWPtr(std::ostream & stream, const typename COWPtr<T>::Ptr & what)
|
||||
{
|
||||
stream << "COWPtr::Ptr(" << what.get();
|
||||
if (what)
|
||||
stream << ", use_count = " << what->use_count();
|
||||
stream << ") {";
|
||||
if (what)
|
||||
stream << *what;
|
||||
else
|
||||
stream << "nullptr";
|
||||
stream << "}";
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
std::ostream & operator<<(std::ostream & stream, const DB::ColumnWithTypeAndName & what)
|
||||
{
|
||||
stream << "ColumnWithTypeAndName(name = " << what.name << ", type = " << what.type << ", column = " << what.column << ")";
|
||||
return stream;
|
||||
stream << "ColumnWithTypeAndName(name = " << what.name << ", type = " << what.type << ", column = ";
|
||||
return printCOWPtr<DB::IColumn>(stream, what.column) << ")";
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & stream, const DB::IColumn & what)
|
||||
{
|
||||
stream << "IColumn(name = " << what.getName()
|
||||
// TODO: maybe many flags here
|
||||
<< ")";
|
||||
stream << "IColumn(" << what.dumpStructure() << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
@ -116,7 +133,7 @@ std::ostream & operator<<(std::ostream & stream, const DB::IAST & what)
|
||||
std::ostream & operator<<(std::ostream & stream, const DB::ExpressionAnalyzer & what)
|
||||
{
|
||||
stream << "ExpressionAnalyzer{"
|
||||
<< "hasAggregation="<<what.hasAggregation()
|
||||
<< "hasAggregation=" << what.hasAggregation()
|
||||
<< ", RequiredColumns=" << what.getRequiredColumns()
|
||||
<< ", SubqueriesForSet=" << what.getSubqueriesForSets()
|
||||
<< ", ExternalTables=" << what.getExternalTables()
|
||||
|
@ -249,7 +249,7 @@ struct Factory3 : IFactory
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
srand(time(0));
|
||||
srand(time(nullptr));
|
||||
|
||||
std::cerr << "f1: " << f1().data << std::endl;
|
||||
std::cerr << "f2: " << f2().data << std::endl;
|
||||
|
@ -41,7 +41,7 @@ void AddingDefaultBlockOutputStream::write(const DB::Block & block)
|
||||
|
||||
/// If for some reason there are different offset columns for one nested structure, then we take nonempty.
|
||||
if (!offsets_column || offsets_column->empty())
|
||||
offsets_column = array->getOffsetsColumn();
|
||||
offsets_column = array->getOffsetsPtr();
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,15 +61,15 @@ void AddingDefaultBlockOutputStream::write(const DB::Block & block)
|
||||
DataTypePtr nested_type = typeid_cast<const DataTypeArray &>(*column_to_add.type).getNestedType();
|
||||
UInt64 nested_rows = rows ? get<UInt64>((*offsets_column)[rows - 1]) : 0;
|
||||
|
||||
ColumnPtr nested_column = nested_type->createColumnConst(nested_rows, nested_type->getDefault())->convertToFullColumnIfConst();
|
||||
column_to_add.column = std::make_shared<ColumnArray>(nested_column, offsets_column);
|
||||
ColumnPtr nested_column = nested_type->createColumnConstWithDefaultValue(nested_rows)->convertToFullColumnIfConst();
|
||||
column_to_add.column = ColumnArray::create(nested_column, offsets_column);
|
||||
}
|
||||
else
|
||||
{
|
||||
/** It is necessary to turn a constant column into a full column, since in part of blocks (from other parts),
|
||||
* it can be full (or the interpreter may decide that it is constant everywhere).
|
||||
*/
|
||||
column_to_add.column = column_to_add.type->createColumnConst(rows, column_to_add.type->getDefault())->convertToFullColumnIfConst();
|
||||
column_to_add.column = column_to_add.type->createColumnConstWithDefaultValue(rows)->convertToFullColumnIfConst();
|
||||
}
|
||||
|
||||
res.insert(std::move(column_to_add));
|
||||
|
@ -6,6 +6,11 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
Block AggregatingSortedBlockInputStream::readImpl()
|
||||
{
|
||||
@ -15,10 +20,14 @@ Block AggregatingSortedBlockInputStream::readImpl()
|
||||
if (children.size() == 1)
|
||||
return children[0]->read();
|
||||
|
||||
Block merged_block;
|
||||
ColumnPlainPtrs merged_columns;
|
||||
Block header;
|
||||
MutableColumns merged_columns;
|
||||
|
||||
init(header, merged_columns);
|
||||
|
||||
if (has_collation)
|
||||
throw Exception("Logical error: " + getName() + " does not support collations", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
init(merged_block, merged_columns);
|
||||
if (merged_columns.empty())
|
||||
return Block();
|
||||
|
||||
@ -30,7 +39,7 @@ Block AggregatingSortedBlockInputStream::readImpl()
|
||||
/// Fill in the column numbers that need to be aggregated.
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
{
|
||||
ColumnWithTypeAndName & column = merged_block.safeGetByPosition(i);
|
||||
ColumnWithTypeAndName & column = header.safeGetByPosition(i);
|
||||
|
||||
/// We leave only states of aggregate functions.
|
||||
if (!startsWith(column.type->getName(), "AggregateFunction"))
|
||||
@ -57,26 +66,21 @@ Block AggregatingSortedBlockInputStream::readImpl()
|
||||
|
||||
columns_to_aggregate.resize(column_numbers_to_aggregate.size());
|
||||
for (size_t i = 0, size = columns_to_aggregate.size(); i < size; ++i)
|
||||
columns_to_aggregate[i] = typeid_cast<ColumnAggregateFunction *>(merged_columns[column_numbers_to_aggregate[i]]);
|
||||
columns_to_aggregate[i] = typeid_cast<ColumnAggregateFunction *>(merged_columns[column_numbers_to_aggregate[i]].get());
|
||||
|
||||
if (has_collation)
|
||||
merge(merged_columns, queue_with_collation);
|
||||
else
|
||||
merge(merged_columns, queue);
|
||||
|
||||
return merged_block;
|
||||
merge(merged_columns, queue);
|
||||
return header.cloneWithColumns(std::move(merged_columns));
|
||||
}
|
||||
|
||||
|
||||
template <typename TSortCursor>
|
||||
void AggregatingSortedBlockInputStream::merge(ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue)
|
||||
void AggregatingSortedBlockInputStream::merge(MutableColumns & merged_columns, std::priority_queue<SortCursor> & queue)
|
||||
{
|
||||
size_t merged_rows = 0;
|
||||
|
||||
/// We take the rows in the correct order and put them in `merged_block`, while the rows are no more than `max_block_size`
|
||||
while (!queue.empty())
|
||||
{
|
||||
TSortCursor current = queue.top();
|
||||
SortCursor current = queue.top();
|
||||
|
||||
setPrimaryKeyRef(next_key, current);
|
||||
|
||||
@ -133,8 +137,7 @@ void AggregatingSortedBlockInputStream::merge(ColumnPlainPtrs & merged_columns,
|
||||
}
|
||||
|
||||
|
||||
template <typename TSortCursor>
|
||||
void AggregatingSortedBlockInputStream::addRow(TSortCursor & cursor)
|
||||
void AggregatingSortedBlockInputStream::addRow(SortCursor & cursor)
|
||||
{
|
||||
for (size_t i = 0, size = column_numbers_to_aggregate.size(); i < size; ++i)
|
||||
{
|
||||
|
@ -70,13 +70,11 @@ private:
|
||||
/** We support two different cursors - with Collation and without.
|
||||
* Templates are used instead of polymorphic SortCursor and calls to virtual functions.
|
||||
*/
|
||||
template <typename TSortCursor>
|
||||
void merge(ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue);
|
||||
void merge(MutableColumns & merged_columns, std::priority_queue<SortCursor> & queue);
|
||||
|
||||
/** Extract all states of aggregate functions and merge them with the current group.
|
||||
*/
|
||||
template <typename TSortCursor>
|
||||
void addRow(TSortCursor & cursor);
|
||||
void addRow(SortCursor & cursor);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -6,20 +6,20 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
BinaryRowInputStream::BinaryRowInputStream(ReadBuffer & istr_)
|
||||
: istr(istr_)
|
||||
BinaryRowInputStream::BinaryRowInputStream(ReadBuffer & istr_, const Block & header_)
|
||||
: istr(istr_), header(header_)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool BinaryRowInputStream::read(Block & block)
|
||||
bool BinaryRowInputStream::read(MutableColumns & columns)
|
||||
{
|
||||
if (istr.eof())
|
||||
return false;
|
||||
|
||||
size_t columns = block.columns();
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
block.getByPosition(i).type->deserializeBinary(*block.getByPosition(i).column.get(), istr);
|
||||
size_t num_columns = columns.size();
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
header.getByPosition(i).type->deserializeBinary(*columns[i], istr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -15,12 +15,13 @@ class ReadBuffer;
|
||||
class BinaryRowInputStream : public IRowInputStream
|
||||
{
|
||||
public:
|
||||
BinaryRowInputStream(ReadBuffer & istr_);
|
||||
BinaryRowInputStream(ReadBuffer & istr_, const Block & header_);
|
||||
|
||||
bool read(Block & block) override;
|
||||
bool read(MutableColumns & columns) override;
|
||||
|
||||
private:
|
||||
ReadBuffer & istr;
|
||||
Block header;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ static bool isParseError(int code)
|
||||
|
||||
Block BlockInputStreamFromRowInputStream::readImpl()
|
||||
{
|
||||
Block res = sample.cloneEmpty();
|
||||
size_t num_columns = sample.columns();
|
||||
MutableColumns columns = sample.cloneEmptyColumns();
|
||||
|
||||
try
|
||||
{
|
||||
@ -52,7 +53,7 @@ Block BlockInputStreamFromRowInputStream::readImpl()
|
||||
try
|
||||
{
|
||||
++total_rows;
|
||||
if (!row_input->read(res))
|
||||
if (!row_input->read(columns))
|
||||
break;
|
||||
}
|
||||
catch (Exception & e)
|
||||
@ -87,14 +88,13 @@ Block BlockInputStreamFromRowInputStream::readImpl()
|
||||
|
||||
/// Truncate all columns in block to minimal size (remove values, that was appended to only part of columns).
|
||||
|
||||
size_t columns = res.columns();
|
||||
size_t min_size = std::numeric_limits<size_t>::max();
|
||||
for (size_t column_idx = 0; column_idx < columns; ++column_idx)
|
||||
min_size = std::min(min_size, res.getByPosition(column_idx).column->size());
|
||||
for (size_t column_idx = 0; column_idx < num_columns; ++column_idx)
|
||||
min_size = std::min(min_size, columns[column_idx]->size());
|
||||
|
||||
for (size_t column_idx = 0; column_idx < columns; ++column_idx)
|
||||
for (size_t column_idx = 0; column_idx < num_columns; ++column_idx)
|
||||
{
|
||||
auto & column = res.getByPosition(column_idx).column;
|
||||
auto & column = columns[column_idx];
|
||||
if (column->size() > min_size)
|
||||
column->popBack(column->size() - min_size);
|
||||
}
|
||||
@ -120,10 +120,10 @@ Block BlockInputStreamFromRowInputStream::readImpl()
|
||||
throw;
|
||||
}
|
||||
|
||||
if (res.rows() == 0)
|
||||
res.clear();
|
||||
if (columns.empty() || columns[0]->empty())
|
||||
return {};
|
||||
|
||||
return res;
|
||||
return sample.cloneWithColumns(std::move(columns));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ protected:
|
||||
|
||||
private:
|
||||
RowInputStreamPtr row_input;
|
||||
const Block sample;
|
||||
Block sample;
|
||||
size_t max_block_size;
|
||||
|
||||
UInt64 allow_errors_num;
|
||||
|
@ -15,13 +15,13 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
CSVRowInputStream::CSVRowInputStream(ReadBuffer & istr_, const Block & sample_, const char delimiter_, bool with_names_, bool with_types_)
|
||||
: istr(istr_), sample(sample_), delimiter(delimiter_), with_names(with_names_), with_types(with_types_)
|
||||
CSVRowInputStream::CSVRowInputStream(ReadBuffer & istr_, const Block & header_, const char delimiter_, bool with_names_, bool with_types_)
|
||||
: istr(istr_), header(header_), delimiter(delimiter_), with_names(with_names_), with_types(with_types_)
|
||||
{
|
||||
size_t columns = sample.columns();
|
||||
data_types.resize(columns);
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
data_types[i] = sample.safeGetByPosition(i).type;
|
||||
size_t num_columns = header.columns();
|
||||
data_types.resize(num_columns);
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
data_types[i] = header.safeGetByPosition(i).type;
|
||||
}
|
||||
|
||||
|
||||
@ -81,16 +81,16 @@ static inline void skipWhitespacesAndTabs(ReadBuffer & buf)
|
||||
}
|
||||
|
||||
|
||||
static void skipRow(ReadBuffer & istr, const char delimiter, size_t columns)
|
||||
static void skipRow(ReadBuffer & istr, const char delimiter, size_t num_columns)
|
||||
{
|
||||
String tmp;
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
{
|
||||
skipWhitespacesAndTabs(istr);
|
||||
readCSVString(tmp, istr);
|
||||
skipWhitespacesAndTabs(istr);
|
||||
|
||||
skipDelimiter(istr, delimiter, i + 1 == columns);
|
||||
skipDelimiter(istr, delimiter, i + 1 == num_columns);
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,18 +101,18 @@ void CSVRowInputStream::readPrefix()
|
||||
/// so BOM at beginning of stream cannot be confused with BOM in first string value, and it is safe to skip it.
|
||||
skipBOMIfExists(istr);
|
||||
|
||||
size_t columns = sample.columns();
|
||||
size_t num_columns = data_types.size();
|
||||
String tmp;
|
||||
|
||||
if (with_names)
|
||||
skipRow(istr, delimiter, columns);
|
||||
skipRow(istr, delimiter, num_columns);
|
||||
|
||||
if (with_types)
|
||||
skipRow(istr, delimiter, columns);
|
||||
skipRow(istr, delimiter, num_columns);
|
||||
}
|
||||
|
||||
|
||||
bool CSVRowInputStream::read(Block & block)
|
||||
bool CSVRowInputStream::read(MutableColumns & columns)
|
||||
{
|
||||
if (istr.eof())
|
||||
return false;
|
||||
@ -124,7 +124,7 @@ bool CSVRowInputStream::read(Block & block)
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
skipWhitespacesAndTabs(istr);
|
||||
data_types[i]->deserializeTextCSV(*block.getByPosition(i).column.get(), istr, delimiter);
|
||||
data_types[i]->deserializeTextCSV(*columns[i], istr, delimiter);
|
||||
skipWhitespacesAndTabs(istr);
|
||||
|
||||
skipDelimiter(istr, delimiter, i + 1 == size);
|
||||
@ -140,7 +140,8 @@ String CSVRowInputStream::getDiagnosticInfo()
|
||||
return {};
|
||||
|
||||
WriteBufferFromOwnString out;
|
||||
Block block = sample.cloneEmpty();
|
||||
|
||||
MutableColumns columns = header.cloneEmptyColumns();
|
||||
|
||||
/// It is possible to display detailed diagnostics only if the last and next to last rows are still in the read buffer.
|
||||
size_t bytes_read_at_start_of_buffer = istr.count() - istr.offset();
|
||||
@ -151,14 +152,14 @@ String CSVRowInputStream::getDiagnosticInfo()
|
||||
}
|
||||
|
||||
size_t max_length_of_column_name = 0;
|
||||
for (size_t i = 0; i < sample.columns(); ++i)
|
||||
if (sample.safeGetByPosition(i).name.size() > max_length_of_column_name)
|
||||
max_length_of_column_name = sample.safeGetByPosition(i).name.size();
|
||||
for (size_t i = 0; i < header.columns(); ++i)
|
||||
if (header.safeGetByPosition(i).name.size() > max_length_of_column_name)
|
||||
max_length_of_column_name = header.safeGetByPosition(i).name.size();
|
||||
|
||||
size_t max_length_of_data_type_name = 0;
|
||||
for (size_t i = 0; i < sample.columns(); ++i)
|
||||
if (sample.safeGetByPosition(i).type->getName().size() > max_length_of_data_type_name)
|
||||
max_length_of_data_type_name = sample.safeGetByPosition(i).type->getName().size();
|
||||
for (size_t i = 0; i < header.columns(); ++i)
|
||||
if (header.safeGetByPosition(i).type->getName().size() > max_length_of_data_type_name)
|
||||
max_length_of_data_type_name = header.safeGetByPosition(i).type->getName().size();
|
||||
|
||||
/// Roll back the cursor to the beginning of the previous or current row and parse all over again. But now we derive detailed information.
|
||||
|
||||
@ -167,7 +168,7 @@ String CSVRowInputStream::getDiagnosticInfo()
|
||||
istr.position() = pos_of_prev_row;
|
||||
|
||||
out << "\nRow " << (row_num - 1) << ":\n";
|
||||
if (!parseRowAndPrintDiagnosticInfo(block, out, max_length_of_column_name, max_length_of_data_type_name))
|
||||
if (!parseRowAndPrintDiagnosticInfo(columns, out, max_length_of_column_name, max_length_of_data_type_name))
|
||||
return out.str();
|
||||
}
|
||||
else
|
||||
@ -182,14 +183,14 @@ String CSVRowInputStream::getDiagnosticInfo()
|
||||
}
|
||||
|
||||
out << "\nRow " << row_num << ":\n";
|
||||
parseRowAndPrintDiagnosticInfo(block, out, max_length_of_column_name, max_length_of_data_type_name);
|
||||
parseRowAndPrintDiagnosticInfo(columns, out, max_length_of_column_name, max_length_of_data_type_name);
|
||||
out << "\n";
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
||||
bool CSVRowInputStream::parseRowAndPrintDiagnosticInfo(Block & block,
|
||||
bool CSVRowInputStream::parseRowAndPrintDiagnosticInfo(MutableColumns & columns,
|
||||
WriteBuffer & out, size_t max_length_of_column_name, size_t max_length_of_data_type_name)
|
||||
{
|
||||
size_t size = data_types.size();
|
||||
@ -202,7 +203,7 @@ bool CSVRowInputStream::parseRowAndPrintDiagnosticInfo(Block & block,
|
||||
}
|
||||
|
||||
out << "Column " << i << ", " << std::string((i < 10 ? 2 : i < 100 ? 1 : 0), ' ')
|
||||
<< "name: " << sample.safeGetByPosition(i).name << ", " << std::string(max_length_of_column_name - sample.safeGetByPosition(i).name.size(), ' ')
|
||||
<< "name: " << header.safeGetByPosition(i).name << ", " << std::string(max_length_of_column_name - header.safeGetByPosition(i).name.size(), ' ')
|
||||
<< "type: " << data_types[i]->getName() << ", " << std::string(max_length_of_data_type_name - data_types[i]->getName().size(), ' ');
|
||||
|
||||
BufferBase::Position prev_position = istr.position();
|
||||
@ -213,7 +214,7 @@ bool CSVRowInputStream::parseRowAndPrintDiagnosticInfo(Block & block,
|
||||
{
|
||||
skipWhitespacesAndTabs(istr);
|
||||
prev_position = istr.position();
|
||||
data_types[i]->deserializeTextCSV(*block.safeGetByPosition(i).column, istr, delimiter);
|
||||
data_types[i]->deserializeTextCSV(*columns[i], istr, delimiter);
|
||||
curr_position = istr.position();
|
||||
skipWhitespacesAndTabs(istr);
|
||||
}
|
||||
|
@ -18,9 +18,9 @@ public:
|
||||
/** with_names - in the first line the header with column names
|
||||
* with_types - on the next line header with type names
|
||||
*/
|
||||
CSVRowInputStream(ReadBuffer & istr_, const Block & sample_, const char delimiter_, bool with_names_ = false, bool with_types_ = false);
|
||||
CSVRowInputStream(ReadBuffer & istr_, const Block & header_, const char delimiter_, bool with_names_ = false, bool with_types_ = false);
|
||||
|
||||
bool read(Block & block) override;
|
||||
bool read(MutableColumns & columns) override;
|
||||
void readPrefix() override;
|
||||
bool allowSyncAfterError() const override { return true; };
|
||||
void syncAfterError() override;
|
||||
@ -29,7 +29,7 @@ public:
|
||||
|
||||
private:
|
||||
ReadBuffer & istr;
|
||||
const Block sample;
|
||||
Block header;
|
||||
const char delimiter;
|
||||
bool with_names;
|
||||
bool with_types;
|
||||
@ -48,7 +48,7 @@ private:
|
||||
|
||||
void updateDiagnosticInfo();
|
||||
|
||||
bool parseRowAndPrintDiagnosticInfo(Block & block,
|
||||
bool parseRowAndPrintDiagnosticInfo(MutableColumns & columns,
|
||||
WriteBuffer & out, size_t max_length_of_column_name, size_t max_length_of_data_type_name);
|
||||
};
|
||||
|
||||
|
@ -20,12 +20,12 @@ static String getSchemaPath(const String & schema_dir, const String & schema_fil
|
||||
return schema_dir + escapeForFileName(schema_file) + ".capnp";
|
||||
}
|
||||
|
||||
CapnProtoRowInputStream::NestedField split(const Block & sample, size_t i)
|
||||
CapnProtoRowInputStream::NestedField split(const Block & header, size_t i)
|
||||
{
|
||||
CapnProtoRowInputStream::NestedField field = {{}, i};
|
||||
|
||||
// Remove leading dot in field definition, e.g. ".msg" -> "msg"
|
||||
String name(sample.safeGetByPosition(i).name);
|
||||
String name(header.safeGetByPosition(i).name);
|
||||
if (name.size() > 0 && name[0] == '.')
|
||||
name.erase(0, 1);
|
||||
|
||||
@ -91,7 +91,7 @@ void CapnProtoRowInputStream::createActions(const NestedFieldList & sortedFields
|
||||
String last;
|
||||
size_t level = 0;
|
||||
capnp::StructSchema::Field parent;
|
||||
|
||||
|
||||
for (const auto & field : sortedFields)
|
||||
{
|
||||
// Move to a different field in the same structure, keep parent
|
||||
@ -115,8 +115,8 @@ void CapnProtoRowInputStream::createActions(const NestedFieldList & sortedFields
|
||||
}
|
||||
}
|
||||
|
||||
CapnProtoRowInputStream::CapnProtoRowInputStream(ReadBuffer & istr_, const Block & sample_, const String & schema_dir, const String & schema_file, const String & root_object)
|
||||
: istr(istr_), sample(sample_), parser(std::make_shared<SchemaParser>())
|
||||
CapnProtoRowInputStream::CapnProtoRowInputStream(ReadBuffer & istr_, const Block & header_, const String & schema_dir, const String & schema_file, const String & root_object)
|
||||
: istr(istr_), header(header_), parser(std::make_shared<SchemaParser>())
|
||||
{
|
||||
|
||||
// Parse the schema and fetch the root object
|
||||
@ -129,9 +129,9 @@ CapnProtoRowInputStream::CapnProtoRowInputStream(ReadBuffer & istr_, const Block
|
||||
* and the nesting level doesn't decrease to make traversal easier.
|
||||
*/
|
||||
NestedFieldList list;
|
||||
size_t columns = sample.columns();
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
list.push_back(split(sample, i));
|
||||
size_t num_columns = header.columns();
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
list.push_back(split(header, i));
|
||||
|
||||
// Reorder list to make sure we don't have to backtrack
|
||||
std::sort(list.begin(), list.end(), [](const NestedField & a, const NestedField & b)
|
||||
@ -145,7 +145,7 @@ CapnProtoRowInputStream::CapnProtoRowInputStream(ReadBuffer & istr_, const Block
|
||||
}
|
||||
|
||||
|
||||
bool CapnProtoRowInputStream::read(Block & block)
|
||||
bool CapnProtoRowInputStream::read(MutableColumns & columns)
|
||||
{
|
||||
if (istr.eof())
|
||||
return false;
|
||||
@ -153,7 +153,7 @@ bool CapnProtoRowInputStream::read(Block & block)
|
||||
// Read from underlying buffer directly
|
||||
auto buf = istr.buffer();
|
||||
auto base = reinterpret_cast<const capnp::word *>(istr.position());
|
||||
|
||||
|
||||
// Check if there's enough bytes in the buffer to read the full message
|
||||
kj::Array<capnp::word> heap_array;
|
||||
auto array = kj::arrayPtr(base, buf.size() - istr.offset());
|
||||
@ -174,9 +174,9 @@ bool CapnProtoRowInputStream::read(Block & block)
|
||||
{
|
||||
switch (action.type) {
|
||||
case Action::READ: {
|
||||
auto & col = block.getByPosition(action.column);
|
||||
auto & col = columns[i];
|
||||
Field value = convertNodeToField(stack.back().get(action.field));
|
||||
col.column->insert(value);
|
||||
col->insert(value);
|
||||
break;
|
||||
}
|
||||
case Action::POP:
|
||||
|
@ -32,9 +32,9 @@ public:
|
||||
* schema_file - location of the capnproto schema, e.g. "schema.canpn"
|
||||
* root_object - name to the root object, e.g. "Message"
|
||||
*/
|
||||
CapnProtoRowInputStream(ReadBuffer & istr_, const Block & sample_, const String & schema_dir, const String & schema_file, const String & root_object);
|
||||
CapnProtoRowInputStream(ReadBuffer & istr_, const Block & header_, const String & schema_dir, const String & schema_file, const String & root_object);
|
||||
|
||||
bool read(Block & block) override;
|
||||
bool read(MutableColumns & columns) override;
|
||||
|
||||
private:
|
||||
// Build a traversal plan from a sorted list of fields
|
||||
@ -62,7 +62,7 @@ private:
|
||||
using SchemaParser = DestructorCatcher<capnp::SchemaParser>;
|
||||
|
||||
ReadBuffer & istr;
|
||||
const Block sample;
|
||||
Block header;
|
||||
std::shared_ptr<SchemaParser> parser;
|
||||
capnp::StructSchema root;
|
||||
std::vector<Action> actions;
|
||||
@ -70,4 +70,4 @@ private:
|
||||
|
||||
}
|
||||
|
||||
#endif // USE_CAPNP
|
||||
#endif // USE_CAPNP
|
||||
|
@ -96,7 +96,7 @@ private:
|
||||
IColumn::Filter filter;
|
||||
|
||||
/// Point to `block`.
|
||||
ConstColumnPlainPtrs sort_columns;
|
||||
ColumnRawPtrs sort_columns;
|
||||
const ColumnInt8 * sign_column;
|
||||
|
||||
/// When it reaches zero, the block can be outputted in response.
|
||||
|
@ -12,6 +12,7 @@ namespace DB
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int INCORRECT_DATA;
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@ -39,14 +40,14 @@ void CollapsingSortedBlockInputStream::reportIncorrectData()
|
||||
}
|
||||
|
||||
|
||||
void CollapsingSortedBlockInputStream::insertRows(ColumnPlainPtrs & merged_columns, size_t & merged_rows, bool last_in_stream)
|
||||
void CollapsingSortedBlockInputStream::insertRows(MutableColumns & merged_columns, size_t & merged_rows, bool last_in_stream)
|
||||
{
|
||||
if (count_positive == 0 && count_negative == 0)
|
||||
return;
|
||||
|
||||
if (count_positive == count_negative && !last_is_positive)
|
||||
{
|
||||
/// If all the rows in the input streams collapsed, we still want to give at least one block in the result.
|
||||
/// If all the rows in the input streams was collapsed, we still want to give at least one block in the result.
|
||||
if (last_in_stream && merged_rows == 0 && !blocks_written)
|
||||
{
|
||||
LOG_INFO(log, "All rows collapsed");
|
||||
@ -97,25 +98,29 @@ void CollapsingSortedBlockInputStream::insertRows(ColumnPlainPtrs & merged_colum
|
||||
|
||||
if (out_row_sources_buf)
|
||||
out_row_sources_buf->write(
|
||||
reinterpret_cast<const char *>(current_row_sources.data()),
|
||||
current_row_sources.size() * sizeof(RowSourcePart));
|
||||
reinterpret_cast<const char *>(current_row_sources.data()),
|
||||
current_row_sources.size() * sizeof(RowSourcePart));
|
||||
}
|
||||
|
||||
|
||||
Block CollapsingSortedBlockInputStream::readImpl()
|
||||
{
|
||||
if (finished)
|
||||
return Block();
|
||||
return {};
|
||||
|
||||
if (children.size() == 1)
|
||||
return children[0]->read();
|
||||
|
||||
Block merged_block;
|
||||
ColumnPlainPtrs merged_columns;
|
||||
Block header;
|
||||
MutableColumns merged_columns;
|
||||
|
||||
init(header, merged_columns);
|
||||
|
||||
if (has_collation)
|
||||
throw Exception("Logical error: " + getName() + " does not support collations", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
init(merged_block, merged_columns);
|
||||
if (merged_columns.empty())
|
||||
return Block();
|
||||
return {};
|
||||
|
||||
/// Additional initialization.
|
||||
if (first_negative.empty())
|
||||
@ -124,27 +129,22 @@ Block CollapsingSortedBlockInputStream::readImpl()
|
||||
last_negative.columns.resize(num_columns);
|
||||
last_positive.columns.resize(num_columns);
|
||||
|
||||
sign_column_number = merged_block.getPositionByName(sign_column);
|
||||
sign_column_number = header.getPositionByName(sign_column);
|
||||
}
|
||||
|
||||
if (has_collation)
|
||||
merge(merged_columns, queue_with_collation);
|
||||
else
|
||||
merge(merged_columns, queue);
|
||||
|
||||
return merged_block;
|
||||
merge(merged_columns, queue);
|
||||
return header.cloneWithColumns(std::move(merged_columns));
|
||||
}
|
||||
|
||||
|
||||
template <typename TSortCursor>
|
||||
void CollapsingSortedBlockInputStream::merge(ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue)
|
||||
void CollapsingSortedBlockInputStream::merge(MutableColumns & merged_columns, std::priority_queue<SortCursor> & queue)
|
||||
{
|
||||
size_t merged_rows = 0;
|
||||
|
||||
/// Take rows in correct order and put them into `merged_block` until the rows no more than `max_block_size`
|
||||
/// Take rows in correct order and put them into `merged_columns` until the rows no more than `max_block_size`
|
||||
for (; !queue.empty(); ++current_pos)
|
||||
{
|
||||
TSortCursor current = queue.top();
|
||||
SortCursor current = queue.top();
|
||||
|
||||
if (current_key.empty())
|
||||
{
|
||||
|
@ -90,11 +90,10 @@ private:
|
||||
/** We support two different cursors - with Collation and without.
|
||||
* Templates are used instead of polymorphic SortCursors and calls to virtual functions.
|
||||
*/
|
||||
template <typename TSortCursor>
|
||||
void merge(ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue);
|
||||
void merge(MutableColumns & merged_columns, std::priority_queue<SortCursor> & queue);
|
||||
|
||||
/// Output to result rows for the current primary key.
|
||||
void insertRows(ColumnPlainPtrs & merged_columns, size_t & merged_rows, bool last_in_stream = false);
|
||||
void insertRows(MutableColumns & merged_columns, size_t & merged_rows, bool last_in_stream = false);
|
||||
|
||||
void reportIncorrectData();
|
||||
};
|
||||
|
@ -65,7 +65,7 @@ void ColumnGathererStream::init()
|
||||
if (i == 0)
|
||||
{
|
||||
column.name = name;
|
||||
column.type = block.getByName(name).type->clone();
|
||||
column.type = block.getByName(name).type;
|
||||
column.column = column.type->createColumn();
|
||||
}
|
||||
|
||||
@ -89,8 +89,12 @@ Block ColumnGathererStream::readImpl()
|
||||
return Block();
|
||||
|
||||
output_block = Block{column.cloneEmpty()};
|
||||
output_block.getByPosition(0).column->gather(*this);
|
||||
return std::move(output_block);
|
||||
MutableColumnPtr output_column = output_block.getByPosition(0).column->mutate();
|
||||
output_column->gather(*this);
|
||||
if (!output_column->empty())
|
||||
output_block.getByPosition(0).column = std::move(output_column);
|
||||
|
||||
return output_block;
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ Block DistinctBlockInputStream::readImpl()
|
||||
if (!block)
|
||||
return Block();
|
||||
|
||||
const ConstColumnPlainPtrs column_ptrs(getKeyColumns(block));
|
||||
const ColumnRawPtrs column_ptrs(getKeyColumns(block));
|
||||
if (column_ptrs.empty())
|
||||
return block;
|
||||
|
||||
@ -106,7 +106,7 @@ bool DistinctBlockInputStream::checkLimits() const
|
||||
template <typename Method>
|
||||
void DistinctBlockInputStream::buildFilter(
|
||||
Method & method,
|
||||
const ConstColumnPlainPtrs & columns,
|
||||
const ColumnRawPtrs & columns,
|
||||
IColumn::Filter & filter,
|
||||
size_t rows,
|
||||
SetVariants & variants) const
|
||||
@ -132,11 +132,11 @@ void DistinctBlockInputStream::buildFilter(
|
||||
}
|
||||
}
|
||||
|
||||
ConstColumnPlainPtrs DistinctBlockInputStream::getKeyColumns(const Block & block) const
|
||||
ColumnRawPtrs DistinctBlockInputStream::getKeyColumns(const Block & block) const
|
||||
{
|
||||
size_t columns = columns_names.empty() ? block.columns() : columns_names.size();
|
||||
|
||||
ConstColumnPlainPtrs column_ptrs;
|
||||
ColumnRawPtrs column_ptrs;
|
||||
column_ptrs.reserve(columns);
|
||||
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
|
@ -30,12 +30,12 @@ protected:
|
||||
private:
|
||||
bool checkLimits() const;
|
||||
|
||||
ConstColumnPlainPtrs getKeyColumns(const Block & block) const;
|
||||
ColumnRawPtrs getKeyColumns(const Block & block) const;
|
||||
|
||||
template <typename Method>
|
||||
void buildFilter(
|
||||
Method & method,
|
||||
const ConstColumnPlainPtrs & key_columns,
|
||||
const ColumnRawPtrs & key_columns,
|
||||
IColumn::Filter & filter,
|
||||
size_t rows,
|
||||
SetVariants & variants) const;
|
||||
|
@ -40,11 +40,11 @@ Block DistinctSortedBlockInputStream::readImpl()
|
||||
if (!block)
|
||||
return Block();
|
||||
|
||||
const ConstColumnPlainPtrs column_ptrs(getKeyColumns(block));
|
||||
const ColumnRawPtrs column_ptrs(getKeyColumns(block));
|
||||
if (column_ptrs.empty())
|
||||
return block;
|
||||
|
||||
const ConstColumnPlainPtrs clearing_hint_columns(getClearingColumns(block, column_ptrs));
|
||||
const ColumnRawPtrs clearing_hint_columns(getClearingColumns(block, column_ptrs));
|
||||
|
||||
if (data.type == ClearableSetVariants::Type::EMPTY)
|
||||
data.init(ClearableSetVariants::chooseMethod(column_ptrs, key_sizes));
|
||||
@ -112,8 +112,8 @@ bool DistinctSortedBlockInputStream::checkLimits() const
|
||||
template <typename Method>
|
||||
bool DistinctSortedBlockInputStream::buildFilter(
|
||||
Method & method,
|
||||
const ConstColumnPlainPtrs & columns,
|
||||
const ConstColumnPlainPtrs & clearing_hint_columns,
|
||||
const ColumnRawPtrs & columns,
|
||||
const ColumnRawPtrs & clearing_hint_columns,
|
||||
IColumn::Filter & filter,
|
||||
size_t rows,
|
||||
ClearableSetVariants & variants) const
|
||||
@ -158,11 +158,11 @@ bool DistinctSortedBlockInputStream::buildFilter(
|
||||
return has_new_data;
|
||||
}
|
||||
|
||||
ConstColumnPlainPtrs DistinctSortedBlockInputStream::getKeyColumns(const Block & block) const
|
||||
ColumnRawPtrs DistinctSortedBlockInputStream::getKeyColumns(const Block & block) const
|
||||
{
|
||||
size_t columns = columns_names.empty() ? block.columns() : columns_names.size();
|
||||
|
||||
ConstColumnPlainPtrs column_ptrs;
|
||||
ColumnRawPtrs column_ptrs;
|
||||
column_ptrs.reserve(columns);
|
||||
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
@ -179,9 +179,9 @@ ConstColumnPlainPtrs DistinctSortedBlockInputStream::getKeyColumns(const Block &
|
||||
return column_ptrs;
|
||||
}
|
||||
|
||||
ConstColumnPlainPtrs DistinctSortedBlockInputStream::getClearingColumns(const Block & block, const ConstColumnPlainPtrs & key_columns) const
|
||||
ColumnRawPtrs DistinctSortedBlockInputStream::getClearingColumns(const Block & block, const ColumnRawPtrs & key_columns) const
|
||||
{
|
||||
ConstColumnPlainPtrs clearing_hint_columns;
|
||||
ColumnRawPtrs clearing_hint_columns;
|
||||
clearing_hint_columns.reserve(description.size());
|
||||
for(const auto & sort_column_description : description)
|
||||
{
|
||||
@ -195,7 +195,7 @@ ConstColumnPlainPtrs DistinctSortedBlockInputStream::getClearingColumns(const Bl
|
||||
return clearing_hint_columns;
|
||||
}
|
||||
|
||||
bool DistinctSortedBlockInputStream::rowsEqual(const ConstColumnPlainPtrs & lhs, size_t n, const ConstColumnPlainPtrs & rhs, size_t m)
|
||||
bool DistinctSortedBlockInputStream::rowsEqual(const ColumnRawPtrs & lhs, size_t n, const ColumnRawPtrs & rhs, size_t m)
|
||||
{
|
||||
for (size_t column_index = 0, num_columns = lhs.size(); column_index < num_columns; ++column_index)
|
||||
{
|
||||
|
@ -33,18 +33,18 @@ protected:
|
||||
private:
|
||||
bool checkLimits() const;
|
||||
|
||||
ConstColumnPlainPtrs getKeyColumns(const Block & block) const;
|
||||
ColumnRawPtrs getKeyColumns(const Block & block) const;
|
||||
/// When clearing_columns changed, we can clean HashSet to memory optimization
|
||||
/// clearing_columns is a left-prefix of SortDescription exists in key_columns
|
||||
ConstColumnPlainPtrs getClearingColumns(const Block & block, const ConstColumnPlainPtrs & key_columns) const;
|
||||
static bool rowsEqual(const ConstColumnPlainPtrs & lhs, size_t n, const ConstColumnPlainPtrs & rhs, size_t m);
|
||||
ColumnRawPtrs getClearingColumns(const Block & block, const ColumnRawPtrs & key_columns) const;
|
||||
static bool rowsEqual(const ColumnRawPtrs & lhs, size_t n, const ColumnRawPtrs & rhs, size_t m);
|
||||
|
||||
/// return true if has new data
|
||||
template <typename Method>
|
||||
bool buildFilter(
|
||||
Method & method,
|
||||
const ConstColumnPlainPtrs & key_columns,
|
||||
const ConstColumnPlainPtrs & clearing_hint_columns,
|
||||
const ColumnRawPtrs & key_columns,
|
||||
const ColumnRawPtrs & clearing_hint_columns,
|
||||
IColumn::Filter & filter,
|
||||
size_t rows,
|
||||
ClearableSetVariants & variants) const;
|
||||
@ -54,7 +54,7 @@ private:
|
||||
struct PreviousBlock
|
||||
{
|
||||
Block block;
|
||||
ConstColumnPlainPtrs clearing_hint_columns;
|
||||
ColumnRawPtrs clearing_hint_columns;
|
||||
};
|
||||
PreviousBlock prev_block;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <Columns/ColumnsNumber.h>
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Columns/ColumnsCommon.h>
|
||||
#include <Columns/ColumnConst.h>
|
||||
#include <Columns/FilterDescription.h>
|
||||
#include <Interpreters/ExpressionActions.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
@ -53,22 +53,6 @@ const Block & FilterBlockInputStream::getTotals()
|
||||
}
|
||||
|
||||
|
||||
static void analyzeConstantFilter(const IColumn & column, bool & filter_always_false, bool & filter_always_true)
|
||||
{
|
||||
if (column.onlyNull())
|
||||
{
|
||||
filter_always_false = true;
|
||||
}
|
||||
else if (column.isColumnConst())
|
||||
{
|
||||
if (static_cast<const ColumnConst &>(column).getValue<UInt8>())
|
||||
filter_always_true = true;
|
||||
else
|
||||
filter_always_false = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Block FilterBlockInputStream::readImpl()
|
||||
{
|
||||
Block res;
|
||||
@ -95,9 +79,9 @@ Block FilterBlockInputStream::readImpl()
|
||||
ColumnPtr column = sample_block.safeGetByPosition(filter_column_in_sample_block).column;
|
||||
|
||||
if (column)
|
||||
analyzeConstantFilter(*column, filter_always_false, filter_always_true);
|
||||
constant_filter_description = ConstantFilterDescription(*column);
|
||||
|
||||
if (filter_always_false)
|
||||
if (constant_filter_description.always_false)
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -110,7 +94,7 @@ Block FilterBlockInputStream::readImpl()
|
||||
|
||||
expression->execute(res);
|
||||
|
||||
if (filter_always_true)
|
||||
if (constant_filter_description.always_true)
|
||||
return res;
|
||||
|
||||
/// Find the current position of the filter column in the block.
|
||||
@ -120,47 +104,23 @@ Block FilterBlockInputStream::readImpl()
|
||||
size_t columns = res.columns();
|
||||
ColumnPtr column = res.safeGetByPosition(filter_column).column;
|
||||
|
||||
IColumn * observed_column = column.get();
|
||||
bool is_nullable_column = observed_column->isColumnNullable();
|
||||
if (is_nullable_column)
|
||||
observed_column = static_cast<const ColumnNullable &>(*column.get()).getNestedColumn().get();
|
||||
/** It happens that at the stage of analysis of expressions (in sample_block) the columns-constants have not been calculated yet,
|
||||
* and now - are calculated. That is, not all cases are covered by the code above.
|
||||
* This happens if the function returns a constant for a non-constant argument.
|
||||
* For example, `ignore` function.
|
||||
*/
|
||||
constant_filter_description = ConstantFilterDescription(*column);
|
||||
|
||||
ColumnUInt8 * column_vec = typeid_cast<ColumnUInt8 *>(observed_column);
|
||||
if (!column_vec)
|
||||
if (constant_filter_description.always_false)
|
||||
{
|
||||
/** It happens that at the stage of analysis of expressions (in sample_block) the columns-constants have not been calculated yet,
|
||||
* and now - are calculated. That is, not all cases are covered by the code above.
|
||||
* This happens if the function returns a constant for a non-constant argument.
|
||||
* For example, `ignore` function.
|
||||
*/
|
||||
analyzeConstantFilter(*observed_column, filter_always_false, filter_always_true);
|
||||
|
||||
if (filter_always_false)
|
||||
{
|
||||
res.clear();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (filter_always_true)
|
||||
return res;
|
||||
|
||||
throw Exception("Illegal type " + column->getName() + " of column for filter. Must be ColumnUInt8 or ColumnConstUInt8 or Nullable variants of them.",
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_COLUMN_FOR_FILTER);
|
||||
res.clear();
|
||||
return res;
|
||||
}
|
||||
|
||||
IColumn::Filter & filter = column_vec->getData();
|
||||
if (constant_filter_description.always_true)
|
||||
return res;
|
||||
|
||||
if (is_nullable_column)
|
||||
{
|
||||
/// Exclude the entries of the filter column that actually are NULL values.
|
||||
|
||||
const NullMap & null_map = static_cast<ColumnNullable &>(*column).getNullMap();
|
||||
|
||||
IColumn::Filter & filter = column_vec->getData();
|
||||
for (size_t i = 0, size = null_map.size(); i < size; ++i)
|
||||
if (null_map[i])
|
||||
filter[i] = 0;
|
||||
}
|
||||
FilterDescription filter_and_holder(*column);
|
||||
|
||||
/** Let's find out how many rows will be in result.
|
||||
* To do this, we filter out the first non-constant column
|
||||
@ -182,12 +142,12 @@ Block FilterBlockInputStream::readImpl()
|
||||
if (first_non_constant_column != static_cast<size_t>(filter_column))
|
||||
{
|
||||
ColumnWithTypeAndName & current_column = res.safeGetByPosition(first_non_constant_column);
|
||||
current_column.column = current_column.column->filter(filter, -1);
|
||||
current_column.column = current_column.column->filter(*filter_and_holder.data, -1);
|
||||
filtered_rows = current_column.column->size();
|
||||
}
|
||||
else
|
||||
{
|
||||
filtered_rows = countBytesInFilter(filter);
|
||||
filtered_rows = countBytesInFilter(*filter_and_holder.data);
|
||||
}
|
||||
|
||||
/// If the current block is completely filtered out, let's move on to the next one.
|
||||
@ -195,7 +155,7 @@ Block FilterBlockInputStream::readImpl()
|
||||
continue;
|
||||
|
||||
/// If all the rows pass through the filter.
|
||||
if (filtered_rows == filter.size())
|
||||
if (filtered_rows == filter_and_holder.data->size())
|
||||
{
|
||||
/// Replace the column with the filter by a constant.
|
||||
res.safeGetByPosition(filter_column).column = res.safeGetByPosition(filter_column).type->createColumnConst(filtered_rows, UInt64(1));
|
||||
@ -225,7 +185,7 @@ Block FilterBlockInputStream::readImpl()
|
||||
if (current_column.column->isColumnConst())
|
||||
current_column.column = current_column.column->cut(0, filtered_rows);
|
||||
else
|
||||
current_column.column = current_column.column->filter(filter, -1);
|
||||
current_column.column = current_column.column->filter(*filter_and_holder.data, -1);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <DataStreams/IProfilingBlockInputStream.h>
|
||||
#include <Columns/FilterDescription.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -36,8 +37,8 @@ private:
|
||||
String filter_column_name;
|
||||
|
||||
bool is_first = true;
|
||||
bool filter_always_true = false;
|
||||
bool filter_always_false = false;
|
||||
|
||||
ConstantFilterDescription constant_filter_description;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ BlockInputStreamPtr FormatFactory::getInput(const String & name, ReadBuffer & bu
|
||||
}
|
||||
else if (name == "RowBinary")
|
||||
{
|
||||
return wrap_row_stream(std::make_shared<BinaryRowInputStream>(buf));
|
||||
return wrap_row_stream(std::make_shared<BinaryRowInputStream>(buf, sample));
|
||||
}
|
||||
else if (name == "TabSeparated" || name == "TSV") /// TSV is a synonym/alias for the original TabSeparated format
|
||||
{
|
||||
@ -79,7 +79,7 @@ BlockInputStreamPtr FormatFactory::getInput(const String & name, ReadBuffer & bu
|
||||
}
|
||||
else if (name == "Values")
|
||||
{
|
||||
return wrap_row_stream(std::make_shared<ValuesRowInputStream>(buf, context, settings.input_format_values_interpret_expressions));
|
||||
return wrap_row_stream(std::make_shared<ValuesRowInputStream>(buf, sample, context, settings.input_format_values_interpret_expressions));
|
||||
}
|
||||
else if (name == "CSV")
|
||||
{
|
||||
|
@ -8,6 +8,7 @@ namespace DB
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int NO_SUCH_COLUMN_IN_TABLE;
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@ -67,10 +68,14 @@ Block GraphiteRollupSortedBlockInputStream::readImpl()
|
||||
if (finished)
|
||||
return Block();
|
||||
|
||||
Block merged_block;
|
||||
ColumnPlainPtrs merged_columns;
|
||||
Block header;
|
||||
MutableColumns merged_columns;
|
||||
|
||||
init(header, merged_columns);
|
||||
|
||||
if (has_collation)
|
||||
throw Exception("Logical error: " + getName() + " does not support collations", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
init(merged_block, merged_columns);
|
||||
if (merged_columns.empty())
|
||||
return Block();
|
||||
|
||||
@ -85,10 +90,10 @@ Block GraphiteRollupSortedBlockInputStream::readImpl()
|
||||
place_for_aggregate_state.resize(max_size_of_aggregate_state);
|
||||
|
||||
/// Memoize column numbers in block.
|
||||
path_column_num = merged_block.getPositionByName(params.path_column_name);
|
||||
time_column_num = merged_block.getPositionByName(params.time_column_name);
|
||||
value_column_num = merged_block.getPositionByName(params.value_column_name);
|
||||
version_column_num = merged_block.getPositionByName(params.version_column_name);
|
||||
path_column_num = header.getPositionByName(params.path_column_name);
|
||||
time_column_num = header.getPositionByName(params.time_column_name);
|
||||
value_column_num = header.getPositionByName(params.value_column_name);
|
||||
version_column_num = header.getPositionByName(params.version_column_name);
|
||||
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
if (i != time_column_num && i != value_column_num && i != version_column_num)
|
||||
@ -98,23 +103,18 @@ Block GraphiteRollupSortedBlockInputStream::readImpl()
|
||||
current_selected_row.columns.resize(num_columns);
|
||||
}
|
||||
|
||||
if (has_collation)
|
||||
merge(merged_columns, queue_with_collation);
|
||||
else
|
||||
merge(merged_columns, queue);
|
||||
|
||||
return merged_block;
|
||||
merge(merged_columns, queue);
|
||||
return header.cloneWithColumns(std::move(merged_columns));
|
||||
}
|
||||
|
||||
|
||||
template <typename TSortCursor>
|
||||
void GraphiteRollupSortedBlockInputStream::merge(ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue)
|
||||
void GraphiteRollupSortedBlockInputStream::merge(MutableColumns & merged_columns, std::priority_queue<SortCursor> & queue)
|
||||
{
|
||||
const DateLUTImpl & date_lut = DateLUT::instance();
|
||||
|
||||
size_t started_rows = 0; /// Number of times startNextRow() has been called.
|
||||
|
||||
/// Take rows in needed order and put them into `merged_block` until we get `max_block_size` rows.
|
||||
/// Take rows in needed order and put them into `merged_columns` until we get `max_block_size` rows.
|
||||
///
|
||||
/// Variables starting with current_* refer to the rows previously popped from the queue that will
|
||||
/// contribute towards current output row.
|
||||
@ -122,7 +122,7 @@ void GraphiteRollupSortedBlockInputStream::merge(ColumnPlainPtrs & merged_column
|
||||
|
||||
while (!queue.empty())
|
||||
{
|
||||
TSortCursor next_cursor = queue.top();
|
||||
SortCursor next_cursor = queue.top();
|
||||
|
||||
StringRef next_path = next_cursor->all_columns[path_column_num]->getDataAt(next_cursor->pos);
|
||||
bool path_differs = is_first || next_path != current_path;
|
||||
@ -218,8 +218,7 @@ void GraphiteRollupSortedBlockInputStream::merge(ColumnPlainPtrs & merged_column
|
||||
}
|
||||
|
||||
|
||||
template <typename TSortCursor>
|
||||
void GraphiteRollupSortedBlockInputStream::startNextRow(ColumnPlainPtrs & merged_columns, TSortCursor & cursor, const Graphite::Pattern * next_pattern)
|
||||
void GraphiteRollupSortedBlockInputStream::startNextRow(MutableColumns & merged_columns, SortCursor & cursor, const Graphite::Pattern * next_pattern)
|
||||
{
|
||||
/// Copy unmodified column values.
|
||||
for (size_t i = 0, size = unmodified_column_numbers.size(); i < size; ++i)
|
||||
@ -238,7 +237,7 @@ void GraphiteRollupSortedBlockInputStream::startNextRow(ColumnPlainPtrs & merged
|
||||
}
|
||||
|
||||
|
||||
void GraphiteRollupSortedBlockInputStream::finishCurrentRow(ColumnPlainPtrs & merged_columns)
|
||||
void GraphiteRollupSortedBlockInputStream::finishCurrentRow(MutableColumns & merged_columns)
|
||||
{
|
||||
/// Insert calculated values of the columns `time`, `value`, `version`.
|
||||
merged_columns[time_column_num]->insert(UInt64(current_time_rounded));
|
||||
@ -252,7 +251,7 @@ void GraphiteRollupSortedBlockInputStream::finishCurrentRow(ColumnPlainPtrs & me
|
||||
}
|
||||
else
|
||||
merged_columns[value_column_num]->insertFrom(
|
||||
*current_selected_row.columns[value_column_num], current_selected_row.row_num);
|
||||
*current_selected_row.columns[value_column_num], current_selected_row.row_num);
|
||||
}
|
||||
|
||||
|
||||
|
@ -195,15 +195,13 @@ private:
|
||||
UInt32 selectPrecision(const Graphite::Retentions & retentions, time_t time) const;
|
||||
|
||||
|
||||
template <typename TSortCursor>
|
||||
void merge(ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue);
|
||||
void merge(MutableColumns & merged_columns, std::priority_queue<SortCursor> & queue);
|
||||
|
||||
/// Insert the values into the resulting columns, which will not be changed in the future.
|
||||
template <typename TSortCursor>
|
||||
void startNextRow(ColumnPlainPtrs & merged_columns, TSortCursor & cursor, const Graphite::Pattern * next_pattern);
|
||||
void startNextRow(MutableColumns & merged_columns, SortCursor & cursor, const Graphite::Pattern * next_pattern);
|
||||
|
||||
/// Insert the calculated `time`, `value`, `version` values into the resulting columns by the last group of rows.
|
||||
void finishCurrentRow(ColumnPlainPtrs & merged_columns);
|
||||
void finishCurrentRow(MutableColumns & merged_columns);
|
||||
|
||||
/// Update the state of the aggregate function with the new `value`.
|
||||
void accumulateRow(RowRef & row);
|
||||
|
@ -91,36 +91,48 @@ void IProfilingBlockInputStream::readSuffix()
|
||||
|
||||
void IProfilingBlockInputStream::updateExtremes(Block & block)
|
||||
{
|
||||
size_t columns = block.columns();
|
||||
size_t num_columns = block.columns();
|
||||
|
||||
if (!extremes)
|
||||
{
|
||||
extremes = block.cloneEmpty();
|
||||
MutableColumns extremes_columns(num_columns);
|
||||
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
{
|
||||
Field min_value;
|
||||
Field max_value;
|
||||
const ColumnPtr & src = block.safeGetByPosition(i).column;
|
||||
|
||||
block.safeGetByPosition(i).column->getExtremes(min_value, max_value);
|
||||
if (src->isColumnConst())
|
||||
{
|
||||
/// Equal min and max.
|
||||
extremes_columns[i] = src->cloneResized(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Field min_value;
|
||||
Field max_value;
|
||||
|
||||
ColumnPtr & column = extremes.safeGetByPosition(i).column;
|
||||
src->getExtremes(min_value, max_value);
|
||||
|
||||
if (auto converted = column->convertToFullColumnIfConst())
|
||||
column = converted;
|
||||
extremes_columns[i] = src->cloneEmpty();
|
||||
|
||||
column->insert(min_value);
|
||||
column->insert(max_value);
|
||||
extremes_columns[i]->insert(min_value);
|
||||
extremes_columns[i]->insert(max_value);
|
||||
}
|
||||
}
|
||||
|
||||
extremes = block.cloneWithColumns(std::move(extremes_columns));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
{
|
||||
ColumnPtr & column = extremes.safeGetByPosition(i).column;
|
||||
ColumnPtr & old_extremes = extremes.safeGetByPosition(i).column;
|
||||
|
||||
Field min_value = (*column)[0];
|
||||
Field max_value = (*column)[1];
|
||||
if (old_extremes->isColumnConst())
|
||||
continue;
|
||||
|
||||
Field min_value = (*old_extremes)[0];
|
||||
Field max_value = (*old_extremes)[1];
|
||||
|
||||
Field cur_min_value;
|
||||
Field cur_max_value;
|
||||
@ -132,9 +144,12 @@ void IProfilingBlockInputStream::updateExtremes(Block & block)
|
||||
if (cur_max_value > max_value)
|
||||
max_value = cur_max_value;
|
||||
|
||||
column = column->cloneEmpty();
|
||||
column->insert(min_value);
|
||||
column->insert(max_value);
|
||||
MutableColumnPtr new_extremes = old_extremes->cloneEmpty();
|
||||
|
||||
new_extremes->insert(min_value);
|
||||
new_extremes->insert(max_value);
|
||||
|
||||
old_extremes = std::move(new_extremes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -299,7 +314,7 @@ void IProfilingBlockInputStream::progressImpl(const Progress & value)
|
||||
|
||||
if (quota != nullptr && limits.mode == LIMITS_TOTAL)
|
||||
{
|
||||
quota->checkAndAddReadRowsBytes(time(0), value.rows, value.bytes);
|
||||
quota->checkAndAddReadRowsBytes(time(nullptr), value.rows, value.bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,21 +4,22 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <Columns/IColumn.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
class Block;
|
||||
|
||||
/** Interface of stream, that allows to read data by rows.
|
||||
*/
|
||||
class IRowInputStream : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/** Read next row and append it to block.
|
||||
/** Read next row and append it to the columns.
|
||||
* If no more rows - return false.
|
||||
*/
|
||||
virtual bool read(Block & block) = 0;
|
||||
virtual bool read(MutableColumns & columns) = 0;
|
||||
|
||||
virtual void readPrefix() {}; /// delimiter before begin of result
|
||||
virtual void readSuffix() {}; /// delimiter after end of result
|
||||
|
@ -12,15 +12,15 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
JSONEachRowRowInputStream::JSONEachRowRowInputStream(ReadBuffer & istr_, const Block & sample_, bool skip_unknown_)
|
||||
: istr(istr_), sample(sample_), skip_unknown(skip_unknown_), name_map(sample.columns())
|
||||
JSONEachRowRowInputStream::JSONEachRowRowInputStream(ReadBuffer & istr_, const Block & header_, bool skip_unknown_)
|
||||
: istr(istr_), header(header_), skip_unknown(skip_unknown_), name_map(header.columns())
|
||||
{
|
||||
/// In this format, BOM at beginning of stream cannot be confused with value, so it is safe to skip it.
|
||||
skipBOMIfExists(istr);
|
||||
|
||||
size_t columns = sample.columns();
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
name_map[sample.safeGetByPosition(i).name] = i; /// NOTE You could place names more cache-locally.
|
||||
size_t num_columns = header.columns();
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
name_map[header.safeGetByPosition(i).name] = i; /// NOTE You could place names more cache-locally.
|
||||
}
|
||||
|
||||
|
||||
@ -58,15 +58,15 @@ static void skipColonDelimeter(ReadBuffer & istr)
|
||||
}
|
||||
|
||||
|
||||
bool JSONEachRowRowInputStream::read(Block & block)
|
||||
bool JSONEachRowRowInputStream::read(MutableColumns & columns)
|
||||
{
|
||||
skipWhitespaceIfAny(istr);
|
||||
|
||||
|
||||
/// We consume ;, or \n before scanning a new row, instead scanning to next row at the end.
|
||||
/// The reason is that if we want an exact number of rows read with LIMIT x
|
||||
/// The reason is that if we want an exact number of rows read with LIMIT x
|
||||
/// from a streaming table engine with text data format, like File or Kafka
|
||||
/// then seeking to next ;, or \n would trigger reading of an extra row at the end.
|
||||
|
||||
|
||||
/// Semicolon is added for convenience as it could be used at end of INSERT query.
|
||||
if (!istr.eof() && (*istr.position() == ',' || *istr.position() == ';'))
|
||||
++istr.position();
|
||||
@ -77,12 +77,12 @@ bool JSONEachRowRowInputStream::read(Block & block)
|
||||
|
||||
assertChar('{', istr);
|
||||
|
||||
size_t columns = block.columns();
|
||||
size_t num_columns = columns.size();
|
||||
|
||||
/// Set of columns for which the values were read. The rest will be filled with default values.
|
||||
/// TODO Ability to provide your DEFAULTs.
|
||||
bool read_columns[columns];
|
||||
memset(read_columns, 0, columns);
|
||||
bool read_columns[num_columns];
|
||||
memset(read_columns, 0, num_columns);
|
||||
|
||||
bool first = true;
|
||||
while (true)
|
||||
@ -130,19 +130,13 @@ bool JSONEachRowRowInputStream::read(Block & block)
|
||||
|
||||
read_columns[index] = true;
|
||||
|
||||
auto & col = block.getByPosition(index);
|
||||
col.type->deserializeTextJSON(*col.column, istr);
|
||||
header.getByPosition(index).type->deserializeTextJSON(*columns[index], istr);
|
||||
}
|
||||
|
||||
/// Fill non-visited columns with the default values.
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
{
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
if (!read_columns[i])
|
||||
{
|
||||
ColumnWithTypeAndName & elem = block.getByPosition(i);
|
||||
elem.type->insertDefaultInto(*elem.column);
|
||||
}
|
||||
}
|
||||
header.getByPosition(i).type->insertDefaultInto(*columns[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -18,15 +18,15 @@ class ReadBuffer;
|
||||
class JSONEachRowRowInputStream : public IRowInputStream
|
||||
{
|
||||
public:
|
||||
JSONEachRowRowInputStream(ReadBuffer & istr_, const Block & sample_, bool skip_unknown_);
|
||||
JSONEachRowRowInputStream(ReadBuffer & istr_, const Block & header_, bool skip_unknown_);
|
||||
|
||||
bool read(Block & block) override;
|
||||
bool read(MutableColumns & columns) override;
|
||||
bool allowSyncAfterError() const override { return true; };
|
||||
void syncAfterError() override;
|
||||
|
||||
private:
|
||||
ReadBuffer & istr;
|
||||
const Block sample;
|
||||
Block header;
|
||||
bool skip_unknown;
|
||||
|
||||
/// Buffer for the read from the stream field name. Used when you have to copy it.
|
||||
|
@ -9,7 +9,7 @@ namespace DB
|
||||
JSONRowOutputStream::JSONRowOutputStream(WriteBuffer & ostr_, const Block & sample_, bool write_statistics_, const FormatSettingsJSON & settings_)
|
||||
: dst_ostr(ostr_), write_statistics(write_statistics_), settings(settings_)
|
||||
{
|
||||
NamesAndTypesList columns(sample_.getColumnsList());
|
||||
NamesAndTypesList columns(sample_.getNamesAndTypesList());
|
||||
fields.assign(columns.begin(), columns.end());
|
||||
|
||||
bool need_validate_utf8 = false;
|
||||
|
@ -20,7 +20,7 @@ Block LimitByBlockInputStream::readImpl()
|
||||
if (!block)
|
||||
return Block();
|
||||
|
||||
const ConstColumnPlainPtrs column_ptrs(getKeyColumns(block));
|
||||
const ColumnRawPtrs column_ptrs(getKeyColumns(block));
|
||||
const size_t rows = block.rows();
|
||||
IColumn::Filter filter(rows);
|
||||
size_t inserted_count = 0;
|
||||
@ -56,9 +56,9 @@ Block LimitByBlockInputStream::readImpl()
|
||||
}
|
||||
}
|
||||
|
||||
ConstColumnPlainPtrs LimitByBlockInputStream::getKeyColumns(Block & block) const
|
||||
ColumnRawPtrs LimitByBlockInputStream::getKeyColumns(Block & block) const
|
||||
{
|
||||
ConstColumnPlainPtrs column_ptrs;
|
||||
ColumnRawPtrs column_ptrs;
|
||||
column_ptrs.reserve(columns_names.size());
|
||||
|
||||
for (const auto & name : columns_names)
|
||||
|
@ -26,7 +26,7 @@ protected:
|
||||
Block readImpl() override;
|
||||
|
||||
private:
|
||||
ConstColumnPlainPtrs getKeyColumns(Block & block) const;
|
||||
ColumnRawPtrs getKeyColumns(Block & block) const;
|
||||
|
||||
private:
|
||||
using MapHashed = HashMap<UInt128, UInt64, UInt128TrivialHash>;
|
||||
|
@ -204,12 +204,10 @@ Block MergeSortingBlocksBlockInputStream::readImpl()
|
||||
template <typename TSortCursor>
|
||||
Block MergeSortingBlocksBlockInputStream::mergeImpl(std::priority_queue<TSortCursor> & queue)
|
||||
{
|
||||
Block merged = blocks[0].cloneEmpty();
|
||||
size_t num_columns = blocks[0].columns();
|
||||
|
||||
ColumnPlainPtrs merged_columns;
|
||||
for (size_t i = 0; i < num_columns; ++i) /// TODO: reserve
|
||||
merged_columns.push_back(merged.safeGetByPosition(i).column.get());
|
||||
MutableColumns merged_columns = blocks[0].cloneEmptyColumns();
|
||||
/// TODO: reserve (in each column)
|
||||
|
||||
/// Take rows from queue in right order and push to 'merged'.
|
||||
size_t merged_rows = 0;
|
||||
@ -230,19 +228,20 @@ Block MergeSortingBlocksBlockInputStream::mergeImpl(std::priority_queue<TSortCur
|
||||
++total_merged_rows;
|
||||
if (limit && total_merged_rows == limit)
|
||||
{
|
||||
auto res = blocks[0].cloneWithColumns(std::move(merged_columns));
|
||||
blocks.clear();
|
||||
return merged;
|
||||
return res;
|
||||
}
|
||||
|
||||
++merged_rows;
|
||||
if (merged_rows == max_merged_block_size)
|
||||
return merged;
|
||||
return blocks[0].cloneWithColumns(std::move(merged_columns));
|
||||
}
|
||||
|
||||
if (merged_rows == 0)
|
||||
merged.clear();
|
||||
return {};
|
||||
|
||||
return merged;
|
||||
return blocks[0].cloneWithColumns(std::move(merged_columns));
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,7 +46,7 @@ String MergingSortedBlockInputStream::getID() const
|
||||
return res.str();
|
||||
}
|
||||
|
||||
void MergingSortedBlockInputStream::init(Block & merged_block, ColumnPlainPtrs & merged_columns)
|
||||
void MergingSortedBlockInputStream::init(Block & header, MutableColumns & merged_columns)
|
||||
{
|
||||
/// Read the first blocks, initialize the queue.
|
||||
if (first)
|
||||
@ -95,7 +95,7 @@ void MergingSortedBlockInputStream::init(Block & merged_block, ColumnPlainPtrs &
|
||||
|
||||
if (*shared_block_ptr)
|
||||
{
|
||||
merged_block = shared_block_ptr->cloneEmpty();
|
||||
header = shared_block_ptr->cloneEmpty();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -114,7 +114,7 @@ void MergingSortedBlockInputStream::init(Block & merged_block, ColumnPlainPtrs &
|
||||
continue;
|
||||
|
||||
size_t src_columns = shared_block_ptr->columns();
|
||||
size_t dst_columns = merged_block.columns();
|
||||
size_t dst_columns = header.columns();
|
||||
|
||||
if (src_columns != dst_columns)
|
||||
throw Exception("Merging blocks has different number of columns ("
|
||||
@ -122,22 +122,17 @@ void MergingSortedBlockInputStream::init(Block & merged_block, ColumnPlainPtrs &
|
||||
ErrorCodes::NUMBER_OF_COLUMNS_DOESNT_MATCH);
|
||||
|
||||
for (size_t i = 0; i < src_columns; ++i)
|
||||
{
|
||||
if (shared_block_ptr->safeGetByPosition(i).name != merged_block.safeGetByPosition(i).name
|
||||
|| shared_block_ptr->safeGetByPosition(i).type->getName() != merged_block.safeGetByPosition(i).type->getName()
|
||||
|| shared_block_ptr->safeGetByPosition(i).column->getName() != merged_block.safeGetByPosition(i).column->getName())
|
||||
{
|
||||
if (!blocksHaveEqualStructure(*shared_block_ptr, header))
|
||||
throw Exception("Merging blocks has different names or types of columns:\n"
|
||||
+ shared_block_ptr->dumpStructure() + "\nand\n" + merged_block.dumpStructure(),
|
||||
+ shared_block_ptr->dumpStructure() + "\nand\n" + header.dumpStructure(),
|
||||
ErrorCodes::BLOCKS_HAVE_DIFFERENT_STRUCTURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
merged_columns.resize(num_columns);
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
{
|
||||
merged_columns.emplace_back(merged_block.safeGetByPosition(i).column.get());
|
||||
merged_columns.back()->reserve(expected_block_size);
|
||||
merged_columns[i] = header.safeGetByPosition(i).column->cloneEmpty();
|
||||
merged_columns[i]->reserve(expected_block_size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,24 +149,24 @@ void MergingSortedBlockInputStream::initQueue(std::priority_queue<TSortCursor> &
|
||||
Block MergingSortedBlockInputStream::readImpl()
|
||||
{
|
||||
if (finished)
|
||||
return Block();
|
||||
return {};
|
||||
|
||||
if (children.size() == 1)
|
||||
return children[0]->read();
|
||||
|
||||
Block merged_block;
|
||||
ColumnPlainPtrs merged_columns;
|
||||
Block header;
|
||||
MutableColumns merged_columns;
|
||||
|
||||
init(merged_block, merged_columns);
|
||||
init(header, merged_columns);
|
||||
if (merged_columns.empty())
|
||||
return Block();
|
||||
return {};
|
||||
|
||||
if (has_collation)
|
||||
merge(merged_block, merged_columns, queue_with_collation);
|
||||
merge(merged_columns, queue_with_collation);
|
||||
else
|
||||
merge(merged_block, merged_columns, queue);
|
||||
merge(merged_columns, queue);
|
||||
|
||||
return merged_block;
|
||||
return header.cloneWithColumns(std::move(merged_columns));
|
||||
}
|
||||
|
||||
|
||||
@ -207,7 +202,7 @@ void MergingSortedBlockInputStream::fetchNextBlock<SortCursorWithCollation>(cons
|
||||
|
||||
|
||||
template <typename TSortCursor>
|
||||
void MergingSortedBlockInputStream::merge(Block & merged_block, ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue)
|
||||
void MergingSortedBlockInputStream::merge(MutableColumns & merged_columns, std::priority_queue<TSortCursor> & queue)
|
||||
{
|
||||
size_t merged_rows = 0;
|
||||
|
||||
@ -235,7 +230,7 @@ void MergingSortedBlockInputStream::merge(Block & merged_block, ColumnPlainPtrs
|
||||
return false;
|
||||
};
|
||||
|
||||
/// Take rows in required order and put them into `merged_block`, while the rows are no more than `max_block_size`
|
||||
/// Take rows in required order and put them into `merged_columns`, while the rows are no more than `max_block_size`
|
||||
while (!queue.empty())
|
||||
{
|
||||
TSortCursor current = queue.top();
|
||||
@ -243,8 +238,8 @@ void MergingSortedBlockInputStream::merge(Block & merged_block, ColumnPlainPtrs
|
||||
|
||||
while (true)
|
||||
{
|
||||
/** And what if the block is smaller or equal than the rest for the current cursor?
|
||||
* Or is there only one data source left in the queue? Then you can take the entire block of current cursor.
|
||||
/** And what if the block is totally less or equal than the rest for the current cursor?
|
||||
* Or is there only one data source left in the queue? Then you can take the entire block on current cursor.
|
||||
*/
|
||||
if (current.impl->isFirst() && (queue.empty() || current.totallyLessOrEquals(queue.top())))
|
||||
{
|
||||
@ -265,18 +260,18 @@ void MergingSortedBlockInputStream::merge(Block & merged_block, ColumnPlainPtrs
|
||||
throw Exception("Logical error in MergingSortedBlockInputStream", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
merged_block.getByPosition(i).column = source_blocks[source_num]->getByPosition(i).column;
|
||||
merged_columns[i] = source_blocks[source_num]->getByPosition(i).column->mutate();
|
||||
|
||||
// std::cerr << "copied columns\n";
|
||||
|
||||
size_t merged_rows = merged_block.rows();
|
||||
size_t merged_rows = merged_columns.at(0)->size();
|
||||
|
||||
if (limit && total_merged_rows + merged_rows > limit)
|
||||
{
|
||||
merged_rows = limit - total_merged_rows;
|
||||
for (size_t i = 0; i < num_columns; ++i)
|
||||
{
|
||||
auto & column = merged_block.getByPosition(i).column;
|
||||
auto & column = merged_columns[i];
|
||||
column = column->cut(0, merged_rows);
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ public:
|
||||
protected:
|
||||
struct RowRef
|
||||
{
|
||||
ConstColumnPlainPtrs columns;
|
||||
ColumnRawPtrs columns;
|
||||
size_t row_num;
|
||||
SharedBlockPtr shared_block;
|
||||
|
||||
@ -113,7 +113,7 @@ protected:
|
||||
void readSuffixImpl() override;
|
||||
|
||||
/// Initializes the queue and the next result block.
|
||||
void init(Block & merged_block, ColumnPlainPtrs & merged_columns);
|
||||
void init(Block & header, MutableColumns & merged_columns);
|
||||
|
||||
/// Gets the next block from the source corresponding to the `current`.
|
||||
template <typename TSortCursor>
|
||||
@ -214,7 +214,7 @@ private:
|
||||
void initQueue(std::priority_queue<TSortCursor> & queue);
|
||||
|
||||
template <typename TSortCursor>
|
||||
void merge(Block & merged_block, ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue);
|
||||
void merge(MutableColumns & merged_columns, std::priority_queue<TSortCursor> & queue);
|
||||
|
||||
Logger * log = &Logger::get("MergingSortedBlockInputStream");
|
||||
|
||||
|
@ -114,11 +114,13 @@ Block NativeBlockInputStream::readImpl()
|
||||
}
|
||||
|
||||
/// Data
|
||||
column.column = column.type->createColumn();
|
||||
MutableColumnPtr read_column = column.type->createColumn();
|
||||
|
||||
double avg_value_size_hint = avg_value_size_hints.empty() ? 0 : avg_value_size_hints[i];
|
||||
if (rows) /// If no rows, nothing to read.
|
||||
readData(*column.type, *column.column, istr, rows, avg_value_size_hint);
|
||||
readData(*column.type, *read_column, istr, rows, avg_value_size_hint);
|
||||
|
||||
column.column = std::move(read_column);
|
||||
|
||||
res.insert(std::move(column));
|
||||
|
||||
|
@ -47,7 +47,7 @@ void NativeBlockOutputStream::writeData(const IDataType & type, const ColumnPtr
|
||||
*/
|
||||
ColumnPtr full_column;
|
||||
|
||||
if (auto converted = column->convertToFullColumnIfConst())
|
||||
if (ColumnPtr converted = column->convertToFullColumnIfConst())
|
||||
full_column = converted;
|
||||
else
|
||||
full_column = column;
|
||||
|
@ -50,7 +50,7 @@ Block NullableAdapterBlockInputStream::readImpl()
|
||||
const auto & nullable_col = static_cast<const ColumnNullable &>(*elem.column);
|
||||
const auto & nullable_type = static_cast<const DataTypeNullable &>(*elem.type);
|
||||
|
||||
const auto & null_map = nullable_col.getNullMap();
|
||||
const auto & null_map = nullable_col.getNullMapData();
|
||||
bool has_nulls = !memoryIsZero(null_map.data(), null_map.size());
|
||||
|
||||
if (has_nulls)
|
||||
@ -58,7 +58,7 @@ Block NullableAdapterBlockInputStream::readImpl()
|
||||
ErrorCodes::CANNOT_INSERT_NULL_IN_ORDINARY_COLUMN};
|
||||
else
|
||||
res.insert({
|
||||
nullable_col.getNestedColumn(),
|
||||
nullable_col.getNestedColumnPtr(),
|
||||
nullable_type.getNestedType(),
|
||||
rename[i].value_or(elem.name)
|
||||
});
|
||||
@ -66,13 +66,12 @@ Block NullableAdapterBlockInputStream::readImpl()
|
||||
}
|
||||
case TO_NULLABLE:
|
||||
{
|
||||
auto null_map = std::make_shared<ColumnUInt8>(elem.column->size(), 0);
|
||||
ColumnPtr null_map = ColumnUInt8::create(elem.column->size(), 0);
|
||||
|
||||
res.insert({
|
||||
std::make_shared<ColumnNullable>(elem.column, null_map),
|
||||
ColumnNullable::create(elem.column, null_map),
|
||||
std::make_shared<DataTypeNullable>(elem.type),
|
||||
rename[i].value_or(elem.name)
|
||||
});
|
||||
rename[i].value_or(elem.name)});
|
||||
break;
|
||||
}
|
||||
case NONE:
|
||||
|
@ -81,7 +81,7 @@ private:
|
||||
size_t src_bytes = 0;
|
||||
|
||||
StringRefs key;
|
||||
ConstColumnPlainPtrs key_columns;
|
||||
ColumnRawPtrs key_columns;
|
||||
Aggregator::AggregateColumns aggregate_columns;
|
||||
Sizes key_sizes;
|
||||
|
||||
|
@ -6,8 +6,13 @@
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
void ReplacingSortedBlockInputStream::insertRow(ColumnPlainPtrs & merged_columns, size_t & merged_rows)
|
||||
|
||||
void ReplacingSortedBlockInputStream::insertRow(MutableColumns & merged_columns, size_t & merged_rows)
|
||||
{
|
||||
if (out_row_sources_buf)
|
||||
{
|
||||
@ -33,10 +38,14 @@ Block ReplacingSortedBlockInputStream::readImpl()
|
||||
if (children.size() == 1)
|
||||
return children[0]->read();
|
||||
|
||||
Block merged_block;
|
||||
ColumnPlainPtrs merged_columns;
|
||||
Block header;
|
||||
MutableColumns merged_columns;
|
||||
|
||||
init(header, merged_columns);
|
||||
|
||||
if (has_collation)
|
||||
throw Exception("Logical error: " + getName() + " does not support collations", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
init(merged_block, merged_columns);
|
||||
if (merged_columns.empty())
|
||||
return Block();
|
||||
|
||||
@ -46,27 +55,22 @@ Block ReplacingSortedBlockInputStream::readImpl()
|
||||
selected_row.columns.resize(num_columns);
|
||||
|
||||
if (!version_column.empty())
|
||||
version_column_number = merged_block.getPositionByName(version_column);
|
||||
version_column_number = header.getPositionByName(version_column);
|
||||
}
|
||||
|
||||
if (has_collation)
|
||||
merge(merged_columns, queue_with_collation);
|
||||
else
|
||||
merge(merged_columns, queue);
|
||||
|
||||
return merged_block;
|
||||
merge(merged_columns, queue);
|
||||
return header.cloneWithColumns(std::move(merged_columns));
|
||||
}
|
||||
|
||||
|
||||
template <typename TSortCursor>
|
||||
void ReplacingSortedBlockInputStream::merge(ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue)
|
||||
void ReplacingSortedBlockInputStream::merge(MutableColumns & merged_columns, std::priority_queue<SortCursor> & queue)
|
||||
{
|
||||
size_t merged_rows = 0;
|
||||
|
||||
/// Take the rows in needed order and put them into `merged_block` until rows no more than `max_block_size`
|
||||
/// Take the rows in needed order and put them into `merged_columns` until rows no more than `max_block_size`
|
||||
while (!queue.empty())
|
||||
{
|
||||
TSortCursor current = queue.top();
|
||||
SortCursor current = queue.top();
|
||||
|
||||
if (current_key.empty())
|
||||
{
|
||||
|
@ -63,11 +63,10 @@ private:
|
||||
|
||||
PODArray<RowSourcePart> current_row_sources; /// Sources of rows with the current primary key
|
||||
|
||||
template <typename TSortCursor>
|
||||
void merge(ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue);
|
||||
void merge(MutableColumns & merged_columns, std::priority_queue<SortCursor> & queue);
|
||||
|
||||
/// Output into result the rows for current primary key.
|
||||
void insertRow(ColumnPlainPtrs & merged_columns, size_t & merged_rows);
|
||||
void insertRow(MutableColumns & merged_columns, size_t & merged_rows);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ SquashingTransform::Result SquashingTransform::add(Block && block)
|
||||
|
||||
/// Return accumulated data (may be it has small size) and place new block to accumulated data.
|
||||
accumulated_block.swap(block);
|
||||
accumulated_block.unshareColumns();
|
||||
return Result(std::move(block));
|
||||
}
|
||||
|
||||
@ -33,7 +32,6 @@ SquashingTransform::Result SquashingTransform::add(Block && block)
|
||||
{
|
||||
/// Return accumulated data and place new block to accumulated data.
|
||||
accumulated_block.swap(block);
|
||||
accumulated_block.unshareColumns();
|
||||
return Result(std::move(block));
|
||||
}
|
||||
|
||||
@ -56,7 +54,6 @@ void SquashingTransform::append(Block && block)
|
||||
if (!accumulated_block)
|
||||
{
|
||||
accumulated_block = std::move(block);
|
||||
accumulated_block.unshareColumns();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -64,8 +61,11 @@ void SquashingTransform::append(Block && block)
|
||||
size_t rows = block.rows();
|
||||
|
||||
for (size_t i = 0; i < columns; ++i)
|
||||
accumulated_block.getByPosition(i).column->insertRangeFrom(
|
||||
*block.getByPosition(i).column, 0, rows);
|
||||
{
|
||||
MutableColumnPtr mutable_column = accumulated_block.getByPosition(i).column->mutate();
|
||||
mutable_column->insertRangeFrom(*block.getByPosition(i).column, 0, rows);
|
||||
accumulated_block.getByPosition(i).column = std::move(mutable_column);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user