Files
oceanbase/src/sql/engine/expr/ob_batch_eval_util.h
obdev 6bf3f38ce4 [FEAT MERGE] ap benchmark opt
Co-authored-by: zhenhan.gong@gmail.com <zhenhan.gong@gmail.com>
Co-authored-by: skylhd <dickylhd@gmail.com>
Co-authored-by: DengzhiLiu <dengzhiliu@gmail.com>
2024-06-19 06:41:44 +00:00

854 lines
37 KiB
C++

/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef OCEANBASE_EXPR_OB_BATCH_EVAL_UTIL_H_
#define OCEANBASE_EXPR_OB_BATCH_EVAL_UTIL_H_
#include <type_traits>
#include "sql/engine/expr/ob_expr.h"
#include "share/vector/ob_uniform_base.h"
#include "share/vector/ob_discrete_base.h"
#include "ob_expr_add.h"
namespace oceanbase
{
namespace sql
{
using common::OB_SUCCESS;
using common::number::ObNumber;
// Batch evaluate operand of binary operator
int binary_operand_batch_eval(const ObExpr &expr,
ObEvalCtx &ctx,
const ObBitVector &skip,
const int64_t size,
const bool null_short_circuit);
int binary_operand_vector_eval(const ObExpr &expr,
ObEvalCtx &ctx,
const ObBitVector &skip,
EvalBound &bound,
const bool null_short_circuit,
bool &right_evaluated);
// Iterate datums of batch result argument
struct ObArgBatchDatumIter
{
explicit ObArgBatchDatumIter(const ObDatum *datums) : datums_(datums) {}
const ObDatum &datum(const int64_t idx) const { return datums_[idx]; }
const ObDatum *datums_;
};
// Iterate datum of scalar result argument
struct ObArgScalarDatumIter
{
explicit ObArgScalarDatumIter(const ObDatum *datum) : datum_(datum) {}
const ObDatum &datum(const int64_t) const { return *datum_; }
const ObDatum *datum_;
};
// Iterate datums of result
struct ObResBatchDatumIter
{
explicit ObResBatchDatumIter(ObDatum *datums) : datums_(datums) {}
ObDatum &datum(const int64_t idx) const { return datums_[idx]; }
ObDatum *datums_;
};
// Iterate raw data of batch result argument
template <typename RawType>
struct ObArgBatchRawIter : public ObArgBatchDatumIter
{
explicit ObArgBatchRawIter(const ObDatum *datums, const char *rev_buf)
: ObArgBatchDatumIter(datums), rev_(reinterpret_cast<const RawType *>(rev_buf)) {}
const RawType &raw(const int64_t i) const { return rev_[i]; }
const RawType *rev_;
};
// Iterate raw data of scalar result argument
template <typename RawType>
struct ObArgScalarRawIter : public ObArgScalarDatumIter
{
using ObArgScalarDatumIter::ObArgScalarDatumIter;
const RawType &raw(const int64_t) const
{
return *reinterpret_cast<const RawType *>(datum_->ptr_);
}
};
// Iterate raw data of result
template <typename RawType>
struct ObResBatchRawIter : public ObResBatchDatumIter
{
explicit ObResBatchRawIter(ObDatum *datums, char *rev_buf)
: ObResBatchDatumIter(datums), rev_(reinterpret_cast<RawType *>(rev_buf)) {}
RawType &raw(int64_t i) const { return rev_[i]; }
RawType *rev_;
};
template <typename ArithOp>
struct ObDoArithBatchEval
{
template <typename ResIter, typename LeftIter, typename RightIter, typename... Args>
inline int operator()(const ObExpr &expr,
ObEvalCtx &ctx,
const ObBitVector &skip,
const int64_t size,
const ResIter &iter,
const LeftIter &l_it,
const RightIter &r_it,
const bool in_frame_notnull,
Args &...args) const
{
int ret = OB_SUCCESS;
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx);
const int64_t step_size = sizeof(uint16_t) * CHAR_BIT;
common::ObDatumDesc desc;
for (int64_t i = 0; i < size && OB_SUCC(ret);) {
const int64_t bit_vec_off = i / step_size;
const uint16_t skip_v = skip.reinterpret_data<uint16_t>()[bit_vec_off];
uint16_t &eval_v = eval_flags.reinterpret_data<uint16_t>()[bit_vec_off];
if (i + step_size < size && (0 == (skip_v | eval_v))) {
if (ArithOp::is_raw_op_supported() && in_frame_notnull) {
for (int64_t j = 0; j < step_size; i++, j++) {
ArithOp::raw_op(iter.raw(i), l_it.raw(i), r_it.raw(i), args...);
}
i -= step_size;
for (int64_t j = 0; OB_SUCC(ret) && j < step_size; i++, j++) {
iter.datum(i).pack_ = sizeof(typename ArithOp::RES_RAW_TYPE);
ret = ArithOp::raw_check(iter.raw(i), l_it.raw(i), r_it.raw(i));
}
} else {
for (int64_t j = 0; OB_SUCC(ret) && j < step_size; i++, j++) {
ret = ArithOp::datum_op(iter.datum(i), l_it.datum(i), r_it.datum(i), args...);
desc.pack_ |= iter.datum(i).pack_;
}
}
if (OB_SUCC(ret)) {
eval_v = 0xFFFF;
}
} else if (i + step_size < size && (0xFFFF == (skip_v | eval_v))) {
i += step_size;
} else {
const int64_t new_size = std::min(size, i + step_size);
for (; i < new_size && OB_SUCC(ret); i++) {
if (!(skip.at(i) || eval_flags.at(i))) {
ret = ArithOp::datum_op(iter.datum(i), l_it.datum(i), r_it.datum(i), args...);
eval_flags.bit_or_assign(i, OB_SUCCESS == ret);
desc.pack_ |= iter.datum(i).pack_;
}
}
}
}
if (OB_SUCC(ret) && desc.is_null()) {
expr.get_eval_info(ctx).notnull_ = false;
}
return ret;
}
};
template <typename ResVector, typename LeftVector, typename RightVector, typename ArithOp>
struct ObDoArithVectorBaseEval
{
template <typename... Args>
inline int operator()(VECTOR_EVAL_FUNC_ARG_DECL, const bool right_evaluated, Args &... args) const
{
int ret = OB_SUCCESS;
const LeftVector *left_vec = static_cast<const LeftVector *>(expr.args_[0]->get_vector(ctx));
const RightVector *right_vec = static_cast<const RightVector *>(expr.args_[1]->get_vector(ctx));
const bool all_not_null = !left_vec->has_null() &&
!(right_evaluated ? right_vec->has_null() : true);
ResVector *res_vec = static_cast<ResVector *>(expr.get_vector(ctx));
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx);
const int64_t cond =
//(bound.get_all_rows_active() << 2) | (expr.get_eval_info(ctx).evaluated_ << 1) | all_not_null;
(bound.get_all_rows_active() << 2) | all_not_null;
if (cond == 4) { // all_rows_active == true, evaluated = false, all_not_null = false
for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) {
ret = ArithOp::null_check_vector_op(*res_vec, *left_vec, *right_vec, idx, args...);
}
eval_flags.set_all(bound.start(), bound.end());
} else if (cond == 5) { // all_rows_active == true, evaluated = false, all_not_null = true
for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) {
ret = ArithOp::vector_op(*res_vec, *left_vec, *right_vec, idx, args...);
}
eval_flags.set_all(bound.start(), bound.end());
} else {
for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) {
if (!skip.at(idx) && !eval_flags.at(idx)) {
ret = ArithOp::null_check_vector_op(*res_vec, *left_vec, *right_vec, idx, args...);
eval_flags.set(idx);
}
}
}
return ret;
}
};
template <typename ResVector, typename LeftVector, typename RightVector, typename ArithOp>
struct ObDoArithFixedVectorEval
{
template <typename... Args>
inline int operator()(VECTOR_EVAL_FUNC_ARG_DECL, const bool right_evaluated, Args &... args) const
{
int ret = OB_SUCCESS;
const LeftVector *left_vec = static_cast<const LeftVector *>(expr.args_[0]->get_vector(ctx));
const RightVector *right_vec = static_cast<const RightVector *>(expr.args_[1]->get_vector(ctx));
ResVector *res_vec = static_cast<ResVector *>(expr.get_vector(ctx));
const typename ArithOp::L_RAW_TYPE *left_arr =
reinterpret_cast<const typename ArithOp::L_RAW_TYPE *>(left_vec->get_data());
const typename ArithOp::R_RAW_TYPE *right_arr =
reinterpret_cast<const typename ArithOp::R_RAW_TYPE *>(right_vec->get_data());
typename ArithOp::RES_RAW_TYPE *res_arr =
reinterpret_cast<typename ArithOp::RES_RAW_TYPE *>(res_vec->get_data());
const bool all_not_null = !left_vec->has_null() &&
!(right_evaluated ? right_vec->has_null() : true);
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx);
const int64_t cond = (ArithOp::is_raw_op_supported() << 3) | (bound.get_all_rows_active() << 2)
//| (expr.get_eval_info(ctx).evaluated_ << 1) | all_not_null;
| all_not_null;
// 1101: row_op_support = true, all_rows_active == true, evaluated = false, all_not_null = true
if (cond == 13) {
for (int64_t idx = bound.start(); idx < bound.end(); ++idx) {
ArithOp::raw_op(res_arr[idx], left_arr[idx], right_arr[idx], args...);
}
res_vec->get_nulls()->unset_all(bound.start(), bound.end());
if (expr.may_not_need_raw_check_ && ob_is_int_less_than_64(expr.args_[0]->datum_meta_.type_)
&& ob_is_int_less_than_64(expr.args_[1]->datum_meta_.type_)) {
// do nothing
} else {
for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) {
ret = ArithOp::raw_check(res_arr[idx], left_arr[idx], right_arr[idx]);
}
}
eval_flags.set_all(bound.start(), bound.end());
} else {
ret = ObDoArithVectorBaseEval<ResVector, LeftVector, RightVector, ArithOp>()(
expr, ctx, skip, bound, right_evaluated, args...);
}
return ret;
}
};
template <typename ResVector, typename LeftVector, typename RightVector, typename ArithOp>
struct ObDoArithFixedConstVectorEval
{
template <typename... Args>
inline int operator()(VECTOR_EVAL_FUNC_ARG_DECL, const bool right_evaluated, Args &... args) const
{
int ret = OB_SUCCESS;
const LeftVector *left_vec = static_cast<const LeftVector *>(expr.args_[0]->get_vector(ctx));
const RightVector *right_vec = static_cast<const RightVector *>(expr.args_[1]->get_vector(ctx));
ResVector *res_vec = static_cast<ResVector *>(expr.get_vector(ctx));
const typename ArithOp::L_RAW_TYPE *left_arr =
reinterpret_cast<const typename ArithOp::L_RAW_TYPE *>(left_vec->get_data());
const typename ArithOp::R_RAW_TYPE *right_val =
reinterpret_cast<const typename ArithOp::R_RAW_TYPE *>(right_vec->get_payload(0));
typename ArithOp::RES_RAW_TYPE *res_arr =
reinterpret_cast<typename ArithOp::RES_RAW_TYPE *>(res_vec->get_data());
const bool all_not_null = !left_vec->has_null() &&
!(right_evaluated ? right_vec->has_null() : true);
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx);
const int cond = (ArithOp::is_raw_op_supported() << 3) | (bound.get_all_rows_active() << 2)
//| (expr.get_eval_info(ctx).evaluated_ << 1) | all_not_null;
| all_not_null;
// 1101: row_op_support = true, all_rows_active == true, evaluated = false, all_not_null = true
if (cond == 13) {
for (int64_t idx = bound.start(); idx < bound.end(); ++idx) {
ArithOp::raw_op(res_arr[idx], left_arr[idx], *right_val, args...);
}
res_vec->get_nulls()->unset_all(bound.start(), bound.end());
if (expr.may_not_need_raw_check_ && ob_is_int_less_than_64(expr.args_[0]->datum_meta_.type_)
&& INT_MIN < *right_val < INT_MAX) {
// do nothing
} else {
for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) {
ret = ArithOp::raw_check(res_arr[idx], left_arr[idx], *right_val);
}
}
eval_flags.set_all(bound.start(), bound.end());
} else {
ret = ObDoArithVectorBaseEval<ResVector, LeftVector, RightVector, ArithOp>()(
expr, ctx, skip, bound, right_evaluated, args...);
}
return ret;
}
};
template <typename ResVector, typename LeftVector, typename RightVector, typename ArithOp>
struct ObDoArithConstFixedVectorEval
{
template <typename... Args>
inline int operator()(VECTOR_EVAL_FUNC_ARG_DECL, const bool right_evaluated, Args &... args) const
{
int ret = OB_SUCCESS;
const LeftVector *left_vec = static_cast<const LeftVector *>(expr.args_[0]->get_vector(ctx));
const RightVector *right_vec = static_cast<const RightVector *>(expr.args_[1]->get_vector(ctx));
ResVector *res_vec = static_cast<ResVector *>(expr.get_vector(ctx));
const typename ArithOp::L_RAW_TYPE *left_val =
reinterpret_cast<const typename ArithOp::L_RAW_TYPE *>(left_vec->get_payload(0));
const typename ArithOp::R_RAW_TYPE *right_arr =
reinterpret_cast<const typename ArithOp::R_RAW_TYPE *>(right_vec->get_data());
typename ArithOp::RES_RAW_TYPE *res_arr =
reinterpret_cast<typename ArithOp::RES_RAW_TYPE *>(res_vec->get_data());
const bool all_not_null = !left_vec->has_null() &&
!(right_evaluated ? right_vec->has_null() : true);
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx);
const int cond = (ArithOp::is_raw_op_supported() << 3) | (bound.get_all_rows_active() << 2)
//| (expr.get_eval_info(ctx).evaluated_ << 1) | all_not_null;
| all_not_null;
// 1101: row_op_support = true, all_rows_active == true, evaluated = false, all_not_null = true
if (cond == 13) {
for (int64_t idx = bound.start(); idx < bound.end(); ++idx) {
ArithOp::raw_op(res_arr[idx], *left_val, right_arr[idx], args...);
}
res_vec->get_nulls()->unset_all(bound.start(), bound.end());
if (expr.may_not_need_raw_check_ && INT_MIN < *left_val < INT_MAX
&& ob_is_int_less_than_64(expr.args_[1]->datum_meta_.type_)) {
} else {
// do nothing
for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) {
ret = ArithOp::raw_check(res_arr[idx], *left_val, right_arr[idx]);
}
}
eval_flags.set_all(bound.start(), bound.end());
} else {
ret = ObDoArithVectorBaseEval<ResVector, LeftVector, RightVector, ArithOp>()(
expr, ctx, skip, bound, right_evaluated, args...);
}
return ret;
}
};
template<typename NmbFastOp, typename ResVector, typename LeftVector, typename RightVector>
struct _nmb_eval_op_impl
{
OB_INLINE int operator()(const int64_t idx, const LeftVector *left_vec,
const RightVector *right_vec, ResVector *res_vec, NmbFastOp &nmb_fast_op,
ObDataBuffer &local_alloc)
{
int ret = OB_SUCCESS;
const number::ObCompactNumber *l_cnum = reinterpret_cast<const number::ObCompactNumber *>(left_vec->get_payload(idx));
const number::ObCompactNumber *r_cnum = reinterpret_cast<const number::ObCompactNumber *>(right_vec->get_payload(idx));
ObNumber l_num(*l_cnum);
ObNumber r_num(*r_cnum);
const number::ObCompactNumber *res_num = reinterpret_cast<const number::ObCompactNumber *>(res_vec->get_payload(idx));
uint32_t *res_digits = const_cast<uint32_t *>(res_num->digits_);
ObNumber::Desc &desc_buf = const_cast<ObNumber::Desc &>(res_num->desc_);
ObNumber::Desc *res_desc = new (&desc_buf) ObNumber::Desc();
// speedup detection
if (nmb_fast_op(l_num, r_num, res_digits, *res_desc)) {
// res_vec->set_payload_shallow(idx, res_num, sizeof(ObNumberDesc) + res_num->desc_.len_ * sizeof(uint32_t));
res_vec->set_length(idx, sizeof(ObNumberDesc) + res_num->desc_.len_ * sizeof(uint32_t));
} else {
ObNumber tmp_num;
if (OB_FAIL(nmb_fast_op(l_num, r_num, tmp_num, local_alloc))) {
SQL_LOG(WARN, "num arith op failed", K(ret), K(l_num), K(r_num));
} else {
const_cast<number::ObCompactNumber *>(res_num)->desc_ = tmp_num.d_;
uint32_t *digits = &(const_cast<number::ObCompactNumber *>(res_num)->digits_[0]);
MEMCPY(digits, tmp_num.get_digits(), tmp_num.d_.len_ * sizeof(uint32_t));
res_vec->set_length(idx, tmp_num.d_.len_ * sizeof(uint32_t) + sizeof(ObNumberDesc));
}
local_alloc.free();
}
return ret;
}
};
template <typename NmbFastOp, typename ResVector, typename LeftVector, typename RightVector>
inline int ObDoNumberVectorEval(VECTOR_EVAL_FUNC_ARG_DECL, const bool right_evaluated,
NmbFastOp &nmb_fast_op)
{
int ret = OB_SUCCESS;
const LeftVector *left_vec = static_cast<const LeftVector *>(expr.args_[0]->get_vector(ctx));
const RightVector *right_vec = static_cast<const RightVector *>(expr.args_[1]->get_vector(ctx));
ResVector *res_vec = static_cast<ResVector *>(expr.get_vector(ctx));
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx);
int64_t calc_cnt = eval_flags.accumulate_bit_cnt(bound);
bool need_calc_all = (calc_cnt == 0);
bool need_calc = (calc_cnt != bound.range_size());
char local_buff[ObNumber::MAX_BYTE_LEN];
ObDataBuffer local_alloc(local_buff, ObNumber::MAX_BYTE_LEN);
_nmb_eval_op_impl<NmbFastOp, ResVector, LeftVector, RightVector> nmb_eval_op;
if (OB_LIKELY(bound.get_all_rows_active() && need_calc_all)) {
if (!left_vec->has_null() && !(right_evaluated ? right_vec->has_null() : true)) {
for (int idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); idx++) {
ret = nmb_eval_op(idx, left_vec, right_vec, res_vec, nmb_fast_op, local_alloc);
}
if (std::is_same<ResVector, ObDiscreteFormat>::value) {
reinterpret_cast<ObDiscreteFormat *>(res_vec)->get_nulls()->unset_all(bound.start(),
bound.end());
}
} else {
for (int idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); idx++) {
if (left_vec->is_null(idx) || right_vec->is_null(idx)) {
res_vec->set_null(idx);
} else {
if (std::is_same<ResVector, ObDiscreteFormat>::value) {
res_vec->unset_null(idx);
}
ret = nmb_eval_op(idx, left_vec, right_vec, res_vec, nmb_fast_op, local_alloc);
}
}
}
eval_flags.set_all(bound.start(), bound.end());
} else if (need_calc) {
for (int64_t idx = bound.start(); OB_SUCC(ret) && idx < bound.end(); ++idx) {
if (eval_flags.at(idx) || skip.at(idx)) { continue; }
if (left_vec->is_null(idx) || right_vec->is_null(idx)) {
res_vec->set_null(idx);
eval_flags.set(idx);
continue;
}
if (std::is_same<ResVector, ObDiscreteFormat>::value) {
res_vec->unset_null(idx);
}
ret = nmb_eval_op(idx, left_vec, right_vec, res_vec, nmb_fast_op, local_alloc);
if (OB_SUCC(ret)) { eval_flags.set(idx); }
}
}
return ret;
}
template <typename ArithOp, template <class> class Functor, typename... Args>
inline int call_functor_with_arg_iter(const ObExpr &expr,
ObEvalCtx &ctx,
const ObBitVector &skip,
const int64_t size,
Args &...args)
{
int ret = OB_SUCCESS;
const ObExpr &left = *expr.args_[0];
const ObExpr &right = *expr.args_[1];
ObResBatchRawIter<typename ArithOp::RES_RAW_TYPE> res(
expr.locate_batch_datums(ctx), expr.get_rev_buf(ctx));
if (left.is_batch_result() && !right.is_batch_result()) {
ObArgBatchRawIter<typename ArithOp::L_RAW_TYPE> l(
left.locate_batch_datums(ctx), left.get_rev_buf(ctx));
ObArgScalarRawIter<typename ArithOp::R_RAW_TYPE> r(&right.locate_expr_datum(ctx));
ret = Functor<ArithOp>()(expr, ctx, skip, size, res, l, r,
(left.get_eval_info(ctx).in_frame_notnull()
&& !right.locate_expr_datum(ctx).is_null()),
args...);
} else if (!left.is_batch_result() && right.is_batch_result()) {
ObArgScalarRawIter<typename ArithOp::L_RAW_TYPE> l(&left.locate_expr_datum(ctx));
ObArgBatchRawIter<typename ArithOp::R_RAW_TYPE> r(
right.locate_batch_datums(ctx), right.get_rev_buf(ctx));
ret = Functor<ArithOp>()(expr, ctx, skip, size, res, l, r,
(right.get_eval_info(ctx).in_frame_notnull()
&& !left.locate_expr_datum(ctx).is_null()),
args...);
} else if (left.is_batch_result() && right.is_batch_result()) {
ObArgBatchRawIter<typename ArithOp::L_RAW_TYPE> l(
left.locate_batch_datums(ctx), left.get_rev_buf(ctx));
ObArgBatchRawIter<typename ArithOp::R_RAW_TYPE> r(
right.locate_batch_datums(ctx), right.get_rev_buf(ctx));
ret = Functor<ArithOp>()(expr, ctx, skip, size, res, l, r,
(left.get_eval_info(ctx).in_frame_notnull()
&& right.get_eval_info(ctx).in_frame_notnull()),
args...);
} else {
ret = common::OB_ERR_UNEXPECTED;
SQL_LOG(WARN, "one argument must be batch result in arith batch evaluate",
K(ret), K(expr), K(left), K(right));
}
return ret;
};
// define arith evaluate batch function.
// see example in ObExprAdd
template <typename ArithOp, typename... Args>
int def_batch_arith_op(const ObExpr &expr,
ObEvalCtx &ctx,
const ObBitVector &skip,
const int64_t size,
Args &...args)
{
int ret = OB_SUCCESS;
if (OB_FAIL(binary_operand_batch_eval(expr, ctx, skip, size, lib::is_oracle_mode()))) {
SQL_LOG(WARN, "bianry operand batch evaluate failed", K(ret), K(expr));
} else {
ret = call_functor_with_arg_iter<ArithOp, ObDoArithBatchEval>(expr, ctx, skip, size, args...);
}
return ret;
}
constexpr int CONVER_FORMAT_VALUE(VectorFormat base_format, VectorFormat format) {
return (format == base_format) ? 0 :
(format == VEC_UNIFORM) ? 1 :
(format == VEC_UNIFORM_CONST) ? 2 : 3;
}
constexpr int64_t GET_FORMAT_CONDITION(VectorFormat base_format, VectorFormat res_format,
VectorFormat left_format, VectorFormat right_format)
{
return ((CONVER_FORMAT_VALUE(base_format, res_format) << 4)
| (CONVER_FORMAT_VALUE(base_format, left_format) << 2)
| CONVER_FORMAT_VALUE(base_format, right_format));
}
using Discrete = ObDiscreteFormat;
template<typename ValueType>
using Fixed = ObFixedLengthFormat<ValueType>;
using Const = ObUniformFormat<true>;
using Uniform = ObUniformFormat<false>;
#define NUMBER_FORMAT_DISPATCH_BRANCH(RES, LEFT, RIGH) \
case GET_FORMAT_CONDITION(VEC_DISCRETE, RES::FORMAT, LEFT::FORMAT, RIGH::FORMAT): { \
ret = ObDoNumberVectorEval<NmbFastOp, RES, LEFT, RIGH>(expr, ctx, skip, pvt_bound, \
right_evaluated, nmb_fast_op); \
break; \
}
template <typename NmbFastOp, typename... Args>
inline int def_number_vector_arith_op(VECTOR_EVAL_FUNC_ARG_DECL, NmbFastOp &nmb_fast_op)
{
int ret = OB_SUCCESS;
EvalBound pvt_bound = bound;
bool right_evaluated = true;
if (OB_FAIL(binary_operand_vector_eval(expr, ctx, skip, pvt_bound, lib::is_oracle_mode(), right_evaluated))) {
SQL_LOG(WARN, "binary number batch evaluation failure", K(ret));
} else {
const VectorFormat left_format = expr.args_[0]->get_format(ctx);
const VectorFormat right_format = expr.args_[1]->get_format(ctx);
const VectorFormat res_format = expr.get_format(ctx);
const int64_t cond = GET_FORMAT_CONDITION(VEC_DISCRETE, res_format, left_format, right_format);
switch (cond) {
NUMBER_FORMAT_DISPATCH_BRANCH(Discrete, Discrete, Discrete);
NUMBER_FORMAT_DISPATCH_BRANCH(Discrete, Discrete, Uniform);
NUMBER_FORMAT_DISPATCH_BRANCH(Discrete, Discrete, Const);
NUMBER_FORMAT_DISPATCH_BRANCH(Discrete, Uniform, Discrete);
NUMBER_FORMAT_DISPATCH_BRANCH(Discrete, Uniform, Uniform);
NUMBER_FORMAT_DISPATCH_BRANCH(Discrete, Uniform, Const);
NUMBER_FORMAT_DISPATCH_BRANCH(Discrete, Const, Discrete);
NUMBER_FORMAT_DISPATCH_BRANCH(Discrete, Const, Uniform);
NUMBER_FORMAT_DISPATCH_BRANCH(Uniform, Discrete, Discrete);
NUMBER_FORMAT_DISPATCH_BRANCH(Uniform, Discrete, Uniform);
NUMBER_FORMAT_DISPATCH_BRANCH(Uniform, Discrete, Const);
NUMBER_FORMAT_DISPATCH_BRANCH(Uniform, Uniform, Discrete);
NUMBER_FORMAT_DISPATCH_BRANCH(Uniform, Uniform, Uniform);
NUMBER_FORMAT_DISPATCH_BRANCH(Uniform, Uniform, Const);
NUMBER_FORMAT_DISPATCH_BRANCH(Uniform, Const, Discrete);
NUMBER_FORMAT_DISPATCH_BRANCH(Uniform, Const, Uniform);
default: {
ret = ObDoNumberVectorEval<NmbFastOp, ObVectorBase, ObVectorBase, ObVectorBase>(
expr, ctx, skip, pvt_bound, right_evaluated, nmb_fast_op);
}
}
}
return ret;
}
#undef NUMBER_FORMAT_DISPATCH_BRANCH
#define FORMAT_DISPATCH_BRANCH(base_format, RES, LEFT, RIGH, OP) \
case GET_FORMAT_CONDITION(base_format, RES::FORMAT, LEFT::FORMAT, RIGH::FORMAT): { \
ret = ObDoArithVectorBaseEval<RES, LEFT, RIGH, OP>()(expr, ctx, skip, pvt_bound, \
right_evaluated, args...); \
break; \
}
template <typename ArithOp, typename... Args>
int def_fixed_len_vector_arith_op(VECTOR_EVAL_FUNC_ARG_DECL, Args &... args)
{
int ret = OB_SUCCESS;
EvalBound pvt_bound = bound;
bool right_evaluated = true;
if (OB_FAIL(binary_operand_vector_eval(expr, ctx, skip, pvt_bound, lib::is_oracle_mode(), right_evaluated))) {
SQL_LOG(WARN, "binary operand vector evaluate failed", K(ret), K(expr));
} else {
const VectorFormat left_format = expr.args_[0]->get_format(ctx);
const VectorFormat right_format = expr.args_[1]->get_format(ctx);
const VectorFormat res_format = expr.get_format(ctx);
#define VEC_ARG_LIST expr, ctx, skip, pvt_bound, right_evaluated
using L_Fixed = Fixed<typename ArithOp::L_RAW_TYPE>;
using R_Fixed = Fixed<typename ArithOp::R_RAW_TYPE>;
using RES_Fixed = Fixed<typename ArithOp::RES_RAW_TYPE>;
const int64_t cond = GET_FORMAT_CONDITION(VEC_FIXED, res_format, left_format, right_format);
switch (cond)
{
case GET_FORMAT_CONDITION(VEC_FIXED, RES_Fixed::FORMAT, L_Fixed::FORMAT, R_Fixed::FORMAT):
ret = ObDoArithFixedVectorEval<RES_Fixed, L_Fixed, R_Fixed, ArithOp>()(VEC_ARG_LIST, args...);
break;
case GET_FORMAT_CONDITION(VEC_FIXED, RES_Fixed::FORMAT, L_Fixed::FORMAT, Const::FORMAT):
ret = ObDoArithFixedConstVectorEval<RES_Fixed, L_Fixed, Const, ArithOp>()(VEC_ARG_LIST,
args...);
break;
case GET_FORMAT_CONDITION(VEC_FIXED, RES_Fixed::FORMAT, Const::FORMAT, R_Fixed::FORMAT):
ret = ObDoArithConstFixedVectorEval<RES_Fixed, Const, R_Fixed, ArithOp>()(VEC_ARG_LIST,
args...);
break;
FORMAT_DISPATCH_BRANCH(VEC_FIXED, RES_Fixed, L_Fixed, Uniform, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, RES_Fixed, Uniform, R_Fixed, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, RES_Fixed, Uniform, Uniform, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, RES_Fixed, Uniform, Const, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, RES_Fixed, Const, Uniform, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, Uniform, L_Fixed, R_Fixed, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, Uniform, L_Fixed, Uniform, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, Uniform, L_Fixed, Const, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, Uniform, Uniform, R_Fixed, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, Uniform, Uniform, Uniform, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, Uniform, Uniform, Const, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, Uniform, Const, R_Fixed, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_FIXED, Uniform, Const, Uniform, ArithOp);
default:
ret = ObDoArithVectorBaseEval<ObVectorBase, ObVectorBase, ObVectorBase, ArithOp>()(
VEC_ARG_LIST, args...);
}
}
if (OB_SUCC(ret)) {
SQL_LOG(DEBUG, "expr", K(ToStrVectorHeader(expr, ctx, &skip, pvt_bound)));
}
return ret;
}
template <typename ArithOp, typename... Args>
int def_variable_len_vector_arith_op(VECTOR_EVAL_FUNC_ARG_DECL, Args &... args)
{
int ret = OB_SUCCESS;
EvalBound pvt_bound = bound;
bool right_evaluated = true;
if (OB_FAIL(binary_operand_vector_eval(expr, ctx, skip, pvt_bound, lib::is_oracle_mode(),
right_evaluated))) {
SQL_LOG(WARN, "binary operand vector evaluate failed", K(ret), K(expr));
} else {
const VectorFormat left_format = expr.args_[0]->get_format(ctx);
const VectorFormat right_format = expr.args_[1]->get_format(ctx);
const VectorFormat res_format = expr.get_format(ctx);
const int64_t cond = GET_FORMAT_CONDITION(VEC_DISCRETE, res_format, left_format, right_format);
switch (cond)
{
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Discrete, Discrete, Discrete, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Discrete, Discrete, Uniform, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Discrete, Discrete, Const, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Discrete, Uniform, Discrete, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Discrete, Uniform, Uniform, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Discrete, Uniform, Const, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Discrete, Const, Discrete, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Discrete, Const, Uniform, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Uniform, Discrete, Discrete, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Uniform, Discrete, Uniform, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Uniform, Discrete, Const, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Uniform, Uniform, Discrete, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Uniform, Uniform, Uniform, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Uniform, Uniform, Const, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Uniform, Const, Discrete, ArithOp);
FORMAT_DISPATCH_BRANCH(VEC_DISCRETE, Uniform, Const, Uniform, ArithOp);
default:
ret = ObDoArithVectorBaseEval<ObVectorBase, ObVectorBase, ObVectorBase, ArithOp>()(
VEC_ARG_LIST, args...);
}
}
if (OB_SUCC(ret)) {
SQL_LOG(DEBUG, "expr", K(ToStrVectorHeader(expr, ctx, &skip, pvt_bound)));
}
return ret;
}
#undef FORMAT_DISPATCH_BRANCH
template <typename Res, typename Left, typename Righ>
struct ObArithOpRawType
{
typedef Res RES_RAW_TYPE;
typedef Left L_RAW_TYPE;
typedef Righ R_RAW_TYPE;
};
struct ObArithOpBase : public ObArithOpRawType<char, char, char>
{
constexpr static bool is_raw_op_supported() { return false; }
template <typename... Args>
static void raw_op(RES_RAW_TYPE &, const L_RAW_TYPE &, const R_RAW_TYPE, Args &...args) {}
static int raw_check(const RES_RAW_TYPE &, const L_RAW_TYPE &, const R_RAW_TYPE &)
{
return common::OB_ERR_UNEXPECTED;
}
};
template <typename Res, typename Left, typename Right>
struct ObArithTypedBase : public ObArithOpRawType<Res, Left, Right>
{
constexpr static bool is_raw_op_supported()
{
return false;
}
template <typename... Args>
static void raw_op(Res &, const Left &, const Right, Args &...args)
{}
static int raw_check(const Res &, const Left &, const Right &)
{
return common::OB_ERR_UNEXPECTED;
}
};
// Wrap arith operate with null check.
template <typename DatumFunctor>
struct ObWrapArithOpNullCheck: public ObArithOpBase
{
template <typename... Args>
static int datum_op(ObDatum &res, const ObDatum &l, const ObDatum &r, Args &...args)
{
int ret = OB_SUCCESS;
if (l.is_null() || r.is_null()) {
res.set_null();
} else {
ret = DatumFunctor()(res, l, r, args...);
}
return ret;
}
};
// Wrap arith operate with null check for vector.
template <typename VectorFunctor, typename Base>
struct ObWrapVectorArithOpNullCheck: public Base
{
template <typename ResVector, typename LeftVector, typename RightVector, typename... Args>
static int vector_op(ResVector &res_vec, const LeftVector &left_vec,
const RightVector &right_vec, const int64_t idx, Args &... args)
{
return VectorFunctor()(res_vec, left_vec, right_vec, idx, args...);
}
template <typename ResVector, typename LeftVector, typename RightVector, typename... Args>
static int null_check_vector_op(ResVector &res_vec, const LeftVector &left_vec,
const RightVector &right_vec, const int64_t idx, Args &... args)
{
int ret = OB_SUCCESS;
if (left_vec.is_null(idx) || right_vec.is_null(idx)) {
res_vec.set_null(idx);
} else {
ret = VectorFunctor()(res_vec, left_vec, right_vec, idx, args...);
}
return ret;
}
};
template <typename DatumFunctor, typename... Args>
int def_batch_arith_op_by_datum_func(BATCH_EVAL_FUNC_ARG_DECL, Args &...args)
{
return def_batch_arith_op<ObWrapArithOpNullCheck<DatumFunctor>, Args...>(
BATCH_EVAL_FUNC_ARG_LIST, args...);
}
template <typename VectorFunctor, typename ArithBase, typename... Args>
int def_fixed_len_vector_arith_op_func(VECTOR_EVAL_FUNC_ARG_DECL, Args &...args)
{
return def_fixed_len_vector_arith_op<ObWrapVectorArithOpNullCheck<VectorFunctor, ArithBase>, Args...>(
VECTOR_EVAL_FUNC_ARG_LIST, args...);
}
template <typename VectorFunctor, typename ArithBase, typename... Args>
int def_variable_len_vector_arith_op_func(VECTOR_EVAL_FUNC_ARG_DECL, Args &...args)
{
return def_variable_len_vector_arith_op<ObWrapVectorArithOpNullCheck<VectorFunctor, ArithBase>, Args...>(
VECTOR_EVAL_FUNC_ARG_LIST, args...);
}
// Wrap arith datum operate from raw operate.
template <typename Base>
struct ObArithOpWrap : public Base
{
constexpr static bool is_raw_op_supported() { return true; }
template <typename... Args>
int operator()(ObDatum &res, const ObDatum &l, const ObDatum &r, Args &...args) const
{
Base::raw_op(
*const_cast<typename Base::RES_RAW_TYPE *>(
reinterpret_cast<const typename Base::RES_RAW_TYPE *>(res.ptr_)),
*reinterpret_cast<const typename Base::L_RAW_TYPE *>(l.ptr_),
*reinterpret_cast<const typename Base::R_RAW_TYPE *>(r.ptr_),
args...);
res.pack_ = sizeof(typename Base::RES_RAW_TYPE);
return Base::raw_check(*reinterpret_cast<const typename Base::RES_RAW_TYPE *>(res.ptr_),
*reinterpret_cast<const typename Base::L_RAW_TYPE *>(l.ptr_),
*reinterpret_cast<const typename Base::R_RAW_TYPE *>(r.ptr_));
}
template <typename... Args>
static int datum_op(ObDatum &res, const ObDatum &l, const ObDatum &r, Args &...args)
{
int ret = OB_SUCCESS;
if (l.is_null() || r.is_null()) {
res.set_null();
} else {
ret = ObArithOpWrap()(res, l, r, args...);
}
return ret;
}
};
// Wrap arith vector operate from raw operate.
template <typename Base>
struct ObVectorArithOpWrap : public Base
{
constexpr static bool is_raw_op_supported() { return true; }
template <typename ResVector, typename LeftVector, typename RightVector, typename... Args>
int operator()(ResVector &res_vec, const LeftVector &left_vec, const RightVector &right_vec,
const int64_t idx, Args &... args) const
{
Base::raw_op(*reinterpret_cast<typename Base::RES_RAW_TYPE *>(
const_cast<char *>(res_vec.get_payload(idx))),
*reinterpret_cast<const typename Base::L_RAW_TYPE *>(left_vec.get_payload(idx)),
*reinterpret_cast<const typename Base::R_RAW_TYPE *>(right_vec.get_payload(idx)),
args...);
res_vec.set_length(idx, sizeof(typename Base::RES_RAW_TYPE));
return Base::raw_check(
*reinterpret_cast<typename Base::RES_RAW_TYPE *>(
const_cast<char *>(res_vec.get_payload(idx))),
*reinterpret_cast<const typename Base::L_RAW_TYPE *>(left_vec.get_payload(idx)),
*reinterpret_cast<const typename Base::R_RAW_TYPE *>(right_vec.get_payload(idx)));
}
template <typename ResVector, typename LeftVector, typename RightVector, typename... Args>
static int vector_op(ResVector &res_vec, const LeftVector &left_vec,
const RightVector &right_vec, const int64_t idx, Args &... args)
{
return ObVectorArithOpWrap()(res_vec, left_vec, right_vec, idx, args...);
}
template <typename ResVector, typename LeftVector, typename RightVector, typename... Args>
static int null_check_vector_op(ResVector &res_vec, const LeftVector &left_vec,
const RightVector &right_vec, const int64_t idx, Args &... args)
{
int ret = OB_SUCCESS;
if (left_vec.is_null(idx) || right_vec.is_null(idx)) {
res_vec.set_null(idx);
} else {
res_vec.unset_null(idx);
ret = ObVectorArithOpWrap()(res_vec, left_vec, right_vec, idx, args...);
}
return ret;
}
};
} // end namespace sql
} // end namespace oceanbase
#endif // OCEANBASE_EXPR_OB_BATCH_EVAL_UTIL_H_