Co-authored-by: wangt1xiuyi <13547954130@163.com> Co-authored-by: XIAO-HOU <372060054@qq.com> Co-authored-by: z404289981 <z404289981@163.com>
1070 lines
45 KiB
C++
1070 lines
45 KiB
C++
/**
|
|
* Copyright (c) 2023 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#ifndef OCEANBASE_STORAGE_OB_PUSHDOWN_AGGREGATE_H_
|
|
#define OCEANBASE_STORAGE_OB_PUSHDOWN_AGGREGATE_H_
|
|
|
|
#include "lib/allocator/ob_allocator.h"
|
|
#include "sql/engine/expr/ob_expr.h"
|
|
#include "lib/utility/ob_hyperloglog.h"
|
|
#include "storage/ob_i_store.h"
|
|
#include "storage/blocksstable/ob_datum_row.h"
|
|
#include "storage/blocksstable/index_block/ob_index_block_row_struct.h"
|
|
|
|
namespace oceanbase
|
|
{
|
|
namespace blocksstable
|
|
{
|
|
struct ObStorageDatum;
|
|
}
|
|
namespace storage
|
|
{
|
|
|
|
#define USE_GROUP_BY_MAX_DISTINCT_CNT 16384
|
|
#define USE_GROUP_BY_BUF_BLOCK_SIZE 256
|
|
#define USE_GROUP_BY_BUF_MAX_BLOCK_CNT USE_GROUP_BY_MAX_DISTINCT_CNT / USE_GROUP_BY_BUF_BLOCK_SIZE
|
|
|
|
class ObAggDatumBuf
|
|
{
|
|
public:
|
|
ObAggDatumBuf(common::ObIAllocator &allocator);
|
|
~ObAggDatumBuf() { reset(); };
|
|
int init(const int64_t size, const bool need_cell_data_ptr, const int64_t datum_size);
|
|
void reset();
|
|
void reuse();
|
|
OB_INLINE int64_t get_size() const { return size_; }
|
|
OB_INLINE ObDatum *get_datums() { return datums_; }
|
|
OB_INLINE const char **get_cell_datas() { return cell_data_ptrs_; }
|
|
static int new_agg_datum_buf(
|
|
const int64_t size,
|
|
const bool need_cell_data_ptr,
|
|
common::ObIAllocator &allocator,
|
|
ObAggDatumBuf *&datum_buf,
|
|
const int64_t datum_size = common::OBJ_DATUM_NUMBER_RES_SIZE);
|
|
TO_STRING_KV(K_(size), K_(datum_size), KP_(datums), KP_(buf), KP_(cell_data_ptrs));
|
|
private:
|
|
int64_t size_;
|
|
int64_t datum_size_;
|
|
ObDatum *datums_;
|
|
char *buf_;
|
|
const char **cell_data_ptrs_;
|
|
common::ObIAllocator &allocator_;
|
|
};
|
|
|
|
enum FillDatumType
|
|
{
|
|
NULL_DATUM,
|
|
ZERO_DATUM
|
|
};
|
|
|
|
// for normal group by pushdown
|
|
// store the distinct of group by column, should be continuous ObDatums
|
|
class ObAggGroupByDatumBuf
|
|
{
|
|
public:
|
|
ObAggGroupByDatumBuf(
|
|
common::ObDatum *basic_data,
|
|
const int32_t basic_size,
|
|
const int32_t datum_size,
|
|
common::ObIAllocator &allocator);
|
|
~ObAggGroupByDatumBuf() { reset(); }
|
|
void reset();
|
|
int reserve(const int32_t size);
|
|
void fill_datums(const FillDatumType datum_type);
|
|
OB_INLINE int32_t get_capacity() const { return capacity_; }
|
|
OB_INLINE common::ObDatum *get_sql_result_datums() { return sql_result_datums_; }
|
|
OB_INLINE common::ObDatum *get_extra_result_datums() { return nullptr == result_datum_buf_ ? nullptr : result_datum_buf_->get_datums(); }
|
|
OB_INLINE common::ObDatum *get_group_by_datums() const { return is_use_extra_buf() ? result_datum_buf_->get_datums() : sql_result_datums_; }
|
|
OB_INLINE const char **get_group_by_cell_datas() const { return is_use_extra_buf() ? result_datum_buf_->get_cell_datas() : nullptr; }
|
|
OB_INLINE bool is_use_extra_buf() const { return capacity_ > sql_datums_cnt_; }
|
|
OB_INLINE int64_t get_extra_buf_size() const {return nullptr == result_datum_buf_ ? 0 : result_datum_buf_->get_size(); }
|
|
TO_STRING_KV(K_(capacity), K_(sql_datums_cnt), KP_(sql_result_datums), KP_(result_datum_buf), K_(datum_size));
|
|
private:
|
|
int32_t capacity_;
|
|
int32_t sql_datums_cnt_;
|
|
common::ObDatum *sql_result_datums_; // agg expr's datums
|
|
ObAggDatumBuf *result_datum_buf_; // used in case that the count of distinct values exceed sql batch size
|
|
int32_t datum_size_;
|
|
common::ObIAllocator &allocator_;
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(ObAggGroupByDatumBuf);
|
|
};
|
|
|
|
// for normal group by pushdown
|
|
// some helpful data buffers,the inner memory is discrete and allocated as need
|
|
template<typename T>
|
|
class ObGroupByExtendableBuf
|
|
{
|
|
public:
|
|
ObGroupByExtendableBuf(
|
|
T *basic_data,
|
|
const int32_t basic_size,
|
|
const int32_t item_size,
|
|
common::ObIAllocator &allocator);
|
|
~ObGroupByExtendableBuf() { reset(); };
|
|
void reset();
|
|
int reserve(const int32_t size);
|
|
void fill_items(const T item);
|
|
void fill_datum_items(const FillDatumType type);
|
|
OB_INLINE int get_item(const int32_t pos, T *&item);
|
|
OB_INLINE T &at(const int32_t pos);
|
|
OB_INLINE int32_t get_capacity() { return capacity_; }
|
|
OB_INLINE int32_t get_basic_count() const { return basic_count_; }
|
|
OB_INLINE T *get_basic_buf() { return basic_data_; }
|
|
OB_INLINE bool is_use_extra_data() const { return capacity_ > basic_count_; }
|
|
OB_INLINE void set_item_size(const int32_t item_size) { OB_ASSERT(0 == extra_block_count_); item_size_ = item_size; }
|
|
TO_STRING_KV(K_(capacity), KP_(basic_data), K_(basic_count), K_(extra_block_count), K_(item_size));
|
|
private:
|
|
struct BufBlock
|
|
{
|
|
union {
|
|
T *data_;
|
|
ObAggDatumBuf *datum_buf_;
|
|
};
|
|
};
|
|
int alloc_bufblock(BufBlock *&block);
|
|
void free_bufblock(BufBlock *&block);
|
|
void fill_datums(ObDatum *datums, const int32_t count, const FillDatumType datum_type);
|
|
int32_t capacity_;
|
|
int32_t basic_count_;
|
|
T *basic_data_;
|
|
BufBlock *extra_blocks_[USE_GROUP_BY_BUF_MAX_BLOCK_CNT];
|
|
int32_t extra_block_count_;
|
|
int32_t item_size_;
|
|
common::ObIAllocator &allocator_;
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(ObGroupByExtendableBuf);
|
|
};
|
|
|
|
template<typename T>
|
|
int ObGroupByExtendableBuf<T>::get_item(const int32_t pos, T *&item)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(pos >= get_capacity())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Invalid argument", K(ret), K(pos), KPC(this));
|
|
} else {
|
|
item = &at(pos);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template<typename T>
|
|
OB_INLINE T& ObGroupByExtendableBuf<T>::at(const int32_t pos)
|
|
{
|
|
OB_ASSERT(pos < get_capacity());
|
|
if (pos < basic_count_) {
|
|
return basic_data_[pos];
|
|
} else {
|
|
const int32_t block_idx = (pos - basic_count_) / USE_GROUP_BY_BUF_BLOCK_SIZE;
|
|
const int32_t data_offset = pos - basic_count_ - block_idx * USE_GROUP_BY_BUF_BLOCK_SIZE;
|
|
return extra_blocks_[block_idx]->data_[data_offset];
|
|
}
|
|
}
|
|
|
|
template<>
|
|
OB_INLINE ObDatum& ObGroupByExtendableBuf<ObDatum>::at(const int32_t pos)
|
|
{
|
|
OB_ASSERT(pos < get_capacity());
|
|
if (pos < basic_count_) {
|
|
return basic_data_[pos];
|
|
} else {
|
|
const int32_t block_idx = (pos - basic_count_) / USE_GROUP_BY_BUF_BLOCK_SIZE;
|
|
const int32_t data_offset = pos - basic_count_ - block_idx * USE_GROUP_BY_BUF_BLOCK_SIZE;
|
|
return extra_blocks_[block_idx]->datum_buf_->get_datums()[data_offset];
|
|
}
|
|
}
|
|
|
|
enum ObPDAggType
|
|
{
|
|
PD_COUNT = 0,
|
|
PD_MIN,
|
|
PD_MAX,
|
|
PD_HLL,
|
|
PD_SUM_OP_SIZE,
|
|
PD_SUM,
|
|
PD_FIRST_ROW,
|
|
PD_MAX_TYPE
|
|
};
|
|
|
|
struct ObAggCellBasicInfo
|
|
{
|
|
ObAggCellBasicInfo(
|
|
const int32_t col_offset,
|
|
const int32_t col_index,
|
|
const share::schema::ObColumnParam *col_param,
|
|
sql::ObExpr *agg_expr,
|
|
const int64_t batch_size,
|
|
const bool is_padding_mode)
|
|
: col_offset_(col_offset),
|
|
col_index_(col_index),
|
|
col_param_(col_param),
|
|
agg_expr_(agg_expr),
|
|
batch_size_(batch_size),
|
|
is_padding_mode_(is_padding_mode)
|
|
{}
|
|
~ObAggCellBasicInfo() { reset(); }
|
|
void reset()
|
|
{
|
|
col_offset_ = -1;
|
|
col_index_ = -1;
|
|
col_param_ = nullptr;
|
|
agg_expr_ = nullptr;
|
|
batch_size_ = 0;
|
|
is_padding_mode_ = false;
|
|
}
|
|
OB_INLINE bool is_valid() const
|
|
{
|
|
return col_offset_ >= 0 && nullptr != agg_expr_ && batch_size_ >= 0;
|
|
}
|
|
OB_INLINE bool need_padding() const
|
|
{
|
|
return is_padding_mode_ && nullptr != col_param_ && col_param_->get_meta_type().is_fixed_len_char_type();
|
|
}
|
|
TO_STRING_KV(K_(col_offset), K_(col_index), KPC_(col_param), K_(agg_expr), K_(batch_size), K_(is_padding_mode));
|
|
int32_t col_offset_; // offset in projector
|
|
int32_t col_index_; // column index
|
|
const share::schema::ObColumnParam *col_param_;
|
|
sql::ObExpr *agg_expr_;
|
|
int64_t batch_size_;
|
|
bool is_padding_mode_;
|
|
};
|
|
|
|
class ObAggCell
|
|
{
|
|
public:
|
|
ObAggCell(const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator);
|
|
virtual ~ObAggCell() { reset(); };
|
|
virtual void reset();
|
|
virtual void reuse();
|
|
virtual int init(const bool is_group_by, sql::ObEvalCtx *eval_ctx);
|
|
// need to fill default value
|
|
virtual int eval(blocksstable::ObStorageDatum &datum, const int64_t row_count = 1) = 0;
|
|
// no need to fill default value
|
|
virtual int eval_batch(const common::ObDatum *datums, const int64_t count) = 0;
|
|
virtual int eval_micro_block(
|
|
const ObTableIterParam &iter_param,
|
|
const ObTableAccessContext &context,
|
|
const int32_t col_offset,
|
|
blocksstable::ObIMicroBlockReader *reader,
|
|
const int64_t *row_ids,
|
|
const int64_t row_count);
|
|
virtual int eval_index_info(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg = false);
|
|
// For group by pushdown
|
|
virtual int eval_batch_in_group_by(
|
|
const common::ObDatum *datums,
|
|
const int64_t count,
|
|
const uint32_t *refs,
|
|
const int64_t distinct_cnt,
|
|
const bool is_group_by_col = false,
|
|
const bool is_default_datum = false) = 0;
|
|
virtual int copy_output_row(const int32_t datum_offset);
|
|
virtual int copy_output_rows(const int32_t datum_offset);
|
|
virtual int copy_single_output_row(sql::ObEvalCtx &ctx);
|
|
virtual int collect_result(sql::ObEvalCtx &ctx);
|
|
virtual int collect_batch_result_in_group_by(const int64_t distinct_cnt);
|
|
virtual int can_use_index_info(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg, bool &can_agg);
|
|
virtual bool need_access_data() const { return true; }
|
|
virtual bool finished() const { return false; }
|
|
virtual int reserve_group_by_buf(const int64_t size);
|
|
virtual int output_extra_group_by_result(const int64_t start, const int64_t count);
|
|
virtual int reserve_bitmap(const int64_t count);
|
|
OB_INLINE ObPDAggType get_type() const { return agg_type_; }
|
|
OB_INLINE bool is_min_agg() const { return agg_type_ == PD_MIN; }
|
|
OB_INLINE bool is_max_agg() const { return agg_type_ == PD_MAX; }
|
|
OB_INLINE bool is_aggregated() const { return aggregated_; }
|
|
OB_INLINE ObBitmap &get_bitmap() { return *bitmap_; }
|
|
OB_INLINE int32_t get_col_offset() const { return basic_info_.col_offset_; }
|
|
OB_INLINE common::ObDatum *get_col_datums() const { return col_datums_; }
|
|
OB_INLINE const sql::ObExpr *get_agg_expr() const { return basic_info_.agg_expr_; }
|
|
OB_INLINE bool is_lob_col() const { return is_lob_col_; }
|
|
OB_INLINE const ObDatum &get_result_datum() const { return result_datum_; }
|
|
OB_INLINE ObObjType get_obj_type() const { return basic_info_.agg_expr_->obj_meta_.get_type(); }
|
|
OB_INLINE common::ObObjDatumMapType get_datum_map_type() const { return basic_info_.agg_expr_->obj_datum_map_; }
|
|
OB_INLINE void set_group_by_result_cnt(const int64_t group_by_result_cnt) { group_by_result_cnt_ = group_by_result_cnt; }
|
|
OB_INLINE bool is_assigned_to_group_by_processor() const { return is_assigned_to_group_by_processor_; }
|
|
OB_INLINE void set_assigned_to_group_by_processor() { is_assigned_to_group_by_processor_ = true; }
|
|
TO_STRING_KV(K_(agg_type), K_(basic_info), K_(result_datum), K_(def_datum), K_(is_lob_col), K_(aggregated), KP_(agg_datum_buf), KP_(agg_row_reader));
|
|
protected:
|
|
static const int64_t DEFAULT_DATUM_OFFSET = -1;
|
|
int fill_default_if_need(blocksstable::ObStorageDatum &datum);
|
|
int pad_column_if_need(blocksstable::ObStorageDatum &datum);
|
|
int deep_copy_datum(const blocksstable::ObStorageDatum &src, common::ObIAllocator &tmp_alloc);
|
|
int read_agg_datum(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg);
|
|
void clear_group_by_info();
|
|
OB_INLINE common::ObDatum &get_group_by_result_datum(const int32_t datum_offset)
|
|
{
|
|
return DEFAULT_DATUM_OFFSET == datum_offset ? result_datum_ : group_by_result_datum_buf_->at(datum_offset);
|
|
}
|
|
int prepare_def_datum();
|
|
ObPDAggType agg_type_;
|
|
ObAggCellBasicInfo basic_info_;
|
|
// for scalar group by pushdown
|
|
blocksstable::ObStorageDatum result_datum_;
|
|
blocksstable::ObStorageDatum def_datum_;
|
|
blocksstable::ObStorageDatum skip_index_datum_;
|
|
common::ObIAllocator &allocator_;
|
|
bool is_lob_col_;
|
|
bool aggregated_;
|
|
ObAggDatumBuf *agg_datum_buf_;
|
|
blocksstable::ObAggRowReader *agg_row_reader_;
|
|
// for normal group by pushdown
|
|
// agg col expr's datums
|
|
common::ObDatum *col_datums_;
|
|
// store the aggregated result
|
|
ObGroupByExtendableBuf<ObDatum> *group_by_result_datum_buf_;
|
|
ObBitmap *bitmap_;
|
|
int64_t group_by_result_cnt_;
|
|
bool is_assigned_to_group_by_processor_;
|
|
private:
|
|
virtual bool can_use_index_info() const { return true; }
|
|
DISALLOW_COPY_AND_ASSIGN(ObAggCell);
|
|
};
|
|
|
|
class ObCountAggCell : public ObAggCell
|
|
{
|
|
public:
|
|
ObCountAggCell(
|
|
const ObAggCellBasicInfo &basic_info,
|
|
common::ObIAllocator &allocator,
|
|
const bool exclude_null);
|
|
virtual ~ObCountAggCell() { reset(); };
|
|
virtual void reset() override;
|
|
virtual void reuse() override;
|
|
virtual int init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) override;
|
|
virtual int eval(blocksstable::ObStorageDatum &datum, const int64_t row_count = 1) override;
|
|
virtual int eval_batch(const common::ObDatum *datums, const int64_t count) override;
|
|
virtual int eval_micro_block(
|
|
const ObTableIterParam &iter_param,
|
|
const ObTableAccessContext &context,
|
|
const int32_t col_offset,
|
|
blocksstable::ObIMicroBlockReader *reader,
|
|
const int64_t *row_ids,
|
|
const int64_t row_count) override;
|
|
virtual int eval_index_info(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg = false) override;
|
|
virtual int eval_batch_in_group_by(
|
|
const common::ObDatum *datums,
|
|
const int64_t count,
|
|
const uint32_t *refs,
|
|
const int64_t distinct_cnt,
|
|
const bool is_group_by_col = false,
|
|
const bool is_default_datum = false) override;
|
|
virtual int copy_output_row(const int32_t datum_offset) override;
|
|
virtual int copy_output_rows(const int32_t datum_offset) override;
|
|
virtual int copy_single_output_row(sql::ObEvalCtx &ctx) override;
|
|
virtual int collect_result(sql::ObEvalCtx &ctx) override;
|
|
virtual int collect_batch_result_in_group_by(const int64_t distinct_cnt) override;
|
|
virtual bool need_access_data() const override { return exclude_null_; }
|
|
INHERIT_TO_STRING_KV("ObAggCell", ObAggCell, K_(exclude_null), K_(row_count));
|
|
private:
|
|
bool exclude_null_;
|
|
int64_t row_count_;
|
|
};
|
|
|
|
class ObMinAggCell : public ObAggCell
|
|
{
|
|
public:
|
|
ObMinAggCell(const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator);
|
|
virtual ~ObMinAggCell() { reset(); };
|
|
virtual void reset() override;
|
|
virtual void reuse() override;
|
|
virtual int init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) override;
|
|
virtual int eval(blocksstable::ObStorageDatum &datum, const int64_t row_count = 1) override;
|
|
virtual int eval_batch(const common::ObDatum *datums, const int64_t count) override;
|
|
virtual int eval_batch_in_group_by(
|
|
const common::ObDatum *datums,
|
|
const int64_t count,
|
|
const uint32_t *refs,
|
|
const int64_t distinct_cnt,
|
|
const bool is_group_by_col = false,
|
|
const bool is_default_datum = false) override;
|
|
INHERIT_TO_STRING_KV("ObAggCell", ObAggCell, K_(cmp_fun));
|
|
private:
|
|
virtual bool can_use_index_info() const override
|
|
{
|
|
return nullptr != basic_info_.col_param_ &&
|
|
(basic_info_.col_param_->get_meta_type().is_numeric_type() || basic_info_.col_param_->get_meta_type().is_temporal_type());
|
|
}
|
|
ObDatumCmpFuncType cmp_fun_;
|
|
uint32_t *group_by_ref_array_;
|
|
common::ObArenaAllocator datum_allocator_;
|
|
};
|
|
|
|
class ObMaxAggCell : public ObAggCell
|
|
{
|
|
public:
|
|
ObMaxAggCell(const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator);
|
|
virtual ~ObMaxAggCell() { reset(); };
|
|
virtual void reset() override;
|
|
virtual void reuse() override;
|
|
virtual int init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) override;
|
|
virtual int eval(blocksstable::ObStorageDatum &datum, const int64_t row_count = 1) override;
|
|
virtual int eval_batch(const common::ObDatum *datums, const int64_t count) override;
|
|
virtual int eval_batch_in_group_by(
|
|
const common::ObDatum *datums,
|
|
const int64_t count,
|
|
const uint32_t *refs,
|
|
const int64_t distinct_cnt,
|
|
const bool is_group_by_col = false,
|
|
const bool is_default_datum = false) override;
|
|
INHERIT_TO_STRING_KV("ObAggCell", ObAggCell, K_(cmp_fun));
|
|
private:
|
|
virtual bool can_use_index_info() const override
|
|
{
|
|
return nullptr != basic_info_.col_param_ &&
|
|
(basic_info_.col_param_->get_meta_type().is_numeric_type() || basic_info_.col_param_->get_meta_type().is_temporal_type());
|
|
}
|
|
ObDatumCmpFuncType cmp_fun_;
|
|
uint32_t *group_by_ref_array_;
|
|
common::ObArenaAllocator datum_allocator_;
|
|
};
|
|
|
|
// For statistical information aggregation pushdown.
|
|
// Not support cross-partition aggregate, not support group by.
|
|
class ObHyperLogLogAggCell : public ObAggCell
|
|
{
|
|
public:
|
|
ObHyperLogLogAggCell(const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator);
|
|
virtual ~ObHyperLogLogAggCell() { reset(); }
|
|
virtual void reset() override;
|
|
virtual void reuse() override;
|
|
virtual int init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) override;
|
|
virtual int eval(blocksstable::ObStorageDatum &storage_datum, const int64_t row_count = 1) override;
|
|
virtual int eval_batch(const common::ObDatum *datums, const int64_t count) override;
|
|
virtual int eval_index_info(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg = false) override
|
|
{ return OB_NOT_SUPPORTED; }
|
|
virtual int eval_batch_in_group_by(
|
|
const common::ObDatum *datums,
|
|
const int64_t count,
|
|
const uint32_t *refs,
|
|
const int64_t distinct_cnt,
|
|
const bool is_group_by_col = false,
|
|
const bool is_default_datum = false) override
|
|
{ return OB_NOT_SUPPORTED; }
|
|
virtual int copy_output_row(const int32_t datum_offset) override { return OB_NOT_SUPPORTED; }
|
|
virtual int copy_output_rows(const int32_t datum_offset) override { return OB_NOT_SUPPORTED; }
|
|
virtual int collect_result(sql::ObEvalCtx &ctx) override;
|
|
virtual int collect_batch_result_in_group_by(const int64_t distinct_cnt) override { return OB_NOT_SUPPORTED; }
|
|
virtual int reserve_group_by_buf(const int64_t size) override { return OB_NOT_SUPPORTED; }
|
|
virtual int output_extra_group_by_result(const int64_t start, const int64_t count) override { return OB_NOT_SUPPORTED; }
|
|
INHERIT_TO_STRING_KV("ObAggCell", ObAggCell, K_(hash_func), K_(def_hash_value), KPC_(ndv_calculator));
|
|
static const int64_t LLC_BUCKET_BITS = 10; // same as ObAggregateProcessor llc bucket bits.
|
|
private:
|
|
virtual bool can_use_index_info() const override { return false; } // can not use now.
|
|
sql::ObExprHashFuncType hash_func_;
|
|
ObHyperLogLogCalculator *ndv_calculator_;
|
|
uint64_t def_hash_value_;
|
|
};
|
|
|
|
// For statistical information aggregation pushdown.
|
|
// Not support cross-partition aggregate, not support group by.
|
|
class ObSumOpSizeAggCell : public ObAggCell
|
|
{
|
|
public:
|
|
ObSumOpSizeAggCell(
|
|
const ObAggCellBasicInfo &basic_info,
|
|
common::ObIAllocator &allocator,
|
|
const bool exclude_null);
|
|
virtual ~ObSumOpSizeAggCell() { reset(); }
|
|
virtual void reset() override;
|
|
virtual void reuse() override;
|
|
virtual int init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) override;
|
|
virtual int eval(blocksstable::ObStorageDatum &storage_datum, const int64_t row_count = 1) override;
|
|
virtual int eval_batch(const common::ObDatum *datums, const int64_t count) override;
|
|
virtual int eval_micro_block(
|
|
const ObTableIterParam &iter_param,
|
|
const ObTableAccessContext &context,
|
|
const int32_t col_offset,
|
|
blocksstable::ObIMicroBlockReader *reader,
|
|
const int64_t *row_ids,
|
|
const int64_t row_count) override;
|
|
virtual int eval_index_info(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg = false);
|
|
virtual int eval_batch_in_group_by(
|
|
const common::ObDatum *datums,
|
|
const int64_t count,
|
|
const uint32_t *refs,
|
|
const int64_t distinct_cnt,
|
|
const bool is_group_by_col = false,
|
|
const bool is_default_datum = false) override
|
|
{ return OB_NOT_SUPPORTED; }
|
|
virtual int copy_output_row(const int32_t datum_offset) override { return OB_NOT_SUPPORTED; }
|
|
virtual int copy_output_rows(const int32_t datum_offset) override { return OB_NOT_SUPPORTED; }
|
|
virtual int collect_result(sql::ObEvalCtx &ctx) override;
|
|
virtual int collect_batch_result_in_group_by(const int64_t distinct_cnt) override { return OB_NOT_SUPPORTED; }
|
|
virtual bool need_access_data() const override
|
|
{
|
|
ObObjDatumMapType type = basic_info_.agg_expr_->args_[0]->obj_datum_map_;
|
|
return type == OBJ_DATUM_STRING || type == OBJ_DATUM_NUMBER || type == OBJ_DATUM_DECIMALINT || exclude_null_;
|
|
}
|
|
virtual int reserve_group_by_buf(const int64_t size) override { return OB_NOT_SUPPORTED; }
|
|
virtual int output_extra_group_by_result(const int64_t start, const int64_t count) override { return OB_NOT_SUPPORTED; }
|
|
INHERIT_TO_STRING_KV("ObAggCell", ObAggCell, K_(total_size), K_(op_size), K_(def_op_size), K_(exclude_null));
|
|
private:
|
|
int set_op_size();
|
|
int get_datum_op_size(const ObDatum &datum, int64_t &length);
|
|
virtual bool can_use_index_info() const override { return is_fixed_length_type(); }
|
|
OB_INLINE bool is_valid_op_size() const { return op_size_ >= 0; }
|
|
OB_INLINE bool is_fixed_length_type() const
|
|
{
|
|
ObObjDatumMapType type = basic_info_.agg_expr_->args_[0]->obj_datum_map_;
|
|
return type != OBJ_DATUM_STRING && type != OBJ_DATUM_NUMBER && type != OBJ_DATUM_DECIMALINT;
|
|
}
|
|
|
|
int64_t op_size_;
|
|
int64_t def_op_size_;
|
|
uint64_t total_size_;
|
|
bool exclude_null_;
|
|
};
|
|
|
|
class ObSumAggCell : public ObAggCell
|
|
{
|
|
typedef int (ObSumAggCell::*ObSumEvalAggFuncType)(const common::ObDatum &datum, const int32_t datum_offset);
|
|
typedef int (ObSumAggCell::*ObSumEvalBatchAggFuncType)(const common::ObDatum *datums, const int64_t count);
|
|
typedef int (ObSumAggCell::*ObSumCopyDatumFuncType)(const ObDatum &datum, ObDatum &result_datum);
|
|
public:
|
|
ObSumAggCell(
|
|
const ObAggCellBasicInfo &basic_info,
|
|
common::ObIAllocator &allocator);
|
|
virtual ~ObSumAggCell() { reset(); }
|
|
virtual void reset() override;
|
|
virtual void reuse() override;
|
|
virtual int init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) override;
|
|
virtual int eval(blocksstable::ObStorageDatum &datum, const int64_t row_count = 1) override;
|
|
virtual int eval_batch(const common::ObDatum *datums, const int64_t count) override;
|
|
virtual int eval_index_info(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg = false) override;
|
|
virtual int eval_batch_in_group_by(
|
|
const common::ObDatum *datums,
|
|
const int64_t count,
|
|
const uint32_t *refs,
|
|
const int64_t distinct_cnt,
|
|
const bool is_group_by_col = false,
|
|
const bool is_default_datum = false) override;
|
|
virtual int copy_output_row(const int32_t datum_offset) override;
|
|
virtual int copy_output_rows(const int32_t datum_offset) override;
|
|
virtual int copy_single_output_row(sql::ObEvalCtx &ctx) override;
|
|
virtual int collect_result(sql::ObEvalCtx &ctx) override;
|
|
virtual int collect_batch_result_in_group_by(const int64_t distinct_cnt) override;
|
|
virtual int reserve_group_by_buf(const int64_t size) override;
|
|
virtual int output_extra_group_by_result(const int64_t start, const int64_t count) override;
|
|
OB_INLINE bool is_sum_use_int() const { return sum_use_int_flag_; }
|
|
INHERIT_TO_STRING_KV("ObAggCell", ObAggCell, K_(obj_tc), K_(sum_use_int_flag), K_(num_int));
|
|
private:
|
|
virtual bool can_use_index_info() const override;
|
|
int init_decimal_int_func();
|
|
OB_INLINE int16_t child_scale() const { return basic_info_.agg_expr_->args_[0]->datum_meta_.scale_; }
|
|
template<typename RES_T>
|
|
int eval_int(const common::ObDatum &datum, const int32_t datum_offset);
|
|
template<typename RES_T>
|
|
int eval_uint(const common::ObDatum &datum, const int32_t datum_offset);
|
|
int eval_float(const common::ObDatum &datum, const int32_t datum_offset);
|
|
int eval_double(const common::ObDatum &datum, const int32_t datum_offset);
|
|
int eval_number(const common::ObDatum &datum, const int32_t datum_offset);
|
|
template<typename RES_T>
|
|
int eval_number_decimal_int(const common::ObDatum &datum, const int32_t datum_offset);
|
|
int init_eval_skip_index_func_for_decimal();
|
|
template<typename RES_T, typename ARG_T>
|
|
int eval_decimal_int(const common::ObDatum &datum, const int32_t datum_offset);
|
|
template<typename ARG_T>
|
|
int eval_decimal_int_number(const common::ObDatum &datum, const int32_t datum_offset);
|
|
template<typename RES_T>
|
|
int eval_int_batch(const common::ObDatum *datums, const int64_t count);
|
|
template<typename RES_T>
|
|
int eval_uint_batch(const common::ObDatum *datums, const int64_t count);
|
|
int eval_float_batch(const common::ObDatum *datums, const int64_t count);
|
|
int eval_double_batch(const common::ObDatum *datums, const int64_t count);
|
|
int eval_number_batch(const common::ObDatum *datums, const int64_t count);
|
|
template<typename RES_T, typename CALC_T, typename ARG_T>
|
|
int eval_decimal_int_batch(const common::ObDatum *datums, const int64_t count);
|
|
template<typename CALC_T, typename ARG_T>
|
|
int eval_decimal_int_number_batch(const common::ObDatum *datums, const int64_t count);
|
|
template<typename RES_T>
|
|
OB_INLINE int eval_int_inner(const common::ObDatum &datum, ObDataBuffer &alloc, const int32_t datum_offset = -1);
|
|
template<>
|
|
OB_INLINE int eval_int_inner<number::ObNumber>(const common::ObDatum &datum, ObDataBuffer &alloc, const int32_t datum_offset);
|
|
template<typename RES_T>
|
|
OB_INLINE int eval_uint_inner(const common::ObDatum &datum, ObDataBuffer &alloc, const int32_t datum_offset = -1);
|
|
template<>
|
|
OB_INLINE int eval_uint_inner<number::ObNumber>(const common::ObDatum &datum, ObDataBuffer &alloc, const int32_t datum_offset);
|
|
OB_INLINE int eval_float_inner(const common::ObDatum &datum, const int32_t datum_offset = -1);
|
|
OB_INLINE int eval_double_inner(const common::ObDatum &datum, const int32_t datum_offset = -1);
|
|
int copy_int_to_number(const ObDatum &datum, ObDatum &result_datum);
|
|
template<typename RES_T>
|
|
int copy_int_to_decimal_int(const ObDatum &datum, ObDatum &result_datum);
|
|
int copy_uint_to_number(const ObDatum &datum, ObDatum &result_datum);
|
|
template<typename RES_T>
|
|
int copy_uint_to_decimal_int(const ObDatum &datum, ObDatum &result_datum);
|
|
int copy_float(const ObDatum &datum, ObDatum &result_datum);
|
|
int copy_double(const ObDatum &datum, ObDatum &result_datum);
|
|
int copy_number(const ObDatum &datum, ObDatum &result_datum);
|
|
template<typename RES_T, typename ARG_T>
|
|
int copy_decimal_int(const ObDatum &datum, ObDatum &result_datum);
|
|
template<typename ARG_T>
|
|
int copy_decimal_int_to_number(const ObDatum &datum, ObDatum &result_datum);
|
|
int collect_result_in_group_by(const int64_t datum_offset);
|
|
int collect_result_to_decimal_int(
|
|
const int128_t &right_nmb,
|
|
const common::ObDatum &datum,
|
|
common::ObDatum &result);
|
|
void clear_group_by_info();
|
|
void reset_aggregate_info();
|
|
ObObjTypeClass obj_tc_;
|
|
bool sum_use_int_flag_;
|
|
bool is_sum_use_temp_buf_;
|
|
union {
|
|
int64_t num_int_;
|
|
uint64_t num_uint_;
|
|
};
|
|
ObGroupByExtendableBuf<bool> *sum_use_int_flag_buf_;
|
|
union {
|
|
ObGroupByExtendableBuf<int64_t> *num_int_buf_;
|
|
ObGroupByExtendableBuf<uint64_t> *num_uint_buf_;
|
|
void *num_buf_;
|
|
};
|
|
ObSumEvalAggFuncType eval_func_;
|
|
ObSumEvalBatchAggFuncType eval_batch_func_;
|
|
ObSumCopyDatumFuncType copy_datum_func_;
|
|
ObSumEvalAggFuncType eval_skip_index_func_;
|
|
blocksstable::ObStorageDatum cast_datum_;
|
|
char *sum_temp_buffer_;
|
|
char *cast_temp_buffer_;
|
|
};
|
|
|
|
// mysql compatibility, select a,count(a), output first value of a
|
|
class ObFirstRowAggCell : public ObAggCell
|
|
{
|
|
public:
|
|
ObFirstRowAggCell(const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator);
|
|
virtual ~ObFirstRowAggCell() { reset(); };
|
|
virtual void reset();
|
|
virtual void reuse();
|
|
virtual int init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) override;
|
|
virtual int eval(blocksstable::ObStorageDatum &datum, const int64_t row_count = 1) override;
|
|
virtual int eval_batch(const common::ObDatum *datums, const int64_t count) override
|
|
{
|
|
UNUSEDx(datums, count);
|
|
return OB_NOT_SUPPORTED;
|
|
}
|
|
virtual int eval_micro_block(
|
|
const ObTableIterParam &iter_param,
|
|
const ObTableAccessContext &context,
|
|
const int32_t col_offset,
|
|
blocksstable::ObIMicroBlockReader *reader,
|
|
const int64_t *row_ids,
|
|
const int64_t row_count) override;
|
|
virtual int eval_index_info(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg = false) override;
|
|
virtual int eval_batch_in_group_by(
|
|
const common::ObDatum *datums,
|
|
const int64_t count,
|
|
const uint32_t *refs,
|
|
const int64_t distinct_cnt,
|
|
const bool is_group_by_col = false,
|
|
const bool is_default_datum = false) override;
|
|
virtual int copy_output_row(const int32_t datum_offset) override
|
|
{
|
|
UNUSED(datum_offset);
|
|
return OB_SUCCESS;
|
|
}
|
|
virtual int copy_output_rows(const int32_t datum_offset) override
|
|
{
|
|
UNUSED(datum_offset);
|
|
return OB_SUCCESS;
|
|
}
|
|
virtual int copy_single_output_row(sql::ObEvalCtx &ctx) override
|
|
{
|
|
UNUSED(ctx);
|
|
return OB_SUCCESS;
|
|
}
|
|
virtual int collect_result(sql::ObEvalCtx &ctx) override;
|
|
virtual int collect_batch_result_in_group_by(const int64_t distinct_cnt) override;
|
|
virtual bool need_access_data() const override { return !finished(); }
|
|
virtual bool finished() const override { return aggregated_; }
|
|
virtual int reserve_group_by_buf(const int64_t size) override;
|
|
virtual int output_extra_group_by_result(const int64_t start, const int64_t count) override;
|
|
virtual int can_use_index_info(const blocksstable::ObMicroIndexInfo &index_info,
|
|
const bool is_cg, bool &can_agg) override;
|
|
OB_INLINE void set_determined_value()
|
|
{
|
|
is_determined_value_ = true;
|
|
result_datum_.reuse();
|
|
result_datum_.set_null();
|
|
aggregated_ = true;
|
|
}
|
|
INHERIT_TO_STRING_KV("ObAggCell", ObAggCell, K_(is_determined_value), K_(aggregated_flag_cnt));
|
|
private:
|
|
virtual bool can_use_index_info() const override { return finished(); }
|
|
void clear_group_by_info();
|
|
bool is_determined_value_;
|
|
int64_t aggregated_flag_cnt_;
|
|
ObGroupByExtendableBuf<bool> *aggregated_flag_buf_;
|
|
common::ObArenaAllocator datum_allocator_;
|
|
};
|
|
|
|
class ObPDAggFactory
|
|
{
|
|
public:
|
|
ObPDAggFactory(common::ObIAllocator &allocator) : allocator_ (allocator) {}
|
|
~ObPDAggFactory() {}
|
|
|
|
int alloc_cell(
|
|
const ObAggCellBasicInfo &basic_info,
|
|
common::ObIArray<ObAggCell*> &agg_cells,
|
|
const bool exclude_null = false,
|
|
const bool is_group_by = false,
|
|
sql::ObEvalCtx *eval_ctx = nullptr);
|
|
void release(common::ObIArray<ObAggCell*> &agg_cells);
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(ObPDAggFactory);
|
|
common::ObIAllocator &allocator_;
|
|
};
|
|
|
|
class ObGroupByCell
|
|
{
|
|
public:
|
|
ObGroupByCell(const int64_t batch_size, common::ObIAllocator &allocator);
|
|
~ObGroupByCell() { reset(); }
|
|
void reset();
|
|
void reuse();
|
|
int init(const ObTableAccessParam ¶m, const ObTableAccessContext &context, sql::ObEvalCtx &eval_ctx);
|
|
int init_for_single_row(const ObTableAccessParam ¶m, const ObTableAccessContext &context, sql::ObEvalCtx &eval_ctx);
|
|
// do group by for aggregate cell indicated by 'agg_idx'
|
|
// datums: batch of datums of this column
|
|
// count: batch size
|
|
// agg_idx: aggregate index in 'agg_cells_'
|
|
// is_group_by_col: true if current column is group by column
|
|
// is_default_datum: true if current column is new added column
|
|
// ref_offset: for column store, may do 'eval_batch' multiple times for one batch
|
|
int eval_batch(
|
|
const common::ObDatum *datums,
|
|
const int64_t count,
|
|
const int32_t agg_idx,
|
|
const bool is_group_by_col = false,
|
|
const bool is_default_datum = false,
|
|
const uint32_t ref_offset = 0);
|
|
// copy row/rows from output to aggregate
|
|
// in the case where can not do batch scan or can not do group by pushdown
|
|
int copy_output_row(const int64_t batch_idx);
|
|
int copy_output_rows(const int64_t batch_idx);
|
|
int copy_single_output_row(sql::ObEvalCtx &ctx);
|
|
int collect_result();
|
|
int add_distinct_null_value();
|
|
// for micro with bitmap, should extract distinct values according bitmap
|
|
int prepare_tmp_group_by_buf();
|
|
int extract_distinct();
|
|
// for case the count of distinct values exceed sql batch size
|
|
int reserve_group_by_buf(const int64_t size);
|
|
int output_extra_group_by_result(int64_t &count);
|
|
// for column store, assign aggregate cells to column group scanner(ObCGGroupByScanner)
|
|
int assign_agg_cells(const sql::ObExpr *col_expr, common::ObIArray<int32_t> &agg_idxs);
|
|
int check_distinct_and_ref_valid();
|
|
OB_INLINE int64_t get_batch_size() const { return batch_size_; }
|
|
OB_INLINE int32_t get_group_by_col_offset() const { return group_by_col_offset_; }
|
|
OB_INLINE ObObjDatumMapType get_obj_datum_map_type() const {return group_by_col_expr_->obj_datum_map_; }
|
|
OB_INLINE bool is_exceed_sql_batch() const { return group_by_col_datum_buf_->is_use_extra_buf(); }
|
|
OB_INLINE common::ObDatum *get_group_by_col_datums_to_fill()
|
|
{ return need_extract_distinct_ ? tmp_group_by_datum_buf_->get_group_by_datums() : group_by_col_datum_buf_->get_group_by_datums(); }
|
|
OB_INLINE const char **get_cell_datas()
|
|
{ return need_extract_distinct_ ? tmp_group_by_datum_buf_->get_group_by_cell_datas() : group_by_col_datum_buf_->get_group_by_cell_datas(); }
|
|
OB_INLINE common::ObDatum *get_group_by_col_datums() const { return group_by_col_datum_buf_->get_group_by_datums(); }
|
|
OB_INLINE common::ObIArray<ObAggCell*> &get_agg_cells() { return agg_cells_; }
|
|
OB_INLINE int64_t get_ref_cnt() const { return ref_cnt_; }
|
|
OB_INLINE void set_ref_cnt(const int64_t ref_cnt) { ref_cnt_ = ref_cnt; }
|
|
OB_INLINE uint32_t *get_refs_buf() { return refs_buf_; }
|
|
OB_INLINE bool need_read_reference() const { return need_extract_distinct_ || agg_cells_.count() > 0; }
|
|
OB_INLINE bool need_do_aggregate() const { return agg_cells_.count() > 0; }
|
|
OB_INLINE int64_t get_distinct_cnt() const { return distinct_cnt_; }
|
|
OB_INLINE void set_distinct_cnt(const int64_t distinct_cnt) { distinct_cnt_ = distinct_cnt; }
|
|
OB_INLINE bool need_extract_distinct() const { return need_extract_distinct_; }
|
|
OB_INLINE bool is_processing() const { return is_processing_; }
|
|
OB_INLINE void set_is_processing(const bool is_processing) { is_processing_ = is_processing; }
|
|
OB_INLINE void reset_projected_cnt() { projected_cnt_ = 0; }
|
|
OB_INLINE void set_row_capacity(const int64_t row_capacity) { row_capacity_ = row_capacity; }
|
|
template <typename T>
|
|
int decide_use_group_by(const int64_t row_cnt, const int64_t read_cnt, const int64_t distinct_cnt, const T *bitmap, bool &use_group_by)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const bool is_valid_bitmap = nullptr != bitmap && !bitmap->is_all_true();
|
|
use_group_by = row_capacity_ == batch_size_ &&
|
|
read_cnt * USE_GROUP_BY_READ_CNT_FACTOR > row_cnt &&
|
|
distinct_cnt < USE_GROUP_BY_MAX_DISTINCT_CNT &&
|
|
distinct_cnt < row_cnt * USE_GROUP_BY_DISTINCT_RATIO &&
|
|
(!is_valid_bitmap ||
|
|
bitmap->popcnt() * USE_GROUP_BY_FILTER_FACTOR > bitmap->size());
|
|
if (use_group_by) {
|
|
if ((is_valid_bitmap || read_cnt < row_cnt) && OB_FAIL(prepare_tmp_group_by_buf())) {
|
|
LOG_WARN("Failed to init extra info", K(ret));
|
|
} else if (OB_FAIL(reserve_group_by_buf(distinct_cnt + 1))) {
|
|
LOG_WARN("Failed to prepare group by datum buf", K(ret));
|
|
}
|
|
}
|
|
LOG_TRACE("[GROUP BY PUSHDOWN]", K(ret), K(row_cnt), K(read_cnt), K(distinct_cnt), K(is_valid_bitmap), K(use_group_by),
|
|
K_(batch_size), K_(row_capacity),
|
|
"popcnt", is_valid_bitmap ? bitmap->popcnt() : 0,
|
|
"size", is_valid_bitmap ? bitmap->size() : 0);
|
|
return ret;
|
|
}
|
|
// TODO remove this after use vectorize 2.0 in group by pushdown
|
|
int init_uniform_header(
|
|
const sql::ObExprPtrIArray *output_exprs,
|
|
const sql::ObExprPtrIArray *agg_exprs,
|
|
sql::ObEvalCtx &eval_ctx,
|
|
const bool init_output = true);
|
|
DECLARE_TO_STRING;
|
|
private:
|
|
int init_agg_cells(const ObTableAccessParam ¶m, const ObTableAccessContext &context, sql::ObEvalCtx &eval_ctx, const bool is_for_single_row);
|
|
static const int64_t DEFAULT_AGG_CELL_CNT = 2;
|
|
static const int64_t USE_GROUP_BY_READ_CNT_FACTOR = 2;
|
|
static constexpr double USE_GROUP_BY_DISTINCT_RATIO = 0.5;
|
|
static const int64_t USE_GROUP_BY_FILTER_FACTOR = 2;
|
|
int64_t batch_size_;
|
|
int64_t row_capacity_;
|
|
int32_t group_by_col_offset_;
|
|
sql::ObExpr *group_by_col_expr_;
|
|
ObAggGroupByDatumBuf *group_by_col_datum_buf_;
|
|
// for micro with bitmap
|
|
// first read all the distinct values into this buffer
|
|
// then extract actual distinct values according bitmap
|
|
ObAggGroupByDatumBuf *tmp_group_by_datum_buf_;
|
|
// aggregate cells
|
|
common::ObSEArray<ObAggCell*, DEFAULT_AGG_CELL_CNT> agg_cells_;
|
|
int64_t distinct_cnt_;
|
|
int64_t ref_cnt_;
|
|
uint32_t *refs_buf_;
|
|
// the 3 following members is for extracting distinct values from rows with bitmap
|
|
bool need_extract_distinct_;
|
|
ObGroupByExtendableBuf<int16_t> *distinct_projector_buf_;
|
|
ObAggDatumBuf *agg_datum_buf_;
|
|
bool is_processing_;
|
|
int64_t projected_cnt_;
|
|
ObPDAggFactory agg_cell_factory_;
|
|
common::ObIAllocator &allocator_;
|
|
DISALLOW_COPY_AND_ASSIGN(ObGroupByCell);
|
|
};
|
|
|
|
class ObAggSelector
|
|
{
|
|
public:
|
|
ObAggSelector(const uint16_t count) : count_(count) {}
|
|
~ObAggSelector() {}
|
|
|
|
bool is_valid() const { return count_ != 0; }
|
|
uint16_t begin() const { return 0; }
|
|
uint16_t end() const { return count_; }
|
|
uint16_t next(uint16_t &i) const { return ++i; }
|
|
uint16_t get_batch_index(uint16_t i) const { return i; }
|
|
private:
|
|
uint16_t count_;
|
|
};
|
|
|
|
class ObAggSource
|
|
{
|
|
public:
|
|
ObAggSource(const ObDatum *datums) : datums_(datums) {}
|
|
~ObAggSource() {}
|
|
const common::ObDatum *at(const int64_t i) const { return &datums_[i]; }
|
|
private:
|
|
const ObDatum *datums_;
|
|
};
|
|
|
|
#define DATUM_TO_DECIMAL_INT(datum, type) \
|
|
*const_cast<type *>(reinterpret_cast<const type*>(datum.get_decimal_int()))
|
|
|
|
#define DATUM_TO_CONST_DECIMAL_INT(datum, type) \
|
|
*reinterpret_cast<const type*>(datum.get_decimal_int())
|
|
|
|
template<typename RES_T>
|
|
OB_INLINE int ObSumAggCell::eval_int_inner(const common::ObDatum &datum, ObDataBuffer &alloc, const int32_t datum_offset)
|
|
{
|
|
UNUSED(alloc);
|
|
int ret = OB_SUCCESS;
|
|
if (datum.is_null()) {
|
|
} else {
|
|
common::ObDatum &result_datum = get_group_by_result_datum(datum_offset);
|
|
int64_t &datum_int = DEFAULT_DATUM_OFFSET == datum_offset ? num_int_ : num_int_buf_->at(datum_offset);
|
|
bool &sum_use_int_flag = DEFAULT_DATUM_OFFSET == datum_offset ? sum_use_int_flag_ : sum_use_int_flag_buf_->at(datum_offset);
|
|
|
|
int64_t new_int = datum.get_int();
|
|
int64_t sum_int = datum_int + new_int;
|
|
if (sql::ObExprAdd::is_int_int_out_of_range(datum_int, new_int, sum_int)) {
|
|
LOG_DEBUG("int64_t add overflow, will use decimal int", K(datum_int), K(new_int), K(sum_int));
|
|
if (OB_UNLIKELY(result_datum.is_null())) {
|
|
DATUM_TO_DECIMAL_INT(result_datum, RES_T) = datum_int;
|
|
DATUM_TO_DECIMAL_INT(result_datum, RES_T) += new_int;
|
|
result_datum.pack_ = sizeof(RES_T);
|
|
} else {
|
|
DATUM_TO_DECIMAL_INT(result_datum, RES_T) =
|
|
DATUM_TO_CONST_DECIMAL_INT(result_datum, RES_T) + datum_int + new_int;
|
|
}
|
|
datum_int = 0;
|
|
} else {
|
|
LOG_DEBUG("int64_t add does not overflow", K(datum_int), K(new_int), K(sum_int));
|
|
datum_int = sum_int;
|
|
}
|
|
sum_use_int_flag = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template<>
|
|
OB_INLINE int ObSumAggCell::eval_int_inner<number::ObNumber>(const common::ObDatum &datum,
|
|
ObDataBuffer &alloc,
|
|
const int32_t datum_offset)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (datum.is_null()) {
|
|
} else {
|
|
common::ObDatum &result_datum = get_group_by_result_datum(datum_offset);
|
|
int64_t &datum_int = DEFAULT_DATUM_OFFSET == datum_offset ? num_int_ : num_int_buf_->at(datum_offset);
|
|
bool &sum_use_int_flag = DEFAULT_DATUM_OFFSET == datum_offset ? sum_use_int_flag_ : sum_use_int_flag_buf_->at(datum_offset);
|
|
|
|
int64_t new_int = datum.get_int();
|
|
int64_t sum_int = datum_int + new_int;
|
|
if (sql::ObExprAdd::is_int_int_out_of_range(datum_int, new_int, sum_int)) {
|
|
LOG_DEBUG("int64_t add overflow, will use number", K(datum_int), K(new_int), K(sum_int));
|
|
common::number::ObNumber result_nmb;
|
|
if (!result_datum.is_null()) {
|
|
common::number::ObCompactNumber &cnum = const_cast<common::number::ObCompactNumber &>(result_datum.get_number());
|
|
result_nmb.assign(cnum.desc_.desc_, cnum.digits_ + 0);
|
|
}
|
|
if (OB_FAIL(result_nmb.add(datum_int, new_int, result_nmb, alloc))) {
|
|
LOG_WARN("number add failed", K(ret));
|
|
} else {
|
|
result_datum.set_number(result_nmb);
|
|
datum_int = 0;
|
|
alloc.free();
|
|
}
|
|
} else {
|
|
LOG_DEBUG("int64_t add does not overflow", K(datum_int), K(new_int), K(sum_int), K(datum_offset));
|
|
datum_int = sum_int;
|
|
}
|
|
sum_use_int_flag = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template<typename RES_T>
|
|
OB_INLINE int ObSumAggCell::eval_uint_inner(const common::ObDatum &datum, ObDataBuffer &alloc, const int32_t datum_offset)
|
|
{
|
|
UNUSED(alloc);
|
|
int ret = OB_SUCCESS;
|
|
if (datum.is_null()) {
|
|
} else {
|
|
common::ObDatum &result_datum = get_group_by_result_datum(datum_offset);
|
|
uint64_t &datum_uint = DEFAULT_DATUM_OFFSET == datum_offset ? num_uint_ : num_uint_buf_->at(datum_offset);
|
|
bool &sum_use_int_flag = DEFAULT_DATUM_OFFSET == datum_offset ? sum_use_int_flag_ : sum_use_int_flag_buf_->at(datum_offset);
|
|
|
|
uint64_t new_uint = datum.get_uint();
|
|
uint64_t sum_uint = datum_uint + new_uint;
|
|
if (sql::ObExprAdd::is_uint_uint_out_of_range(datum_uint, new_uint, sum_uint)) {
|
|
LOG_DEBUG("uint64_t add overflow, will use number", K(datum_uint), K(new_uint), K(sum_uint));
|
|
if (OB_UNLIKELY(result_datum_.is_null())) {
|
|
DATUM_TO_DECIMAL_INT(result_datum_, RES_T) = datum_uint;
|
|
DATUM_TO_DECIMAL_INT(result_datum_, RES_T) += new_uint;
|
|
result_datum_.pack_ = sizeof(RES_T);
|
|
} else {
|
|
DATUM_TO_DECIMAL_INT(result_datum_, RES_T) =
|
|
DATUM_TO_CONST_DECIMAL_INT(result_datum_, RES_T) + datum_uint + new_uint;
|
|
}
|
|
datum_uint = 0;
|
|
} else {
|
|
LOG_DEBUG("uint64_t add does not overflow", K(datum_uint), K(new_uint), K(sum_uint), K(datum_offset));
|
|
datum_uint = sum_uint;
|
|
}
|
|
sum_use_int_flag = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template<>
|
|
OB_INLINE int ObSumAggCell::eval_uint_inner<number::ObNumber>(const common::ObDatum &datum,
|
|
ObDataBuffer &alloc,
|
|
const int32_t datum_offset)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (datum.is_null()) {
|
|
} else {
|
|
common::ObDatum &result_datum = get_group_by_result_datum(datum_offset);
|
|
uint64_t &datum_uint = DEFAULT_DATUM_OFFSET == datum_offset ? num_uint_ : num_uint_buf_->at(datum_offset);
|
|
bool &sum_use_int_flag = DEFAULT_DATUM_OFFSET == datum_offset ? sum_use_int_flag_ : sum_use_int_flag_buf_->at(datum_offset);
|
|
|
|
uint64_t new_uint = datum.get_uint();
|
|
uint64_t sum_uint = datum_uint + new_uint;
|
|
if (sql::ObExprAdd::is_uint_uint_out_of_range(datum_uint, new_uint, sum_uint)) {
|
|
LOG_DEBUG("uint64_t add overflow, will use number", K(datum_uint), K(new_uint), K(sum_uint));
|
|
common::number::ObNumber result_nmb;
|
|
if (!result_datum.is_null()) {
|
|
common::number::ObCompactNumber &cnum = const_cast<common::number::ObCompactNumber &>(result_datum.get_number());
|
|
result_nmb.assign(cnum.desc_.desc_, cnum.digits_ + 0);
|
|
}
|
|
if (OB_FAIL(result_nmb.add(datum_uint, new_uint, result_nmb, alloc))) {
|
|
LOG_WARN("number add failed", K(ret));
|
|
} else {
|
|
result_datum.set_number(result_nmb);
|
|
datum_uint = 0;
|
|
alloc.free();
|
|
}
|
|
} else {
|
|
LOG_DEBUG("uint64_t add does not overflow", K(datum_uint), K(new_uint), K(sum_uint));
|
|
datum_uint = sum_uint;
|
|
}
|
|
sum_use_int_flag = true;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
OB_INLINE int ObSumAggCell::eval_float_inner(const common::ObDatum &datum, const int32_t datum_offset)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
common::ObDatum &result_datum = get_group_by_result_datum(datum_offset);
|
|
if (datum.is_null()) {
|
|
} else if (result_datum.is_null()) {
|
|
result_datum.set_float(datum.get_float());
|
|
} else {
|
|
float left_f = result_datum.get_float();
|
|
float right_f = datum.get_float();
|
|
if (OB_UNLIKELY(sql::ObArithExprOperator::is_float_out_of_range(left_f + right_f))
|
|
&& !lib::is_oracle_mode()) {
|
|
ret = OB_OPERATE_OVERFLOW;
|
|
char expr_str[OB_MAX_TWO_OPERATOR_EXPR_LENGTH];
|
|
int64_t pos = 0;
|
|
databuff_printf(expr_str,
|
|
OB_MAX_TWO_OPERATOR_EXPR_LENGTH,
|
|
pos,
|
|
"'(%e + %e)'", left_f, right_f);
|
|
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "BINARY_FLOAT", expr_str);
|
|
LOG_WARN("float out of range", K(left_f), K(right_f));
|
|
} else {
|
|
result_datum.set_float(left_f + right_f);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
OB_INLINE int ObSumAggCell::eval_double_inner(const common::ObDatum &datum, const int32_t datum_offset)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
common::ObDatum &result_datum = get_group_by_result_datum(datum_offset);
|
|
if (datum.is_null()) {
|
|
} else if (result_datum.is_null()) {
|
|
result_datum.set_double(datum.get_double());
|
|
} else {
|
|
double left_d = result_datum.get_double();
|
|
double right_d = datum.get_double();
|
|
result_datum.set_double(left_d + right_d);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#endif // OCEANBASE_STORAGE_OB_PUSHDOWN_AGGREGATE_H_
|