2012-08-26 12:18:50 +00:00
|
|
|
#pragma once
|
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
#include <IO/ReadHelpers.h>
|
2012-08-26 12:18:50 +00:00
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <DataTypes/DataTypeArray.h>
|
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
2017-06-26 12:16:29 +00:00
|
|
|
#include <DataTypes/DataTypeString.h>
|
2015-11-15 04:54:56 +00:00
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Columns/ColumnVector.h>
|
|
|
|
#include <Columns/ColumnArray.h>
|
2017-06-26 12:16:29 +00:00
|
|
|
#include <Columns/ColumnString.h>
|
|
|
|
|
2017-07-24 13:32:31 +00:00
|
|
|
#include <Common/ArenaAllocator.h>
|
2012-08-26 12:18:50 +00:00
|
|
|
|
2017-12-20 07:36:30 +00:00
|
|
|
#include <AggregateFunctions/IAggregateFunction.h>
|
2012-08-26 12:18:50 +00:00
|
|
|
|
2017-06-26 12:16:29 +00:00
|
|
|
#include <common/likely.h>
|
|
|
|
#include <type_traits>
|
|
|
|
|
2012-08-26 12:18:50 +00:00
|
|
|
#define AGGREGATE_FUNCTION_GROUP_ARRAY_MAX_ARRAY_SIZE 0xFFFFFF
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2016-01-12 02:21:15 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int TOO_LARGE_ARRAY_SIZE;
|
2017-07-27 23:23:13 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
2016-01-12 02:21:15 +00:00
|
|
|
}
|
|
|
|
|
2015-11-15 04:54:56 +00:00
|
|
|
|
2017-06-26 12:16:29 +00:00
|
|
|
/// A particular case is an implementation for numeric types.
|
|
|
|
template <typename T>
|
2017-07-14 13:09:52 +00:00
|
|
|
struct GroupArrayNumericData
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
2017-07-14 13:09:52 +00:00
|
|
|
// Switch to ordinary Allocator after 4096 bytes to avoid fragmentation and trash in Arena
|
2018-09-02 19:20:27 +00:00
|
|
|
using Allocator = MixedAlignedArenaAllocator<alignof(T), 4096>;
|
2017-07-24 13:32:31 +00:00
|
|
|
using Array = PODArray<T, 32, Allocator>;
|
2017-06-26 12:16:29 +00:00
|
|
|
|
|
|
|
Array value;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-07-10 23:30:17 +00:00
|
|
|
template <typename T, typename Tlimit_num_elems>
|
2017-07-14 13:09:52 +00:00
|
|
|
class GroupArrayNumericImpl final
|
2017-12-20 07:36:30 +00:00
|
|
|
: public IAggregateFunctionDataHelper<GroupArrayNumericData<T>, GroupArrayNumericImpl<T, Tlimit_num_elems>>
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
2017-07-10 23:30:17 +00:00
|
|
|
static constexpr bool limit_num_elems = Tlimit_num_elems::value;
|
2019-02-11 19:26:32 +00:00
|
|
|
DataTypePtr & data_type;
|
2017-07-10 23:30:17 +00:00
|
|
|
UInt64 max_elems;
|
|
|
|
|
2017-06-26 12:16:29 +00:00
|
|
|
public:
|
2017-08-11 23:25:03 +00:00
|
|
|
explicit GroupArrayNumericImpl(const DataTypePtr & data_type_, UInt64 max_elems_ = std::numeric_limits<UInt64>::max())
|
2019-02-12 09:31:20 +00:00
|
|
|
: IAggregateFunctionDataHelper<GroupArrayNumericData<T>, GroupArrayNumericImpl<T, Tlimit_num_elems>>({data_type_}, {})
|
|
|
|
, data_type(this->argument_types[0]), max_elems(max_elems_) {}
|
2017-07-10 23:30:17 +00:00
|
|
|
|
2017-07-14 13:09:52 +00:00
|
|
|
String getName() const override { return "groupArray"; }
|
2017-06-26 12:16:29 +00:00
|
|
|
|
|
|
|
DataTypePtr getReturnType() const override
|
|
|
|
{
|
2017-08-11 23:25:03 +00:00
|
|
|
return std::make_shared<DataTypeArray>(data_type);
|
2017-06-26 12:16:29 +00:00
|
|
|
}
|
|
|
|
|
2017-12-20 07:36:30 +00:00
|
|
|
void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena * arena) const override
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
2017-07-10 23:30:17 +00:00
|
|
|
if (limit_num_elems && this->data(place).value.size() >= max_elems)
|
|
|
|
return;
|
|
|
|
|
2017-12-20 08:19:54 +00:00
|
|
|
this->data(place).value.push_back(static_cast<const ColumnVector<T> &>(*columns[0]).getData()[row_num], arena);
|
2017-06-26 12:16:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena * arena) const override
|
|
|
|
{
|
2017-07-10 23:30:17 +00:00
|
|
|
auto & cur_elems = this->data(place);
|
|
|
|
auto & rhs_elems = this->data(rhs);
|
|
|
|
|
|
|
|
if (!limit_num_elems)
|
|
|
|
{
|
2018-12-26 04:40:16 +00:00
|
|
|
if (rhs_elems.value.size())
|
|
|
|
cur_elems.value.insert(rhs_elems.value.begin(), rhs_elems.value.end(), arena);
|
2017-07-10 23:30:17 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-09-01 17:21:03 +00:00
|
|
|
UInt64 elems_to_insert = std::min(static_cast<size_t>(max_elems) - cur_elems.value.size(), rhs_elems.value.size());
|
2018-12-26 04:40:16 +00:00
|
|
|
if (elems_to_insert)
|
|
|
|
cur_elems.value.insert(rhs_elems.value.begin(), rhs_elems.value.begin() + elems_to_insert, arena);
|
2017-07-10 23:30:17 +00:00
|
|
|
}
|
2017-06-26 12:16:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override
|
|
|
|
{
|
|
|
|
const auto & value = this->data(place).value;
|
|
|
|
size_t size = value.size();
|
|
|
|
writeVarUInt(size, buf);
|
2018-09-02 03:00:04 +00:00
|
|
|
buf.write(reinterpret_cast<const char *>(value.data()), size * sizeof(value[0]));
|
2017-06-26 12:16:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena * arena) const override
|
|
|
|
{
|
|
|
|
size_t size = 0;
|
|
|
|
readVarUInt(size, buf);
|
|
|
|
|
|
|
|
if (unlikely(size > AGGREGATE_FUNCTION_GROUP_ARRAY_MAX_ARRAY_SIZE))
|
|
|
|
throw Exception("Too large array size", ErrorCodes::TOO_LARGE_ARRAY_SIZE);
|
|
|
|
|
2017-07-10 23:30:17 +00:00
|
|
|
if (limit_num_elems && unlikely(size > max_elems))
|
|
|
|
throw Exception("Too large array size, it should not exceed " + toString(max_elems), ErrorCodes::TOO_LARGE_ARRAY_SIZE);
|
|
|
|
|
2017-06-26 12:16:29 +00:00
|
|
|
auto & value = this->data(place).value;
|
|
|
|
|
|
|
|
value.resize(size, arena);
|
2018-09-02 03:00:04 +00:00
|
|
|
buf.read(reinterpret_cast<char *>(value.data()), size * sizeof(value[0]));
|
2017-06-26 12:16:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
|
|
|
{
|
|
|
|
const auto & value = this->data(place).value;
|
|
|
|
size_t size = value.size();
|
|
|
|
|
|
|
|
ColumnArray & arr_to = static_cast<ColumnArray &>(to);
|
2017-12-15 21:32:25 +00:00
|
|
|
ColumnArray::Offsets & offsets_to = arr_to.getOffsets();
|
2017-06-26 12:16:29 +00:00
|
|
|
|
2018-12-24 14:26:38 +00:00
|
|
|
offsets_to.push_back(offsets_to.back() + size);
|
2017-06-26 12:16:29 +00:00
|
|
|
|
2018-12-26 04:12:14 +00:00
|
|
|
if (size)
|
|
|
|
{
|
|
|
|
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());
|
|
|
|
}
|
2017-06-26 12:16:29 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-07-14 13:09:52 +00:00
|
|
|
bool allocatesMemoryInArena() const override
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-07-14 13:09:52 +00:00
|
|
|
return true;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2017-09-17 20:22:39 +00:00
|
|
|
|
|
|
|
const char * getHeaderFilePath() const override { return __FILE__; }
|
2012-08-26 12:18:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-07-14 13:09:52 +00:00
|
|
|
/// General case
|
2017-06-26 12:16:29 +00:00
|
|
|
|
2017-07-14 13:09:52 +00:00
|
|
|
|
2017-08-22 20:29:15 +00:00
|
|
|
/// Nodes used to implement a linked list for storage of groupArray states
|
2017-06-26 12:16:29 +00:00
|
|
|
|
|
|
|
template <typename Node>
|
2017-08-22 20:29:15 +00:00
|
|
|
struct GroupArrayListNodeBase
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
|
|
|
Node * next;
|
2017-07-14 13:09:52 +00:00
|
|
|
UInt64 size; // size of payload
|
2017-06-26 12:16:29 +00:00
|
|
|
|
2017-07-14 13:09:52 +00:00
|
|
|
/// Returns pointer to actual payload
|
2017-06-26 12:16:29 +00:00
|
|
|
char * data()
|
|
|
|
{
|
2017-08-22 20:29:15 +00:00
|
|
|
static_assert(sizeof(GroupArrayListNodeBase) == sizeof(Node));
|
2017-06-26 12:16:29 +00:00
|
|
|
return reinterpret_cast<char *>(this) + sizeof(Node);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Clones existing node (does not modify next field)
|
|
|
|
Node * clone(Arena * arena)
|
|
|
|
{
|
2018-09-02 19:53:35 +00:00
|
|
|
return reinterpret_cast<Node *>(const_cast<char *>(arena->alignedInsert(reinterpret_cast<char *>(this), sizeof(Node) + size, alignof(Node))));
|
2017-06-26 12:16:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Write node to buffer
|
|
|
|
void write(WriteBuffer & buf)
|
|
|
|
{
|
|
|
|
writeVarUInt(size, buf);
|
|
|
|
buf.write(data(), size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Reads and allocates node from ReadBuffer's data (doesn't set next)
|
|
|
|
static Node * read(ReadBuffer & buf, Arena * arena)
|
|
|
|
{
|
|
|
|
UInt64 size;
|
|
|
|
readVarUInt(size, buf);
|
|
|
|
|
2018-12-26 00:30:11 +00:00
|
|
|
Node * node = reinterpret_cast<Node *>(arena->alignedAlloc(sizeof(Node) + size, alignof(Node)));
|
2017-06-26 12:16:29 +00:00
|
|
|
node->size = size;
|
|
|
|
buf.read(node->data(), size);
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-08-22 20:29:15 +00:00
|
|
|
struct GroupArrayListNodeString : public GroupArrayListNodeBase<GroupArrayListNodeString>
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
2017-08-22 20:29:15 +00:00
|
|
|
using Node = GroupArrayListNodeString;
|
2017-06-26 12:16:29 +00:00
|
|
|
|
|
|
|
/// Create node from string
|
|
|
|
static Node * allocate(const IColumn & column, size_t row_num, Arena * arena)
|
|
|
|
{
|
|
|
|
StringRef string = static_cast<const ColumnString &>(column).getDataAt(row_num);
|
|
|
|
|
2018-12-26 00:30:11 +00:00
|
|
|
Node * node = reinterpret_cast<Node *>(arena->alignedAlloc(sizeof(Node) + string.size, alignof(Node)));
|
2017-06-26 12:16:29 +00:00
|
|
|
node->next = nullptr;
|
|
|
|
node->size = string.size;
|
|
|
|
memcpy(node->data(), string.data, string.size);
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
void insertInto(IColumn & column)
|
|
|
|
{
|
|
|
|
static_cast<ColumnString &>(column).insertData(data(), size);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-08-22 20:29:15 +00:00
|
|
|
struct GroupArrayListNodeGeneral : public GroupArrayListNodeBase<GroupArrayListNodeGeneral>
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
2017-08-22 20:29:15 +00:00
|
|
|
using Node = GroupArrayListNodeGeneral;
|
2017-06-26 12:16:29 +00:00
|
|
|
|
|
|
|
static Node * allocate(const IColumn & column, size_t row_num, Arena * arena)
|
|
|
|
{
|
2018-09-02 04:41:40 +00:00
|
|
|
const char * begin = arena->alignedAlloc(sizeof(Node), alignof(Node));
|
2017-06-26 12:16:29 +00:00
|
|
|
StringRef value = column.serializeValueIntoArena(row_num, *arena, begin);
|
|
|
|
|
|
|
|
Node * node = reinterpret_cast<Node *>(const_cast<char *>(begin));
|
|
|
|
node->next = nullptr;
|
|
|
|
node->size = value.size;
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
void insertInto(IColumn & column)
|
|
|
|
{
|
|
|
|
column.deserializeAndInsertFromArena(data());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Node>
|
2017-07-14 13:09:52 +00:00
|
|
|
struct GroupArrayGeneralListData
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
|
|
|
UInt64 elems = 0;
|
|
|
|
Node * first = nullptr;
|
|
|
|
Node * last = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-07-14 13:09:52 +00:00
|
|
|
/// Implementation of groupArray for String or any ComplexObject via linked list
|
2017-06-26 12:16:29 +00:00
|
|
|
/// It has poor performance in case of many small objects
|
2017-07-10 23:30:17 +00:00
|
|
|
template <typename Node, bool limit_num_elems>
|
2017-07-14 13:09:52 +00:00
|
|
|
class GroupArrayGeneralListImpl final
|
2017-12-20 07:36:30 +00:00
|
|
|
: public IAggregateFunctionDataHelper<GroupArrayGeneralListData<Node>, GroupArrayGeneralListImpl<Node, limit_num_elems>>
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
2017-07-14 13:09:52 +00:00
|
|
|
using Data = GroupArrayGeneralListData<Node>;
|
2017-06-26 12:16:29 +00:00
|
|
|
static Data & data(AggregateDataPtr place) { return *reinterpret_cast<Data*>(place); }
|
|
|
|
static const Data & data(ConstAggregateDataPtr place) { return *reinterpret_cast<const Data*>(place); }
|
|
|
|
|
2019-02-12 09:31:20 +00:00
|
|
|
DataTypePtr & data_type;
|
2017-07-10 23:30:17 +00:00
|
|
|
UInt64 max_elems;
|
2017-06-26 12:16:29 +00:00
|
|
|
|
|
|
|
public:
|
2019-08-03 11:02:40 +00:00
|
|
|
GroupArrayGeneralListImpl(const DataTypePtr & data_type_, UInt64 max_elems_ = std::numeric_limits<UInt64>::max())
|
|
|
|
: IAggregateFunctionDataHelper<GroupArrayGeneralListData<Node>, GroupArrayGeneralListImpl<Node, limit_num_elems>>({data_type_}, {})
|
2019-02-12 09:31:20 +00:00
|
|
|
, data_type(this->argument_types[0]), max_elems(max_elems_) {}
|
2017-06-26 12:16:29 +00:00
|
|
|
|
2017-07-14 13:09:52 +00:00
|
|
|
String getName() const override { return "groupArray"; }
|
2017-06-26 12:16:29 +00:00
|
|
|
|
|
|
|
DataTypePtr getReturnType() const override { return std::make_shared<DataTypeArray>(data_type); }
|
|
|
|
|
2017-12-20 07:36:30 +00:00
|
|
|
void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena * arena) const override
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
2017-07-10 23:30:17 +00:00
|
|
|
if (limit_num_elems && data(place).elems >= max_elems)
|
2017-07-04 19:24:13 +00:00
|
|
|
return;
|
|
|
|
|
2017-12-20 07:36:30 +00:00
|
|
|
Node * node = Node::allocate(*columns[0], row_num, arena);
|
2017-06-26 12:16:29 +00:00
|
|
|
|
|
|
|
if (unlikely(!data(place).first))
|
|
|
|
{
|
|
|
|
data(place).first = node;
|
|
|
|
data(place).last = node;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
data(place).last->next = node;
|
|
|
|
data(place).last = node;
|
|
|
|
}
|
|
|
|
|
|
|
|
++data(place).elems;
|
|
|
|
}
|
|
|
|
|
|
|
|
void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena * arena) const override
|
|
|
|
{
|
|
|
|
/// It is sadly, but rhs's Arena could be destroyed
|
|
|
|
|
|
|
|
if (!data(rhs).first) /// rhs state is empty
|
|
|
|
return;
|
|
|
|
|
2017-07-04 19:24:13 +00:00
|
|
|
UInt64 new_elems;
|
|
|
|
UInt64 cur_elems = data(place).elems;
|
2017-07-10 23:30:17 +00:00
|
|
|
if (limit_num_elems)
|
2017-07-04 19:24:13 +00:00
|
|
|
{
|
|
|
|
if (data(place).elems >= max_elems)
|
|
|
|
return;
|
|
|
|
|
|
|
|
new_elems = std::min(data(place).elems + data(rhs).elems, max_elems);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new_elems = data(place).elems + data(rhs).elems;
|
|
|
|
}
|
2017-06-26 12:16:29 +00:00
|
|
|
|
|
|
|
Node * p_rhs = data(rhs).first;
|
|
|
|
Node * p_lhs;
|
|
|
|
|
|
|
|
if (unlikely(!data(place).last)) /// lhs state is empty
|
|
|
|
{
|
|
|
|
p_lhs = p_rhs->clone(arena);
|
|
|
|
data(place).first = data(place).last = p_lhs;
|
|
|
|
p_rhs = p_rhs->next;
|
2017-07-04 19:24:13 +00:00
|
|
|
++cur_elems;
|
2017-06-26 12:16:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p_lhs = data(place).last;
|
|
|
|
}
|
|
|
|
|
2017-07-04 19:24:13 +00:00
|
|
|
for (; cur_elems < new_elems; ++cur_elems)
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
|
|
|
Node * p_new = p_rhs->clone(arena);
|
|
|
|
p_lhs->next = p_new;
|
|
|
|
p_rhs = p_rhs->next;
|
|
|
|
p_lhs = p_new;
|
|
|
|
}
|
|
|
|
|
|
|
|
p_lhs->next = nullptr;
|
|
|
|
data(place).last = p_lhs;
|
2017-07-04 19:24:13 +00:00
|
|
|
data(place).elems = new_elems;
|
2017-06-26 12:16:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override
|
|
|
|
{
|
|
|
|
writeVarUInt(data(place).elems, buf);
|
|
|
|
|
|
|
|
Node * p = data(place).first;
|
|
|
|
while (p)
|
|
|
|
{
|
|
|
|
p->write(buf);
|
|
|
|
p = p->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena * arena) const override
|
|
|
|
{
|
|
|
|
UInt64 elems;
|
|
|
|
readVarUInt(elems, buf);
|
|
|
|
data(place).elems = elems;
|
|
|
|
|
|
|
|
if (unlikely(elems == 0))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (unlikely(elems > AGGREGATE_FUNCTION_GROUP_ARRAY_MAX_ARRAY_SIZE))
|
|
|
|
throw Exception("Too large array size", ErrorCodes::TOO_LARGE_ARRAY_SIZE);
|
|
|
|
|
2017-07-10 23:30:17 +00:00
|
|
|
if (limit_num_elems && unlikely(elems > max_elems))
|
2017-07-04 19:24:13 +00:00
|
|
|
throw Exception("Too large array size, it should not exceed " + toString(max_elems), ErrorCodes::TOO_LARGE_ARRAY_SIZE);
|
|
|
|
|
2017-06-26 12:16:29 +00:00
|
|
|
Node * prev = Node::read(buf, arena);
|
|
|
|
data(place).first = prev;
|
|
|
|
|
|
|
|
for (UInt64 i = 1; i < elems; ++i)
|
|
|
|
{
|
|
|
|
Node * cur = Node::read(buf, arena);
|
|
|
|
prev->next = cur;
|
|
|
|
prev = cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
prev->next = nullptr;
|
|
|
|
data(place).last = prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
|
|
|
{
|
|
|
|
auto & column_array = static_cast<ColumnArray &>(to);
|
|
|
|
|
|
|
|
auto & offsets = column_array.getOffsets();
|
2018-12-24 14:26:38 +00:00
|
|
|
offsets.push_back(offsets.back() + data(place).elems);
|
2017-06-26 12:16:29 +00:00
|
|
|
|
|
|
|
auto & column_data = column_array.getData();
|
|
|
|
|
2017-12-25 04:01:46 +00:00
|
|
|
if (std::is_same_v<Node, GroupArrayListNodeString>)
|
2017-06-26 12:16:29 +00:00
|
|
|
{
|
|
|
|
auto & string_offsets = static_cast<ColumnString &>(column_data).getOffsets();
|
|
|
|
string_offsets.reserve(string_offsets.size() + data(place).elems);
|
|
|
|
}
|
|
|
|
|
|
|
|
Node * p = data(place).first;
|
|
|
|
while (p)
|
|
|
|
{
|
|
|
|
p->insertInto(column_data);
|
|
|
|
p = p->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool allocatesMemoryInArena() const override
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2017-09-17 20:22:39 +00:00
|
|
|
|
|
|
|
const char * getHeaderFilePath() const override { return __FILE__; }
|
2017-06-26 12:16:29 +00:00
|
|
|
};
|
|
|
|
|
2012-08-26 12:18:50 +00:00
|
|
|
#undef AGGREGATE_FUNCTION_GROUP_ARRAY_MAX_ARRAY_SIZE
|
|
|
|
|
|
|
|
}
|