2013-05-20 15:42:57 +00:00
|
|
|
#pragma once
|
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <DataTypes/DataTypeArray.h>
|
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
|
|
|
#include <Interpreters/ExpressionActions.h>
|
|
|
|
#include <Columns/ColumnsNumber.h>
|
|
|
|
#include <Columns/ColumnArray.h>
|
|
|
|
#include <Columns/ColumnConst.h>
|
2017-07-13 20:58:19 +00:00
|
|
|
#include <Common/typeid_cast.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Functions/IFunction.h>
|
|
|
|
#include <Functions/FunctionsMiscellaneous.h>
|
2017-07-21 06:35:58 +00:00
|
|
|
#include <Functions/FunctionHelpers.h>
|
2013-05-20 15:42:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
2014-06-12 18:41:09 +00:00
|
|
|
|
2016-01-12 02:21:15 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
|
2017-12-07 23:07:41 +00:00
|
|
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
2016-01-12 02:21:15 +00:00
|
|
|
}
|
|
|
|
|
2017-05-27 15:45:25 +00:00
|
|
|
/** Higher-order functions for arrays:
|
2014-06-12 18:41:09 +00:00
|
|
|
*
|
2017-05-27 15:45:25 +00:00
|
|
|
* arrayMap(x1,...,xn -> expression, array1,...,arrayn) - apply the expression to each element of the array (or set of parallel arrays).
|
|
|
|
* arrayFilter(x -> predicate, array) - leave in the array only the elements for which the expression is true.
|
|
|
|
* arrayCount(x1,...,xn -> expression, array1,...,arrayn) - for how many elements of the array the expression is true.
|
|
|
|
* arrayExists(x1,...,xn -> expression, array1,...,arrayn) - is the expression true for at least one array element.
|
|
|
|
* arrayAll(x1,...,xn -> expression, array1,...,arrayn) - is the expression true for all elements of the array.
|
2014-06-12 18:41:09 +00:00
|
|
|
*
|
2017-05-27 15:45:25 +00:00
|
|
|
* For functions arrayCount, arrayExists, arrayAll, an overload of the form f(array) is available, which works in the same way as f(x -> x, array).
|
2013-05-20 15:42:57 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
struct ArrayMapImpl
|
|
|
|
{
|
2017-05-27 15:45:25 +00:00
|
|
|
/// true if the expression (for an overload of f(expression, arrays)) or an array (for f(array)) should be boolean.
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needBoolean() { return false; }
|
2017-05-27 15:45:25 +00:00
|
|
|
/// true if the f(array) overload is unavailable.
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needExpression() { return true; }
|
2017-05-27 15:45:25 +00:00
|
|
|
/// true if the array must be exactly one.
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needOneArray() { return false; }
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
static DataTypePtr getReturnType(const DataTypePtr & expression_return, const DataTypePtr & /*array_element*/)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
return std::make_shared<DataTypeArray>(expression_return);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
|
|
|
|
{
|
2017-12-09 10:14:45 +00:00
|
|
|
return mapped->isColumnConst()
|
2017-12-15 02:36:40 +00:00
|
|
|
? ColumnArray::create(mapped->convertToFullColumnIfConst(), array.getOffsetsPtr())
|
|
|
|
: ColumnArray::create(mapped, array.getOffsetsPtr());
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2013-05-20 15:42:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ArrayFilterImpl
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needBoolean() { return true; }
|
|
|
|
static bool needExpression() { return true; }
|
|
|
|
static bool needOneArray() { return false; }
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
static DataTypePtr getReturnType(const DataTypePtr & /*expression_return*/, const DataTypePtr & array_element)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
return std::make_shared<DataTypeArray>(array_element);
|
|
|
|
}
|
|
|
|
|
2017-05-27 15:45:25 +00:00
|
|
|
/// If there are several arrays, the first one is passed here.
|
2017-04-01 07:20:54 +00:00
|
|
|
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
|
|
|
|
{
|
|
|
|
const ColumnUInt8 * column_filter = typeid_cast<const ColumnUInt8 *>(&*mapped);
|
|
|
|
|
|
|
|
if (!column_filter)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
auto column_filter_const = checkAndGetColumnConst<ColumnUInt8>(&*mapped);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column_filter_const)
|
|
|
|
throw Exception("Unexpected type of filter column", ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
if (column_filter_const->getValue<UInt8>())
|
2017-04-01 07:20:54 +00:00
|
|
|
return array.clone();
|
|
|
|
else
|
2017-12-14 01:43:19 +00:00
|
|
|
return ColumnArray::create(
|
2017-04-01 07:20:54 +00:00
|
|
|
array.getDataPtr()->cloneEmpty(),
|
2017-12-16 05:34:07 +00:00
|
|
|
ColumnArray::ColumnOffsets::create(array.size(), 0));
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const IColumn::Filter & filter = column_filter->getData();
|
|
|
|
ColumnPtr filtered = array.getData().filter(filter, -1);
|
|
|
|
|
2017-12-15 21:32:25 +00:00
|
|
|
const IColumn::Offsets & in_offsets = array.getOffsets();
|
2017-12-16 05:34:07 +00:00
|
|
|
auto column_offsets = ColumnArray::ColumnOffsets::create(in_offsets.size());
|
2017-12-15 21:32:25 +00:00
|
|
|
IColumn::Offsets & out_offsets = column_offsets->getData();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t in_pos = 0;
|
|
|
|
size_t out_pos = 0;
|
|
|
|
for (size_t i = 0; i < in_offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
for (; in_pos < in_offsets[i]; ++in_pos)
|
|
|
|
{
|
|
|
|
if (filter[in_pos])
|
|
|
|
++out_pos;
|
|
|
|
}
|
|
|
|
out_offsets[i] = out_pos;
|
|
|
|
}
|
|
|
|
|
2017-12-16 05:34:07 +00:00
|
|
|
return ColumnArray::create(filtered, std::move(column_offsets));
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2013-05-20 15:42:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ArrayCountImpl
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needBoolean() { return true; }
|
|
|
|
static bool needExpression() { return false; }
|
|
|
|
static bool needOneArray() { return false; }
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
static DataTypePtr getReturnType(const DataTypePtr & /*expression_return*/, const DataTypePtr & /*array_element*/)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
return std::make_shared<DataTypeUInt32>();
|
|
|
|
}
|
|
|
|
|
|
|
|
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
|
|
|
|
{
|
|
|
|
const ColumnUInt8 * column_filter = typeid_cast<const ColumnUInt8 *>(&*mapped);
|
|
|
|
|
|
|
|
if (!column_filter)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
auto column_filter_const = checkAndGetColumnConst<ColumnUInt8>(&*mapped);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column_filter_const)
|
|
|
|
throw Exception("Unexpected type of filter column", ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
if (column_filter_const->getValue<UInt8>())
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-12-15 21:32:25 +00:00
|
|
|
const IColumn::Offsets & offsets = array.getOffsets();
|
2017-12-14 01:43:19 +00:00
|
|
|
auto out_column = ColumnUInt32::create(offsets.size());
|
2017-12-15 21:32:25 +00:00
|
|
|
ColumnUInt32::Container & out_counts = out_column->getData();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t pos = 0;
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
out_counts[i] = offsets[i] - pos;
|
|
|
|
pos = offsets[i];
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return out_column;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
2017-12-10 22:44:04 +00:00
|
|
|
return DataTypeUInt32().createColumnConst(array.size(), UInt64(0));
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const IColumn::Filter & filter = column_filter->getData();
|
2017-12-15 21:32:25 +00:00
|
|
|
const IColumn::Offsets & offsets = array.getOffsets();
|
2017-12-14 01:43:19 +00:00
|
|
|
auto out_column = ColumnUInt32::create(offsets.size());
|
2017-12-15 21:32:25 +00:00
|
|
|
ColumnUInt32::Container & out_counts = out_column->getData();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t pos = 0;
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
size_t count = 0;
|
|
|
|
for (; pos < offsets[i]; ++pos)
|
|
|
|
{
|
|
|
|
if (filter[pos])
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
out_counts[i] = count;
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return out_column;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2013-05-20 15:42:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ArrayExistsImpl
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needBoolean() { return true; }
|
|
|
|
static bool needExpression() { return false; }
|
|
|
|
static bool needOneArray() { return false; }
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
static DataTypePtr getReturnType(const DataTypePtr & /*expression_return*/, const DataTypePtr & /*array_element*/)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
return std::make_shared<DataTypeUInt8>();
|
|
|
|
}
|
|
|
|
|
|
|
|
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
|
|
|
|
{
|
|
|
|
const ColumnUInt8 * column_filter = typeid_cast<const ColumnUInt8 *>(&*mapped);
|
|
|
|
|
|
|
|
if (!column_filter)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
auto column_filter_const = checkAndGetColumnConst<ColumnUInt8>(&*mapped);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column_filter_const)
|
|
|
|
throw Exception("Unexpected type of filter column", ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
if (column_filter_const->getValue<UInt8>())
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-12-15 21:32:25 +00:00
|
|
|
const IColumn::Offsets & offsets = array.getOffsets();
|
2017-12-14 01:43:19 +00:00
|
|
|
auto out_column = ColumnUInt8::create(offsets.size());
|
2017-12-15 21:32:25 +00:00
|
|
|
ColumnUInt8::Container & out_exists = out_column->getData();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t pos = 0;
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
out_exists[i] = offsets[i] - pos > 0;
|
|
|
|
pos = offsets[i];
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return out_column;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
2017-12-10 22:44:04 +00:00
|
|
|
return DataTypeUInt8().createColumnConst(array.size(), UInt64(0));
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const IColumn::Filter & filter = column_filter->getData();
|
2017-12-15 21:32:25 +00:00
|
|
|
const IColumn::Offsets & offsets = array.getOffsets();
|
2017-12-14 01:43:19 +00:00
|
|
|
auto out_column = ColumnUInt8::create(offsets.size());
|
2017-12-15 21:32:25 +00:00
|
|
|
ColumnUInt8::Container & out_exists = out_column->getData();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t pos = 0;
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
UInt8 exists = 0;
|
|
|
|
for (; pos < offsets[i]; ++pos)
|
|
|
|
{
|
|
|
|
if (filter[pos])
|
|
|
|
{
|
|
|
|
exists = 1;
|
|
|
|
pos = offsets[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out_exists[i] = exists;
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return out_column;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2013-05-20 15:42:57 +00:00
|
|
|
};
|
|
|
|
|
2013-06-20 12:27:33 +00:00
|
|
|
struct ArrayAllImpl
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needBoolean() { return true; }
|
|
|
|
static bool needExpression() { return false; }
|
|
|
|
static bool needOneArray() { return false; }
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
static DataTypePtr getReturnType(const DataTypePtr & /*expression_return*/, const DataTypePtr & /*array_element*/)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
return std::make_shared<DataTypeUInt8>();
|
|
|
|
}
|
|
|
|
|
|
|
|
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
|
|
|
|
{
|
|
|
|
const ColumnUInt8 * column_filter = typeid_cast<const ColumnUInt8 *>(&*mapped);
|
|
|
|
|
|
|
|
if (!column_filter)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
auto column_filter_const = checkAndGetColumnConst<ColumnUInt8>(&*mapped);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column_filter_const)
|
|
|
|
throw Exception("Unexpected type of filter column", ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
if (column_filter_const->getValue<UInt8>())
|
2017-12-10 22:44:04 +00:00
|
|
|
return DataTypeUInt8().createColumnConst(array.size(), UInt64(1));
|
2017-04-01 07:20:54 +00:00
|
|
|
else
|
|
|
|
{
|
2017-12-15 21:32:25 +00:00
|
|
|
const IColumn::Offsets & offsets = array.getOffsets();
|
2017-12-14 01:43:19 +00:00
|
|
|
auto out_column = ColumnUInt8::create(offsets.size());
|
2017-12-15 21:32:25 +00:00
|
|
|
ColumnUInt8::Container & out_all = out_column->getData();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t pos = 0;
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
out_all[i] = offsets[i] == pos;
|
|
|
|
pos = offsets[i];
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return out_column;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const IColumn::Filter & filter = column_filter->getData();
|
2017-12-15 21:32:25 +00:00
|
|
|
const IColumn::Offsets & offsets = array.getOffsets();
|
2017-12-14 01:43:19 +00:00
|
|
|
auto out_column = ColumnUInt8::create(offsets.size());
|
2017-12-15 21:32:25 +00:00
|
|
|
ColumnUInt8::Container & out_all = out_column->getData();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t pos = 0;
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
UInt8 all = 1;
|
|
|
|
for (; pos < offsets[i]; ++pos)
|
|
|
|
{
|
|
|
|
if (!filter[pos])
|
|
|
|
{
|
|
|
|
all = 0;
|
|
|
|
pos = offsets[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out_all[i] = all;
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return out_column;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2013-06-20 12:27:33 +00:00
|
|
|
};
|
|
|
|
|
2013-06-21 12:11:35 +00:00
|
|
|
struct ArraySumImpl
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needBoolean() { return false; }
|
|
|
|
static bool needExpression() { return false; }
|
|
|
|
static bool needOneArray() { return false; }
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
static DataTypePtr getReturnType(const DataTypePtr & expression_return, const DataTypePtr & /*array_element*/)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
if (checkDataType<DataTypeUInt8>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeUInt16>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeUInt32>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeUInt64>(&*expression_return))
|
2017-04-01 07:20:54 +00:00
|
|
|
return std::make_shared<DataTypeUInt64>();
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
if (checkDataType<DataTypeInt8>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeInt16>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeInt32>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeInt64>(&*expression_return))
|
2017-04-01 07:20:54 +00:00
|
|
|
return std::make_shared<DataTypeInt64>();
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
if (checkDataType<DataTypeFloat32>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeFloat64>(&*expression_return))
|
2017-04-01 07:20:54 +00:00
|
|
|
return std::make_shared<DataTypeFloat64>();
|
|
|
|
|
|
|
|
throw Exception("arraySum cannot add values of type " + expression_return->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
}
|
|
|
|
|
2017-09-15 12:16:12 +00:00
|
|
|
template <typename Element, typename Result>
|
2017-12-15 21:32:25 +00:00
|
|
|
static bool executeType(const ColumnPtr & mapped, const ColumnArray::Offsets & offsets, ColumnPtr & res_ptr)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
const ColumnVector<Element> * column = checkAndGetColumn<ColumnVector<Element>>(&*mapped);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
const ColumnConst * column_const = checkAndGetColumnConst<ColumnVector<Element>>(&*mapped);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column_const)
|
|
|
|
return false;
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
const Element x = column_const->template getValue<Element>();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-12-14 01:43:19 +00:00
|
|
|
auto res_column = ColumnVector<Result>::create(offsets.size());
|
2017-12-15 21:32:25 +00:00
|
|
|
typename ColumnVector<Result>::Container & res = res_column->getData();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t pos = 0;
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
res[i] = x * (offsets[i] - pos);
|
|
|
|
pos = offsets[i];
|
|
|
|
}
|
|
|
|
|
2017-12-16 05:46:46 +00:00
|
|
|
res_ptr = std::move(res_column);
|
2017-04-01 07:20:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-12-15 21:32:25 +00:00
|
|
|
const typename ColumnVector<Element>::Container & data = column->getData();
|
2017-12-14 01:43:19 +00:00
|
|
|
auto res_column = ColumnVector<Result>::create(offsets.size());
|
2017-12-15 21:32:25 +00:00
|
|
|
typename ColumnVector<Result>::Container & res = res_column->getData();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t pos = 0;
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
Result s = 0;
|
|
|
|
for (; pos < offsets[i]; ++pos)
|
|
|
|
{
|
|
|
|
s += data[pos];
|
|
|
|
}
|
|
|
|
res[i] = s;
|
|
|
|
}
|
|
|
|
|
2017-12-16 05:46:46 +00:00
|
|
|
res_ptr = std::move(res_column);
|
2017-04-01 07:20:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
|
|
|
|
{
|
2017-12-15 21:32:25 +00:00
|
|
|
const IColumn::Offsets & offsets = array.getOffsets();
|
2017-04-01 07:20:54 +00:00
|
|
|
ColumnPtr res;
|
|
|
|
|
|
|
|
if (executeType< UInt8 , UInt64>(mapped, offsets, res) ||
|
|
|
|
executeType< UInt16, UInt64>(mapped, offsets, res) ||
|
|
|
|
executeType< UInt32, UInt64>(mapped, offsets, res) ||
|
|
|
|
executeType< UInt64, UInt64>(mapped, offsets, res) ||
|
|
|
|
executeType< Int8 , Int64>(mapped, offsets, res) ||
|
|
|
|
executeType< Int16, Int64>(mapped, offsets, res) ||
|
|
|
|
executeType< Int32, Int64>(mapped, offsets, res) ||
|
|
|
|
executeType< Int64, Int64>(mapped, offsets, res) ||
|
|
|
|
executeType<Float32,Float64>(mapped, offsets, res) ||
|
|
|
|
executeType<Float64,Float64>(mapped, offsets, res))
|
|
|
|
return res;
|
|
|
|
else
|
|
|
|
throw Exception("Unexpected column for arraySum: " + mapped->getName());
|
|
|
|
}
|
2013-06-21 12:11:35 +00:00
|
|
|
};
|
|
|
|
|
2014-10-28 15:49:11 +00:00
|
|
|
struct ArrayFirstImpl
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needBoolean() { return false; }
|
|
|
|
static bool needExpression() { return true; }
|
|
|
|
static bool needOneArray() { return false; }
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
static DataTypePtr getReturnType(const DataTypePtr & /*expression_return*/, const DataTypePtr & array_element)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
return array_element;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
|
|
|
|
{
|
|
|
|
auto column_filter = typeid_cast<const ColumnUInt8 *>(&*mapped);
|
|
|
|
|
|
|
|
if (!column_filter)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
auto column_filter_const = checkAndGetColumnConst<ColumnUInt8>(&*mapped);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column_filter_const)
|
|
|
|
throw Exception("Unexpected type of filter column", ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
if (column_filter_const->getValue<UInt8>())
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
const auto & offsets = array.getOffsets();
|
|
|
|
const auto & data = array.getData();
|
2017-12-16 05:46:46 +00:00
|
|
|
auto out = data.cloneEmpty();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t pos{};
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
if (offsets[i] - pos > 0)
|
|
|
|
out->insert(data[pos]);
|
|
|
|
else
|
|
|
|
out->insertDefault();
|
|
|
|
|
|
|
|
pos = offsets[i];
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return out;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-12-16 05:46:46 +00:00
|
|
|
auto out = array.getData().cloneEmpty();
|
2017-04-01 07:20:54 +00:00
|
|
|
out->insertDefault();
|
2017-12-15 21:32:25 +00:00
|
|
|
return out->replicate(IColumn::Offsets(1, array.size()));
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto & filter = column_filter->getData();
|
|
|
|
const auto & offsets = array.getOffsets();
|
|
|
|
const auto & data = array.getData();
|
2017-12-16 05:46:46 +00:00
|
|
|
auto out = data.cloneEmpty();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t pos{};
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
auto exists = false;
|
|
|
|
for (; pos < offsets[i]; ++pos)
|
|
|
|
{
|
|
|
|
if (filter[pos])
|
|
|
|
{
|
|
|
|
out->insert(data[pos]);
|
|
|
|
exists = true;
|
|
|
|
pos = offsets[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!exists)
|
|
|
|
out->insertDefault();
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return out;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2014-10-28 15:49:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ArrayFirstIndexImpl
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needBoolean() { return false; }
|
|
|
|
static bool needExpression() { return true; }
|
|
|
|
static bool needOneArray() { return false; }
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
static DataTypePtr getReturnType(const DataTypePtr & /*expression_return*/, const DataTypePtr & /*array_element*/)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
return std::make_shared<DataTypeUInt32>();
|
|
|
|
}
|
|
|
|
|
|
|
|
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
|
|
|
|
{
|
|
|
|
auto column_filter = typeid_cast<const ColumnUInt8 *>(&*mapped);
|
|
|
|
|
|
|
|
if (!column_filter)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
auto column_filter_const = checkAndGetColumnConst<ColumnUInt8>(&*mapped);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column_filter_const)
|
|
|
|
throw Exception("Unexpected type of filter column", ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
if (column_filter_const->getValue<UInt8>())
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
const auto & offsets = array.getOffsets();
|
2017-12-14 01:43:19 +00:00
|
|
|
auto out_column = ColumnUInt32::create(offsets.size());
|
2017-04-01 07:20:54 +00:00
|
|
|
auto & out_index = out_column->getData();
|
|
|
|
|
|
|
|
size_t pos{};
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
out_index[i] = offsets[i] - pos > 0;
|
|
|
|
pos = offsets[i];
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return out_column;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
2017-12-10 22:44:04 +00:00
|
|
|
return DataTypeUInt32().createColumnConst(array.size(), UInt64(0));
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const auto & filter = column_filter->getData();
|
|
|
|
const auto & offsets = array.getOffsets();
|
2017-12-14 01:43:19 +00:00
|
|
|
auto out_column = ColumnUInt32::create(offsets.size());
|
2017-04-01 07:20:54 +00:00
|
|
|
auto & out_index = out_column->getData();
|
|
|
|
|
|
|
|
size_t pos{};
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
UInt32 index{};
|
|
|
|
for (size_t idx{1}; pos < offsets[i]; ++pos, ++idx)
|
|
|
|
{
|
|
|
|
if (filter[pos])
|
|
|
|
{
|
|
|
|
index = idx;
|
|
|
|
pos = offsets[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out_index[i] = index;
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return out_column;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2014-10-28 15:49:11 +00:00
|
|
|
};
|
|
|
|
|
2016-11-20 06:44:38 +00:00
|
|
|
|
2016-11-20 06:49:24 +00:00
|
|
|
/** Sort arrays, by values of its elements, or by values of corresponding elements of calculated expression (known as "schwartzsort").
|
2016-11-20 06:44:38 +00:00
|
|
|
*/
|
|
|
|
template <bool positive>
|
|
|
|
struct ArraySortImpl
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool needBoolean() { return false; }
|
|
|
|
static bool needExpression() { return false; }
|
|
|
|
static bool needOneArray() { return false; }
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
static DataTypePtr getReturnType(const DataTypePtr & /*expression_return*/, const DataTypePtr & array_element)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
return std::make_shared<DataTypeArray>(array_element);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Less
|
|
|
|
{
|
|
|
|
const IColumn & column;
|
|
|
|
|
|
|
|
Less(const IColumn & column) : column(column) {}
|
|
|
|
|
|
|
|
bool operator()(size_t lhs, size_t rhs) const
|
|
|
|
{
|
|
|
|
if (positive)
|
|
|
|
return column.compareAt(lhs, rhs, column, 1) < 0;
|
|
|
|
else
|
|
|
|
return column.compareAt(lhs, rhs, column, -1) > 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
|
|
|
|
{
|
2017-12-15 21:32:25 +00:00
|
|
|
const ColumnArray::Offsets & offsets = array.getOffsets();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
size_t size = offsets.size();
|
|
|
|
size_t nested_size = array.getData().size();
|
|
|
|
IColumn::Permutation permutation(nested_size);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < nested_size; ++i)
|
|
|
|
permutation[i] = i;
|
|
|
|
|
2017-12-15 21:32:25 +00:00
|
|
|
ColumnArray::Offset current_offset = 0;
|
2017-04-01 07:20:54 +00:00
|
|
|
for (size_t i = 0; i < size; ++i)
|
|
|
|
{
|
|
|
|
auto next_offset = offsets[i];
|
|
|
|
std::sort(&permutation[current_offset], &permutation[next_offset], Less(*mapped));
|
|
|
|
current_offset = next_offset;
|
|
|
|
}
|
|
|
|
|
2017-12-15 02:36:40 +00:00
|
|
|
return ColumnArray::create(array.getData().permute(permutation, 0), array.getOffsetsPtr());
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2016-11-20 06:44:38 +00:00
|
|
|
};
|
|
|
|
|
2018-02-15 10:13:46 +00:00
|
|
|
struct ArrayCumSumImpl
|
|
|
|
{
|
|
|
|
static bool needBoolean() { return false; }
|
|
|
|
static bool needExpression() { return false; }
|
|
|
|
static bool needOneArray() { return false; }
|
|
|
|
|
|
|
|
static DataTypePtr getReturnType(const DataTypePtr & expression_return, const DataTypePtr & /*array_element*/)
|
|
|
|
{
|
|
|
|
if (checkDataType<DataTypeUInt8>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeUInt16>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeUInt32>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeUInt64>(&*expression_return))
|
|
|
|
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeUInt64>());
|
|
|
|
|
|
|
|
if (checkDataType<DataTypeInt8>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeInt16>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeInt32>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeInt64>(&*expression_return))
|
|
|
|
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeInt64>());
|
|
|
|
|
|
|
|
if (checkDataType<DataTypeFloat32>(&*expression_return) ||
|
|
|
|
checkDataType<DataTypeFloat64>(&*expression_return))
|
|
|
|
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeFloat64>());
|
|
|
|
|
|
|
|
throw Exception("arrayCumSum cannot add values of type " + expression_return->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Element, typename Result>
|
|
|
|
static bool executeType(const ColumnPtr & mapped, const ColumnArray & array, ColumnPtr & res_ptr)
|
|
|
|
{
|
|
|
|
const ColumnVector<Element> * column = checkAndGetColumn<ColumnVector<Element>>(&*mapped);
|
|
|
|
|
|
|
|
if (!column)
|
|
|
|
{
|
|
|
|
const ColumnConst * column_const = checkAndGetColumnConst<ColumnVector<Element>>(&*mapped);
|
|
|
|
|
|
|
|
if (!column_const)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const Element x = column_const->template getValue<Element>();
|
|
|
|
const IColumn::Offsets & offsets = array.getOffsets();
|
|
|
|
|
|
|
|
auto res_nested = ColumnVector<Result>::create();
|
|
|
|
typename ColumnVector<Result>::Container & res_values = res_nested->getData();
|
|
|
|
res_values.resize(column_const->size());
|
|
|
|
|
|
|
|
size_t pos = 0;
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
// skip empty arrays
|
|
|
|
if (pos < offsets[i])
|
|
|
|
{
|
|
|
|
res_values[pos++] = x;
|
|
|
|
for (; pos < offsets[i]; ++pos)
|
|
|
|
{
|
|
|
|
res_values[pos] = res_values[pos - 1] + x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
res_ptr = ColumnArray::create(std::move(res_nested), array.getOffsetsPtr());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const IColumn::Offsets & offsets = array.getOffsets();
|
|
|
|
const typename ColumnVector<Element>::Container & data = column->getData();
|
|
|
|
|
|
|
|
auto res_nested = ColumnVector<Result>::create();
|
|
|
|
typename ColumnVector<Result>::Container & res_values = res_nested->getData();
|
|
|
|
res_values.resize(data.size());
|
|
|
|
|
|
|
|
size_t pos = 0;
|
|
|
|
for (size_t i = 0; i < offsets.size(); ++i)
|
|
|
|
{
|
|
|
|
// skip empty arrays
|
|
|
|
if (pos < offsets[i])
|
|
|
|
{
|
|
|
|
res_values[pos] = data[pos];
|
|
|
|
for (++pos; pos < offsets[i]; ++pos)
|
|
|
|
{
|
|
|
|
res_values[pos] = res_values[pos - 1] + data[pos];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res_ptr = ColumnArray::create(std::move(res_nested), array.getOffsetsPtr());
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
|
|
|
|
{
|
|
|
|
ColumnPtr res;
|
|
|
|
|
|
|
|
if (executeType< UInt8 , UInt64>(mapped, array, res) ||
|
|
|
|
executeType< UInt16, UInt64>(mapped, array, res) ||
|
|
|
|
executeType< UInt32, UInt64>(mapped, array, res) ||
|
|
|
|
executeType< UInt64, UInt64>(mapped, array, res) ||
|
|
|
|
executeType< Int8 , Int64>(mapped, array, res) ||
|
|
|
|
executeType< Int16, Int64>(mapped, array, res) ||
|
|
|
|
executeType< Int32, Int64>(mapped, array, res) ||
|
|
|
|
executeType< Int64, Int64>(mapped, array, res) ||
|
|
|
|
executeType<Float32,Float64>(mapped, array, res) ||
|
|
|
|
executeType<Float64,Float64>(mapped, array, res))
|
|
|
|
return res;
|
|
|
|
else
|
|
|
|
throw Exception("Unexpected column for arrayCumSum: " + mapped->getName());
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2016-11-20 06:44:38 +00:00
|
|
|
|
2013-05-20 15:42:57 +00:00
|
|
|
template <typename Impl, typename Name>
|
|
|
|
class FunctionArrayMapped : public IFunction
|
|
|
|
{
|
|
|
|
public:
|
2017-04-01 07:20:54 +00:00
|
|
|
static constexpr auto name = Name::name;
|
2018-06-03 20:39:06 +00:00
|
|
|
static FunctionPtr create(const Context &) { return std::make_shared<FunctionArrayMapped>(); }
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
String getName() const override
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isVariadic() const override { return true; }
|
|
|
|
size_t getNumberOfArguments() const override { return 0; }
|
|
|
|
|
2017-05-27 15:45:25 +00:00
|
|
|
/// Called if at least one function argument is a lambda expression.
|
|
|
|
/// For argument-lambda expressions, it defines the types of arguments of these expressions.
|
2017-04-01 07:20:54 +00:00
|
|
|
void getLambdaArgumentTypesImpl(DataTypes & arguments) const override
|
|
|
|
{
|
|
|
|
if (arguments.size() < 1)
|
|
|
|
throw Exception("Function " + getName() + " needs at least one argument; passed "
|
|
|
|
+ toString(arguments.size()) + ".",
|
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
|
|
|
if (arguments.size() == 1)
|
|
|
|
throw Exception("Function " + getName() + " needs at least one array argument.",
|
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
|
|
|
DataTypes nested_types(arguments.size() - 1);
|
|
|
|
for (size_t i = 0; i < nested_types.size(); ++i)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
const DataTypeArray * array_type = checkAndGetDataType<DataTypeArray>(&*arguments[i + 1]);
|
2017-04-01 07:20:54 +00:00
|
|
|
if (!array_type)
|
|
|
|
throw Exception("Argument " + toString(i + 2) + " of function " + getName() + " must be array. Found "
|
|
|
|
+ arguments[i + 1]->getName() + " instead.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
nested_types[i] = array_type->getNestedType();
|
|
|
|
}
|
|
|
|
|
2018-09-02 03:33:48 +00:00
|
|
|
const DataTypeFunction * function_type = checkAndGetDataType<DataTypeFunction>(arguments[0].get());
|
2018-02-06 19:34:53 +00:00
|
|
|
if (!function_type || function_type->getArgumentTypes().size() != nested_types.size())
|
|
|
|
throw Exception("First argument for this overload of " + getName() + " must be a function with "
|
2017-04-01 07:20:54 +00:00
|
|
|
+ toString(nested_types.size()) + " arguments. Found "
|
|
|
|
+ arguments[0]->getName() + " instead.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
arguments[0] = std::make_shared<DataTypeFunction>(nested_types);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
/*
|
2017-04-24 04:31:03 +00:00
|
|
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
|
|
|
{
|
|
|
|
size_t min_args = Impl::needExpression() ? 2 : 1;
|
|
|
|
if (arguments.size() < min_args)
|
|
|
|
throw Exception("Function " + getName() + " needs at least "
|
|
|
|
+ toString(min_args) + " argument; passed "
|
|
|
|
+ toString(arguments.size()) + ".",
|
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
|
|
|
if (arguments.size() == 1)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
const DataTypeArray * array_type = checkAndGetDataType<DataTypeArray>(arguments[0].get());
|
2017-04-24 04:31:03 +00:00
|
|
|
|
|
|
|
if (!array_type)
|
|
|
|
throw Exception("The only argument for function " + getName() + " must be array. Found "
|
|
|
|
+ arguments[0]->getName() + " instead.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
|
|
|
DataTypePtr nested_type = array_type->getNestedType();
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
if (Impl::needBoolean() && !checkDataType<DataTypeUInt8>(&*nested_type))
|
2017-04-24 04:31:03 +00:00
|
|
|
throw Exception("The only argument for function " + getName() + " must be array of UInt8. Found "
|
|
|
|
+ arguments[0]->getName() + " instead.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
|
|
|
return Impl::getReturnType(nested_type, nested_type);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (arguments.size() > 2 && Impl::needOneArray())
|
|
|
|
throw Exception("Function " + getName() + " needs one array argument.",
|
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
const DataTypeExpression * expression = checkAndGetDataType<DataTypeExpression>(arguments[0].get());
|
2017-04-24 04:31:03 +00:00
|
|
|
|
|
|
|
if (!expression)
|
|
|
|
throw Exception("Type of first argument for function " + getName() + " must be an expression.",
|
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2017-05-27 15:45:25 +00:00
|
|
|
/// The types of the remaining arguments are already checked in getLambdaArgumentTypes.
|
2017-04-24 04:31:03 +00:00
|
|
|
|
|
|
|
DataTypePtr return_type = expression->getReturnType();
|
2017-07-21 06:35:58 +00:00
|
|
|
if (Impl::needBoolean() && !checkDataType<DataTypeUInt8>(&*return_type))
|
2017-04-24 04:31:03 +00:00
|
|
|
throw Exception("Expression for function " + getName() + " must return UInt8, found "
|
|
|
|
+ return_type->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
const DataTypeArray * first_array_type = checkAndGetDataType<DataTypeArray>(arguments[1].get());
|
2017-04-24 04:31:03 +00:00
|
|
|
|
|
|
|
return Impl::getReturnType(return_type, first_array_type->getNestedType());
|
|
|
|
}
|
|
|
|
}
|
2018-02-06 19:34:53 +00:00
|
|
|
*/
|
2017-04-24 04:31:03 +00:00
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
size_t min_args = Impl::needExpression() ? 2 : 1;
|
|
|
|
if (arguments.size() < min_args)
|
|
|
|
throw Exception("Function " + getName() + " needs at least "
|
|
|
|
+ toString(min_args) + " argument; passed "
|
|
|
|
+ toString(arguments.size()) + ".",
|
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
|
|
|
if (arguments.size() == 1)
|
|
|
|
{
|
2018-09-02 03:33:48 +00:00
|
|
|
const auto array_type = checkAndGetDataType<DataTypeArray>(arguments[0].type.get());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!array_type)
|
|
|
|
throw Exception("The only argument for function " + getName() + " must be array. Found "
|
|
|
|
+ arguments[0].type->getName() + " instead.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
|
|
|
DataTypePtr nested_type = array_type->getNestedType();
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
if (Impl::needBoolean() && !checkDataType<DataTypeUInt8>(&*nested_type))
|
2017-04-01 07:20:54 +00:00
|
|
|
throw Exception("The only argument for function " + getName() + " must be array of UInt8. Found "
|
|
|
|
+ arguments[0].type->getName() + " instead.", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
return Impl::getReturnType(nested_type, nested_type);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (arguments.size() > 2 && Impl::needOneArray())
|
|
|
|
throw Exception("Function " + getName() + " needs one array argument.",
|
|
|
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
const auto data_type_function = checkAndGetDataType<DataTypeFunction>(arguments[0].type.get());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
if (!data_type_function)
|
|
|
|
throw Exception("First argument for function " + getName() + " must be a function.",
|
2017-04-01 07:20:54 +00:00
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2017-05-27 15:45:25 +00:00
|
|
|
/// The types of the remaining arguments are already checked in getLambdaArgumentTypes.
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
DataTypePtr return_type = data_type_function->getReturnType();
|
2017-07-21 06:35:58 +00:00
|
|
|
if (Impl::needBoolean() && !checkDataType<DataTypeUInt8>(&*return_type))
|
2017-04-01 07:20:54 +00:00
|
|
|
throw Exception("Expression for function " + getName() + " must return UInt8, found "
|
|
|
|
+ return_type->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2018-09-02 03:33:48 +00:00
|
|
|
const auto first_array_type = checkAndGetDataType<DataTypeArray>(arguments[1].type.get());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
return Impl::getReturnType(return_type, first_array_type->getNestedType());
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-24 07:16:39 +00:00
|
|
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
if (arguments.size() == 1)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
ColumnPtr column_array_ptr = block.getByPosition(arguments[0]).column;
|
2018-02-06 19:34:53 +00:00
|
|
|
const auto * column_array = checkAndGetColumn<ColumnArray>(column_array_ptr.get());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column_array)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
const ColumnConst * column_const_array = checkAndGetColumnConst<ColumnArray>(column_array_ptr.get());
|
2017-04-01 07:20:54 +00:00
|
|
|
if (!column_const_array)
|
|
|
|
throw Exception("Expected array column, found " + column_array_ptr->getName(), ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
column_array_ptr = column_const_array->convertToFullColumn();
|
2017-07-21 06:35:58 +00:00
|
|
|
column_array = static_cast<const ColumnArray *>(column_array_ptr.get());
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2017-07-21 06:35:58 +00:00
|
|
|
block.getByPosition(result).column = Impl::execute(*column_array, column_array->getDataPtr());
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
const auto & column_with_type_and_name = block.getByPosition(arguments[0]);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column_with_type_and_name.column)
|
2018-02-06 19:34:53 +00:00
|
|
|
throw Exception("First argument for function " + getName() + " must be a function.",
|
2017-04-01 07:20:54 +00:00
|
|
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
const auto * column_function = typeid_cast<const ColumnFunction *>(column_with_type_and_name.column.get());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
ColumnPtr offsets_column;
|
|
|
|
|
|
|
|
ColumnPtr column_first_array_ptr;
|
|
|
|
const ColumnArray * column_first_array = nullptr;
|
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
ColumnsWithTypeAndName arrays;
|
|
|
|
arrays.reserve(arguments.size() - 1);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
for (size_t i = 1; i < arguments.size(); ++i)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2018-02-06 19:34:53 +00:00
|
|
|
const auto & array_with_type_and_name = block.getByPosition(arguments[i]);
|
|
|
|
|
|
|
|
ColumnPtr column_array_ptr = array_with_type_and_name.column;
|
|
|
|
const auto * column_array = checkAndGetColumn<ColumnArray>(column_array_ptr.get());
|
|
|
|
|
|
|
|
const DataTypePtr & array_type_ptr = array_with_type_and_name.type;
|
|
|
|
const auto * array_type = checkAndGetDataType<DataTypeArray>(array_type_ptr.get());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (!column_array)
|
|
|
|
{
|
2017-07-21 06:35:58 +00:00
|
|
|
const ColumnConst * column_const_array = checkAndGetColumnConst<ColumnArray>(column_array_ptr.get());
|
2017-04-01 07:20:54 +00:00
|
|
|
if (!column_const_array)
|
|
|
|
throw Exception("Expected array column, found " + column_array_ptr->getName(), ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
column_array_ptr = column_const_array->convertToFullColumn();
|
2017-07-21 06:35:58 +00:00
|
|
|
column_array = checkAndGetColumn<ColumnArray>(column_array_ptr.get());
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
if (!array_type)
|
2018-06-04 15:05:19 +00:00
|
|
|
throw Exception("Expected array type, found " + array_type_ptr->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
2018-02-06 19:34:53 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (!offsets_column)
|
|
|
|
{
|
2017-12-15 02:36:40 +00:00
|
|
|
offsets_column = column_array->getOffsetsPtr();
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-05-27 15:45:25 +00:00
|
|
|
/// The first condition is optimization: do not compare data if the pointers are equal.
|
2017-12-15 02:36:40 +00:00
|
|
|
if (column_array->getOffsetsPtr() != offsets_column
|
2017-12-15 21:32:25 +00:00
|
|
|
&& column_array->getOffsets() != typeid_cast<const ColumnArray::ColumnOffsets &>(*offsets_column).getData())
|
2017-04-01 07:20:54 +00:00
|
|
|
throw Exception("Arrays passed to " + getName() + " must have equal size", ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH);
|
|
|
|
}
|
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
if (i == 1)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
column_first_array_ptr = column_array_ptr;
|
|
|
|
column_first_array = column_array;
|
|
|
|
}
|
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
arrays.emplace_back(ColumnWithTypeAndName(column_array->getDataPtr(),
|
|
|
|
array_type->getNestedType(), array_with_type_and_name.name));
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2017-05-27 15:45:25 +00:00
|
|
|
/// Put all the necessary columns multiplied by the sizes of arrays into the block.
|
2018-03-20 14:17:09 +00:00
|
|
|
auto replicated_column_function_ptr = (*column_function->replicate(column_first_array->getOffsets())).mutate();
|
2018-02-06 19:34:53 +00:00
|
|
|
auto * replicated_column_function = typeid_cast<ColumnFunction *>(replicated_column_function_ptr.get());
|
|
|
|
replicated_column_function->appendArguments(arrays);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-02-06 19:34:53 +00:00
|
|
|
block.getByPosition(result).column = Impl::execute(*column_first_array,
|
|
|
|
replicated_column_function->reduce().column);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-20 15:42:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-11-23 02:12:09 +00:00
|
|
|
struct NameArrayMap { static constexpr auto name = "arrayMap"; };
|
|
|
|
struct NameArrayFilter { static constexpr auto name = "arrayFilter"; };
|
|
|
|
struct NameArrayCount { static constexpr auto name = "arrayCount"; };
|
|
|
|
struct NameArrayExists { static constexpr auto name = "arrayExists"; };
|
|
|
|
struct NameArrayAll { static constexpr auto name = "arrayAll"; };
|
|
|
|
struct NameArraySum { static constexpr auto name = "arraySum"; };
|
|
|
|
struct NameArrayFirst { static constexpr auto name = "arrayFirst"; };
|
|
|
|
struct NameArrayFirstIndex { static constexpr auto name = "arrayFirstIndex"; };
|
2017-04-01 07:20:54 +00:00
|
|
|
struct NameArraySort { static constexpr auto name = "arraySort"; };
|
2017-11-23 02:12:09 +00:00
|
|
|
struct NameArrayReverseSort { static constexpr auto name = "arrayReverseSort"; };
|
2018-02-08 07:13:50 +00:00
|
|
|
struct NameArrayCumSum { static constexpr auto name = "arrayCumSum"; };
|
2016-11-20 06:44:38 +00:00
|
|
|
|
|
|
|
using FunctionArrayMap = FunctionArrayMapped<ArrayMapImpl, NameArrayMap>;
|
|
|
|
using FunctionArrayFilter = FunctionArrayMapped<ArrayFilterImpl, NameArrayFilter>;
|
|
|
|
using FunctionArrayCount = FunctionArrayMapped<ArrayCountImpl, NameArrayCount>;
|
|
|
|
using FunctionArrayExists = FunctionArrayMapped<ArrayExistsImpl, NameArrayExists>;
|
|
|
|
using FunctionArrayAll = FunctionArrayMapped<ArrayAllImpl, NameArrayAll>;
|
|
|
|
using FunctionArraySum = FunctionArrayMapped<ArraySumImpl, NameArraySum>;
|
|
|
|
using FunctionArrayFirst = FunctionArrayMapped<ArrayFirstImpl, NameArrayFirst>;
|
|
|
|
using FunctionArrayFirstIndex = FunctionArrayMapped<ArrayFirstIndexImpl, NameArrayFirstIndex>;
|
|
|
|
using FunctionArraySort = FunctionArrayMapped<ArraySortImpl<true>, NameArraySort>;
|
|
|
|
using FunctionArrayReverseSort = FunctionArrayMapped<ArraySortImpl<false>, NameArrayReverseSort>;
|
2018-02-08 07:13:50 +00:00
|
|
|
using FunctionArrayCumSum = FunctionArrayMapped<ArrayCumSumImpl, NameArrayCumSum>;
|
2014-06-12 18:41:09 +00:00
|
|
|
|
2013-05-20 15:42:57 +00:00
|
|
|
}
|