Fix error with ownership of aggregate function states with nested states

This commit is contained in:
Alexey Milovidov 2020-07-10 08:28:34 +03:00
parent 12e00411b4
commit c610a4b0a8
5 changed files with 61 additions and 23 deletions

View File

@ -247,6 +247,11 @@ public:
{
return true;
}
bool isState() const override
{
return nested_func->isState();
}
};

View File

@ -122,8 +122,9 @@ public:
throw Exception("Method predictValues is not supported for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
}
/** Returns true for aggregate functions of type -State.
/** Returns true for aggregate functions of type -State
* They are executed as other aggregate functions, but not finalized (return an aggregation state that can be combined with another).
* Also returns true when the final value of this aggregate function contains State of other aggregate function inside.
*/
virtual bool isState() const { return false; }

View File

@ -85,6 +85,20 @@ void ColumnAggregateFunction::addArena(ConstArenaPtr arena_)
foreign_arenas.push_back(arena_);
}
namespace
{
ConstArenas concatArenas(const ConstArenas & array, ConstArenaPtr arena)
{
ConstArenas result = array;
if (arena)
result.push_back(std::move(arena));
return result;
}
}
MutableColumnPtr ColumnAggregateFunction::convertToValues(MutableColumnPtr column)
{
/** If the aggregate function returns an unfinalized/unfinished state,
@ -121,19 +135,26 @@ MutableColumnPtr ColumnAggregateFunction::convertToValues(MutableColumnPtr colum
auto & func = column_aggregate_func.func;
auto & data = column_aggregate_func.data;
if (const AggregateFunctionState *function_state = typeid_cast<const AggregateFunctionState *>(func.get()))
{
auto res = column_aggregate_func.createView();
res->set(function_state->getNestedFunction());
res->data.assign(data.begin(), data.end());
return res;
}
column_aggregate_func.ensureOwnership();
MutableColumnPtr res = func->getReturnType()->createColumn();
res->reserve(data.size());
/// If there are references to states in final column, we must hold their ownership
/// by holding arenas and source.
auto callback = [&](auto & subcolumn)
{
if (auto * aggregate_subcolumn = typeid_cast<ColumnAggregateFunction *>(subcolumn.get()))
{
aggregate_subcolumn->foreign_arenas = concatArenas(column_aggregate_func.foreign_arenas, column_aggregate_func.my_arena);
aggregate_subcolumn->src = column_aggregate_func.getPtr();
}
};
callback(res);
res->forEachSubcolumn(callback);
for (auto * val : data)
func->insertResultInto(val, *res, &column_aggregate_func.createOrGetArena());
@ -629,20 +650,6 @@ void ColumnAggregateFunction::getExtremes(Field & min, Field & max) const
max = serialized;
}
namespace
{
ConstArenas concatArenas(const ConstArenas & array, ConstArenaPtr arena)
{
ConstArenas result = array;
if (arena)
result.push_back(std::move(arena));
return result;
}
}
ColumnAggregateFunction::MutablePtr ColumnAggregateFunction::createView() const
{
auto res = create(func, concatArenas(foreign_arenas, my_arena));

View File

@ -0,0 +1,16 @@
5B27015C30012CCBC234272C27015C305C30275D
02000000000000000100012CCBC234010000
['0100012CCBC234','010000']
[1,0]
5B27015C30012CCBC234272C27015C305C30275D
5B27015C30012CCBC234272C27015C305C30275D
02000000000000000100012CCBC234010000
02000000000000000100012CCBC234010000
['0100012CCBC234','010000']
['0100012CCBC234','010000']
[1,0]
[1,0]

View File

@ -0,0 +1,9 @@
SELECT hex(toString(uniqStateForEach([1, NULL])));
SELECT hex(toString(uniqStateForEachState([1, NULL])));
SELECT arrayMap(x -> hex(toString(x)), finalizeAggregation(uniqStateForEachState([1, NULL])));
SELECT arrayMap(x -> finalizeAggregation(x), finalizeAggregation(uniqStateForEachState([1, NULL])));
SELECT hex(toString(uniqStateForEach([1, NULL]))) WITH TOTALS;
SELECT hex(toString(uniqStateForEachState([1, NULL]))) WITH TOTALS;
SELECT arrayMap(x -> hex(toString(x)), finalizeAggregation(uniqStateForEachState([1, NULL]))) WITH TOTALS;
SELECT arrayMap(x -> finalizeAggregation(x), finalizeAggregation(uniqStateForEachState([1, NULL]))) WITH TOTALS;