Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions be/src/exprs/aggregate/aggregate_function_reader_first_last.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

#pragma once

#include <type_traits>

#include "core/column/column_array.h"
#include "core/column/column_map.h"
#include "core/column/column_nullable.h"
Expand All @@ -32,7 +34,7 @@
namespace doris {
#include "common/compile_check_begin.h"

template <typename ColVecType, bool arg_is_nullable>
template <bool arg_is_nullable>
struct Value {
public:
bool is_null() const {
Expand All @@ -46,6 +48,7 @@ struct Value {
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);
Expand All @@ -56,6 +59,17 @@ struct Value {
}
}

// 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;
Expand All @@ -71,15 +85,17 @@ struct Value {
size_t _offset = 0;
};

template <typename ColVecType, bool arg_is_nullable>
struct CopiedValue : public Value<ColVecType, arg_is_nullable> {
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
Expand Down Expand Up @@ -108,8 +124,8 @@ struct CopiedValue : public Value<ColVecType, arg_is_nullable> {
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<ColVecType, arg_is_nullable>,
Value<ColVecType, arg_is_nullable>>;
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;

Expand All @@ -126,17 +142,29 @@ struct ReaderFirstAndLastData {
} else {
auto& col = assert_cast<ColumnNullable&>(to);
col.get_null_map_data().push_back(0);
_data_value.insert_into(col.get_nested_column());
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 {
_data_value.insert_into(to);
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) {
_data_value.set_value(columns[0], 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;
}

Expand Down
38 changes: 36 additions & 2 deletions be/src/exprs/aggregate/aggregate_function_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,17 @@ AggregateFunctionPtr create_aggregate_function_window_first(const std::string& n
const DataTypePtr& result_type,
const bool result_is_nullable,
const AggregateFunctionAttr& attr);
AggregateFunctionPtr create_aggregate_function_window_first_ignore_null(
const std::string& name, const DataTypes& argument_types, const DataTypePtr& result_type,
const bool result_is_nullable, const AggregateFunctionAttr& attr);
AggregateFunctionPtr create_aggregate_function_window_last(const std::string& name,
const DataTypes& argument_types,
const DataTypePtr& result_type,
const bool result_is_nullable,
const AggregateFunctionAttr& attr);
AggregateFunctionPtr create_aggregate_function_window_last_ignore_null(
const std::string& name, const DataTypes& argument_types, const DataTypePtr& result_type,
const bool result_is_nullable, const AggregateFunctionAttr& attr);
AggregateFunctionPtr create_aggregate_function_window_nth_value(const std::string& name,
const DataTypes& argument_types,
const DataTypePtr& result_type,
Expand Down Expand Up @@ -89,8 +95,36 @@ void register_aggregate_function_window_lead_lag_first_last(
AggregateFunctionSimpleFactory& factory) {
factory.register_function_both("lead", create_aggregate_function_window_lead);
factory.register_function_both("lag", create_aggregate_function_window_lag);
factory.register_function_both("first_value", create_aggregate_function_window_first);
factory.register_function_both("last_value", create_aggregate_function_window_last);
// FE rewrites first_value(k1, false) → first_value(k1), so argument_types.size() == 2
// means arg_ignore_null = true. Dispatch at registration to avoid runtime branching
// that would double template instantiations.
factory.register_function_both(
"first_value",
[](const std::string& name, const DataTypes& argument_types,
const DataTypePtr& result_type, const bool result_is_nullable,
const AggregateFunctionAttr& attr) -> AggregateFunctionPtr {
if (argument_types.size() == 2) {
return create_aggregate_function_window_first_ignore_null(
name, argument_types, result_type, result_is_nullable, attr);
}
return create_aggregate_function_window_first(name, argument_types, result_type,
result_is_nullable, attr);
});
factory.register_function_both(
"last_value",
[](const std::string& name, const DataTypes& argument_types,
const DataTypePtr& result_type, const bool result_is_nullable,
const AggregateFunctionAttr& attr) -> AggregateFunctionPtr {
if (argument_types.size() == 2) {
return create_aggregate_function_window_last_ignore_null(
name, argument_types, result_type, result_is_nullable, attr);
}
return create_aggregate_function_window_last(name, argument_types, result_type,
result_is_nullable, attr);
});
// nth_value always has 2 args (column, N) from FE.
// WindowFunctionNthValueImpl does not implement ignore-null logic,
// so register directly without dispatch.
factory.register_function_both("nth_value", create_aggregate_function_window_nth_value);
}

Expand Down
16 changes: 8 additions & 8 deletions be/src/exprs/aggregate/aggregate_function_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,15 +397,15 @@ class WindowFunctionNTile final
void deserialize(AggregateDataPtr place, BufferReadable& buf, Arena&) const override {}
};

template <typename ColVecType, bool result_is_nullable, bool arg_is_nullable>
template <bool result_is_nullable, bool arg_is_nullable>
struct FirstLastData
: public ReaderFirstAndLastData<ColVecType, result_is_nullable, arg_is_nullable, false> {
: public ReaderFirstAndLastData<void, result_is_nullable, arg_is_nullable, false> {
public:
void set_is_null() { this->_data_value.reset(); }
};

template <typename ColVecType, bool result_is_nullable, bool arg_is_nullable>
struct NthValueData : public FirstLastData<ColVecType, result_is_nullable, arg_is_nullable> {
template <bool result_is_nullable, bool arg_is_nullable>
struct NthValueData : public FirstLastData<result_is_nullable, arg_is_nullable> {
public:
void reset() {
this->_data_value.reset();
Expand All @@ -418,16 +418,16 @@ struct NthValueData : public FirstLastData<ColVecType, result_is_nullable, arg_i
int64_t _frame_total_rows = 0;
};

template <typename ColVecType, bool arg_is_nullable>
struct BaseValue : public Value<ColVecType, arg_is_nullable> {
template <bool arg_is_nullable>
struct BaseValue : public Value<arg_is_nullable> {
public:
bool is_null() const { return this->_ptr == nullptr; }
// because _ptr pointer to first_argument or third argument, so it's difficult to cast ptr
// so here will call virtual function
StringRef get_value() const { return this->_ptr->get_data_at(this->_offset); }
};

template <typename ColVecType, bool result_is_nullable, bool arg_is_nullable>
template <bool result_is_nullable, bool arg_is_nullable>
struct LeadLagData {
public:
static constexpr bool result_nullable = result_is_nullable;
Expand Down Expand Up @@ -492,7 +492,7 @@ struct LeadLagData {
int64_t get_offset_value() const { return _offset_value; }

private:
BaseValue<ColVecType, arg_is_nullable> _data_value;
BaseValue<arg_is_nullable> _data_value;
bool _is_inited = false;
int64_t _offset_value = 0;
};
Expand Down
7 changes: 5 additions & 2 deletions be/src/exprs/aggregate/aggregate_function_window_first.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
namespace doris {
#include "common/compile_check_begin.h"

CREATE_WINDOW_FUNCTION_WITH_NAME_AND_DATA(create_aggregate_function_window_first, FirstLastData,
WindowFunctionFirstImpl);
CREATE_WINDOW_FUNCTION_DIRECT(create_aggregate_function_window_first, FirstLastData,
WindowFunctionFirstImpl, false);

CREATE_WINDOW_FUNCTION_DIRECT(create_aggregate_function_window_first_ignore_null, FirstLastData,
WindowFunctionFirstImpl, true);

#include "common/compile_check_end.h"
} // namespace doris
Loading
Loading