[feature-wip](decimalv3) Support basic agg and arithmetic operations for decimal v3 (#14513)

This commit is contained in:
Gabriel
2022-11-29 15:12:41 +08:00
committed by GitHub
parent 82da071b45
commit 3e8b3658c7
211 changed files with 29230 additions and 8063 deletions

View File

@ -227,25 +227,11 @@ struct DecimalBinaryOperation {
using ArrayC = typename ColumnDecimal<ResultType>::Container;
static void vector_vector(const typename Traits::ArrayA& a, const typename Traits::ArrayB& b,
ArrayC& c, ResultType scale_a [[maybe_unused]],
ResultType scale_b [[maybe_unused]]) {
ArrayC& c) {
size_t size = a.size();
if constexpr (OpTraits::is_plus_minus) {
if (scale_a != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled<true>(a[i], b[i], scale_a);
}
return;
} else if (scale_b != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled<false>(a[i], b[i], scale_b);
}
return;
}
}
if constexpr (OpTraits::is_multiply && std::is_same_v<A, Decimal128> &&
std::is_same_v<B, Decimal128>) {
if constexpr (OpTraits::is_multiply && IsDecimalV2<A> && IsDecimalV2<B> &&
IsDecimalV2<ResultType>) {
Op::vector_vector(a, b, c);
} else {
for (size_t i = 0; i < size; i++) {
@ -256,8 +242,7 @@ struct DecimalBinaryOperation {
/// null_map for divide and mod
static void vector_vector(const typename Traits::ArrayA& a, const typename Traits::ArrayB& b,
ArrayC& c, ResultType scale_a [[maybe_unused]],
ResultType scale_b [[maybe_unused]], NullMap& null_map) {
ArrayC& c, NullMap& null_map) {
size_t size = a.size();
if constexpr (IsDecimalV2<B> || IsDecimalV2<A>) {
/// default: use it if no return before
@ -267,44 +252,18 @@ struct DecimalBinaryOperation {
} else {
if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_div(a[i], b[i], scale_a, null_map[i]);
c[i] = apply_scaled_div(a[i], b[i], null_map[i]);
}
return;
} else if constexpr (OpTraits::is_mod) {
if (scale_a != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_mod<true>(a[i], b[i], scale_a, null_map[i]);
}
return;
} else if (scale_b != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_mod<false>(a[i], b[i], scale_b, null_map[i]);
}
return;
}
}
}
}
static void vector_constant(const typename Traits::ArrayA& a, B b, ArrayC& c,
ResultType scale_a [[maybe_unused]],
ResultType scale_b [[maybe_unused]]) {
static void vector_constant(const typename Traits::ArrayA& a, B b, ArrayC& c) {
size_t size = a.size();
if constexpr (OpTraits::is_plus_minus) {
if (scale_a != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled<true>(a[i], b, scale_a);
}
return;
} else if (scale_b != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled<false>(a[i], b, scale_b);
}
return;
}
} else if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_div(a[i], b, scale_a);
c[i] = apply_scaled_div(a[i], b);
}
return;
}
@ -316,26 +275,13 @@ struct DecimalBinaryOperation {
}
static void vector_constant(const typename Traits::ArrayA& a, B b, ArrayC& c,
ResultType scale_a [[maybe_unused]],
ResultType scale_b [[maybe_unused]], NullMap& null_map) {
NullMap& null_map) {
size_t size = a.size();
if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_div(a[i], b, scale_a, null_map[i]);
c[i] = apply_scaled_div(a[i], b, null_map[i]);
}
return;
} else if constexpr (OpTraits::is_mod) {
if (scale_a != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_mod<true>(a[i], b, scale_a, null_map[i]);
}
return;
} else if (scale_b != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_mod<false>(a[i], b, scale_b, null_map[i]);
}
return;
}
}
for (size_t i = 0; i < size; ++i) {
@ -343,25 +289,11 @@ struct DecimalBinaryOperation {
}
}
static void constant_vector(A a, const typename Traits::ArrayB& b, ArrayC& c,
ResultType scale_a [[maybe_unused]],
ResultType scale_b [[maybe_unused]]) {
static void constant_vector(A a, const typename Traits::ArrayB& b, ArrayC& c) {
size_t size = b.size();
if constexpr (OpTraits::is_plus_minus) {
if (scale_a != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled<true>(a, b[i], scale_a);
}
return;
} else if (scale_b != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled<false>(a, b[i], scale_b);
}
return;
}
} else if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_div(a, b[i], scale_a);
c[i] = apply_scaled_div(a, b[i]);
}
return;
}
@ -373,26 +305,13 @@ struct DecimalBinaryOperation {
}
static void constant_vector(A a, const typename Traits::ArrayB& b, ArrayC& c,
ResultType scale_a [[maybe_unused]],
ResultType scale_b [[maybe_unused]], NullMap& null_map) {
NullMap& null_map) {
size_t size = b.size();
if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_div(a, b[i], scale_a, null_map[i]);
c[i] = apply_scaled_div(a, b[i], null_map[i]);
}
return;
} else if constexpr (OpTraits::is_mod) {
if (scale_a != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_mod<true>(a, b[i], scale_a, null_map[i]);
}
return;
} else if (scale_b != 1) {
for (size_t i = 0; i < size; ++i) {
c[i] = apply_scaled_mod<false>(a, b[i], scale_b, null_map[i]);
}
return;
}
}
for (size_t i = 0; i < size; ++i) {
@ -400,108 +319,90 @@ struct DecimalBinaryOperation {
}
}
static ResultType constant_constant(A a, B b, ResultType scale_a [[maybe_unused]],
ResultType scale_b [[maybe_unused]]) {
if constexpr (OpTraits::is_plus_minus) {
if (scale_a != 1) {
return apply_scaled<true>(a, b, scale_a);
} else if (scale_b != 1) {
return apply_scaled<false>(a, b, scale_b);
}
} else if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
return apply_scaled_div(a, b, scale_a);
static ResultType constant_constant(A a, B b) {
if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
return apply_scaled_div(a, b);
}
return apply(a, b);
}
static ResultType constant_constant(A a, B b, ResultType scale_a [[maybe_unused]],
ResultType scale_b [[maybe_unused]], UInt8& is_null) {
if constexpr (OpTraits::is_plus_minus) {
if (scale_a != 1) {
return apply_scaled<true>(a, b, scale_a, is_null);
} else if (scale_b != 1) {
return apply_scaled<false>(a, b, scale_b, is_null);
}
} else if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
return apply_scaled_div(a, b, scale_a, is_null);
} else if constexpr (OpTraits::is_mod) {
if (scale_a != 1) {
return apply_scaled_mod<true>(a, b, scale_a, is_null);
} else if (scale_b != 1) {
return apply_scaled_mod<false>(a, b, scale_b, is_null);
}
static ResultType constant_constant(A a, B b, UInt8& is_null) {
if constexpr (OpTraits::is_division && IsDecimalNumber<B>) {
return apply_scaled_div(a, b, is_null);
}
return apply(a, b, is_null);
}
static ColumnPtr adapt_decimal_constant_constant(A a, B b, UInt32 scale, ResultType scale_a,
ResultType scale_b) {
auto column_result = ColumnDecimal<ResultType>::create(1, scale);
static ColumnPtr adapt_decimal_constant_constant(A a, B b, DataTypePtr res_data_type) {
auto column_result = ColumnDecimal<ResultType>::create(
1, assert_cast<const DataTypeDecimal<ResultType>&>(*res_data_type).get_scale());
if constexpr (is_to_null_type) {
auto null_map = ColumnUInt8::create(1, 0);
column_result->get_element(0) =
constant_constant(a, b, scale_a, scale_b, null_map->get_element(0));
column_result->get_element(0) = constant_constant(a, b, null_map->get_element(0));
return ColumnNullable::create(std::move(column_result), std::move(null_map));
} else {
column_result->get_element(0) = constant_constant(a, b, scale_a, scale_b);
column_result->get_element(0) = constant_constant(a, b);
return column_result;
}
}
static ColumnPtr adapt_decimal_vector_constant(ColumnPtr column_left, B b, UInt32 column_scale,
ResultType scale_a, ResultType scale_b) {
static ColumnPtr adapt_decimal_vector_constant(ColumnPtr column_left, B b,
DataTypePtr res_data_type) {
auto column_left_ptr = check_and_get_column<typename Traits::ColumnVectorA>(column_left);
auto column_result = ColumnDecimal<ResultType>::create(column_left->size(), column_scale);
auto column_result = ColumnDecimal<ResultType>::create(
column_left->size(),
assert_cast<const DataTypeDecimal<ResultType>&>(*res_data_type).get_scale());
DCHECK(column_left_ptr != nullptr);
if constexpr (is_to_null_type) {
auto null_map = ColumnUInt8::create(column_left->size(), 0);
vector_constant(column_left_ptr->get_data(), b, column_result->get_data(), scale_a,
scale_b, null_map->get_data());
vector_constant(column_left_ptr->get_data(), b, column_result->get_data(),
null_map->get_data());
return ColumnNullable::create(std::move(column_result), std::move(null_map));
} else {
vector_constant(column_left_ptr->get_data(), b, column_result->get_data(), scale_a,
scale_b);
vector_constant(column_left_ptr->get_data(), b, column_result->get_data());
return column_result;
}
}
static ColumnPtr adapt_decimal_constant_vector(A a, ColumnPtr column_right, UInt32 column_scale,
ResultType scale_a, ResultType scale_b) {
static ColumnPtr adapt_decimal_constant_vector(A a, ColumnPtr column_right,
DataTypePtr res_data_type) {
auto column_right_ptr = check_and_get_column<typename Traits::ColumnVectorB>(column_right);
auto column_result = ColumnDecimal<ResultType>::create(column_right->size(), column_scale);
auto column_result = ColumnDecimal<ResultType>::create(
column_right->size(),
assert_cast<const DataTypeDecimal<ResultType>&>(*res_data_type).get_scale());
DCHECK(column_right_ptr != nullptr);
if constexpr (is_to_null_type) {
auto null_map = ColumnUInt8::create(column_right->size(), 0);
constant_vector(a, column_right_ptr->get_data(), column_result->get_data(), scale_a,
scale_b, null_map->get_data());
constant_vector(a, column_right_ptr->get_data(), column_result->get_data(),
null_map->get_data());
return ColumnNullable::create(std::move(column_result), std::move(null_map));
} else {
constant_vector(a, column_right_ptr->get_data(), column_result->get_data(), scale_a,
scale_b);
constant_vector(a, column_right_ptr->get_data(), column_result->get_data());
return column_result;
}
}
static ColumnPtr adapt_decimal_vector_vector(ColumnPtr column_left, ColumnPtr column_right,
UInt32 column_scale, ResultType scale_a,
ResultType scale_b) {
DataTypePtr res_data_type) {
auto column_left_ptr = check_and_get_column<typename Traits::ColumnVectorA>(column_left);
auto column_right_ptr = check_and_get_column<typename Traits::ColumnVectorB>(column_right);
auto column_result = ColumnDecimal<ResultType>::create(column_left->size(), column_scale);
auto column_result = ColumnDecimal<ResultType>::create(
column_left->size(),
assert_cast<const DataTypeDecimal<ResultType>&>(*res_data_type).get_scale());
DCHECK(column_left_ptr != nullptr && column_right_ptr != nullptr);
if constexpr (is_to_null_type) {
auto null_map = ColumnUInt8::create(column_result->size(), 0);
vector_vector(column_left_ptr->get_data(), column_right_ptr->get_data(),
column_result->get_data(), scale_a, scale_b, null_map->get_data());
column_result->get_data(), null_map->get_data());
return ColumnNullable::create(std::move(column_result), std::move(null_map));
} else {
vector_vector(column_left_ptr->get_data(), column_right_ptr->get_data(),
column_result->get_data(), scale_a, scale_b);
column_result->get_data());
return column_result;
}
}
@ -547,19 +448,12 @@ private:
}
}
template <bool scale_left>
static NativeResultType apply_scaled(NativeResultType a, NativeResultType b,
NativeResultType scale) {
static NativeResultType apply_scaled(NativeResultType a, NativeResultType b) {
if constexpr (OpTraits::is_plus_minus) {
NativeResultType res;
if constexpr (check_overflow) {
bool overflow = false;
if constexpr (scale_left) {
overflow |= common::mul_overflow(a, scale, a);
} else {
overflow |= common::mul_overflow(b, scale, b);
}
if constexpr (OpTraits::can_overflow) {
overflow |= Op::template apply<NativeResultType>(a, b, res);
@ -573,11 +467,6 @@ private:
res = max_decimal_value<ResultType>();
}
} else {
if constexpr (scale_left) {
a *= scale;
} else {
b *= scale;
}
res = apply(a, b);
}
@ -586,52 +475,14 @@ private:
}
static NativeResultType apply_scaled_div(NativeResultType a, NativeResultType b,
NativeResultType scale, UInt8& is_null) {
UInt8& is_null) {
if constexpr (OpTraits::is_division) {
if constexpr (check_overflow) {
bool overflow = false;
if constexpr (!IsDecimalNumber<A>) {
overflow |= common::mul_overflow(scale, scale, scale);
}
overflow |= common::mul_overflow(a, scale, a);
// TODO handle overflow gracefully
if (overflow) {
LOG(WARNING) << "Decimal math overflow";
return max_decimal_value<ResultType>();
}
} else {
if constexpr (!IsDecimalNumber<A>) {
scale *= scale;
}
a *= scale;
}
return apply(a, b, is_null);
}
}
template <bool scale_left>
static NativeResultType apply_scaled_mod(NativeResultType a, NativeResultType b,
NativeResultType scale, UInt8& is_null) {
if constexpr (check_overflow) {
bool overflow = false;
if constexpr (scale_left)
overflow |= common::mul_overflow(a, scale, a);
else
overflow |= common::mul_overflow(b, scale, b);
// TODO handle overflow gracefully
if (overflow) {
LOG(WARNING) << "Decimal math overflow";
return max_decimal_value<ResultType>();
}
} else {
if constexpr (scale_left)
a *= scale;
else
b *= scale;
}
UInt8& is_null) {
return apply(a, b, is_null);
}
};
@ -718,15 +569,13 @@ struct BinaryOperationTraits {
DataTypeFromFieldType<typename Op::ResultType>>>;
};
template <typename LeftDataType, typename RightDataType,
template <typename LeftDataType, typename RightDataType, typename ExpectedResultDataType,
template <typename, typename> class Operation, bool is_to_null_type>
struct ConstOrVectorAdapter {
static constexpr bool result_is_decimal =
IsDataTypeDecimal<LeftDataType> || IsDataTypeDecimal<RightDataType>;
using OpTraits = OperationTraits<Operation>;
using ResultDataType =
typename BinaryOperationTraits<Operation, LeftDataType, RightDataType>::ResultDataType;
using ResultDataType = ExpectedResultDataType;
using ResultType = typename ResultDataType::FieldType;
using A = typename LeftDataType::FieldType;
using B = typename RightDataType::FieldType;
@ -737,42 +586,27 @@ struct ConstOrVectorAdapter {
BinaryOperationImpl<A, B, Operation<A, B>, is_to_null_type, ResultType>>;
static ColumnPtr execute(ColumnPtr column_left, ColumnPtr column_right,
const LeftDataType& type_left, const RightDataType& type_right) {
const LeftDataType& type_left, const RightDataType& type_right,
DataTypePtr res_data_type) {
bool is_const_left = is_column_const(*column_left);
bool is_const_right = is_column_const(*column_right);
if (is_const_left && is_const_right) {
return constant_constant(column_left, column_right, type_left, type_right);
return constant_constant(column_left, column_right, type_left, type_right,
res_data_type);
} else if (is_const_left) {
return constant_vector(column_left, column_right, type_left, type_right);
return constant_vector(column_left, column_right, type_left, type_right, res_data_type);
} else if (is_const_right) {
return vector_constant(column_left, column_right, type_left, type_right);
return vector_constant(column_left, column_right, type_left, type_right, res_data_type);
} else {
return vector_vector(column_left, column_right, type_left, type_right);
return vector_vector(column_left, column_right, type_left, type_right, res_data_type);
}
}
private:
static auto get_decimal_infos(const LeftDataType& type_left, const RightDataType& type_right) {
ResultDataType type = decimal_result_type(type_left, type_right, OpTraits::is_multiply,
OpTraits::is_division);
typename ResultDataType::FieldType scale_a;
typename ResultDataType::FieldType scale_b;
if constexpr (OpTraits::is_division && IsDataTypeDecimal<RightDataType> &&
!IsDecimalV2<B> && !IsDecimalV2<A>) {
scale_a = type_right.get_scale_multiplier();
scale_b = 1;
return std::make_tuple(type, scale_a, scale_b);
}
scale_a = type.scale_factor_for(type_left, OpTraits::is_multiply);
scale_b = type.scale_factor_for(type_right, OpTraits::is_multiply || OpTraits::is_division);
return std::make_tuple(type, scale_a, scale_b);
}
static ColumnPtr constant_constant(ColumnPtr column_left, ColumnPtr column_right,
const LeftDataType& type_left,
const RightDataType& type_right) {
const RightDataType& type_right, DataTypePtr res_data_type) {
auto column_left_ptr = check_and_get_column<ColumnConst>(column_left);
auto column_right_ptr = check_and_get_column<ColumnConst>(column_right);
DCHECK(column_left_ptr != nullptr && column_right_ptr != nullptr);
@ -780,11 +614,9 @@ private:
ColumnPtr column_result = nullptr;
if constexpr (result_is_decimal) {
auto [type, scale_a, scale_b] = get_decimal_infos(type_left, type_right);
column_result = OperationImpl::adapt_decimal_constant_constant(
column_left_ptr->template get_value<A>(),
column_right_ptr->template get_value<B>(), type.get_scale(), scale_a, scale_b);
column_right_ptr->template get_value<B>(), res_data_type);
} else {
column_result = OperationImpl::adapt_normal_constant_constant(
@ -796,17 +628,15 @@ private:
}
static ColumnPtr vector_constant(ColumnPtr column_left, ColumnPtr column_right,
const LeftDataType& type_left,
const RightDataType& type_right) {
const LeftDataType& type_left, const RightDataType& type_right,
DataTypePtr res_data_type) {
auto column_right_ptr = check_and_get_column<ColumnConst>(column_right);
DCHECK(column_right_ptr != nullptr);
if constexpr (result_is_decimal) {
auto [type, scale_a, scale_b] = get_decimal_infos(type_left, type_right);
return OperationImpl::adapt_decimal_vector_constant(
column_left->get_ptr(), column_right_ptr->template get_value<B>(),
type.get_scale(), scale_a, scale_b);
res_data_type);
} else {
return OperationImpl::adapt_normal_vector_constant(
column_left->get_ptr(), column_right_ptr->template get_value<B>());
@ -814,17 +644,15 @@ private:
}
static ColumnPtr constant_vector(ColumnPtr column_left, ColumnPtr column_right,
const LeftDataType& type_left,
const RightDataType& type_right) {
const LeftDataType& type_left, const RightDataType& type_right,
DataTypePtr res_data_type) {
auto column_left_ptr = check_and_get_column<ColumnConst>(column_left);
DCHECK(column_left_ptr != nullptr);
if constexpr (result_is_decimal) {
auto [type, scale_a, scale_b] = get_decimal_infos(type_left, type_right);
return OperationImpl::adapt_decimal_constant_vector(
column_left_ptr->template get_value<A>(), column_right->get_ptr(),
type.get_scale(), scale_a, scale_b);
res_data_type);
} else {
return OperationImpl::adapt_normal_constant_vector(
column_left_ptr->template get_value<A>(), column_right->get_ptr());
@ -832,13 +660,11 @@ private:
}
static ColumnPtr vector_vector(ColumnPtr column_left, ColumnPtr column_right,
const LeftDataType& type_left, const RightDataType& type_right) {
const LeftDataType& type_left, const RightDataType& type_right,
DataTypePtr res_data_type) {
if constexpr (result_is_decimal) {
auto [type, scale_a, scale_b] = get_decimal_infos(type_left, type_right);
return OperationImpl::adapt_decimal_vector_vector(column_left->get_ptr(),
column_right->get_ptr(),
type.get_scale(), scale_a, scale_b);
return OperationImpl::adapt_decimal_vector_vector(
column_left->get_ptr(), column_right->get_ptr(), res_data_type);
} else {
return OperationImpl::adapt_normal_vector_vector(column_left->get_ptr(),
column_right->get_ptr());
@ -866,6 +692,16 @@ class FunctionBinaryArithmetic : public IFunction {
});
}
template <typename F>
static bool cast_both_types(const IDataType* left, const IDataType* right, const IDataType* res,
F&& f) {
return cast_type(left, [&](const auto& left_) {
return cast_type(right, [&](const auto& right_) {
return cast_type(res, [&](const auto& res_) { return f(left_, right_, res_); });
});
});
}
public:
static constexpr auto name = Name::name;
@ -932,6 +768,7 @@ public:
size_t result, size_t input_rows_count) override {
auto* left_generic = block.get_by_position(arguments[0]).type.get();
auto* right_generic = block.get_by_position(arguments[1]).type.get();
auto* result_generic = block.get_by_position(result).type.get();
if (left_generic->is_nullable()) {
left_generic =
static_cast<const DataTypeNullable*>(left_generic)->get_nested_type().get();
@ -940,19 +777,35 @@ public:
right_generic =
static_cast<const DataTypeNullable*>(right_generic)->get_nested_type().get();
}
if (result_generic->is_nullable()) {
result_generic =
static_cast<const DataTypeNullable*>(result_generic)->get_nested_type().get();
}
bool valid = cast_both_types(
left_generic, right_generic, [&](const auto& left, const auto& right) {
left_generic, right_generic, result_generic,
[&](const auto& left, const auto& right, const auto& res) {
using LeftDataType = std::decay_t<decltype(left)>;
using RightDataType = std::decay_t<decltype(right)>;
using ExpectedResultDataType = std::decay_t<decltype(res)>;
using ResultDataType =
typename BinaryOperationTraits<Operation, LeftDataType,
RightDataType>::ResultDataType;
if constexpr (!std::is_same_v<ResultDataType, InvalidType>) {
auto column_result = ConstOrVectorAdapter<LeftDataType, RightDataType,
Operation, is_to_null_type>::
if constexpr (
!std::is_same_v<ResultDataType, InvalidType> &&
(IsDataTypeDecimal<ExpectedResultDataType> ==
IsDataTypeDecimal<
ResultDataType>)&&(IsDataTypeDecimal<ExpectedResultDataType> ==
(IsDataTypeDecimal<LeftDataType> ||
IsDataTypeDecimal<RightDataType>))) {
auto column_result = ConstOrVectorAdapter<
LeftDataType, RightDataType,
std::conditional_t<IsDataTypeDecimal<ExpectedResultDataType>,
ExpectedResultDataType, ResultDataType>,
Operation, is_to_null_type>::
execute(block.get_by_position(arguments[0]).column,
block.get_by_position(arguments[1]).column, left, right);
block.get_by_position(arguments[1]).column, left, right,
remove_nullable(block.get_by_position(result).type));
block.replace_by_position(result, std::move(column_result));
return true;
}