blob: 4a2caaee43feaf466804d84ec701d83a52bb921c [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma once
#include <type_traits>
#include "core/column/column_array.h"
#include "core/column/column_map.h"
#include "core/column/column_nullable.h"
#include "core/column/column_struct.h"
#include "core/column/column_variant.h"
#include "core/column/column_vector.h"
#include "core/data_type/data_type_decimal.h"
#include "core/data_type/data_type_nullable.h"
#include "core/data_type/data_type_string.h"
#include "exprs/aggregate/aggregate_function.h"
#include "exprs/function/function.h"
namespace doris {
#include "common/compile_check_begin.h"
template <bool arg_is_nullable>
struct Value {
public:
bool is_null() const {
if (_ptr == nullptr) {
return true;
}
if constexpr (arg_is_nullable) {
return assert_cast<const ColumnNullable*, TypeCheckOnRelease::DISABLE>(_ptr)
->is_null_at(_offset);
}
return false;
}
template <typename ColVecType>
void insert_into(IColumn& to) const {
if constexpr (arg_is_nullable) {
const auto* col = assert_cast<const ColumnNullable*, TypeCheckOnRelease::DISABLE>(_ptr);
assert_cast<ColVecType&, TypeCheckOnRelease::DISABLE>(to).insert_from(
col->get_nested_column(), _offset);
} else {
assert_cast<ColVecType&, TypeCheckOnRelease::DISABLE>(to).insert_from(*_ptr, _offset);
}
}
// Non-template version: virtual dispatch on IColumn::insert_from.
// Used by window path where devirtualization is not beneficial.
void insert_into(IColumn& to) const {
if constexpr (arg_is_nullable) {
const auto* col = assert_cast<const ColumnNullable*, TypeCheckOnRelease::DISABLE>(_ptr);
to.insert_from(col->get_nested_column(), _offset);
} else {
to.insert_from(*_ptr, _offset);
}
}
void set_value(const IColumn* column, size_t row) {
_ptr = column;
_offset = row;
}
void reset() {
_ptr = nullptr;
_offset = 0;
}
protected:
const IColumn* _ptr = nullptr;
size_t _offset = 0;
};
template <bool arg_is_nullable>
struct CopiedValue : public Value<arg_is_nullable> {
public:
template <typename ColVecType>
void insert_into(IColumn& to) const {
assert_cast<ColVecType&, TypeCheckOnRelease::DISABLE>(to).insert(_copied_value);
}
bool is_null() const { return this->_ptr == nullptr; }
template <typename ColVecType>
void set_value(const IColumn* column, size_t row) {
// here _ptr, maybe null at row, so call reset to set nullptr
// But we will use is_null() check first, others have set _ptr column to a meaningless address
// because the address have meaningless, only need it to check is nullptr
this->_ptr = (IColumn*)0x00000001;
if constexpr (arg_is_nullable) {
const auto* col =
assert_cast<const ColumnNullable*, TypeCheckOnRelease::DISABLE>(column);
if (col->is_null_at(row)) {
this->reset();
return;
} else {
auto& nested_col = assert_cast<const ColVecType&, TypeCheckOnRelease::DISABLE>(
col->get_nested_column());
nested_col.get(row, _copied_value);
}
} else {
column->get(row, _copied_value);
}
}
private:
Field _copied_value;
};
template <typename ColVecType, bool result_is_nullable, bool arg_is_nullable, bool is_copy>
struct ReaderFirstAndLastData {
public:
using StoreType =
std::conditional_t<is_copy, CopiedValue<arg_is_nullable>, Value<arg_is_nullable>>;
static constexpr bool nullable = arg_is_nullable;
static constexpr bool result_nullable = result_is_nullable;
void reset() {
_data_value.reset();
_has_value = false;
}
void insert_result_into(IColumn& to) const {
if constexpr (result_is_nullable) {
if (_data_value.is_null()) { //_ptr == nullptr || null data at row
auto& col = assert_cast<ColumnNullable&>(to);
col.insert_default();
} else {
auto& col = assert_cast<ColumnNullable&>(to);
col.get_null_map_data().push_back(0);
if constexpr (!std::is_same_v<ColVecType, void>) {
_data_value.template insert_into<ColVecType>(col.get_nested_column());
} else {
_data_value.insert_into(col.get_nested_column());
}
}
} else {
if constexpr (!std::is_same_v<ColVecType, void>) {
_data_value.template insert_into<ColVecType>(to);
} else {
_data_value.insert_into(to);
}
}
}
// here not check the columns[0] is null at the row,
// but it is need to check in other
void set_value(const IColumn** columns, size_t pos) {
if constexpr (is_copy) {
_data_value.template set_value<ColVecType>(columns[0], pos);
} else {
_data_value.set_value(columns[0], pos);
}
_has_value = true;
}
bool has_set_value() { return _has_value; }
bool is_null() { return _data_value.is_null(); }
protected:
StoreType _data_value;
bool _has_value = false;
};
template <typename ColVecType, bool result_is_nullable, bool arg_is_nullable, bool is_copy>
struct ReaderFunctionFirstData
: ReaderFirstAndLastData<ColVecType, result_is_nullable, arg_is_nullable, is_copy> {
void add(int64_t row, const IColumn** columns) {
if (this->has_set_value()) {
return;
}
this->set_value(columns, row);
}
static const char* name() { return "first_value"; }
};
template <typename ColVecType, bool result_is_nullable, bool arg_is_nullable, bool is_copy>
struct ReaderFunctionFirstNonNullData
: ReaderFirstAndLastData<ColVecType, result_is_nullable, arg_is_nullable, is_copy> {
void add(int64_t row, const IColumn** columns) {
if (this->has_set_value()) {
return;
}
if constexpr (ReaderFirstAndLastData<ColVecType, result_is_nullable, arg_is_nullable,
is_copy>::nullable) {
const auto* nullable_column =
assert_cast<const ColumnNullable*, TypeCheckOnRelease::DISABLE>(columns[0]);
if (nullable_column->is_null_at(row)) {
return;
}
}
this->set_value(columns, row);
}
static const char* name() { return "first_non_null_value"; }
};
template <typename ColVecType, bool result_is_nullable, bool arg_is_nullable, bool is_copy>
struct ReaderFunctionLastData
: ReaderFirstAndLastData<ColVecType, result_is_nullable, arg_is_nullable, is_copy> {
void add(int64_t row, const IColumn** columns) { this->set_value(columns, row); }
static const char* name() { return "last_value"; }
};
template <typename ColVecType, bool result_is_nullable, bool arg_is_nullable, bool is_copy>
struct ReaderFunctionLastNonNullData
: ReaderFirstAndLastData<ColVecType, result_is_nullable, arg_is_nullable, is_copy> {
void add(int64_t row, const IColumn** columns) {
if constexpr (ReaderFirstAndLastData<ColVecType, result_is_nullable, arg_is_nullable,
is_copy>::nullable) {
const auto* nullable_column =
assert_cast<const ColumnNullable*, TypeCheckOnRelease::DISABLE>(columns[0]);
if (nullable_column->is_null_at(row)) {
return;
}
}
this->set_value(columns, row);
}
static const char* name() { return "last_non_null_value"; }
};
template <typename Data>
class ReaderFunctionData final
: public IAggregateFunctionDataHelper<Data, ReaderFunctionData<Data>> {
public:
ReaderFunctionData(const DataTypes& argument_types_)
: IAggregateFunctionDataHelper<Data, ReaderFunctionData<Data>>(argument_types_),
_argument_type(argument_types_[0]) {}
String get_name() const override { return Data::name(); }
DataTypePtr get_return_type() const override {
if constexpr (Data::result_nullable) {
return make_nullable(_argument_type);
} else {
return _argument_type;
}
}
void insert_result_into(ConstAggregateDataPtr place, IColumn& to) const override {
this->data(place).insert_result_into(to);
}
void add(AggregateDataPtr place, const IColumn** columns, ssize_t row_num,
Arena&) const override {
this->data(place).add(row_num, columns);
}
void reset(AggregateDataPtr place) const override { this->data(place).reset(); }
void add_range_single_place(int64_t partition_start, int64_t partition_end, int64_t frame_start,
int64_t frame_end, AggregateDataPtr place, const IColumn** columns,
Arena& arena, UInt8*, UInt8*) const override {
throw doris::Exception(
Status::FatalError("ReaderFunctionData do not support add_range_single_place"));
}
void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena&) const override {
throw doris::Exception(Status::FatalError("ReaderFunctionData do not support merge"));
}
void serialize(ConstAggregateDataPtr place, BufferWritable& buf) const override {
throw doris::Exception(Status::FatalError("ReaderFunctionData do not support serialize"));
}
void deserialize(AggregateDataPtr place, BufferReadable& buf, Arena&) const override {
throw doris::Exception(Status::FatalError("ReaderFunctionData do not support deserialize"));
}
private:
DataTypePtr _argument_type;
};
template <template <typename, bool, bool, bool> class FunctionData, bool result_is_nullable,
bool arg_is_nullable, bool is_copy = false>
AggregateFunctionPtr create_function_single_value(const String& name,
const DataTypes& argument_types) {
switch (argument_types[0]->get_primitive_type()) {
case PrimitiveType::TYPE_BOOLEAN: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnUInt8, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_TINYINT: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnInt8, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_SMALLINT: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnInt16, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_INT: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnInt32, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_BIGINT: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnInt64, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_LARGEINT: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnInt128, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_FLOAT: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnFloat32, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_DOUBLE: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnFloat64, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_DECIMAL32: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnDecimal32, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_DECIMAL64: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnDecimal64, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_DECIMAL128I: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnDecimal128V3, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_DECIMALV2: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnDecimal128V2, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_DECIMAL256: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnDecimal256, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_STRING:
case PrimitiveType::TYPE_CHAR:
case PrimitiveType::TYPE_VARCHAR:
case PrimitiveType::TYPE_JSONB: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnString, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_DATE: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnDate, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_DATETIME: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnDateTime, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_DATETIMEV2: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnDateTimeV2, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_TIMESTAMPTZ: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnTimeStampTz, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_DATEV2: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnDateV2, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_IPV4: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnIPv4, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_IPV6: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnIPv6, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_ARRAY: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnArray, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_MAP: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnMap, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_STRUCT: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnStruct, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_VARIANT: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnVariant, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_BITMAP: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnBitmap, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_HLL: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnHLL, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
case PrimitiveType::TYPE_QUANTILE_STATE: {
return std::make_shared<ReaderFunctionData<
FunctionData<ColumnQuantileState, result_is_nullable, arg_is_nullable, is_copy>>>(
argument_types);
}
default:
LOG(WARNING) << "with unknowed type, failed in create_aggregate_function_" << name
<< " and type is: " << argument_types[0]->get_name();
return nullptr;
}
}
#define CREATE_READER_FUNCTION_WITH_NAME_AND_DATA(CREATE_FUNCTION_NAME, FUNCTION_DATA) \
template <bool is_copy> \
AggregateFunctionPtr CREATE_FUNCTION_NAME( \
const std::string& name, const DataTypes& argument_types, \
const DataTypePtr& result_type, bool result_is_nullable, \
const AggregateFunctionAttr& attr) { \
const bool arg_is_nullable = argument_types[0]->is_nullable(); \
AggregateFunctionPtr res = nullptr; \
std::visit( \
[&](auto result_is_nullable, auto arg_is_nullable) { \
res = AggregateFunctionPtr( \
create_function_single_value<FUNCTION_DATA, result_is_nullable, \
arg_is_nullable, is_copy>( \
name, argument_types)); \
}, \
make_bool_variant(result_is_nullable), make_bool_variant(arg_is_nullable)); \
if (!res) { \
LOG(WARNING) << " failed in create_aggregate_function_" << name \
<< " and type is: " << argument_types[0]->get_name(); \
} \
return res; \
}
CREATE_READER_FUNCTION_WITH_NAME_AND_DATA(create_aggregate_function_first, ReaderFunctionFirstData);
CREATE_READER_FUNCTION_WITH_NAME_AND_DATA(create_aggregate_function_first_non_null_value,
ReaderFunctionFirstNonNullData);
CREATE_READER_FUNCTION_WITH_NAME_AND_DATA(create_aggregate_function_last, ReaderFunctionLastData);
CREATE_READER_FUNCTION_WITH_NAME_AND_DATA(create_aggregate_function_last_non_null_value,
ReaderFunctionLastNonNullData);
#undef CREATE_READER_FUNCTION_WITH_NAME_AND_DATA
} // namespace doris
#include "common/compile_check_end.h"