ClickHouse
797 строк · 29.1 Кб
1#include <AggregateFunctions/AggregateFunctionFactory.h>
2#include <Functions/FunctionHelpers.h>
3
4#include <IO/ReadHelpers.h>
5
6#include <DataTypes/DataTypeArray.h>
7#include <DataTypes/DataTypeTuple.h>
8#include <DataTypes/DataTypeNullable.h>
9
10#include <Columns/ColumnArray.h>
11#include <Columns/ColumnTuple.h>
12#include <Columns/ColumnString.h>
13
14#include <Common/FieldVisitorSum.h>
15#include <Common/assert_cast.h>
16#include <AggregateFunctions/IAggregateFunction.h>
17#include <AggregateFunctions/FactoryHelpers.h>
18#include <map>
19
20
21namespace DB
22{
23
24struct Settings;
25
26namespace ErrorCodes
27{
28extern const int BAD_ARGUMENTS;
29extern const int ILLEGAL_TYPE_OF_ARGUMENT;
30extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
31extern const int LOGICAL_ERROR;
32}
33
34namespace
35{
36
37struct AggregateFunctionMapData
38{
39// Map needs to be ordered to maintain function properties
40std::map<Field, Array> merged_maps;
41};
42
43/** Aggregate function, that takes at least two arguments: keys and values, and as a result, builds a tuple of at least 2 arrays -
44* ordered keys and variable number of argument values aggregated by corresponding keys.
45*
46* sumMap function is the most useful when using SummingMergeTree to sum Nested columns, which name ends in "Map".
47*
48* Example: sumMap(k, v...) of:
49* k v
50* [1,2,3] [10,10,10]
51* [3,4,5] [10,10,10]
52* [4,5,6] [10,10,10]
53* [6,7,8] [10,10,10]
54* [7,5,3] [5,15,25]
55* [8,9,10] [20,20,20]
56* will return:
57* ([1,2,3,4,5,6,7,8,9,10],[10,10,45,20,35,20,15,30,20,20])
58*
59* minMap and maxMap share the same idea, but calculate min and max correspondingly.
60*
61* NOTE: The implementation of these functions are "amateur grade" - not efficient and low quality.
62*/
63
64template <typename Derived, typename Visitor, bool overflow, bool tuple_argument, bool compact>
65class AggregateFunctionMapBase : public IAggregateFunctionDataHelper<
66AggregateFunctionMapData, Derived>
67{
68private:
69static constexpr auto STATE_VERSION_1_MIN_REVISION = 54452;
70
71DataTypePtr keys_type;
72SerializationPtr keys_serialization;
73DataTypes values_types;
74Serializations values_serializations;
75Serializations promoted_values_serializations;
76
77public:
78using Base = IAggregateFunctionDataHelper<AggregateFunctionMapData, Derived>;
79
80AggregateFunctionMapBase(const DataTypePtr & keys_type_,
81const DataTypes & values_types_, const DataTypes & argument_types_)
82: Base(argument_types_, {} /* parameters */, createResultType(keys_type_, values_types_))
83, keys_type(keys_type_)
84, keys_serialization(keys_type->getDefaultSerialization())
85, values_types(values_types_)
86{
87values_serializations.reserve(values_types.size());
88promoted_values_serializations.reserve(values_types.size());
89for (const auto & type : values_types)
90{
91values_serializations.emplace_back(type->getDefaultSerialization());
92if (type->canBePromoted())
93{
94if (type->isNullable())
95promoted_values_serializations.emplace_back(
96makeNullable(removeNullable(type)->promoteNumericType())->getDefaultSerialization());
97else
98promoted_values_serializations.emplace_back(type->promoteNumericType()->getDefaultSerialization());
99}
100else
101{
102promoted_values_serializations.emplace_back(type->getDefaultSerialization());
103}
104}
105}
106
107bool isVersioned() const override { return true; }
108
109size_t getDefaultVersion() const override { return 1; }
110
111size_t getVersionFromRevision(size_t revision) const override
112{
113if (revision >= STATE_VERSION_1_MIN_REVISION)
114return 1;
115else
116return 0;
117}
118
119static DataTypePtr createResultType(
120const DataTypePtr & keys_type_,
121const DataTypes & values_types_)
122{
123DataTypes types;
124types.emplace_back(std::make_shared<DataTypeArray>(keys_type_));
125
126for (const auto & value_type : values_types_)
127{
128if constexpr (std::is_same_v<Visitor, FieldVisitorSum>)
129{
130if (!value_type->isSummable())
131throw Exception{ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
132"Values for -Map cannot be summed, passed type {}",
133value_type->getName()};
134}
135
136DataTypePtr result_type;
137
138if constexpr (overflow)
139{
140if (value_type->onlyNull())
141throw Exception{ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
142"Cannot calculate -Map of type {}",
143value_type->getName()};
144
145// Overflow, meaning that the returned type is the same as
146// the input type. Nulls are skipped.
147result_type = removeNullable(value_type);
148}
149else
150{
151auto value_type_without_nullable = removeNullable(value_type);
152
153// No overflow, meaning we promote the types if necessary.
154if (!value_type_without_nullable->canBePromoted())
155throw Exception{ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
156"Values for -Map are expected to be Numeric, Float or Decimal, passed type {}",
157value_type->getName()};
158
159WhichDataType value_type_to_check(value_type_without_nullable);
160
161/// Do not promote decimal because of implementation issues of this function design
162/// Currently we cannot get result column type in case of decimal we cannot get decimal scale
163/// in method void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override
164/// If we decide to make this function more efficient we should promote decimal type during summ
165if (value_type_to_check.isDecimal())
166result_type = value_type_without_nullable;
167else
168result_type = value_type_without_nullable->promoteNumericType();
169}
170
171types.emplace_back(std::make_shared<DataTypeArray>(result_type));
172}
173
174return std::make_shared<DataTypeTuple>(types);
175}
176
177bool allocatesMemoryInArena() const override { return false; }
178
179static auto getArgumentColumns(const IColumn ** columns)
180{
181if constexpr (tuple_argument)
182{
183return assert_cast<const ColumnTuple *>(columns[0])->getColumns();
184}
185else
186{
187return columns;
188}
189}
190
191void add(AggregateDataPtr __restrict place, const IColumn ** columns_, const size_t row_num, Arena *) const override
192{
193const auto & columns = getArgumentColumns(columns_);
194
195// Column 0 contains array of keys of known type
196const ColumnArray & array_column0 = assert_cast<const ColumnArray &>(*columns[0]);
197const IColumn::Offsets & offsets0 = array_column0.getOffsets();
198const IColumn & key_column = array_column0.getData();
199const size_t keys_vec_offset = offsets0[row_num - 1];
200const size_t keys_vec_size = (offsets0[row_num] - keys_vec_offset);
201
202// Columns 1..n contain arrays of numeric values to sum
203auto & merged_maps = this->data(place).merged_maps;
204for (size_t col = 0, size = values_types.size(); col < size; ++col)
205{
206const auto & array_column = assert_cast<const ColumnArray &>(*columns[col + 1]);
207const IColumn & value_column = array_column.getData();
208const IColumn::Offsets & offsets = array_column.getOffsets();
209const size_t values_vec_offset = offsets[row_num - 1];
210const size_t values_vec_size = (offsets[row_num] - values_vec_offset);
211
212// Expect key and value arrays to be of same length
213if (keys_vec_size != values_vec_size)
214throw Exception(ErrorCodes::BAD_ARGUMENTS, "Sizes of keys and values arrays do not match");
215
216// Insert column values for all keys
217for (size_t i = 0; i < keys_vec_size; ++i)
218{
219Field value = value_column[values_vec_offset + i];
220Field key = key_column[keys_vec_offset + i];
221
222if (!keepKey(key))
223continue;
224
225auto [it, inserted] = merged_maps.emplace(key, Array());
226
227if (inserted)
228{
229it->second.resize(size);
230it->second[col] = value;
231}
232else
233{
234if (!value.isNull())
235{
236if (it->second[col].isNull())
237it->second[col] = value;
238else
239applyVisitor(Visitor(value), it->second[col]);
240}
241}
242}
243}
244}
245
246void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena *) const override
247{
248auto & merged_maps = this->data(place).merged_maps;
249const auto & rhs_maps = this->data(rhs).merged_maps;
250
251for (const auto & elem : rhs_maps)
252{
253const auto & it = merged_maps.find(elem.first);
254if (it != merged_maps.end())
255{
256for (size_t col = 0; col < values_types.size(); ++col)
257{
258if (!elem.second[col].isNull())
259{
260if (it->second[col].isNull())
261it->second[col] = elem.second[col];
262else
263applyVisitor(Visitor(elem.second[col]), it->second[col]);
264}
265}
266}
267else
268{
269merged_maps[elem.first] = elem.second;
270}
271}
272}
273
274void serialize(ConstAggregateDataPtr __restrict place, WriteBuffer & buf, std::optional<size_t> version) const override
275{
276if (!version)
277version = getDefaultVersion();
278
279const auto & merged_maps = this->data(place).merged_maps;
280size_t size = merged_maps.size();
281writeVarUInt(size, buf);
282
283std::function<void(size_t, const Array &)> serialize;
284switch (*version)
285{
286case 0:
287{
288serialize = [&](size_t col_idx, const Array & values)
289{
290values_serializations[col_idx]->serializeBinary(values[col_idx], buf, {});
291};
292break;
293}
294case 1:
295{
296serialize = [&](size_t col_idx, const Array & values)
297{
298Field value = values[col_idx];
299
300/// Compatibility with previous versions.
301if (value.getType() == Field::Types::Decimal32)
302{
303auto source = value.get<DecimalField<Decimal32>>();
304value = DecimalField<Decimal128>(source.getValue(), source.getScale());
305}
306else if (value.getType() == Field::Types::Decimal64)
307{
308auto source = value.get<DecimalField<Decimal64>>();
309value = DecimalField<Decimal128>(source.getValue(), source.getScale());
310}
311
312promoted_values_serializations[col_idx]->serializeBinary(value, buf, {});
313};
314break;
315}
316default:
317throw Exception(ErrorCodes::LOGICAL_ERROR, "Unknown version {}, of -Map aggregate function serialization state", *version);
318}
319
320for (const auto & elem : merged_maps)
321{
322keys_serialization->serializeBinary(elem.first, buf, {});
323for (size_t col = 0; col < values_types.size(); ++col)
324serialize(col, elem.second);
325}
326}
327
328void deserialize(AggregateDataPtr __restrict place, ReadBuffer & buf, std::optional<size_t> version, Arena *) const override
329{
330if (!version)
331version = getDefaultVersion();
332
333auto & merged_maps = this->data(place).merged_maps;
334size_t size = 0;
335readVarUInt(size, buf);
336
337std::function<void(size_t, Array &)> deserialize;
338switch (*version)
339{
340case 0:
341{
342deserialize = [&](size_t col_idx, Array & values)
343{
344values_serializations[col_idx]->deserializeBinary(values[col_idx], buf, {});
345};
346break;
347}
348case 1:
349{
350deserialize = [&](size_t col_idx, Array & values)
351{
352Field & value = values[col_idx];
353promoted_values_serializations[col_idx]->deserializeBinary(value, buf, {});
354
355/// Compatibility with previous versions.
356if (value.getType() == Field::Types::Decimal128)
357{
358auto source = value.get<DecimalField<Decimal128>>();
359WhichDataType value_type(values_types[col_idx]);
360if (value_type.isDecimal32())
361{
362value = DecimalField<Decimal32>(source.getValue(), source.getScale());
363}
364else if (value_type.isDecimal64())
365{
366value = DecimalField<Decimal64>(source.getValue(), source.getScale());
367}
368}
369};
370break;
371}
372default:
373throw Exception(ErrorCodes::BAD_ARGUMENTS, "Unexpected version {} of -Map aggregate function serialization state", *version);
374}
375
376for (size_t i = 0; i < size; ++i)
377{
378Field key;
379keys_serialization->deserializeBinary(key, buf, {});
380
381Array values;
382values.resize(values_types.size());
383
384for (size_t col = 0; col < values_types.size(); ++col)
385deserialize(col, values);
386
387merged_maps[key] = values;
388}
389}
390
391void insertResultInto(AggregateDataPtr __restrict place, IColumn & to, Arena *) const override
392{
393size_t num_columns = values_types.size();
394
395// Final step does compaction of keys that have zero values, this mutates the state
396auto & merged_maps = this->data(place).merged_maps;
397
398// Remove keys which are zeros or empty. This should be enabled only for sumMap.
399if constexpr (compact)
400{
401for (auto it = merged_maps.cbegin(); it != merged_maps.cend();)
402{
403// Key is not compacted if it has at least one non-zero value
404bool erase = true;
405for (size_t col = 0; col < num_columns; ++col)
406{
407if (!it->second[col].isNull() && it->second[col] != values_types[col]->getDefault())
408{
409erase = false;
410break;
411}
412}
413
414if (erase)
415it = merged_maps.erase(it);
416else
417++it;
418}
419}
420
421size_t size = merged_maps.size();
422
423auto & to_tuple = assert_cast<ColumnTuple &>(to);
424auto & to_keys_arr = assert_cast<ColumnArray &>(to_tuple.getColumn(0));
425auto & to_keys_col = to_keys_arr.getData();
426
427// Advance column offsets
428auto & to_keys_offsets = to_keys_arr.getOffsets();
429to_keys_offsets.push_back(to_keys_offsets.back() + size);
430to_keys_col.reserve(size);
431
432for (size_t col = 0; col < num_columns; ++col)
433{
434auto & to_values_arr = assert_cast<ColumnArray &>(to_tuple.getColumn(col + 1));
435auto & to_values_offsets = to_values_arr.getOffsets();
436to_values_offsets.push_back(to_values_offsets.back() + size);
437to_values_arr.getData().reserve(size);
438}
439
440// Write arrays of keys and values
441for (const auto & elem : merged_maps)
442{
443// Write array of keys into column
444to_keys_col.insert(elem.first);
445
446// Write 0..n arrays of values
447for (size_t col = 0; col < num_columns; ++col)
448{
449auto & to_values_col = assert_cast<ColumnArray &>(to_tuple.getColumn(col + 1)).getData();
450if (elem.second[col].isNull())
451to_values_col.insertDefault();
452else
453to_values_col.insert(elem.second[col]);
454}
455}
456}
457
458bool keepKey(const Field & key) const { return static_cast<const Derived &>(*this).keepKey(key); }
459String getName() const override { return Derived::getNameImpl(); }
460};
461
462template <bool overflow, bool tuple_argument>
463class AggregateFunctionSumMap final :
464public AggregateFunctionMapBase<AggregateFunctionSumMap<overflow, tuple_argument>, FieldVisitorSum, overflow, tuple_argument, true>
465{
466private:
467using Self = AggregateFunctionSumMap<overflow, tuple_argument>;
468using Base = AggregateFunctionMapBase<Self, FieldVisitorSum, overflow, tuple_argument, true>;
469
470public:
471AggregateFunctionSumMap(const DataTypePtr & keys_type_,
472DataTypes & values_types_, const DataTypes & argument_types_,
473const Array & params_)
474: Base{keys_type_, values_types_, argument_types_}
475{
476// The constructor accepts parameters to have a uniform interface with
477// sumMapFiltered, but this function doesn't have any parameters.
478assertNoParameters(getNameImpl(), params_);
479}
480
481static String getNameImpl()
482{
483if constexpr (overflow)
484{
485return "sumMapWithOverflow";
486}
487else
488{
489return "sumMap";
490}
491}
492
493bool keepKey(const Field &) const { return true; }
494};
495
496
497template <bool overflow, bool tuple_argument>
498class AggregateFunctionSumMapFiltered final :
499public AggregateFunctionMapBase<
500AggregateFunctionSumMapFiltered<overflow, tuple_argument>,
501FieldVisitorSum,
502overflow,
503tuple_argument,
504true>
505{
506private:
507using Self = AggregateFunctionSumMapFiltered<overflow, tuple_argument>;
508using Base = AggregateFunctionMapBase<Self, FieldVisitorSum, overflow, tuple_argument, true>;
509
510using ContainerT = std::set<Field>;
511ContainerT keys_to_keep;
512
513public:
514AggregateFunctionSumMapFiltered(const DataTypePtr & keys_type_,
515const DataTypes & values_types_, const DataTypes & argument_types_,
516const Array & params_)
517: Base{keys_type_, values_types_, argument_types_}
518{
519if (params_.size() != 1)
520throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
521"Aggregate function '{}' requires exactly one parameter "
522"of Array type", getNameImpl());
523
524Array keys_to_keep_values;
525if (!params_.front().tryGet<Array>(keys_to_keep_values))
526throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
527"Aggregate function {} requires an Array as a parameter",
528getNameImpl());
529
530this->parameters = params_;
531
532for (const Field & f : keys_to_keep_values)
533keys_to_keep.emplace(f);
534}
535
536static String getNameImpl()
537{
538if constexpr (overflow)
539{
540return "sumMapFilteredWithOverflow";
541}
542else
543{
544return "sumMapFiltered";
545}
546}
547
548bool keepKey(const Field & key) const { return keys_to_keep.contains(key); }
549};
550
551
552/** Implements `Max` operation.
553* Returns true if changed
554*/
555class FieldVisitorMax : public StaticVisitor<bool>
556{
557private:
558const Field & rhs;
559
560template <typename FieldType>
561bool compareImpl(FieldType & x) const
562{
563auto val = rhs.get<FieldType>();
564if (val > x)
565{
566x = val;
567return true;
568}
569
570return false;
571}
572
573public:
574explicit FieldVisitorMax(const Field & rhs_) : rhs(rhs_) {}
575
576bool operator() (Null &) const
577{
578/// Do not update current value, skip nulls
579return false;
580}
581
582bool operator() (AggregateFunctionStateData &) const { throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot compare AggregateFunctionStates"); }
583
584bool operator() (Array & x) const { return compareImpl<Array>(x); }
585bool operator() (Tuple & x) const { return compareImpl<Tuple>(x); }
586template <typename T>
587bool operator() (DecimalField<T> & x) const { return compareImpl<DecimalField<T>>(x); }
588template <typename T>
589bool operator() (T & x) const { return compareImpl<T>(x); }
590};
591
592/** Implements `Min` operation.
593* Returns true if changed
594*/
595class FieldVisitorMin : public StaticVisitor<bool>
596{
597private:
598const Field & rhs;
599
600template <typename FieldType>
601bool compareImpl(FieldType & x) const
602{
603auto val = rhs.get<FieldType>();
604if (val < x)
605{
606x = val;
607return true;
608}
609
610return false;
611}
612
613public:
614explicit FieldVisitorMin(const Field & rhs_) : rhs(rhs_) {}
615
616
617bool operator() (Null &) const
618{
619/// Do not update current value, skip nulls
620return false;
621}
622
623bool operator() (AggregateFunctionStateData &) const { throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot sum AggregateFunctionStates"); }
624
625bool operator() (Array & x) const { return compareImpl<Array>(x); }
626bool operator() (Tuple & x) const { return compareImpl<Tuple>(x); }
627template <typename T>
628bool operator() (DecimalField<T> & x) const { return compareImpl<DecimalField<T>>(x); }
629template <typename T>
630bool operator() (T & x) const { return compareImpl<T>(x); }
631};
632
633
634template <bool tuple_argument>
635class AggregateFunctionMinMap final :
636public AggregateFunctionMapBase<AggregateFunctionMinMap<tuple_argument>, FieldVisitorMin, true, tuple_argument, false>
637{
638private:
639using Self = AggregateFunctionMinMap<tuple_argument>;
640using Base = AggregateFunctionMapBase<Self, FieldVisitorMin, true, tuple_argument, false>;
641
642public:
643AggregateFunctionMinMap(const DataTypePtr & keys_type_,
644DataTypes & values_types_, const DataTypes & argument_types_,
645const Array & params_)
646: Base{keys_type_, values_types_, argument_types_}
647{
648// The constructor accepts parameters to have a uniform interface with
649// sumMapFiltered, but this function doesn't have any parameters.
650assertNoParameters(getNameImpl(), params_);
651}
652
653static String getNameImpl() { return "minMap"; }
654
655bool keepKey(const Field &) const { return true; }
656};
657
658template <bool tuple_argument>
659class AggregateFunctionMaxMap final :
660public AggregateFunctionMapBase<AggregateFunctionMaxMap<tuple_argument>, FieldVisitorMax, true, tuple_argument, false>
661{
662private:
663using Self = AggregateFunctionMaxMap<tuple_argument>;
664using Base = AggregateFunctionMapBase<Self, FieldVisitorMax, true, tuple_argument, false>;
665
666public:
667AggregateFunctionMaxMap(const DataTypePtr & keys_type_,
668DataTypes & values_types_, const DataTypes & argument_types_,
669const Array & params_)
670: Base{keys_type_, values_types_, argument_types_}
671{
672// The constructor accepts parameters to have a uniform interface with
673// sumMapFiltered, but this function doesn't have any parameters.
674assertNoParameters(getNameImpl(), params_);
675}
676
677static String getNameImpl() { return "maxMap"; }
678
679bool keepKey(const Field &) const { return true; }
680};
681
682
683auto parseArguments(const std::string & name, const DataTypes & arguments)
684{
685DataTypes args;
686bool tuple_argument = false;
687
688if (arguments.size() == 1)
689{
690// sumMap state is fully given by its result, so it can be stored in
691// SimpleAggregateFunction columns. There is a caveat: it must support
692// sumMap(sumMap(...)), e.g. it must be able to accept its own output as
693// an input. This is why it also accepts a Tuple(keys, values) argument.
694const auto * tuple_type = checkAndGetDataType<DataTypeTuple>(arguments[0].get());
695if (!tuple_type)
696throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "When function {} gets one argument it must be a tuple", name);
697
698const auto elems = tuple_type->getElements();
699args.insert(args.end(), elems.begin(), elems.end());
700tuple_argument = true;
701}
702else
703{
704args.insert(args.end(), arguments.begin(), arguments.end());
705tuple_argument = false;
706}
707
708if (args.size() < 2)
709throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
710"Aggregate function {} requires at least two arguments of Array type or one argument of tuple of two arrays", name);
711
712const auto * array_type = checkAndGetDataType<DataTypeArray>(args[0].get());
713if (!array_type)
714throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "First argument for function {} must be an array, not {}",
715name, args[0]->getName());
716
717DataTypePtr keys_type = array_type->getNestedType();
718
719DataTypes values_types;
720values_types.reserve(args.size() - 1);
721for (size_t i = 1; i < args.size(); ++i)
722{
723array_type = checkAndGetDataType<DataTypeArray>(args[i].get());
724if (!array_type)
725throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Argument #{} for function {} must be an array.",
726i, name);
727values_types.push_back(array_type->getNestedType());
728}
729
730return std::tuple<DataTypePtr, DataTypes, bool>{std::move(keys_type), std::move(values_types), tuple_argument};
731}
732
733}
734
735void registerAggregateFunctionSumMap(AggregateFunctionFactory & factory)
736{
737// these functions used to be called *Map, with now these names occupied by
738// Map combinator, which redirects calls here if was called with
739// array or tuple arguments.
740factory.registerFunction("sumMappedArrays", [](const std::string & name, const DataTypes & arguments, const Array & params, const Settings *) -> AggregateFunctionPtr
741{
742auto [keys_type, values_types, tuple_argument] = parseArguments(name, arguments);
743if (tuple_argument)
744return std::make_shared<AggregateFunctionSumMap<false, true>>(keys_type, values_types, arguments, params);
745else
746return std::make_shared<AggregateFunctionSumMap<false, false>>(keys_type, values_types, arguments, params);
747});
748
749factory.registerFunction("minMappedArrays", [](const std::string & name, const DataTypes & arguments, const Array & params, const Settings *) -> AggregateFunctionPtr
750{
751auto [keys_type, values_types, tuple_argument] = parseArguments(name, arguments);
752if (tuple_argument)
753return std::make_shared<AggregateFunctionMinMap<true>>(keys_type, values_types, arguments, params);
754else
755return std::make_shared<AggregateFunctionMinMap<false>>(keys_type, values_types, arguments, params);
756});
757
758factory.registerFunction("maxMappedArrays", [](const std::string & name, const DataTypes & arguments, const Array & params, const Settings *) -> AggregateFunctionPtr
759{
760auto [keys_type, values_types, tuple_argument] = parseArguments(name, arguments);
761if (tuple_argument)
762return std::make_shared<AggregateFunctionMaxMap<true>>(keys_type, values_types, arguments, params);
763else
764return std::make_shared<AggregateFunctionMaxMap<false>>(keys_type, values_types, arguments, params);
765});
766
767// these functions could be renamed to *MappedArrays too, but it would
768// break backward compatibility
769factory.registerFunction("sumMapWithOverflow", [](const std::string & name, const DataTypes & arguments, const Array & params, const Settings *) -> AggregateFunctionPtr
770{
771auto [keys_type, values_types, tuple_argument] = parseArguments(name, arguments);
772if (tuple_argument)
773return std::make_shared<AggregateFunctionSumMap<true, true>>(keys_type, values_types, arguments, params);
774else
775return std::make_shared<AggregateFunctionSumMap<true, false>>(keys_type, values_types, arguments, params);
776});
777
778factory.registerFunction("sumMapFiltered", [](const std::string & name, const DataTypes & arguments, const Array & params, const Settings *) -> AggregateFunctionPtr
779{
780auto [keys_type, values_types, tuple_argument] = parseArguments(name, arguments);
781if (tuple_argument)
782return std::make_shared<AggregateFunctionSumMapFiltered<false, true>>(keys_type, values_types, arguments, params);
783else
784return std::make_shared<AggregateFunctionSumMapFiltered<false, false>>(keys_type, values_types, arguments, params);
785});
786
787factory.registerFunction("sumMapFilteredWithOverflow", [](const std::string & name, const DataTypes & arguments, const Array & params, const Settings *) -> AggregateFunctionPtr
788{
789auto [keys_type, values_types, tuple_argument] = parseArguments(name, arguments);
790if (tuple_argument)
791return std::make_shared<AggregateFunctionSumMapFiltered<true, true>>(keys_type, values_types, arguments, params);
792else
793return std::make_shared<AggregateFunctionSumMapFiltered<true, false>>(keys_type, values_types, arguments, params);
794});
795}
796
797}
798