/** * 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. */ #define USING_LOG_PREFIX STORAGE #include "ob_pushdown_aggregate.h" #include "sql/engine/ob_exec_context.h" #include "sql/engine/expr/ob_expr_util.h" #include "sql/engine/aggregate/ob_aggregate_util.h" #include "storage/blocksstable/ob_datum_row.h" #include "storage/blocksstable/ob_micro_block_reader.h" #include "storage/blocksstable/encoding/ob_micro_block_decoder.h" namespace oceanbase { using namespace common; namespace storage { ObAggDatumBuf::ObAggDatumBuf(common::ObIAllocator &allocator) : size_(0), datum_size_(0), datums_(nullptr), buf_(nullptr), cell_data_ptrs_(nullptr), allocator_(allocator) { } int ObAggDatumBuf::init(const int64_t size, const bool need_cell_data_ptr, const int64_t datum_size) { int ret = OB_SUCCESS; void *buf = nullptr; if (OB_UNLIKELY(size <= 0 || datum_size <= 0 || datum_size > common::OBJ_DATUM_DECIMALINT_MAX_RES_SIZE)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(size), K(datum_size)); } else if (OB_ISNULL(buf = allocator_.alloc(sizeof(ObDatum) * size))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc datum buf", K(ret), K(size)); } else if (FALSE_IT(datums_ = new (buf) ObDatum[size])) { } else if (OB_ISNULL(buf = allocator_.alloc(datum_size * size))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc datum buf", K(ret), K(size)); } else if (FALSE_IT(buf_ = static_cast(buf))) { } else if (need_cell_data_ptr) { if (OB_ISNULL(buf = allocator_.alloc(sizeof(char*) * size))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc cell data ptrs", K(ret), K(size)); } else { cell_data_ptrs_ = static_cast (buf); } } if (OB_SUCC(ret)) { size_ = size; datum_size_ = datum_size; reuse(); } else { reset(); } return ret; } void ObAggDatumBuf::reset() { if (OB_NOT_NULL(datums_)) { allocator_.free(datums_); datums_ = nullptr; } if (OB_NOT_NULL(buf_)) { allocator_.free(buf_); buf_ = nullptr; } if (OB_NOT_NULL(cell_data_ptrs_)) { allocator_.free(cell_data_ptrs_); cell_data_ptrs_ = nullptr; } size_ = 0; datum_size_ = 0; } void ObAggDatumBuf::reuse() { for(int64_t i = 0; i < size_; ++i) { datums_[i].pack_ = 0; datums_[i].ptr_ = buf_ + i * datum_size_; } } int ObAggDatumBuf::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) { int ret = OB_SUCCESS; if (nullptr == datum_buf) { void *buf = nullptr; if (OB_ISNULL(buf = allocator.alloc(sizeof(ObAggDatumBuf)))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc agg datum buffer", K(ret)); } else if (FALSE_IT(datum_buf = new (buf) ObAggDatumBuf(allocator))) { } else if (OB_FAIL(datum_buf->init(size, need_cell_data_ptr, datum_size))) { LOG_WARN("Failed to init agg datum buf", K(ret)); } } return ret; } template int new_group_by_buf( DATA_TYPE *basic_data, const int32_t basic_size, const int32_t item_size, common::ObIAllocator &allocator, BUF_TYPE *&group_by_buf) { int ret = OB_SUCCESS; if (OB_UNLIKELY(item_size <= 0 || item_size > common::OBJ_DATUM_DECIMALINT_MAX_RES_SIZE || (nullptr != basic_data && basic_size <= 0) || nullptr == basic_data && basic_size > 0)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), KP(basic_data), K(basic_size)); } else { void *buf = nullptr; if (OB_ISNULL(buf = allocator.alloc(sizeof(BUF_TYPE)))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memory", K(ret)); } else { group_by_buf = new (buf) BUF_TYPE(basic_data, basic_size, item_size, allocator); } } return ret; } template void free_group_by_buf(common::ObIAllocator &allocator, BUF_TYPE *&group_by_buf) { if (nullptr != group_by_buf) { group_by_buf->~BUF_TYPE(); allocator.free(group_by_buf); group_by_buf = nullptr; } } ObAggGroupByDatumBuf::ObAggGroupByDatumBuf( common::ObDatum *basic_data, const int32_t basic_size, const int32_t datum_size, common::ObIAllocator &allocator) : capacity_(basic_size), sql_datums_cnt_(basic_size), sql_result_datums_(basic_data), result_datum_buf_(nullptr), datum_size_(datum_size), allocator_(allocator) { } void ObAggGroupByDatumBuf::reset() { capacity_ = 0; sql_result_datums_ = nullptr; sql_datums_cnt_ = 0; if (nullptr != result_datum_buf_) { result_datum_buf_->reset(); allocator_.free(result_datum_buf_); } result_datum_buf_ = nullptr; datum_size_ = 0; } int ObAggGroupByDatumBuf::reserve(const int32_t size) { int ret = OB_SUCCESS; if (OB_UNLIKELY(size <= 0 || size > USE_GROUP_BY_MAX_DISTINCT_CNT)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Unexpected size", K(ret), K(size)); } else { capacity_ = MAX(sql_datums_cnt_, size); if (is_use_extra_buf()) { if (OB_ISNULL(result_datum_buf_)) { if (OB_FAIL(ObAggDatumBuf::new_agg_datum_buf(USE_GROUP_BY_MAX_DISTINCT_CNT, true, allocator_, result_datum_buf_, datum_size_))) { LOG_WARN("Failed to alloc agg datum buf", K(ret)); } } } } return ret; } void ObAggGroupByDatumBuf::fill_datums(const FillDatumType datum_type) { common::ObDatum *datums = get_group_by_datums(); if (FillDatumType::NULL_DATUM == datum_type) { for (int64_t i = 0; i < capacity_; ++i) { datums[i].set_null(); } } else if (FillDatumType::ZERO_DATUM == datum_type) { for (int64_t i = 0; i < capacity_; ++i) { datums[i].set_int(0); } } } template ObGroupByExtendableBuf::ObGroupByExtendableBuf( T *basic_data, const int32_t basic_size, const int32_t item_size, common::ObIAllocator &allocator) : capacity_(basic_size), basic_count_(basic_size), basic_data_(basic_data), extra_block_count_(0), item_size_(item_size), allocator_(allocator) { MEMSET(extra_blocks_, 0, sizeof(extra_blocks_)); } template void ObGroupByExtendableBuf::reset() { capacity_ = 0; basic_data_ = nullptr; basic_count_ = 0; if (extra_block_count_ > 0) { for (int64_t i = 0; i < extra_block_count_; ++i) { free_bufblock(extra_blocks_[i]); } } extra_block_count_ = 0; item_size_ = 0; } template int ObGroupByExtendableBuf::reserve(const int32_t size) { int ret = OB_SUCCESS; if (OB_UNLIKELY(size <= 0 || size > USE_GROUP_BY_MAX_DISTINCT_CNT)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Unexpected size", K(ret), K(size)); } else { capacity_ = MAX(basic_count_, size); int32_t cur_capacity = basic_count_ + extra_block_count_ * USE_GROUP_BY_BUF_BLOCK_SIZE; if (capacity_ > cur_capacity) { int32_t required_block_cnt = ceil((double)(size - cur_capacity) / USE_GROUP_BY_BUF_BLOCK_SIZE); for (int64_t i = 0; OB_SUCC(ret) && i < required_block_cnt; ++i) { if (OB_FAIL(alloc_bufblock(extra_blocks_[extra_block_count_]))) { LOG_WARN("Failed to allock buf block", K(ret)); } else { extra_block_count_++; } } } } return ret; } template void ObGroupByExtendableBuf::fill_items(const T item) { if (capacity_ <= basic_count_) { MEMSET(basic_data_, item, item_size_ * capacity_); } else { if (basic_count_ > 0) { MEMSET(basic_data_, item, item_size_ * basic_count_); } const int32_t used_block_cnt = ceil((double)(capacity_ - basic_count_) / USE_GROUP_BY_BUF_BLOCK_SIZE); for (int64_t i = 0; i < used_block_cnt; ++i) { if (i < used_block_cnt - 1) { MEMSET(extra_blocks_[i]->data_, item, item_size_ * USE_GROUP_BY_BUF_BLOCK_SIZE); } else { const int32_t remain_cnt = capacity_ - basic_count_ - (used_block_cnt - 1) * USE_GROUP_BY_BUF_BLOCK_SIZE; MEMSET(extra_blocks_[i]->data_, item, item_size_ * remain_cnt); } } } } template void ObGroupByExtendableBuf::fill_datum_items(const FillDatumType type) { if (capacity_ <= basic_count_) { fill_datums(basic_data_, capacity_, type); } else { if (basic_count_ > 0) { fill_datums(basic_data_, basic_count_, type); } const int32_t used_block_cnt = ceil((double)(capacity_ - basic_count_) / USE_GROUP_BY_BUF_BLOCK_SIZE); for (int64_t i = 0; i < used_block_cnt; ++i) { if (i < used_block_cnt - 1) { fill_datums(extra_blocks_[i]->datum_buf_->get_datums(), USE_GROUP_BY_BUF_BLOCK_SIZE, type); } else { const int32_t remain_cnt = capacity_ - basic_count_ - (used_block_cnt - 1) * USE_GROUP_BY_BUF_BLOCK_SIZE; fill_datums(extra_blocks_[i]->datum_buf_->get_datums(), remain_cnt, type); } } } } template int ObGroupByExtendableBuf::alloc_bufblock(BufBlock *&block) { int ret = OB_SUCCESS; void *buf = nullptr; if (OB_ISNULL(buf = allocator_.alloc(sizeof(BufBlock)))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memory", K(ret)); } else if(FALSE_IT(block = new (buf) BufBlock())) { } else if (OB_ISNULL(buf = allocator_.alloc(item_size_ * USE_GROUP_BY_BUF_BLOCK_SIZE))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memory", K(ret)); } else { block->data_ =reinterpret_cast(buf); } return ret; } template<> int ObGroupByExtendableBuf::alloc_bufblock(BufBlock *&block) { int ret = OB_SUCCESS; void *buf = nullptr; if (OB_ISNULL(buf = allocator_.alloc(sizeof(BufBlock)))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memory", K(ret)); } else if(FALSE_IT(block = new (buf) BufBlock())) { } else if (OB_FAIL(ObAggDatumBuf::new_agg_datum_buf( USE_GROUP_BY_BUF_BLOCK_SIZE, false, allocator_, block->datum_buf_, item_size_))) { LOG_WARN("Failed to alloc agg datum buf", K(ret)); } return ret; } template void ObGroupByExtendableBuf::free_bufblock(BufBlock *&block) { if (nullptr != block) { if (nullptr != block->data_) { allocator_.free(block->data_); } allocator_.free(block); block = nullptr; } } template<> void ObGroupByExtendableBuf::free_bufblock(BufBlock *&block) { if (nullptr != block) { if (nullptr != block->datum_buf_) { block->datum_buf_->~ObAggDatumBuf(); allocator_.free(block->datum_buf_); } allocator_.free(block); block = nullptr; } } template void ObGroupByExtendableBuf::fill_datums(ObDatum *datums, const int32_t count, const FillDatumType datum_type) { if (FillDatumType::NULL_DATUM == datum_type) { for (int64_t i = 0; i < count; ++i) { datums[i].set_null(); } } else if (FillDatumType::ZERO_DATUM == datum_type) { for (int64_t i = 0; i < count; ++i) { datums[i].set_int(0); } } } ObAggCell::ObAggCell(const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator) : agg_type_(ObPDAggType::PD_MAX_TYPE), basic_info_(basic_info), result_datum_(), def_datum_(), allocator_(allocator), is_lob_col_(false), aggregated_(false), agg_datum_buf_(nullptr), agg_row_reader_(nullptr), col_datums_(nullptr), group_by_result_datum_buf_(nullptr), group_by_result_cnt_(0), is_assigned_to_group_by_processor_(false) { if (basic_info_.col_param_ != nullptr) { is_lob_col_ = basic_info_.col_param_->get_meta_type().is_lob_storage(); } } void ObAggCell::reset() { agg_type_ = ObPDAggType::PD_MAX_TYPE; basic_info_.reset(); result_datum_.reset(); is_lob_col_ = false; aggregated_ = false; if (nullptr != agg_datum_buf_) { agg_datum_buf_->reset(); allocator_.free(agg_datum_buf_); agg_datum_buf_ = nullptr; } if (nullptr != agg_row_reader_) { agg_row_reader_->reset(); allocator_.free(agg_row_reader_); agg_row_reader_ = nullptr; } col_datums_ = nullptr; free_group_by_buf(allocator_, group_by_result_datum_buf_); group_by_result_cnt_ = 0; is_assigned_to_group_by_processor_ = false; } void ObAggCell::reuse() { aggregated_ = false; result_datum_.reuse(); result_datum_.set_null(); group_by_result_cnt_ = 0; if (nullptr != col_datums_) { for (int64_t i = 0; i < basic_info_.batch_size_; ++i) { col_datums_[i].set_null(); } } } void ObAggCell::clear_group_by_info() { if (nullptr != group_by_result_datum_buf_) { if (PD_COUNT != agg_type_) { group_by_result_datum_buf_->fill_datum_items(FillDatumType::NULL_DATUM); } else { group_by_result_datum_buf_->fill_datum_items(FillDatumType::ZERO_DATUM); } } } int ObAggCell::init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) { int ret = OB_SUCCESS; if (is_group_by) { if (PD_FIRST_ROW != agg_type_) { common::ObDatum *result_datums = basic_info_.agg_expr_->locate_batch_datums(*eval_ctx); if (OB_ISNULL(result_datums)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "Unexpected null agg datums", K(ret)); } else if (OB_FAIL(new_group_by_buf(result_datums, basic_info_.batch_size_, common::OBJ_DATUM_NUMBER_RES_SIZE, allocator_, group_by_result_datum_buf_))) { LOG_WARN("Failed to new buf", K(ret)); } else if (OB_UNLIKELY(nullptr == basic_info_.agg_expr_->args_ || nullptr == basic_info_.agg_expr_->args_[0] || basic_info_.agg_expr_->args_[0]->type_ != T_REF_COLUMN)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("args is invalid", K(ret), KPC(basic_info_.agg_expr_)); } else if (OB_ISNULL(col_datums_ = basic_info_.agg_expr_->args_[0]->locate_batch_datums(*eval_ctx))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "Unexpected null col datums", K(ret)); } } else if (OB_ISNULL(col_datums_ = basic_info_.agg_expr_->locate_batch_datums(*eval_ctx))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "Unexpected null col datums", K(ret)); } } return ret; } int ObAggCell::eval_micro_block( const int32_t col_offset, blocksstable::ObIMicroBlockReader *reader, const int64_t *row_ids, const int64_t row_count) { int ret = OB_SUCCESS; if (OB_FAIL(ObAggDatumBuf::new_agg_datum_buf(basic_info_.batch_size_, true, allocator_, agg_datum_buf_))) { LOG_WARN("Failed to alloc agg datum buf", K(ret)); } else if (OB_FAIL(reader->get_aggregate_result(col_offset, basic_info_.col_param_, row_ids, row_count, *agg_datum_buf_, *this))) { LOG_WARN("Failed to get aggregate result", K(ret)); } LOG_DEBUG("eval_micro_block", K(ret), KPC(this)); return ret; } int ObAggCell::eval_index_info(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg) { int ret = OB_SUCCESS; if (!is_cg && (!index_info.can_blockscan(is_lob_col()) || index_info.is_left_border() || index_info.is_right_border())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected, the micro index info must can blockscan and not border", K(ret), K(index_info)); } else { blocksstable::ObStorageDatum agg_datum; if (OB_FAIL(read_agg_datum(index_info, is_cg, agg_datum))) { LOG_WARN("Failed to read agg row", K(ret)); } else if (OB_FAIL(eval(agg_datum))) { LOG_WARN("Failed to process datum", K(ret), K(agg_datum), KPC(this)); } } LOG_DEBUG("eval_index_info", K(ret), KPC(this)); return ret; } int ObAggCell::copy_output_row(const int32_t datum_offset) { int ret = OB_SUCCESS; if (OB_UNLIKELY(datum_offset >= group_by_result_datum_buf_->get_basic_count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(datum_offset), KPC(group_by_result_datum_buf_)); } else { common::ObDatum *result_datums = group_by_result_datum_buf_->get_basic_buf(); const common::ObDatum &datum = col_datums_[datum_offset]; if (OB_FAIL(result_datums[datum_offset].from_storage_datum( datum, basic_info_.agg_expr_->obj_datum_map_))) { LOG_WARN("Failed to clone datum", K(ret), K(datum), K(basic_info_.agg_expr_->obj_datum_map_)); } } return ret; } int ObAggCell::copy_output_rows(const int32_t datum_offset) { int ret = OB_SUCCESS; if (OB_UNLIKELY(datum_offset > group_by_result_datum_buf_->get_basic_count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(datum_offset), KPC(group_by_result_datum_buf_)); } else { common::ObDatum *result_datums = group_by_result_datum_buf_->get_basic_buf(); for (int64_t i = 0; OB_SUCC(ret) && i < datum_offset; i++) { // Although one batch of rows will be returned to SQL layer directly // it's needed to use 'from_storage_datum' to avoid overrided prevous memory of datum // as the ptr of datum may be not redirected to SQL memory and will be overrided in following 'eval_batch_in_group_by' if (OB_FAIL(result_datums[i].from_storage_datum( col_datums_[i], basic_info_.agg_expr_->obj_datum_map_))) { LOG_WARN("Failed to clone datum", K(ret), K(i), K(col_datums_[i]), K(basic_info_.agg_expr_->obj_datum_map_)); } } } return ret; } int ObAggCell::collect_result(sql::ObEvalCtx &ctx, bool need_padding) { int ret = OB_SUCCESS; ObDatum &result = basic_info_.agg_expr_->locate_datum_for_write(ctx); if (OB_FAIL(fill_default_if_need(result_datum_))) { LOG_WARN("Failed to fill default", K(ret), KPC(this)); } else if (need_padding && OB_FAIL(pad_column_if_need(result_datum_))) { LOG_WARN("Failed to pad column", K(ret), KPC(this)); } else if (OB_FAIL(result.from_storage_datum(result_datum_, basic_info_.agg_expr_->obj_datum_map_))) { LOG_WARN("Failed to from storage datum", K(ret), K(result_datum_), K(result), KPC(this)); } else { sql::ObEvalInfo &eval_info = basic_info_.agg_expr_->get_eval_info(ctx); eval_info.evaluated_ = true; LOG_DEBUG("collect_result", K(result), KPC(this)); } return ret; } int ObAggCell::collect_batch_result_in_group_by(const int64_t distinct_cnt) { UNUSED(distinct_cnt); return OB_SUCCESS; } int ObAggCell::reserve_group_by_buf(const int64_t size) { int ret = OB_SUCCESS; if (OB_FAIL(group_by_result_datum_buf_->reserve(size))) { LOG_WARN("Failed to prepare extra buf", K(ret)); } else { clear_group_by_info(); } return ret; } int ObAggCell::output_extra_group_by_result(const int64_t start, const int64_t count) { int ret = OB_SUCCESS; if (OB_UNLIKELY(start < group_by_result_datum_buf_->get_basic_count() || start + count > group_by_result_datum_buf_->get_capacity())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Unexpected argument, should be not exceed the buf size", K(ret), K(start), K(count), KPC(group_by_result_datum_buf_)); } else if (OB_UNLIKELY(!group_by_result_datum_buf_->is_use_extra_data())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected state", K(ret), KPC(group_by_result_datum_buf_)); } else { common::ObDatum *sql_result_datums = group_by_result_datum_buf_->get_basic_buf(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { if (OB_FAIL(sql_result_datums[i].from_storage_datum( group_by_result_datum_buf_->at(start + i), basic_info_.agg_expr_->obj_datum_map_))) { LOG_WARN("Failed to output extra buf", K(ret)); } } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(start), K(count), K(common::ObArrayWrap(sql_result_datums, count))); } return ret; } int ObAggCell::prepare_def_datum() { int ret = OB_SUCCESS; if (def_datum_.is_nop()) { def_datum_.reuse(); const ObObj &def_cell = basic_info_.col_param_->get_orig_default_value(); if (!def_cell.is_nop_value()) { if (OB_FAIL(def_datum_.from_obj_enhance(def_cell))) { STORAGE_LOG(WARN, "Failed to transfer obj to datum", K(ret)); } else if (def_cell.is_lob_storage() && !def_cell.is_null()) { // lob def value must have no lob header when not null, should add lob header for default value ObString data = def_datum_.get_string(); ObString out; if (OB_FAIL(ObLobManager::fill_lob_header(allocator_, data, out))) { LOG_WARN("failed to fill lob header for column.", K(ret), K(def_cell), K(data)); } else { def_datum_.set_string(out); } } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected, virtual column is not supported", K(ret), K(basic_info_.col_offset_)); } } return ret; } int ObAggCell::fill_default_if_need(blocksstable::ObStorageDatum &datum) { int ret = OB_SUCCESS; if (OB_ISNULL(basic_info_.col_param_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected, col param is null", K(ret), K(basic_info_.col_offset_)); } else if (datum.is_nop()) { if (OB_FAIL(prepare_def_datum())) { LOG_WARN("failed to prepare default datum", K(ret)); } else { datum.reuse(); const ObObjDatumMapType map_type = ObDatum::get_obj_datum_map_type(basic_info_.col_param_->get_meta_type().get_type()); if (OB_FAIL(datum.from_storage_datum(def_datum_, map_type))) { LOG_WARN("Failed to from storage datum", K(ret), K(def_datum_), K(datum), K(*this)); } } } return ret; } int ObAggCell::pad_column_if_need(blocksstable::ObStorageDatum &datum) { int ret = OB_SUCCESS; if (OB_ISNULL(basic_info_.col_param_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected, col param is null", K(ret), K(basic_info_.col_offset_)); } else if (OB_FAIL(pad_column(basic_info_.col_param_->get_meta_type(), basic_info_.col_param_->get_accuracy(), allocator_, datum))) { LOG_WARN("Fail to pad column", K(ret), K(basic_info_.col_offset_), KPC(this)); } return ret; } int ObAggCell::deep_copy_datum(const blocksstable::ObStorageDatum &src, common::ObIAllocator &tmp_alloc) { int ret = OB_SUCCESS; if (src.is_null() || src.is_nop()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected datum", K(ret), K(src)); } else { if (!result_datum_.is_local_buf()) { tmp_alloc.reuse(); } if (OB_FAIL(result_datum_.deep_copy(src, tmp_alloc))) { LOG_WARN("Failed to deep copy", K(ret), K(src), K(result_datum_)); } } return ret; } int ObAggCell::read_agg_datum( const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg, blocksstable::ObStorageDatum &agg_datum) { int ret = OB_SUCCESS; if (nullptr == agg_row_reader_) { void *buf = nullptr; if (OB_ISNULL(buf = allocator_.alloc(sizeof(blocksstable::ObAggRowReader)))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc agg row reader", K(ret)); } else { agg_row_reader_ = new (buf) blocksstable::ObAggRowReader(); } } if (OB_SUCC(ret)) { agg_datum.set_null(); blocksstable::ObSkipIndexColMeta meta; // TODO: @luhaopeng.lhp fix col_index in cg, use 0 temporarily meta.col_idx_ = is_cg ? 0 : static_cast(basic_info_.col_index_); switch (agg_type_) { case ObPDAggType::PD_COUNT: { meta.col_type_ = blocksstable::SK_IDX_NULL_COUNT; break; } case ObPDAggType::PD_MIN: { meta.col_type_ = blocksstable::SK_IDX_MIN; break; } case ObPDAggType::PD_MAX: { meta.col_type_ = blocksstable::SK_IDX_MAX; break; } default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected agg type", K(agg_type_)); } } agg_row_reader_->reset(); if (OB_FAIL(agg_row_reader_->init(index_info.agg_row_buf_, index_info.agg_buf_size_))) { LOG_WARN("Fail to init aggregate row reader", K(ret)); } else if (OB_FAIL(agg_row_reader_->read(meta, agg_datum))) { LOG_WARN("Failed read aggregate row", K(ret), K(meta)); } else if (ObPDAggType::PD_COUNT == agg_type_ && agg_datum.is_null()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected, agg_datum is null", K(ret), K(meta), K(index_info)); } } return ret; } struct ObDummyNumber { public: ObDummyNumber(int &cons_ret) { int ret = OB_SUCCESS; common::ObDataBuffer local_alloc0(number_local_buff0_, common::number::ObNumber::MAX_BYTE_LEN ); common::ObDataBuffer local_alloc1(number_local_buff1_, common::number::ObNumber::MAX_BYTE_LEN ); if (OB_FAIL(number_zero_.from(static_cast(0), local_alloc0))) { LOG_WARN("Failed to cons number from int", K(ret)); } else if (OB_FAIL(number_one_.from(static_cast(1), local_alloc1))) { LOG_WARN("Failed to cons number from int", K(ret)); } cons_ret = ret; } ~ObDummyNumber() {} static char number_local_buff0_[common::number::ObNumber::MAX_BYTE_LEN]; static char number_local_buff1_[common::number::ObNumber::MAX_BYTE_LEN]; static common::number::ObNumber number_zero_; static common::number::ObNumber number_one_; }; char ObDummyNumber::number_local_buff0_[common::number::ObNumber::MAX_BYTE_LEN]; char ObDummyNumber::number_local_buff1_[common::number::ObNumber::MAX_BYTE_LEN]; common::number::ObNumber ObDummyNumber::number_zero_; common::number::ObNumber ObDummyNumber::number_one_; ObCountAggCell::ObCountAggCell( const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator, bool exclude_null) : ObAggCell(basic_info, allocator), exclude_null_(exclude_null), row_count_(0) { agg_type_ = ObPDAggType::PD_COUNT; } void ObCountAggCell::reset() { ObAggCell::reset(); exclude_null_ = false; row_count_ = 0; } void ObCountAggCell::reuse() { ObAggCell::reuse(); row_count_ = 0; } int ObCountAggCell::init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) { int ret = OB_SUCCESS; if (exclude_null_) { if (OB_FAIL(ObAggCell::init(is_group_by, eval_ctx))) { LOG_WARN("Failed to init agg cell", K(ret)); } } else if (is_group_by) { common::ObDatum *result_datums = basic_info_.agg_expr_->locate_batch_datums(*eval_ctx); if (OB_ISNULL(result_datums)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "Unexpected null agg datums", K(ret)); } else if (OB_FAIL(new_group_by_buf(result_datums, basic_info_.batch_size_, common::OBJ_DATUM_NUMBER_RES_SIZE, allocator_, group_by_result_datum_buf_))) { LOG_WARN("Failed to new buf", K(ret)); } } if (OB_SUCC(ret) && is_group_by && lib::is_oracle_mode()) { static ObDummyNumber dummy(ret); if (OB_FAIL(ret)) { LOG_WARN("Failed to cons number from int", K(ret)); } } return ret; } int ObCountAggCell::eval(blocksstable::ObStorageDatum &datum, const int64_t row_count) { int ret = OB_SUCCESS; if (!exclude_null_) { row_count_ += row_count; } else if (OB_FAIL(fill_default_if_need(datum))) { LOG_WARN("Failed to fill default", K(ret), KPC(this)); } else if (!datum.is_null()) { row_count_ += row_count; } aggregated_ = true; LOG_DEBUG("after count row", K(ret), K(row_count), K(row_count_)); return ret; } int ObCountAggCell::eval_batch(const common::ObDatum *datums, const int64_t row_count) { int ret = OB_SUCCESS; if (OB_UNLIKELY(exclude_null_ || nullptr != datums)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("should not read data", K(ret), K(exclude_null_), KP(datums)); } else { row_count_ += row_count; } aggregated_ = true; LOG_DEBUG("after count batch", K(ret), K(row_count), K(row_count_)); return ret; } int ObCountAggCell::eval_micro_block( const int32_t col_offset, blocksstable::ObIMicroBlockReader *reader, const int64_t *row_ids, const int64_t row_count) { int ret = OB_SUCCESS; if (!exclude_null_) { row_count_ += row_count; } else { int64_t valid_row_count = 0; if (OB_ISNULL(row_ids)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected, row_ids is null", K(ret), KPC(this), K(row_count)); } else if (OB_FAIL(reader->get_row_count(col_offset, row_ids, row_count, false, valid_row_count))) { LOG_WARN("Failed to get row count from micro block decoder", K(ret), KPC(this), K(row_count)); } else { row_count_ += valid_row_count; } } aggregated_ = true; LOG_DEBUG("eval_micro_block", K(ret), K(row_count), K(row_count_)); return ret; } int ObCountAggCell::eval_index_info(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg) { int ret = OB_SUCCESS; if (!is_cg && (!index_info.can_blockscan(is_lob_col()) || index_info.is_left_border() || index_info.is_right_border())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected, the micro index info must can blockscan and not border", K(ret)); } else if (!exclude_null_) { row_count_ += index_info.get_row_count(); } else { blocksstable::ObStorageDatum null_count; if (OB_FAIL(read_agg_datum(index_info, is_cg, null_count))) { LOG_WARN("Failed to read agg row", K(ret)); } else { row_count_ += index_info.get_row_count() - null_count.get_int(); } } aggregated_ = true; LOG_DEBUG("eval_index_info", K(ret), K(index_info.get_row_count()), K(row_count_)); return ret; } template void eval_batch_for_count( const common::ObDatum *datums, const int64_t count, const uint32_t *refs, ObGroupByExtendableBuf *result_datums) {} template<> void eval_batch_for_count( const common::ObDatum *datums, const int64_t count, const uint32_t *refs, ObGroupByExtendableBuf *result_datums) { for (int64_t i = 0; i < count; ++i) { common::ObDatum &result_datum = result_datums->at(refs[i]); result_datum.set_int(result_datum.get_int() + 1); } } template<> void eval_batch_for_count( const common::ObDatum *datums, const int64_t count, const uint32_t *refs, ObGroupByExtendableBuf *result_datums) { for (int64_t i = 0; i < count; ++i) { common::ObDatum &result_datum = result_datums->at(refs[i]); if (!datums[i].is_null()) { result_datum.set_int(result_datum.get_int() + 1); } } } template<> void eval_batch_for_count( const common::ObDatum *datums, const int64_t count, const uint32_t *refs, ObGroupByExtendableBuf *result_datums) { for (int64_t i = 0; i < count; ++i) { common::ObDatum &result_datum = result_datums->at(refs[i]); if (!datums[refs[i]].is_null()) { result_datum.set_int(result_datum.get_int() + 1); } } } typedef void (*eval_batch_for_count_func) ( const common::ObDatum *datums, const int64_t count, const uint32_t *refs, ObGroupByExtendableBuf *result_datums); static eval_batch_for_count_func EVAL_BATCH_COUNT_FUNCS[2][2] = { {eval_batch_for_count, eval_batch_for_count}, {eval_batch_for_count, eval_batch_for_count} }; int ObCountAggCell::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, const bool is_default_datum) { int ret = OB_SUCCESS; if (OB_UNLIKELY(is_default_datum)) { const bool should_inc = !exclude_null_ || !datums[0].is_null(); if (should_inc) { for (int64_t i = 0; i < count; ++i) { common::ObDatum &result_datum = group_by_result_datum_buf_->at(refs[i]); result_datum.set_int(result_datum.get_int() + 1); } } } else { eval_batch_for_count_func eval_func = EVAL_BATCH_COUNT_FUNCS[exclude_null_][is_group_by_col]; eval_func(datums, count, refs, group_by_result_datum_buf_); } return ret; } int ObCountAggCell::copy_output_row(const int32_t datum_offset) { int ret = OB_SUCCESS; if (OB_UNLIKELY(datum_offset >= group_by_result_datum_buf_->get_basic_count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(datum_offset), KPC(group_by_result_datum_buf_)); } else { common::ObDatum &result_datum = group_by_result_datum_buf_->at(datum_offset); if (exclude_null_) { const common::ObDatum &datum = col_datums_[datum_offset]; if (!datum.is_null()) { lib::is_oracle_mode() ? result_datum.set_number(ObDummyNumber::number_one_) : result_datum.set_int(1); } else { lib::is_oracle_mode() ? result_datum.set_number(ObDummyNumber::number_zero_) : result_datum.set_int(0); } } else { lib::is_oracle_mode() ? result_datum.set_number(ObDummyNumber::number_one_) : result_datum.set_int(1); } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(datum_offset), K(result_datum)); } return ret; } int ObCountAggCell::copy_output_rows(const int32_t datum_offset) { int ret = OB_SUCCESS; if (OB_UNLIKELY(datum_offset > group_by_result_datum_buf_->get_basic_count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(datum_offset), KPC(group_by_result_datum_buf_)); } else { common::ObDatum *result_datums = group_by_result_datum_buf_->get_basic_buf(); if (exclude_null_) { if (lib::is_oracle_mode()) { for (int64_t i = 0; i < datum_offset; i++) { col_datums_[i].is_null() ? result_datums[i].set_number(ObDummyNumber::number_zero_) : result_datums[i].set_number(ObDummyNumber::number_one_); } } else { for (int64_t i = 0; i < datum_offset; i++) { col_datums_[i].is_null() ? result_datums[i].set_int(0) : result_datums[i].set_int(1); } } } else if (lib::is_oracle_mode()) { for (int64_t i = 0; i < datum_offset; i++) { result_datums[i].set_number(ObDummyNumber::number_one_); } } else { for (int64_t i = 0; i < datum_offset; i++) { result_datums[i].set_int(1); } } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(datum_offset), K(common::ObArrayWrap(col_datums_, datum_offset)), K(common::ObArrayWrap(result_datums, datum_offset))); } return ret; } int ObCountAggCell::collect_batch_result_in_group_by(const int64_t distinct_cnt) { int ret = OB_SUCCESS; if (OB_UNLIKELY(distinct_cnt > group_by_result_datum_buf_->get_capacity())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(distinct_cnt), KPC(group_by_result_datum_buf_)); } else if (lib::is_oracle_mode()) { common::number::ObNumber result_num; char local_buf[common::number::ObNumber::MAX_BYTE_LEN]; common::ObDataBuffer local_alloc(local_buf, common::number::ObNumber::MAX_BYTE_LEN); for (int64_t i = 0; OB_SUCC(ret) && i < distinct_cnt; ++i) { local_alloc.free(); common::ObDatum &result_datum = group_by_result_datum_buf_->at(i); const int64_t row_count = result_datum.get_int(); if (OB_FAIL(result_num.from(row_count, local_alloc))) { LOG_WARN("Failed to cons number from int", K(ret), K(row_count)); } else { result_datum.set_number(result_num); } } } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(distinct_cnt)); return ret; } int ObCountAggCell::collect_result(sql::ObEvalCtx &ctx, bool need_padding) { UNUSED(need_padding); int ret = OB_SUCCESS; ObDatum &result = basic_info_.agg_expr_->locate_datum_for_write(ctx); sql::ObEvalInfo &eval_info = basic_info_.agg_expr_->get_eval_info(ctx); if (lib::is_oracle_mode()) { common::number::ObNumber result_num; char local_buff[common::number::ObNumber::MAX_BYTE_LEN]; common::ObDataBuffer local_alloc(local_buff, common::number::ObNumber::MAX_BYTE_LEN); if (OB_FAIL(result_num.from(row_count_, local_alloc))) { LOG_WARN("Failed to cons number from int", K(ret), K(row_count_)); } else { result.set_number(result_num); eval_info.evaluated_ = true; } } else { result.set_int(row_count_); eval_info.evaluated_ = true; } LOG_DEBUG("collect_result", K(result), KPC(this)); return ret; } ObMinAggCell::ObMinAggCell(const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator) : ObAggCell(basic_info, allocator), group_by_ref_array_(nullptr), datum_allocator_("ObStorageAgg", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()) { agg_type_ =ObPDAggType::PD_MIN; cmp_fun_ = basic_info_.agg_expr_->basic_funcs_->null_first_cmp_; result_datum_.set_null(); } void ObMinAggCell::reset() { ObAggCell::reset(); if (nullptr != group_by_ref_array_) { allocator_.free(group_by_ref_array_); group_by_ref_array_ = nullptr; } datum_allocator_.reset(); } void ObMinAggCell::reuse() { ObAggCell::reuse(); datum_allocator_.reuse(); } int ObMinAggCell::eval(blocksstable::ObStorageDatum &storage_datum, const int64_t row_count) { UNUSED(row_count); int ret = OB_SUCCESS; int cmp_ret = 0; if (OB_FAIL(fill_default_if_need(storage_datum))) { LOG_WARN("Failed to fill default", K(ret), K(storage_datum), K(*this)); } else if (storage_datum.is_null()) { } else if (result_datum_.is_null()) { if (OB_FAIL(result_datum_.deep_copy(storage_datum, datum_allocator_))) { LOG_WARN("Failed to deep copy datum", K(ret), K(storage_datum), K(basic_info_.col_offset_)); } } else if (OB_FAIL(cmp_fun_(result_datum_, storage_datum, cmp_ret))) { LOG_WARN("Failed to compare", K(ret), K(result_datum_), K(storage_datum)); } else if (cmp_ret > 0 && OB_FAIL(deep_copy_datum(storage_datum, datum_allocator_))) { LOG_WARN("Failed to deep copy datum", K(ret), K(storage_datum), K(result_datum_), K(basic_info_.col_offset_)); } aggregated_ = true; return ret; } int ObMinAggCell::eval_batch(const common::ObDatum *datums, const int64_t count) { int ret = OB_SUCCESS; if (OB_ISNULL(cmp_fun_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected null cmp fun", K(ret)); } else { int cmp_ret = 0; blocksstable::ObStorageDatum tmp_min_datum; tmp_min_datum.set_null(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { const common::ObDatum &datum = datums[i]; if (datum.is_null()) { } else if (tmp_min_datum.is_null()) { tmp_min_datum.shallow_copy_from_datum(datum); } else if (OB_FAIL(cmp_fun_(tmp_min_datum, datum, cmp_ret))) { LOG_WARN("Failed to compare", K(ret), K(tmp_min_datum), K(datum)); } else if (cmp_ret > 0) { tmp_min_datum.shallow_copy_from_datum(datum); } } if (OB_FAIL(ret) || tmp_min_datum.is_null()) { } else if (result_datum_.is_null()) { if (OB_FAIL(deep_copy_datum(tmp_min_datum, datum_allocator_))) { LOG_WARN("Failed to deep copy datum", K(ret), K(tmp_min_datum), K(result_datum_), K(basic_info_.col_offset_)); } } else if (OB_FAIL(cmp_fun_(result_datum_, tmp_min_datum, cmp_ret))) { LOG_WARN("Failed to compare", K(ret), K(result_datum_), K(tmp_min_datum)); } else if (cmp_ret > 0) { if (OB_FAIL(deep_copy_datum(tmp_min_datum, datum_allocator_))) { LOG_WARN("Failed to deep copy datum", K(ret), K(tmp_min_datum), K(result_datum_), K(basic_info_.col_offset_)); } } } aggregated_ = true; return ret; } int ObMinAggCell::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, const bool is_default_datum) { int ret = OB_SUCCESS; if (OB_UNLIKELY(count > basic_info_.batch_size_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(count), K(basic_info_.batch_size_)); } else if (OB_UNLIKELY(nullptr == cmp_fun_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected state", K(ret), KP(cmp_fun_)); } else { const bool read_distinct_val = is_group_by_col || is_default_datum; const bool need_deep_copy = !read_distinct_val && OBJ_DATUM_STRING == basic_info_.agg_expr_->obj_datum_map_; if (need_deep_copy && nullptr == group_by_ref_array_) { void *buf = nullptr; if (OB_ISNULL(buf = allocator_.alloc(sizeof(uint32_t) * basic_info_.batch_size_))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memory", K(ret), K(basic_info_.batch_size_)); } else { group_by_ref_array_ = static_cast(buf); MEMSET(group_by_ref_array_, -1, basic_info_.batch_size_); } } int64_t updated_cnt = 0; for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { const uint32_t distinct_ref = refs[i]; const uint32_t dictinct_datum_offset = is_default_datum ? 0 : refs[i]; const common::ObDatum &datum = read_distinct_val ? datums[dictinct_datum_offset] : datums[i]; if (datum.is_null()) { } else { common::ObDatum &result_datum = group_by_result_datum_buf_->at(distinct_ref); int cmp_ret = 0; if (!result_datum.is_null() && OB_FAIL(cmp_fun_(result_datum, datum, cmp_ret))) { LOG_WARN("Failed to cmp", K(ret), K(result_datum), K(datum)); } else if (result_datum.is_null() || cmp_ret > 0) { // This function may be invoked for many times in one micro block, // so instead of '=', it's needed to use 'from_storage_datum' to avoid overrided prevous memory of datum if (OB_FAIL(result_datum.from_storage_datum(datum, basic_info_.agg_expr_->obj_datum_map_))) { LOG_WARN("Failed to clone datum", K(ret), K(datum), K(basic_info_.agg_expr_->obj_datum_map_)); } else if (need_deep_copy) { group_by_ref_array_[updated_cnt++] = distinct_ref; } } } } // deep copy updated distinct values // as there is no guarantee of the validness of the previous memory in next round if (OB_FAIL(ret)) { } else if (updated_cnt > 0) { std::sort(group_by_ref_array_, group_by_ref_array_ + updated_cnt); int64_t last_ref_cnt = -1; for (int64_t i = 0; OB_SUCC(ret) && i < updated_cnt; ++i) { if (-1 == group_by_ref_array_[i]) { } else if (last_ref_cnt == group_by_ref_array_[i]) { group_by_ref_array_[i] = -1; } else { common::ObDatum &result_datum = group_by_result_datum_buf_->at(group_by_ref_array_[i]); if (OB_FAIL(result_datum.deep_copy(result_datum, datum_allocator_))) { LOG_WARN("Failed to deep copy distinct datum", K(ret)); } else { last_ref_cnt = group_by_ref_array_[i]; group_by_ref_array_[i] = -1; } } } } } return ret; } ObMaxAggCell::ObMaxAggCell(const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator) : ObAggCell(basic_info, allocator), group_by_ref_array_(nullptr), datum_allocator_("ObStorageAgg", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()) { agg_type_ = ObPDAggType::PD_MAX; cmp_fun_ = basic_info_.agg_expr_->basic_funcs_->null_first_cmp_; result_datum_.set_null(); } void ObMaxAggCell::reset() { ObAggCell::reset(); if (nullptr != group_by_ref_array_) { allocator_.free(group_by_ref_array_); group_by_ref_array_ = nullptr; } datum_allocator_.reset(); } void ObMaxAggCell::reuse() { ObAggCell::reuse(); datum_allocator_.reuse(); } int ObMaxAggCell::eval(blocksstable::ObStorageDatum &storage_datum, const int64_t row_count) { UNUSED(row_count); int ret = OB_SUCCESS; int cmp_ret = 0; if (OB_FAIL(fill_default_if_need(storage_datum))) { LOG_WARN("Failed to fill default", K(ret), K(storage_datum), K(*this)); } else if (storage_datum.is_null()) { } else if (result_datum_.is_null()) { if (OB_FAIL(result_datum_.deep_copy(storage_datum, datum_allocator_))) { LOG_WARN("Failed to deep copy datum", K(ret), K(storage_datum), K(basic_info_.col_offset_)); } } else if (OB_FAIL(cmp_fun_(result_datum_, storage_datum, cmp_ret))) { LOG_WARN("Failed to compare", K(ret), K(result_datum_), K(storage_datum)); } else if (cmp_ret < 0 && OB_FAIL(deep_copy_datum(storage_datum, datum_allocator_))) { LOG_WARN("Failed to deep copy datum", K(ret), K(storage_datum), K(result_datum_), K(basic_info_.col_offset_)); } aggregated_ = true; return ret; } int ObMaxAggCell::eval_batch(const common::ObDatum *datums, const int64_t count) { int ret = OB_SUCCESS; if (OB_ISNULL(cmp_fun_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected null cmp fun", K(ret)); } else { int cmp_ret = 0; blocksstable::ObStorageDatum tmp_min_datum; tmp_min_datum.set_null(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { const common::ObDatum &datum = datums[i]; if (datum.is_null()) { } else if (tmp_min_datum.is_null()) { tmp_min_datum.shallow_copy_from_datum(datum); } else if (OB_FAIL(cmp_fun_(tmp_min_datum, datum, cmp_ret))) { LOG_WARN("Failed to compare", K(ret), K(tmp_min_datum), K(datum)); } else if (cmp_ret < 0) { tmp_min_datum.shallow_copy_from_datum(datum); } } if (OB_FAIL(ret) || tmp_min_datum.is_null()) { } else if (result_datum_.is_null()) { if (OB_FAIL(deep_copy_datum(tmp_min_datum, datum_allocator_))) { LOG_WARN("Failed to deep copy datum", K(ret), K(tmp_min_datum), K(result_datum_), K(basic_info_.col_offset_)); } } else if (OB_FAIL(cmp_fun_(result_datum_, tmp_min_datum, cmp_ret))) { LOG_WARN("Failed to compare", K(ret), K(result_datum_), K(tmp_min_datum)); } else if (cmp_ret < 0) { if (OB_FAIL(deep_copy_datum(tmp_min_datum, datum_allocator_))) { LOG_WARN("Failed to deep copy datum", K(ret), K(tmp_min_datum), K(result_datum_), K(basic_info_.col_offset_)); } } } aggregated_ = true; return ret; } int ObMaxAggCell::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, const bool is_default_datum) { int ret = OB_SUCCESS; if (OB_UNLIKELY(count > basic_info_.batch_size_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(count), K(basic_info_.batch_size_)); } else if (OB_UNLIKELY(nullptr == cmp_fun_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected state", K(ret), KP(cmp_fun_)); } else { const bool read_distinct_val = is_group_by_col || is_default_datum; const bool need_deep_copy = !read_distinct_val && OBJ_DATUM_STRING == basic_info_.agg_expr_->obj_datum_map_; if (need_deep_copy && nullptr == group_by_ref_array_) { void *buf = nullptr; if (OB_ISNULL(buf = allocator_.alloc(sizeof(uint32_t) * basic_info_.batch_size_))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memory", K(ret), K(basic_info_.batch_size_)); } else { group_by_ref_array_ = static_cast(buf); MEMSET(group_by_ref_array_, -1, basic_info_.batch_size_); } } int64_t updated_cnt = 0; for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { const uint32_t distinct_ref = refs[i]; const uint32_t dictinct_datum_offset = is_default_datum ? 0 : refs[i]; const common::ObDatum &datum = read_distinct_val ? datums[dictinct_datum_offset] : datums[i]; if (datum.is_null()) { } else { common::ObDatum &result_datum = group_by_result_datum_buf_->at(distinct_ref); int cmp_ret = 0; if (!result_datum.is_null() && OB_FAIL(cmp_fun_(result_datum, datum, cmp_ret))) { LOG_WARN("Failed to cmp", K(ret), K(result_datum), K(datum)); } else if (result_datum.is_null() || cmp_ret < 0) { if (OB_FAIL(result_datum.from_storage_datum(datum, basic_info_.agg_expr_->obj_datum_map_))) { LOG_WARN("Failed to clone datum", K(ret), K(datum), K(basic_info_.agg_expr_->obj_datum_map_)); } else if (need_deep_copy) { group_by_ref_array_[updated_cnt++] = distinct_ref; } } } } if (OB_FAIL(ret)) { } else if (updated_cnt > 0) { std::sort(group_by_ref_array_, group_by_ref_array_ + updated_cnt); int64_t last_ref_cnt = -1; for (int64_t i = 0; OB_SUCC(ret) && i < updated_cnt; ++i) { if (-1 == group_by_ref_array_[i]) { } else if (last_ref_cnt == group_by_ref_array_[i]) { group_by_ref_array_[i] = -1; } else { common::ObDatum &result_datum = group_by_result_datum_buf_->at(group_by_ref_array_[i]); if (OB_FAIL(result_datum.deep_copy(result_datum, datum_allocator_))) { LOG_WARN("Failed to deep copy distinct datum", K(ret)); } else { last_ref_cnt = group_by_ref_array_[i]; group_by_ref_array_[i] = -1; } } } } } return ret; } ObSumAggCell::ObSumAggCell(const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator) : ObAggCell(basic_info, allocator), obj_tc_(ObNullTC), sum_use_int_flag_(false), is_sum_use_temp_buf_(false), num_int_(0), sum_use_int_flag_buf_(nullptr), num_buf_(nullptr), eval_func_(nullptr), eval_batch_func_(nullptr), copy_datum_func_(nullptr), sum_temp_buffer_(nullptr) { agg_type_ = ObPDAggType::PD_SUM; result_datum_.set_null(); } void ObSumAggCell::reset() { obj_tc_ = ObNullTC; sum_use_int_flag_ = false; num_int_ = 0; free_group_by_buf(allocator_, sum_use_int_flag_buf_); free_group_by_buf(allocator_, num_int_buf_); eval_func_ = nullptr; eval_batch_func_ = nullptr; copy_datum_func_ = nullptr; if (is_sum_use_temp_buf_) { allocator_.free(sum_temp_buffer_); sum_temp_buffer_ = nullptr; is_sum_use_temp_buf_ = false; } ObAggCell::reset(); } void ObSumAggCell::reuse() { ObAggCell::reuse(); if (is_sum_use_temp_buf_) { result_datum_.ptr_ = sum_temp_buffer_; } sum_use_int_flag_ = false; num_int_ = 0; // reset_aggregate_info(); } void ObSumAggCell::clear_group_by_info() { if (nullptr != sum_use_int_flag_buf_) { sum_use_int_flag_buf_->fill_items(false); } if (nullptr != num_int_buf_) { num_int_buf_->fill_items(0); } } void ObSumAggCell::reset_aggregate_info() { if (nullptr != group_by_result_datum_buf_) { ObDatum *datums = group_by_result_datum_buf_->get_basic_buf(); for (int64_t i = 0; i < group_by_result_datum_buf_->get_basic_count(); ++i) { datums[i].set_null(); } if (sum_use_int_flag_buf_->get_basic_count() > 0) { MEMSET(sum_use_int_flag_buf_->get_basic_buf(), false, sizeof(bool) * sum_use_int_flag_buf_->get_basic_count()); } if (num_int_buf_->get_basic_count() > 0) { MEMSET(num_int_buf_->get_basic_buf(), 0, sizeof(int64_t) * num_int_buf_->get_basic_count()); } } } int ObSumAggCell::init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) { int ret = OB_SUCCESS; if (OB_UNLIKELY(nullptr == basic_info_.agg_expr_->args_ || nullptr == basic_info_.agg_expr_->args_[0] || T_REF_COLUMN != basic_info_.agg_expr_->args_[0]->type_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("args is NULL", K(ret), KPC(basic_info_.agg_expr_)); } else if (OB_FAIL(ObAggCell::init(is_group_by, eval_ctx))) { LOG_WARN("Failed to init agg cell", K(ret)); } else { obj_tc_ = ob_obj_type_class(basic_info_.agg_expr_->args_[0]->datum_meta_.type_); const ObObjTypeClass res_tc = ob_obj_type_class(basic_info_.agg_expr_->datum_meta_.type_); const int16_t precision = basic_info_.agg_expr_->datum_meta_.precision_; switch (obj_tc_) { case ObObjTypeClass::ObIntTC: { switch (res_tc) { case ObObjTypeClass::ObNumberTC: { eval_func_ = &ObSumAggCell::eval_int; eval_batch_func_ = &ObSumAggCell::eval_int_batch; copy_datum_func_ = &ObSumAggCell::copy_int_to_number; break; } case ObObjTypeClass::ObDecimalIntTC: { if (OB_UNLIKELY(precision < OB_DECIMAL_LONGLONG_DIGITS || precision > MAX_PRECISION_DECIMAL_INT_256)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected precision", K(ret), K(precision)); } else if (precision <= MAX_PRECISION_DECIMAL_INT_128) { eval_func_ = &ObSumAggCell::eval_int; eval_batch_func_ = &ObSumAggCell::eval_int_batch; copy_datum_func_ = &ObSumAggCell::copy_int_to_decimal_int; } else { eval_func_ = &ObSumAggCell::eval_int; eval_batch_func_ = &ObSumAggCell::eval_int_batch; copy_datum_func_ = &ObSumAggCell::copy_int_to_decimal_int; } break; } default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected type", K(ret), K(obj_tc_)); break; } } break; } case ObObjTypeClass::ObUIntTC: { switch (res_tc) { case ObObjTypeClass::ObNumberTC: { eval_func_ = &ObSumAggCell::eval_uint; eval_batch_func_ = &ObSumAggCell::eval_uint_batch; copy_datum_func_ = &ObSumAggCell::copy_uint_to_number; break; } case ObObjTypeClass::ObDecimalIntTC: { if (OB_UNLIKELY(precision < OB_DECIMAL_LONGLONG_DIGITS || precision > MAX_PRECISION_DECIMAL_INT_256)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected precision", K(ret), K(precision)); } else if (precision <= MAX_PRECISION_DECIMAL_INT_128) { eval_func_ = &ObSumAggCell::eval_uint; eval_batch_func_ = &ObSumAggCell::eval_uint_batch; copy_datum_func_ = &ObSumAggCell::copy_uint_to_decimal_int; } else { eval_func_ = &ObSumAggCell::eval_uint; eval_batch_func_ = &ObSumAggCell::eval_uint_batch; copy_datum_func_ = &ObSumAggCell::copy_uint_to_decimal_int; } break; } default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected type", K(ret), K(obj_tc_)); break; } } break; } case ObObjTypeClass::ObFloatTC: { eval_func_ = &ObSumAggCell::eval_float; eval_batch_func_ = &ObSumAggCell::eval_float_batch; copy_datum_func_ = &ObSumAggCell::copy_float; break; } case ObObjTypeClass::ObDoubleTC: { eval_func_ = &ObSumAggCell::eval_double; eval_batch_func_ = &ObSumAggCell::eval_double_batch; copy_datum_func_ = &ObSumAggCell::copy_double; break; } case ObObjTypeClass::ObNumberTC: { eval_func_ = &ObSumAggCell::eval_number; eval_batch_func_ = &ObSumAggCell::eval_number_batch; copy_datum_func_ = &ObSumAggCell::copy_number; break; } case ObObjTypeClass::ObDecimalIntTC: { ret = ObSumAggCell::init_decimal_int_func(); break; } default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected type", K(ret), K(obj_tc_)); break; } } } if (OB_SUCC(ret) && is_group_by) { const int64_t datum_size = is_sum_use_temp_buf_ ? common::OBJ_DATUM_DECIMALINT_MAX_RES_SIZE : common::OBJ_DATUM_NUMBER_RES_SIZE; group_by_result_datum_buf_->set_item_size(datum_size); if (ObObjTypeClass::ObIntTC == obj_tc_ || ObObjTypeClass::ObUIntTC == obj_tc_) { if (OB_FAIL(new_group_by_buf((bool*)nullptr, 0, sizeof(bool), allocator_, sum_use_int_flag_buf_))) { LOG_WARN("Failed to new buf", K(ret)); } else if (OB_FAIL(sum_use_int_flag_buf_->reserve(basic_info_.batch_size_))) { LOG_WARN("Failed to reserve buf", K(ret)); } else if (OB_FAIL(new_group_by_buf((int64_t*)(nullptr), 0, sizeof(int64_t), allocator_, num_int_buf_))) { LOG_WARN("Failed to new buf", K(ret)); } else if (OB_FAIL(num_int_buf_->reserve(basic_info_.batch_size_))) { LOG_WARN("Failed to new buf", K(ret)); } } } return ret; } int ObSumAggCell::init_decimal_int_func() { int ret = OB_SUCCESS; // The sum aggregation function will increase the precision by 22. Based on this rule, // we can get the mapping of each input to output: // a. int32_t [0 - 9] => result precision range [22 - 31], which always be int128_t. // b. int64_t [10 - 18] => result P range [32, 40], which can be int128_t or int256_t. // c. int128_t [19 - 38] => result P range [41, 60], which always be int256. // d. int256_t [39 - 76] => result P range [61, 98], which can be int256_t or int512_t. const static ObSumEvalAggFuncType AGG_FUNCS[][3] = { // int32_t { &ObSumAggCell::eval_decimal_int, nullptr, &ObSumAggCell::eval_decimal_int_number }, // int64_t { &ObSumAggCell::eval_decimal_int, &ObSumAggCell::eval_decimal_int, &ObSumAggCell::eval_decimal_int_number }, // int128_t { &ObSumAggCell::eval_decimal_int, nullptr, &ObSumAggCell::eval_decimal_int_number }, // int256_t { &ObSumAggCell::eval_decimal_int, &ObSumAggCell::eval_decimal_int, &ObSumAggCell::eval_decimal_int_number } }; const static ObSumCopyDatumFuncType COPY_FUNCS[][3] = { // int32_t { &ObSumAggCell::copy_decimal_int, nullptr, &ObSumAggCell::copy_decimal_int_to_number }, // int64_t { &ObSumAggCell::copy_decimal_int, &ObSumAggCell::copy_decimal_int, &ObSumAggCell::copy_decimal_int_to_number }, // int128_t { &ObSumAggCell::copy_decimal_int, nullptr, &ObSumAggCell::copy_decimal_int_to_number }, // int256_t { &ObSumAggCell::copy_decimal_int, &ObSumAggCell::copy_decimal_int, &ObSumAggCell::copy_decimal_int_to_number } }; const static ObSumEvalBatchAggFuncType AGG_BATCH_FUNCS[][3][2] = { // int32_t { { &ObSumAggCell::eval_decimal_int_batch, &ObSumAggCell::eval_decimal_int_batch }, { nullptr, nullptr,}, { &ObSumAggCell::eval_decimal_int_number_batch, &ObSumAggCell::eval_decimal_int_number_batch } }, // int64_t { { &ObSumAggCell::eval_decimal_int_batch, &ObSumAggCell::eval_decimal_int_batch }, { &ObSumAggCell::eval_decimal_int_batch, &ObSumAggCell::eval_decimal_int_batch }, { &ObSumAggCell::eval_decimal_int_number_batch, &ObSumAggCell::eval_decimal_int_number_batch } }, // int128_t { { &ObSumAggCell::eval_decimal_int_batch, &ObSumAggCell::eval_decimal_int_batch }, { nullptr, nullptr,}, { &ObSumAggCell::eval_decimal_int_number_batch, &ObSumAggCell::eval_decimal_int_number_batch } }, // int256_t { { &ObSumAggCell::eval_decimal_int_batch, nullptr }, { &ObSumAggCell::eval_decimal_int_batch, nullptr }, { &ObSumAggCell::eval_decimal_int_number_batch, nullptr } } }; const ObObjTypeClass res_tc = ob_obj_type_class(basic_info_.agg_expr_->datum_meta_.type_); const int16_t arg_prec = basic_info_.agg_expr_->args_[0]->datum_meta_.precision_; const int16_t res_prec = basic_info_.agg_expr_->datum_meta_.precision_; const int16_t buffer_prec = get_max_decimalint_precision(arg_prec) - arg_prec; const int arg_type = static_cast(get_decimalint_type(arg_prec)); const bool need_cast = (buffer_prec < MAX_PRECISION_DECIMAL_INT_64) && get_scale_factor(buffer_prec) < basic_info_.batch_size_; if (ObObjTypeClass::ObNumberTC == res_tc) { eval_func_ = AGG_FUNCS[arg_type][2]; eval_batch_func_ = AGG_BATCH_FUNCS[arg_type][2][need_cast]; copy_datum_func_ = COPY_FUNCS[arg_type][2]; } else { const int res_type = static_cast(get_decimalint_type(res_prec)); int res_func_idx = 0; if (OB_UNLIKELY(res_prec < arg_prec || res_prec - arg_prec > OB_DECIMAL_LONGLONG_DIGITS)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected precision", K(ret), K(arg_prec), K(res_prec)); } else { switch (arg_type) { case DECIMAL_INT_32: case DECIMAL_INT_128: res_func_idx = 0; break; case DECIMAL_INT_64: res_func_idx = res_type == DECIMAL_INT_128 ? 0 : 1; break; case DECIMAL_INT_256: res_func_idx = res_type == DECIMAL_INT_256 ? 0 : 1; break; default: ret = OB_ERR_UNEXPECTED; } if (OB_SUCC(ret)) { eval_func_ = AGG_FUNCS[arg_type][res_func_idx]; eval_batch_func_ = AGG_BATCH_FUNCS[arg_type][res_func_idx][need_cast]; copy_datum_func_ = COPY_FUNCS[arg_type][res_func_idx]; } } } if (OB_SUCC(ret)) { if (OB_ISNULL(eval_func_) || OB_ISNULL(eval_batch_func_) || OB_ISNULL(copy_datum_func_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("function does not init", K(ret), K(*this)); } else if (res_prec > MAX_PRECISION_DECIMAL_INT_256) { // Special scenarios: ObStorageDatum can only store 40 bytes, and int512 has 64 bytes, // so need to allocate temporary memory to store result is_sum_use_temp_buf_ = true; if (OB_ISNULL(sum_temp_buffer_ = static_cast(allocator_.alloc(sizeof(int512_t))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc memory", K(ret)); } else { result_datum_.ptr_ = sum_temp_buffer_; } } } return ret; } int ObSumAggCell::eval(blocksstable::ObStorageDatum &datum, const int64_t row_count) { UNUSED(row_count); int ret = OB_SUCCESS; if (OB_FAIL(fill_default_if_need(datum))) { LOG_WARN("Failed to fill default", K(ret), K(datum), KPC(this)); } else if (datum.is_null()) { } else { for (int64_t i = 0; OB_SUCC(ret) && i < row_count; ++i) { if (OB_FAIL((this->*eval_func_)(datum, DEFAULT_DATUM_OFFSET))) { LOG_WARN("Fail to eval", K(ret), K(obj_tc_)); } } } aggregated_ = true; LOG_DEBUG("after process rows", KPC(this)); return ret; } int ObSumAggCell::eval_batch(const common::ObDatum *datums, const int64_t count) { int ret = OB_SUCCESS; if (OB_FAIL((this->*eval_batch_func_)(datums, count))) { LOG_WARN("Failed to eval batch", K(ret)); } aggregated_ = true; return ret; } int ObSumAggCell::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, const bool is_default_datum) { int ret = OB_SUCCESS; if (OB_UNLIKELY(nullptr == datums || count <= 0 || nullptr == refs || distinct_cnt <= 0)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), KP(datums), K(count), KP(refs), K(distinct_cnt)); } else { const bool read_distinct_val = is_group_by_col || is_default_datum; for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { const uint32_t dictinct_datum_offset = is_default_datum ? 0 : refs[i]; const common::ObDatum &datum = read_distinct_val ? datums[dictinct_datum_offset] : datums[i]; if (datum.is_null()) { } else if (OB_FAIL((this->*eval_func_)(datum, refs[i]))) { LOG_WARN("Fail to eval", K(ret), K(obj_tc_)); } } } return ret; } int ObSumAggCell::copy_output_row(const int32_t datum_offset) { int ret = OB_SUCCESS; if (OB_UNLIKELY(datum_offset >= group_by_result_datum_buf_->get_basic_count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(datum_offset), KPC(group_by_result_datum_buf_)); } else { const common::ObDatum &datum = col_datums_[datum_offset]; common::ObDatum *result_datums = group_by_result_datum_buf_->get_basic_buf(); if (datum.is_null()) { result_datums[datum_offset].set_null(); } else if (OB_FAIL((this->*copy_datum_func_)(datum, result_datums[datum_offset]))) { LOG_WARN("Failed to copy output datum", K(ret)); } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(datum_offset), K(datum), K(result_datums[datum_offset])); } return ret; } int ObSumAggCell::copy_output_rows(const int32_t datum_offset) { int ret = OB_SUCCESS; if (OB_UNLIKELY(datum_offset > group_by_result_datum_buf_->get_basic_count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(datum_offset), KPC(group_by_result_datum_buf_)); } else { common::ObDatum *result_datums = group_by_result_datum_buf_->get_basic_buf(); for (int64_t i = 0; OB_SUCC(ret) && i < datum_offset; ++i) { const common::ObDatum &datum = col_datums_[i]; if (datum.is_null()) { result_datums[i].set_null(); } else if (OB_FAIL((this->*copy_datum_func_)(datum, result_datums[i]))) { LOG_WARN("Failed to copy output datum", K(ret)); } } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(datum_offset), K(common::ObArrayWrap(col_datums_, datum_offset)), K(common::ObArrayWrap(result_datums, datum_offset))); } return ret; } int ObSumAggCell::copy_int_to_number(const ObDatum &datum, ObDatum &result_datum) { int ret = OB_SUCCESS; sql::ObNumStackAllocator<1> tmp_alloc; common::number::ObNumber nmb; if (OB_FAIL(nmb.from(datum.get_int(), tmp_alloc))) { LOG_WARN("create number from int failed", K(ret)); } else { result_datum.set_number(nmb); } return ret; } template int ObSumAggCell::copy_int_to_decimal_int(const ObDatum &datum, ObDatum &result_datum) { int ret = OB_SUCCESS; if (datum.is_null()) { result_datum.set_null(); } else { DATUM_TO_DECIMAL_INT(result_datum, RES_T) = datum.get_int(); result_datum.pack_ = sizeof(RES_T); } return ret; } int ObSumAggCell::copy_uint_to_number(const ObDatum &datum, ObDatum &result_datum) { int ret = OB_SUCCESS; sql::ObNumStackAllocator<1> tmp_alloc; common::number::ObNumber nmb; if (OB_FAIL(nmb.from(datum.get_uint(), tmp_alloc))) { LOG_WARN("create number from int failed", K(ret)); } else { result_datum.set_number(nmb); } return ret; } template int ObSumAggCell::copy_uint_to_decimal_int(const ObDatum &datum, ObDatum &result_datum) { int ret = OB_SUCCESS; DATUM_TO_DECIMAL_INT(result_datum, RES_T) = datum.get_uint(); result_datum.pack_ = sizeof(RES_T); return ret; } int ObSumAggCell::copy_float(const ObDatum &datum, ObDatum &result_datum) { int ret = OB_SUCCESS; result_datum.set_float(datum.get_float()); return ret; } int ObSumAggCell::copy_double(const ObDatum &datum, ObDatum &result_datum) { int ret = OB_SUCCESS; result_datum.set_double(datum.get_double()); return ret; } int ObSumAggCell::copy_number(const ObDatum &datum, ObDatum &result_datum) { int ret = OB_SUCCESS; result_datum.set_number(datum.get_number()); return ret; } template int ObSumAggCell::copy_decimal_int(const ObDatum &datum, ObDatum &result_datum) { int ret = OB_SUCCESS; DATUM_TO_DECIMAL_INT(result_datum, RES_T) = DATUM_TO_CONST_DECIMAL_INT(datum, ARG_T); result_datum.pack_ = sizeof(RES_T); return ret; } template int ObSumAggCell::copy_decimal_int_to_number(const ObDatum &datum, ObDatum &result_datum) { int ret = OB_SUCCESS; sql::ObNumStackAllocator<2> tmp_alloc; number::ObNumber right_nmb; if (OB_FAIL(wide::to_number(DATUM_TO_CONST_DECIMAL_INT(datum, ARG_T), child_scale(), tmp_alloc, right_nmb))) { LOG_WARN("fail to cast decimal int to number", K(ret)); } else { result_datum.set_number(right_nmb); } return ret; } int ObSumAggCell::collect_batch_result_in_group_by(const int64_t distinct_cnt) { int ret = OB_SUCCESS; if (OB_UNLIKELY(distinct_cnt > group_by_result_datum_buf_->get_capacity())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(distinct_cnt), KPC(group_by_result_datum_buf_)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < distinct_cnt; ++i) { if (OB_FAIL(collect_result_in_group_by(i))) { LOG_WARN("Failed to collect result in group by", K(ret)); } } } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(distinct_cnt)); return ret; } int ObSumAggCell::collect_result(sql::ObEvalCtx &ctx, bool need_padding) { int ret = OB_SUCCESS; ObDatum &result = basic_info_.agg_expr_->locate_datum_for_write(ctx); sql::ObEvalInfo &eval_info = basic_info_.agg_expr_->get_eval_info(ctx); if (!sum_use_int_flag_) { if (OB_FAIL(ObAggCell::collect_result(ctx, need_padding))) { LOG_WARN("Failed to collect_result", K(ret), KPC(this)); } } else if (ObIntTC != obj_tc_ && ObUIntTC != obj_tc_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected type class", K(ret), K(obj_tc_)); } else if (ob_is_decimal_int(basic_info_.agg_expr_->datum_meta_.type_)) { int128_t right_nmb = 0; if (ObIntTC == obj_tc_) { right_nmb = num_int_; } else { right_nmb = num_uint_; } if (OB_FAIL(collect_result_to_decimal_int(right_nmb, result_datum_, result))) { LOG_WARN("Failed to collect result to decimal int", K(ret)); } else { eval_info.evaluated_ = true; } } else { sql::ObNumStackAllocator<2> tmp_alloc; common::number::ObNumber right_nmb; const bool strict_mode = false; //this is tmp allocator, so we can ues non-strinct mode if (ObIntTC == obj_tc_) { if (OB_FAIL(right_nmb.from(num_int_, tmp_alloc))) { LOG_WARN("create number from int failed", K(ret), K(right_nmb), K(obj_tc_)); } } else if (OB_FAIL(right_nmb.from(num_uint_, tmp_alloc))) { LOG_WARN("create number from int failed", K(ret), K(right_nmb), K(obj_tc_)); } if (OB_SUCC(ret)) { if (result_datum_.is_null()) { result.set_number(right_nmb); } else { common::number::ObNumber left_nmb(result_datum_.get_number()); common::number::ObNumber result_nmb; if (OB_FAIL(left_nmb.add_v3(right_nmb, result_nmb, tmp_alloc, strict_mode))) { LOG_WARN("number add failed", K(ret), K(left_nmb), K(right_nmb)); } else { result.set_number(result_nmb); } } eval_info.evaluated_ = true; } } LOG_DEBUG("collect_result", K(result), KPC(this)); return ret; } template int ObSumAggCell::eval_int(const common::ObDatum &datum, const int32_t datum_offset) { int ret = OB_SUCCESS; char buf_alloc[common::number::ObNumber::MAX_CALC_BYTE_LEN]; ObDataBuffer allocator(buf_alloc, common::number::ObNumber::MAX_CALC_BYTE_LEN); if (OB_FAIL(eval_int_inner(datum, allocator, datum_offset))) { LOG_WARN("Failed to eval int", K(ret)); } return ret; } template int ObSumAggCell::eval_uint(const common::ObDatum &datum, const int32_t datum_offset) { int ret = OB_SUCCESS; char buf_alloc[common::number::ObNumber::MAX_CALC_BYTE_LEN]; ObDataBuffer allocator(buf_alloc, common::number::ObNumber::MAX_CALC_BYTE_LEN); if (OB_FAIL(eval_uint_inner(datum, allocator, datum_offset))) { LOG_WARN("Failed to eval uint", K(ret)); } return ret; } int ObSumAggCell::eval_float(const common::ObDatum &datum, const int32_t datum_offset) { return eval_float_inner(datum, datum_offset); } int ObSumAggCell::eval_double(const common::ObDatum &datum, const int32_t datum_offset) { return eval_double_inner(datum, datum_offset); } int ObSumAggCell::eval_number(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_number(datum.get_number()); } else { common::number::ObNumber left_nmb(result_datum.get_number()); common::number::ObNumber right_nmb(datum.get_number()); char buf_alloc[common::number::ObNumber::MAX_CALC_BYTE_LEN]; ObDataBuffer allocator(buf_alloc, common::number::ObNumber::MAX_CALC_BYTE_LEN); const bool strict_mode = false; //this is tmp allocator, so we can ues non-strinct mode common::number::ObNumber result_nmb; if (OB_FAIL(left_nmb.add_v3(right_nmb, result_nmb, allocator, strict_mode))) { LOG_WARN("number add failed", K(ret), K(left_nmb), K(right_nmb)); } else { result_datum.set_number(result_nmb); } } return ret; } template int ObSumAggCell::eval_decimal_int(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()) { DATUM_TO_DECIMAL_INT(result_datum, RES_T) = DATUM_TO_CONST_DECIMAL_INT(datum, ARG_T); result_datum.pack_ = sizeof(RES_T); } else { DATUM_TO_DECIMAL_INT(result_datum, RES_T) += DATUM_TO_CONST_DECIMAL_INT(datum, ARG_T); } return ret; } template int ObSumAggCell::eval_decimal_int_number(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()) { sql::ObNumStackAllocator<2> tmp_alloc; number::ObNumber right_nmb; if (OB_FAIL(wide::to_number(DATUM_TO_CONST_DECIMAL_INT(datum, ARG_T), child_scale(), tmp_alloc, right_nmb))) { LOG_WARN("fail to cast decimal int to number", K(ret)); } else if (result_datum.is_null()) { result_datum.set_number(right_nmb); } else { number::ObNumber left_nmb(result_datum.get_number()); number::ObNumber result_nmb; if (OB_FAIL(left_nmb.add_v3(right_nmb, result_nmb, tmp_alloc, false))) { LOG_WARN("number add failed", K(ret), K(left_nmb), K(right_nmb)); } else { result_datum.set_number(result_nmb); } } } return ret; } template int ObSumAggCell::eval_int_batch(const common::ObDatum *datums, const int64_t count) { int ret = OB_SUCCESS; char buf_alloc[common::number::ObNumber::MAX_CALC_BYTE_LEN]; ObDataBuffer allocator(buf_alloc, common::number::ObNumber::MAX_CALC_BYTE_LEN); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { if (OB_FAIL(eval_int_inner(datums[i], allocator))) { LOG_WARN("Failed to eval int", K(ret)); } } return ret; } template int ObSumAggCell::eval_uint_batch(const common::ObDatum *datums, const int64_t count) { int ret = OB_SUCCESS; char buf_alloc[common::number::ObNumber::MAX_CALC_BYTE_LEN]; ObDataBuffer allocator(buf_alloc, common::number::ObNumber::MAX_CALC_BYTE_LEN); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { if (OB_FAIL(eval_uint_inner(datums[i], allocator))) { LOG_WARN("Failed to eval uint", K(ret)); } } return ret; } int ObSumAggCell::eval_float_batch(const common::ObDatum *datums, const int64_t count) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { if (OB_FAIL(eval_float_inner(datums[i]))) { LOG_WARN("Failed to eval float", K(ret)); } } return ret; } int ObSumAggCell::eval_double_batch(const common::ObDatum *datums, const int64_t count) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { if (OB_FAIL(eval_double_inner(datums[i]))) { LOG_WARN("Failed to eval float", K(ret)); } } return ret; } int ObSumAggCell::eval_number_batch(const common::ObDatum *datums, const int64_t count) { int ret = OB_SUCCESS; common::number::ObNumber result_nmb; char buf_alloc1[common::number::ObNumber::MAX_CALC_BYTE_LEN]; char buf_alloc2[common::number::ObNumber::MAX_CALC_BYTE_LEN]; uint32_t sum_digits_buf[common::number::ObNumber::OB_CALC_BUFFER_SIZE]; MEMSET(sum_digits_buf, 0, common::number::ObNumber::MAX_CALC_BYTE_LEN); ObDataBuffer allocator1(buf_alloc1, common::number::ObNumber::MAX_CALC_BYTE_LEN); ObDataBuffer allocator2(buf_alloc2, common::number::ObNumber::MAX_CALC_BYTE_LEN); bool all_skip = true; if (!result_datum_.is_null()) { result_nmb.assign(result_datum_.get_number_desc().desc_, const_cast(result_datum_.get_number_digits())); } ObAggSource src(datums); ObAggSelector selector(count); if (OB_FAIL(sql::number_accumulator(src, allocator1, allocator2, result_nmb, sum_digits_buf, all_skip, selector))) { LOG_WARN("number add failed", K(ret), K(result_nmb)); } else if (!all_skip) { result_datum_.set_number(result_nmb); } LOG_DEBUG("number result", K(result_nmb)); return ret; } template int ObSumAggCell::eval_decimal_int_batch(const common::ObDatum *datums, const int64_t count) { int ret = OB_SUCCESS; CALC_T accum = 0; bool accumulated = false; for (int64_t i = 0; i < count; ++i) { if (datums[i].is_null()) { continue; } accum += DATUM_TO_CONST_DECIMAL_INT(datums[i], ARG_T); accumulated = true; } if (accumulated) { if (result_datum_.is_null()) { DATUM_TO_DECIMAL_INT(result_datum_, RES_T) = accum; result_datum_.pack_ = sizeof(RES_T); } else { DATUM_TO_DECIMAL_INT(result_datum_, RES_T) += accum; } } return ret; } template int ObSumAggCell::eval_decimal_int_number_batch(const common::ObDatum *datums, const int64_t count) { int ret = OB_SUCCESS; CALC_T accum = 0; bool accumulated = false; for (int64_t i = 0; i < count; ++i) { if (datums[i].is_null()) { continue; } accum += DATUM_TO_CONST_DECIMAL_INT(datums[i], ARG_T); accumulated = true; } if (accumulated) { sql::ObNumStackAllocator<2> tmp_alloc; number::ObNumber right_nmb; if (OB_FAIL(wide::to_number(accum, child_scale(), tmp_alloc, right_nmb))) { LOG_WARN("fail to cast decimal int to number", K(ret)); } else if (result_datum_.is_null()) { result_datum_.set_number(right_nmb); } else { number::ObNumber left_nmb(result_datum_.get_number()); number::ObNumber result_nmb; if (OB_FAIL(left_nmb.add_v3(right_nmb, result_nmb, tmp_alloc, false))) { LOG_WARN("number add failed", K(ret), K(left_nmb), K(right_nmb)); } else { result_datum_.set_number(result_nmb); } } } return ret; } int ObSumAggCell::collect_result_in_group_by(const int64_t datum_offset) { int ret = OB_SUCCESS; if (OB_UNLIKELY(datum_offset > group_by_result_cnt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected datum offset", K(ret), K(datum_offset), K(group_by_result_cnt_)); } else if (ObObjTypeClass::ObIntTC != obj_tc_ && ObObjTypeClass::ObUIntTC != obj_tc_) { } else if (ob_is_decimal_int(basic_info_.agg_expr_->datum_meta_.type_)) { common::ObDatum &result_datum = get_group_by_result_datum(datum_offset); if (sum_use_int_flag_buf_->at(datum_offset)) { int128_t right_nmb = 0; if (ObIntTC == obj_tc_) { right_nmb = num_int_buf_->at(datum_offset); } else { right_nmb = num_uint_buf_->at(datum_offset); } if (OB_FAIL(collect_result_to_decimal_int(right_nmb, result_datum, result_datum))) { LOG_WARN("Failed to collect result to decimal int", K(ret)); } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(result_datum)); } } else { common::ObDatum &result_datum = get_group_by_result_datum(datum_offset); if (sum_use_int_flag_buf_->at(datum_offset)) { sql::ObNumStackAllocator<2> tmp_alloc; common::number::ObNumber right_nmb; const bool strict_mode = false; //this is tmp allocator, so we can ues non-strinct mode if (ObIntTC == obj_tc_) { int64_t *num = nullptr; if (OB_FAIL(right_nmb.from(num_int_buf_->at(datum_offset), tmp_alloc))) { LOG_WARN("create number from int failed", K(ret), K(right_nmb), K(obj_tc_)); } } else { uint64_t *num = nullptr; if (OB_FAIL(right_nmb.from(num_uint_buf_->at(datum_offset), tmp_alloc))) { LOG_WARN("create number from int failed", K(ret), K(right_nmb), K(obj_tc_)); } } if (OB_SUCC(ret)) { if (result_datum.is_null()) { result_datum.set_number(right_nmb); } else { common::number::ObNumber left_nmb(result_datum.get_number()); common::number::ObNumber result_nmb; if (OB_FAIL(left_nmb.add_v3(right_nmb, result_nmb, tmp_alloc, strict_mode))) { LOG_WARN("number add failed", K(ret), K(left_nmb), K(right_nmb)); } else { result_datum.set_number(result_nmb); } } } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(right_nmb), K(result_datum)); } } return ret; } int ObSumAggCell::reserve_group_by_buf(const int64_t size) { int ret = OB_SUCCESS; if (OB_FAIL(group_by_result_datum_buf_->reserve(size))) { LOG_WARN("Failed to prepare extra buf", K(ret)); } else if (FALSE_IT(ObAggCell::clear_group_by_info())) { } else if (nullptr != sum_use_int_flag_buf_) { if (OB_FAIL(sum_use_int_flag_buf_->reserve(size))) { LOG_WARN("Failed to reserve flags", K(ret)); } else if (OB_FAIL(num_int_buf_->reserve(size))) { LOG_WARN("Failed to prepare buf", K(ret)); } else { clear_group_by_info(); } } return ret; } int ObSumAggCell::output_extra_group_by_result(const int64_t start, const int64_t count) { int ret = OB_SUCCESS; common::ObDatum *sql_result_datums = group_by_result_datum_buf_->get_basic_buf(); if (OB_UNLIKELY(start < group_by_result_datum_buf_->get_basic_count() || start + count > group_by_result_datum_buf_->get_capacity())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Unexpected argument, should be not exceed the buf size", K(ret), K(start), K(count), KPC(group_by_result_datum_buf_)); } else if (ob_is_decimal_int(basic_info_.agg_expr_->datum_meta_.type_)) { for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { common::ObDatum &result_datum = group_by_result_datum_buf_->at(start + i); if (result_datum.is_null()) { sql_result_datums[i].set_null(); } else if (OB_FAIL((this->*copy_datum_func_)(result_datum, sql_result_datums[i]))) { LOG_WARN("Failed to copy decimal int datum", K(ret)); } } } else { for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { common::ObDatum &result_datum = group_by_result_datum_buf_->at(start + i); if (OB_FAIL(sql_result_datums[i].from_storage_datum( result_datum, basic_info_.agg_expr_->obj_datum_map_))) { LOG_WARN("Failed to output extra buf", K(ret)); } } } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(start), K(count), K(ObArrayWrap(sql_result_datums, count))); return ret; } int ObSumAggCell::collect_result_to_decimal_int( const int128_t &right_nmb, const common::ObDatum &datum, common::ObDatum &result) { int ret = OB_SUCCESS; if (basic_info_.agg_expr_->datum_meta_.precision_ <= MAX_PRECISION_DECIMAL_INT_128) { if (datum.is_null()) { DATUM_TO_DECIMAL_INT(result, int128_t) = right_nmb; } else { DATUM_TO_DECIMAL_INT(result, int128_t) = DATUM_TO_CONST_DECIMAL_INT(datum, int128_t) + right_nmb; } result.pack_ = sizeof(int128_t); } else { // int256; if (datum.is_null()) { DATUM_TO_DECIMAL_INT(result, int256_t) = right_nmb; } else { DATUM_TO_DECIMAL_INT(result, int256_t) = DATUM_TO_CONST_DECIMAL_INT(datum, int256_t) + right_nmb; } result.pack_ = sizeof(int256_t); } return ret; } ObFirstRowAggCell::ObFirstRowAggCell(const ObAggCellBasicInfo &basic_info, common::ObIAllocator &allocator) : ObAggCell(basic_info, allocator), is_determined_value_(false), aggregated_flag_cnt_(0), aggregated_flag_buf_(), datum_allocator_("ObStorageAgg", OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()) { agg_type_ = ObPDAggType::PD_FIRST_ROW; } void ObFirstRowAggCell::reset() { is_determined_value_ = false; aggregated_flag_cnt_ = 0; free_group_by_buf(allocator_, aggregated_flag_buf_); if (nullptr != agg_datum_buf_) { agg_datum_buf_->reset(); allocator_.free(agg_datum_buf_); agg_datum_buf_ = nullptr; } datum_allocator_.reset(); ObAggCell::reset(); } void ObFirstRowAggCell::reuse() { ObAggCell::reuse(); aggregated_flag_cnt_ = 0; datum_allocator_.reuse(); if (is_determined_value_) { set_determined_value(); } } void ObFirstRowAggCell::clear_group_by_info() { if (nullptr != aggregated_flag_buf_) { aggregated_flag_buf_->fill_items(false); } } int ObFirstRowAggCell::init(const bool is_group_by, sql::ObEvalCtx *eval_ctx) { int ret = OB_SUCCESS; if (OB_FAIL(ObAggCell::init(is_group_by, eval_ctx))) { LOG_WARN("Failed to init agg cell", K(ret)); } else if (is_group_by) { if (OB_FAIL(new_group_by_buf((bool*)nullptr, 0, sizeof(bool), allocator_, aggregated_flag_buf_))) { LOG_WARN("Failed to new buf", K(ret)); } else if (OB_FAIL(aggregated_flag_buf_->reserve(basic_info_.batch_size_))) { LOG_WARN("Failed to reserve buf", K(ret)); } else if (OB_FAIL(ObAggDatumBuf::new_agg_datum_buf(basic_info_.batch_size_, false, allocator_, agg_datum_buf_))) { LOG_WARN("Failed to alloc agg datum buf", K(ret)); } else if (OB_FAIL(new_group_by_buf(agg_datum_buf_->get_datums(), basic_info_.batch_size_, common::OBJ_DATUM_NUMBER_RES_SIZE, allocator_, group_by_result_datum_buf_))) { LOG_WARN("Failed to new buf", K(ret)); } } return ret; } int ObFirstRowAggCell::eval(blocksstable::ObStorageDatum &datum, const int64_t row_count) { int ret = OB_SUCCESS; if (!aggregated_) { if (OB_FAIL(fill_default_if_need(datum))) { LOG_WARN("Failed to fill default", K(ret), KPC(this)); } else if (OB_FAIL(result_datum_.deep_copy(datum, datum_allocator_))) { LOG_WARN("Failed to deep copy datum", K(ret), K(datum)); } else { aggregated_ = true; } } return ret; } int ObFirstRowAggCell::eval_micro_block( const int32_t col_offset, blocksstable::ObIMicroBlockReader *reader, const int64_t *row_ids, const int64_t row_count) { int ret = OB_SUCCESS; if (!aggregated_) { if (OB_UNLIKELY(nullptr == row_ids || 0 == row_count)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), KP(row_ids), K(row_count)); } else { blocksstable::ObStorageDatum datum; if (OB_FAIL(reader->get_column_datum(col_offset, row_ids[0], datum))) { LOG_WARN("Failed to get first datum", K(ret), K(col_offset), K(row_ids[0]), K(row_count)); } else if (OB_FAIL(result_datum_.deep_copy(datum, datum_allocator_))) { LOG_WARN("Failed to deep copy datum", K(ret), K(datum)); } else { aggregated_ = true; } } } return ret; } int ObFirstRowAggCell::eval_index_info(const blocksstable::ObMicroIndexInfo &index_info, const bool is_cg) { UNUSEDx(index_info, is_cg); int ret = OB_SUCCESS; if (!aggregated_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected, must be aggregated in single/batch rows", K(ret)); } return ret; } int ObFirstRowAggCell::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, const bool is_default_datum) { int ret = OB_SUCCESS; const bool read_distinct_val = is_group_by_col || is_default_datum; const bool need_deep_copy = !read_distinct_val && OBJ_DATUM_STRING == basic_info_.agg_expr_->obj_datum_map_; for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { const uint32_t distinct_ref = refs[i]; const uint32_t dictinct_datum_offset = is_default_datum ? 0 : refs[i]; const common::ObDatum &datum = read_distinct_val ? datums[dictinct_datum_offset] : datums[i]; bool &aggregated_flag = aggregated_flag_buf_->at(distinct_ref); ObDatum &result_datum = group_by_result_datum_buf_->at(distinct_ref); if (aggregated_flag) { } else if (datum.is_null()) { } else if (need_deep_copy) { if (OB_FAIL(result_datum.deep_copy(datum, datum_allocator_))) { LOG_WARN("Failed to clone datum", K(ret), K(datum)); } else { aggregated_flag_cnt_++; aggregated_flag = true; } } else if (OB_FAIL(result_datum.from_storage_datum(datum, basic_info_.agg_expr_->obj_datum_map_))) { LOG_WARN("Failed to clone datum", K(ret), K(datum), K(basic_info_.agg_expr_->obj_datum_map_)); } else { aggregated_flag_cnt_++; aggregated_flag = true; } if (OB_SUCC(ret) && aggregated_flag_cnt_ == distinct_cnt) { // this micro block is finished, no need do eval any more aggregated_ = true; } } return ret; } int ObFirstRowAggCell::collect_result(sql::ObEvalCtx &ctx, bool need_padding) { int ret = OB_SUCCESS; if (!aggregated_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected, must be aggregated in single/batch row", K(ret)); } else if (OB_FAIL(ObAggCell::collect_result(ctx, need_padding))) { LOG_WARN("Failed to collect_result", K(ret), KPC(this)); } return ret; } int ObFirstRowAggCell::collect_batch_result_in_group_by(const int64_t distinct_cnt) { int ret = OB_SUCCESS; if (OB_UNLIKELY(distinct_cnt > group_by_result_datum_buf_->get_capacity())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(distinct_cnt), KPC(group_by_result_datum_buf_)); } else { const int collected_cnt = MIN(distinct_cnt, basic_info_.batch_size_); common::ObDatum *result_datums = group_by_result_datum_buf_->get_basic_buf(); for (int64_t i = 0; OB_SUCC(ret) && i < collected_cnt; ++i) { if (OB_FAIL(col_datums_[i].from_storage_datum(result_datums[i], basic_info_.agg_expr_->obj_datum_map_))) { LOG_WARN("Failed to clone datum", K(ret), K(result_datums[i]), K(basic_info_.agg_expr_->obj_datum_map_)); } } } return ret; } int ObFirstRowAggCell::reserve_group_by_buf(const int64_t size) { int ret = OB_SUCCESS; if (OB_FAIL(ObAggCell::reserve_group_by_buf(size))) { LOG_WARN("Failed to prepare extra group by buf", K(ret)); } else if (nullptr != aggregated_flag_buf_) { if (OB_FAIL(aggregated_flag_buf_->reserve(size))) { LOG_WARN("Failed to reserve flag", K(ret)); } else { clear_group_by_info(); } } return ret; } int ObFirstRowAggCell::output_extra_group_by_result(const int64_t start, const int64_t count) { int ret = OB_SUCCESS; if (OB_UNLIKELY(start < group_by_result_datum_buf_->get_basic_count() || start + count > group_by_result_datum_buf_->get_capacity())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Unexpected argument, should be not exceed the buf size", K(ret), K(start), K(count), KPC(group_by_result_datum_buf_)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { common::ObDatum &result_datum = group_by_result_datum_buf_->at(start + i); if (OB_FAIL(col_datums_[i].from_storage_datum(result_datum, basic_info_.agg_expr_->obj_datum_map_))) { LOG_WARN("Failed to clone datum", K(ret), K(result_datum), K(basic_info_.agg_expr_->obj_datum_map_)); } } } return ret; } int ObPDAggFactory::alloc_cell( const ObAggCellBasicInfo &basic_info, common::ObIArray &agg_cells, const bool exclude_null, const bool is_group_by, sql::ObEvalCtx *eval_ctx) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!basic_info.is_valid())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(basic_info)); } else { void *buf = nullptr; ObAggCell *cell = nullptr; switch (basic_info.agg_expr_->type_) { case T_REF_COLUMN: { if (OB_ISNULL(buf = allocator_.alloc(sizeof(ObFirstRowAggCell))) || OB_ISNULL(cell = new(buf) ObFirstRowAggCell(basic_info, allocator_))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memroy for agg cell", K(ret)); } break; } case T_FUN_COUNT: { if (OB_ISNULL(buf = allocator_.alloc(sizeof(ObCountAggCell))) || OB_ISNULL(cell = new(buf) ObCountAggCell(basic_info, allocator_, exclude_null))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memroy for agg cell", K(ret)); } break; } case T_FUN_MIN: { const ObDatumCmpFuncType cmp_fun = basic_info.agg_expr_->basic_funcs_->null_first_cmp_; if (OB_ISNULL(cmp_fun)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cmp_func is NULL", K(ret), KPC(basic_info.agg_expr_)); } else if (OB_ISNULL(buf = allocator_.alloc(sizeof(ObMinAggCell))) || OB_ISNULL(cell = new(buf) ObMinAggCell(basic_info, allocator_))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memroy for agg cell", K(ret)); } break; } case T_FUN_MAX: { const ObDatumCmpFuncType cmp_fun = basic_info.agg_expr_->basic_funcs_->null_first_cmp_; if (OB_ISNULL(cmp_fun)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cmp_func is NULL", K(ret), KPC(basic_info.agg_expr_)); } else if (OB_ISNULL(buf = allocator_.alloc(sizeof(ObMaxAggCell))) || OB_ISNULL(cell = new(buf) ObMaxAggCell(basic_info, allocator_))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memroy for agg cell", K(ret)); } break; } case T_FUN_SUM: { if (OB_ISNULL(buf = allocator_.alloc(sizeof(ObSumAggCell))) || OB_ISNULL(cell = new(buf) ObSumAggCell(basic_info, allocator_))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memroy for agg cell", K(ret)); } break; } default: { ret = OB_NOT_SUPPORTED; LOG_WARN("Agg is not supported", K(ret), K(basic_info.agg_expr_->type_)); } } if (OB_FAIL(ret)) { } else if (OB_FAIL(cell->init(is_group_by, eval_ctx))) { LOG_WARN("Failed to init agg cell", K(ret)); } else if (OB_FAIL(agg_cells.push_back(cell))) { LOG_WARN("Failed to push back agg cell", K(ret)); } } return ret; } void ObPDAggFactory::release(common::ObIArray &agg_cells) { for (int64_t i = 0; i < agg_cells.count(); ++i) { if (OB_NOT_NULL(agg_cells.at(i))) { agg_cells.at(i)->reset(); allocator_.free(agg_cells.at(i)); } } agg_cells.reset(); } ObGroupByCell::ObGroupByCell(const int64_t batch_size, common::ObIAllocator &allocator) : batch_size_(batch_size), group_by_col_offset_(-1), group_by_col_expr_(nullptr), group_by_col_datum_buf_(nullptr), tmp_group_by_datum_buf_(nullptr), agg_cells_(), distinct_cnt_(0), ref_cnt_(0), refs_buf_(nullptr), need_extract_distinct_(false), distinct_projector_buf_(nullptr), agg_datum_buf_(nullptr), is_processing_(false), projected_cnt_(0), agg_cell_factory_(allocator), allocator_(allocator) { } void ObGroupByCell::reset() { batch_size_ = 0; group_by_col_offset_ = -1; group_by_col_expr_ = nullptr; agg_cell_factory_.release(agg_cells_); distinct_cnt_ = 0; ref_cnt_ = 0; free_group_by_buf(allocator_, group_by_col_datum_buf_); free_group_by_buf(allocator_, tmp_group_by_datum_buf_); if (nullptr != refs_buf_) { allocator_.free(refs_buf_); refs_buf_ = nullptr; } need_extract_distinct_ = false; free_group_by_buf(allocator_, distinct_projector_buf_); if (nullptr != agg_datum_buf_) { agg_datum_buf_->reset(); allocator_.free(agg_datum_buf_); agg_datum_buf_ = nullptr; } is_processing_ = false; projected_cnt_ = 0; } void ObGroupByCell::reuse() { distinct_cnt_ = 0; ref_cnt_ = 0; for (int64_t i = 0; i < agg_cells_.count(); ++i) { agg_cells_.at(i)->reuse(); } need_extract_distinct_ = false; if (nullptr != distinct_projector_buf_) { distinct_projector_buf_->fill_items(-1); } is_processing_ = false; projected_cnt_ = 0; } int ObGroupByCell::init(const ObTableAccessParam ¶m, sql::ObEvalCtx &eval_ctx) { int ret = OB_SUCCESS; const common::ObIArray *out_cols_param = param.iter_param_.get_col_params(); if (OB_UNLIKELY(nullptr == param.iter_param_.group_by_cols_project_ || 0 == param.iter_param_.group_by_cols_project_->count() || nullptr == out_cols_param)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(param.iter_param_)); } else { common::ObDatum *group_by_col_datums = nullptr; group_by_col_offset_ = param.iter_param_.group_by_cols_project_->at(0); for (int64_t i = 0; OB_SUCC(ret) && i < param.output_exprs_->count(); ++i) { if (T_PSEUDO_GROUP_ID == param.output_exprs_->at(i)->type_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Unexpected group idx expr", K(ret)); } else if (nullptr == param.output_sel_mask_ || param.output_sel_mask_->at(i)) { int32_t col_offset = param.iter_param_.out_cols_project_->at(i); int32_t col_index = param.iter_param_.read_info_->get_columns_index().at(col_offset); const share::schema::ObColumnParam *col_param = out_cols_param->at(col_offset); sql::ObExpr *expr = param.output_exprs_->at(i); ObAggCellBasicInfo basic_info(col_offset, col_index, col_param, expr, batch_size_); if (group_by_col_offset_ == col_offset) { group_by_col_datums = expr->locate_batch_datums(eval_ctx); if (OB_ISNULL(group_by_col_datums)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "Unexpected null datums", K(ret), K(i), KPC(expr)); } else if (OB_FAIL(new_group_by_buf(group_by_col_datums, batch_size_, common::OBJ_DATUM_NUMBER_RES_SIZE, allocator_, group_by_col_datum_buf_))) { LOG_WARN("Failed to new buf", K(ret)); } else { group_by_col_expr_ = expr; } } else if (OB_FAIL(agg_cell_factory_.alloc_cell(basic_info, agg_cells_, false, true, &eval_ctx))) { LOG_WARN("Failed to alloc agg cell", K(ret), K(i)); } } } if (OB_FAIL(ret)) { } else if (OB_ISNULL(group_by_col_datums)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected group by col datums", K(ret), K(param)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < param.aggregate_exprs_->count(); ++i) { int32_t col_offset = param.iter_param_.agg_cols_project_->at(i); int32_t col_index = OB_COUNT_AGG_PD_COLUMN_ID == col_offset ? -1 : param.iter_param_.read_info_->get_columns_index().at(col_offset); const share::schema::ObColumnParam *col_param = OB_COUNT_AGG_PD_COLUMN_ID == col_offset ? nullptr : out_cols_param->at(col_offset); sql::ObExpr *agg_expr = param.aggregate_exprs_->at(i); bool exclude_null = false; if (T_FUN_COUNT == agg_expr->type_) { if (OB_COUNT_AGG_PD_COLUMN_ID != col_offset) { exclude_null = col_param->is_nullable_for_write(); } } ObAggCellBasicInfo basic_info(col_offset, col_index, col_param, agg_expr, batch_size_); if (OB_FAIL(agg_cell_factory_.alloc_cell(basic_info, agg_cells_, exclude_null, true, &eval_ctx))) { LOG_WARN("Failed to alloc agg cell", K(ret), K(i)); } } } if (OB_SUCC(ret)) { if (agg_cells_.count() > 2) { std::sort(agg_cells_.begin(), agg_cells_.end(), [](ObAggCell *a, ObAggCell *b) { return a->get_col_offset() < b->get_col_offset(); }); } void *buf = nullptr; if (OB_ISNULL(buf = allocator_.alloc(sizeof(uint32_t) * batch_size_))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to alloc memory", K(ret)); } else { refs_buf_ = reinterpret_cast(buf); } } } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), KPC(this)); return ret; } int ObGroupByCell::eval_batch( const common::ObDatum *datums, const int64_t count, const int32_t agg_idx, const bool is_group_by_col, const bool is_default_datum, const uint32_t ref_offset) { int ret = OB_SUCCESS; if (OB_UNLIKELY(agg_idx >= agg_cells_.count())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(agg_idx), K(agg_cells_.count())); } else if (OB_UNLIKELY(0 == distinct_cnt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected state, not load distinct yet", K(ret)); } else if (agg_cells_.at(agg_idx)->finished()) { } else if (OB_FAIL(agg_cells_.at(agg_idx)->eval_batch_in_group_by( datums, count, refs_buf_ + ref_offset, distinct_cnt_, is_group_by_col, is_default_datum))) { LOG_WARN("Failed to eval batch with in group by", K(ret)); } else { agg_cells_.at(agg_idx)->set_group_by_result_cnt(distinct_cnt_); } return ret; } int ObGroupByCell::copy_output_row(const int64_t batch_idx) { int ret = OB_SUCCESS; // just shallow copy output datum to agg for (int64_t i = 0; OB_SUCC(ret) && i < agg_cells_.count(); ++i) { agg_cells_.at(i)->set_group_by_result_cnt(batch_idx); if (OB_FAIL(agg_cells_.at(i)->copy_output_row(batch_idx - 1))) { LOG_WARN("Failed to copy output row", K(ret)); } } if (OB_SUCC(ret)) { set_distinct_cnt(batch_idx); } return ret; } int ObGroupByCell::copy_output_rows(const int64_t batch_idx) { int ret = OB_SUCCESS; // just shallow copy output datums to agg for (int64_t i = 0; OB_SUCC(ret) && i < agg_cells_.count(); ++i) { agg_cells_.at(i)->set_group_by_result_cnt(batch_idx); if (OB_FAIL(agg_cells_.at(i)->copy_output_rows(batch_idx))) { LOG_WARN("Failed to copy output rows", K(ret)); } } if (OB_SUCC(ret)) { set_distinct_cnt(batch_idx); } return ret; } int ObGroupByCell::collect_result() { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < agg_cells_.count(); ++i) { agg_cells_.at(i)->collect_batch_result_in_group_by(distinct_cnt_); } return ret; } int ObGroupByCell::add_distinct_null_value() { int ret = OB_SUCCESS; if (distinct_cnt_ + 1 > group_by_col_datum_buf_->get_capacity()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected distinct cnt", K(ret), K(distinct_cnt_), K(batch_size_), KPC(group_by_col_datum_buf_)); } else { common::ObDatum *datums = get_group_by_col_datums_to_fill(); datums[distinct_cnt_].set_null(); distinct_cnt_++; } return ret; } int ObGroupByCell::prepare_tmp_group_by_buf() { int ret = OB_SUCCESS; void *buf = nullptr; if (OB_ISNULL(distinct_projector_buf_)) { if (OB_FAIL(new_group_by_buf((int16_t*)nullptr, 0, sizeof(int16_t), allocator_, distinct_projector_buf_))) { LOG_WARN("Failed to new buf", K(ret)); } else if (OB_FAIL(distinct_projector_buf_->reserve(batch_size_))) { LOG_WARN("Failed to new buf", K(ret)); } else if (OB_FAIL(ObAggDatumBuf::new_agg_datum_buf(batch_size_, false, allocator_, agg_datum_buf_))) { LOG_WARN("Failed to alloc agg datum buf", K(ret)); } else if (OB_FAIL(new_group_by_buf(agg_datum_buf_->get_datums(), batch_size_, common::OBJ_DATUM_NUMBER_RES_SIZE, allocator_, tmp_group_by_datum_buf_))) { LOG_WARN("Failed to new buf", K(ret)); } else { distinct_projector_buf_->fill_items(-1); } } if (OB_SUCC(ret)) { need_extract_distinct_ = true; } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(need_extract_distinct_), K(batch_size_)); return ret; } int ObGroupByCell::reserve_group_by_buf(const int64_t size) { int ret = OB_SUCCESS; if (OB_FAIL(group_by_col_datum_buf_->reserve(size))) { LOG_WARN("Failed to reserve buf", K(ret)); } else if (nullptr != distinct_projector_buf_) { if (OB_FAIL(distinct_projector_buf_->reserve(size))) { LOG_WARN("Failed to reserve buf", K(ret)); } else if (FALSE_IT(distinct_projector_buf_->fill_items(-1))) { } else if (OB_FAIL(tmp_group_by_datum_buf_->reserve(size))) { LOG_WARN("Failed to reserve buf", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < agg_cells_.count(); ++i) { if (OB_FAIL(agg_cells_.at(i)->reserve_group_by_buf(size))) { LOG_WARN("Failed to prepare extra buf", K(ret), K(i), KPC(agg_cells_.at(i))); } } return ret; } int ObGroupByCell::output_extra_group_by_result(int64_t &count) { int ret = OB_SUCCESS; count = 0; if (OB_UNLIKELY(!group_by_col_datum_buf_->is_use_extra_buf())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected state", K(ret), KPC(group_by_col_datum_buf_)); } else if (projected_cnt_ >= distinct_cnt_) { ret = OB_ITER_END; } else { count = MIN(batch_size_, distinct_cnt_ - projected_cnt_); common::ObDatum *result_datum = nullptr; common::ObDatum *sql_result_datums = group_by_col_datum_buf_->get_sql_result_datums(); common::ObDatum *extra_result_datums = group_by_col_datum_buf_->get_extra_result_datums(); for (int64_t i = 0; OB_SUCC(ret) && i < count; ++i) { if (OB_FAIL(sql_result_datums[i].from_storage_datum( extra_result_datums[projected_cnt_ + i], group_by_col_expr_->obj_datum_map_))) { LOG_WARN("Failed to output extra buf", K(ret)); } } // do nothing for the first batch, the aggregated values is already in the sql datum if (OB_SUCC(ret) && projected_cnt_ >= batch_size_) { for (int64_t i = 0; OB_SUCC(ret) && i < agg_cells_.count(); ++i) { if (OB_FAIL(agg_cells_.at(i)->output_extra_group_by_result(projected_cnt_, count))) { LOG_WARN("Failed to prepare extra buf", K(ret), K(i), KPC(agg_cells_.at(i))); } } } } if (OB_SUCC(ret)) { projected_cnt_ += count; if (projected_cnt_ >= distinct_cnt_) { ret = OB_ITER_END; } } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(count), K(projected_cnt_), K(distinct_cnt_)); return ret; } int ObGroupByCell::extract_distinct() { int ret = OB_SUCCESS; if (OB_UNLIKELY(ref_cnt_ <= 0)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected state", K(ret), K(ref_cnt_)); } else { common::ObDatum *group_by_col_datums = group_by_col_datum_buf_->get_group_by_datums(); common::ObDatum *tmp_group_by_datums = tmp_group_by_datum_buf_->get_group_by_datums(); for (int64_t i = 0; OB_SUCC(ret) && i < ref_cnt_; ++i) { uint32_t &ref = refs_buf_[i]; if (OB_UNLIKELY(ref >= group_by_col_datum_buf_->get_capacity())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected ref", K(ret), K(ref), K(batch_size_)); } else { int16_t &distinct_projector = distinct_projector_buf_->at(ref); if (-1 == distinct_projector) { // distinct val is not extracted yet if (OB_FAIL(group_by_col_datums[distinct_cnt_].from_storage_datum(tmp_group_by_datums[ref], group_by_col_expr_->obj_datum_map_))) { LOG_WARN("Failed to clone datum", K(ret), K(tmp_group_by_datums[ref]), K(group_by_col_expr_->obj_datum_map_)); } else { distinct_projector = distinct_cnt_; ref = distinct_cnt_; distinct_cnt_++; } } else { // distinct val is already extracted ref = distinct_projector; } } } LOG_DEBUG("[GROUP BY PUSHDOWN]", K(ret), K(ref_cnt_), K(distinct_cnt_)); } return ret; } int ObGroupByCell::assign_agg_cells(const sql::ObExpr *col_expr, common::ObIArray &agg_idxs) { int ret = OB_SUCCESS; for (int64_t i = 0; OB_SUCC(ret) && i < agg_cells_.count(); ++i) { ObAggCell *agg_cell = agg_cells_.at(i); if (agg_cell->is_assigned_to_group_by_processor()) { } else if ((ObPDAggType::PD_FIRST_ROW == agg_cell->get_type() && col_expr == agg_cell->get_agg_expr()) || (ObPDAggType::PD_COUNT == agg_cell->get_type() && !agg_cell->need_access_data()) || (ObPDAggType::PD_FIRST_ROW != agg_cell->get_type() &&col_expr == agg_cell->get_agg_expr()->args_[0])) { if (OB_FAIL(agg_idxs.push_back(i))) { LOG_WARN("Failed to push back", K(ret)); } else { agg_cell->set_assigned_to_group_by_processor(); } } } return ret; } int ObGroupByCell::check_distinct_and_ref_valid() { int ret = OB_SUCCESS; if (OB_UNLIKELY(ref_cnt_ <= 0 || distinct_cnt_ <= 0)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected state", K(ret), K(ref_cnt_), K(distinct_cnt_)); } for (int64_t i = 0; OB_SUCC(ret) && i < ref_cnt_; ++i) { if (OB_UNLIKELY(refs_buf_[i] >= distinct_cnt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Unexpected ref", K(ret), K(i), K(ref_cnt_), K(distinct_cnt_), K(ObArrayWrap(refs_buf_, ref_cnt_))); } } return ret; } int64_t ObGroupByCell::to_string(char *buf, const int64_t buf_len) const { int64_t pos = 0; J_OBJ_START(); J_KV(K_(batch_size), K_(group_by_col_offset), KP_(group_by_col_expr), K_(agg_cells), K_(distinct_cnt), K_(ref_cnt), K_(is_processing), K_(projected_cnt), KPC_(group_by_col_datum_buf)); J_COMMA(); J_KV(K(ObArrayWrap(refs_buf_, ref_cnt_))); J_OBJ_END(); return pos; } } }