Refactor vec2.0 between expr
This commit is contained in:
@ -239,94 +239,6 @@ template <> int get_cmp_ret<CO_CMP> (const int ret) { return ret; }
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define DO_VECTOR_BETWEEN_CMP(LVec, RVec, ResVec) \
|
||||
do { \
|
||||
LVec *l_vector = static_cast<LVec *>(left.get_vector(ctx)); \
|
||||
RVec *r_vector = static_cast<RVec *>(right.get_vector(ctx)); \
|
||||
ResVec *res_vec = static_cast<ResVec *>(expr.get_vector(ctx)); \
|
||||
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx); \
|
||||
const char *l_payload = nullptr, *r_payload = nullptr; \
|
||||
ObLength l_len = 0, r_len = 0; \
|
||||
int cmp_ret = 0; \
|
||||
if (!l_vector->has_null() && !r_vector->has_null()) { \
|
||||
if (OB_LIKELY(bound.get_all_rows_active() \
|
||||
&& eval_flags.accumulate_bit_cnt(bound) == 0)) { \
|
||||
for (int i = bound.start(); OB_SUCC(ret) && i < bound.end(); i++) { \
|
||||
l_vector->get_payload(i, l_payload, l_len); \
|
||||
r_vector->get_payload(i, r_payload, r_len); \
|
||||
ret = VecTCCmpCalc<l_tc, r_tc>::cmp(left.obj_meta_, right.obj_meta_, \
|
||||
(const void *)l_payload, l_len, \
|
||||
(const void *)r_payload, r_len, cmp_ret); \
|
||||
/* Result priority: false > null > true */ \
|
||||
if (OB_FAIL(ret)) { \
|
||||
} else if (Stage == ObExprBetween::BETWEEN_LEFT) { \
|
||||
/* If the current calculation is left<=val, any result is directly filled in. \
|
||||
If the result is false, the subsequent calculation results are meaningless, \
|
||||
and skip is set to true. */ \
|
||||
res_vec->set_int(i, (cmp_ret <= 0)); \
|
||||
if (cmp_ret > 0) { \
|
||||
skip.set(i); \
|
||||
} \
|
||||
} else if (cmp_ret > 0) { /*BETWEEN_RIGHT*/ \
|
||||
/* If currently calculating val<=right, \
|
||||
only when the result is false will it be filled in. \
|
||||
Note that set_null may have been called before, \
|
||||
so unset_null should be called here. */ \
|
||||
res_vec->unset_null(i); \
|
||||
res_vec->set_int(i, 0); \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
for (int i = bound.start(); OB_SUCC(ret) && i < bound.end(); i++) { \
|
||||
if (skip.at(i) || eval_flags.at(i)) { continue; } \
|
||||
l_vector->get_payload(i, l_payload, l_len); \
|
||||
r_vector->get_payload(i, r_payload, r_len); \
|
||||
ret = VecTCCmpCalc<l_tc, r_tc>::cmp(left.obj_meta_, right.obj_meta_, \
|
||||
(const void *)l_payload, l_len, \
|
||||
(const void *)r_payload, r_len, cmp_ret); \
|
||||
if (OB_FAIL(ret)) { \
|
||||
} else if (Stage == ObExprBetween::BETWEEN_LEFT) { \
|
||||
res_vec->set_int(i, (cmp_ret <= 0)); \
|
||||
if (cmp_ret > 0) { \
|
||||
skip.set(i); \
|
||||
} \
|
||||
} else if (cmp_ret > 0) { /*BETWEEN_RIGHT*/ \
|
||||
res_vec->unset_null(i); \
|
||||
res_vec->set_int(i, 0); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
for (int i = bound.start(); OB_SUCC(ret) && i < bound.end(); i++) { \
|
||||
if (skip.at(i) || eval_flags.at(i)) { continue; } \
|
||||
if (l_vector->is_null(i) || r_vector->is_null(i)) { \
|
||||
res_vec->set_null(i); \
|
||||
/* Cannot set skip here. \
|
||||
Because the priority of the "between" results \
|
||||
is consistent with the "and" expression: false > null > true. \
|
||||
If the result of the right branch is false, \
|
||||
it should override the null in the left branch. */ \
|
||||
} else { \
|
||||
l_vector->get_payload(i, l_payload, l_len); \
|
||||
r_vector->get_payload(i, r_payload, r_len); \
|
||||
ret = VecTCCmpCalc<l_tc, r_tc>::cmp(left.obj_meta_, right.obj_meta_, \
|
||||
(const void *)l_payload, l_len, \
|
||||
(const void *)r_payload, r_len, cmp_ret); \
|
||||
if (OB_FAIL(ret)) { \
|
||||
} else if (Stage == ObExprBetween::BETWEEN_LEFT) { \
|
||||
res_vec->set_int(i, (cmp_ret <= 0)); \
|
||||
if (cmp_ret > 0) { \
|
||||
skip.set(i); \
|
||||
} \
|
||||
} else if (cmp_ret > 0) { /*BETWEEN_RIGHT*/ \
|
||||
res_vec->unset_null(i); \
|
||||
res_vec->set_int(i, 0); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CALC_FORMAT(l, r, res) \
|
||||
((int32_t)l + (((int32_t)r) << VEC_MAX_FORMAT) + (((int32_t)res) << (VEC_MAX_FORMAT * 2)))
|
||||
template <VecValueTypeClass l_tc, VecValueTypeClass r_tc, ObCmpOp cmp_op>
|
||||
@ -451,57 +363,9 @@ struct EvalVectorCmp<VEC_TC_NULL, r_tc, cmp_op>: public EvalVectorCmpWithNull {}
|
||||
template<ObCmpOp cmp_op>
|
||||
struct EvalVectorCmp<VEC_TC_NULL, VEC_TC_NULL, cmp_op>: public EvalVectorCmpWithNull {};
|
||||
|
||||
template <VecValueTypeClass l_tc, VecValueTypeClass r_tc, ObExprBetween::EvalBetweenStage Stage>
|
||||
struct EvalVectorBetweenCmp
|
||||
{
|
||||
#define VECTOR_BETWEEN_CMP_CASE(l_fmt, r_fmt, res_fmt) \
|
||||
case CALC_FORMAT(l_fmt, r_fmt, res_fmt): { \
|
||||
DO_VECTOR_BETWEEN_CMP(L_##l_fmt##_FMT, R_##r_fmt##_FMT, RES_##res_fmt##_FMT); \
|
||||
} break
|
||||
static int eval_between_vector(const ObExpr &expr, const ObExpr &left, const ObExpr &right,
|
||||
ObEvalCtx &ctx, ObBitVector &skip, const EvalBound &bound)
|
||||
{
|
||||
using L_VEC_FIXED_FMT = ObFixedLengthFormat<RTCType<l_tc>>;
|
||||
using R_VEC_FIXED_FMT = ObFixedLengthFormat<RTCType<r_tc>>;
|
||||
using RES_VEC_FIXED_FMT = ObFixedLengthFormat<int64_t>;
|
||||
using L_VEC_DISCRETE_FMT = ObDiscreteFormat;
|
||||
using R_VEC_DISCRETE_FMT = ObDiscreteFormat;
|
||||
using L_VEC_UNIFORM_FMT = ObUniformFormat<false>;
|
||||
using R_VEC_UNIFORM_FMT = ObUniformFormat<false>;
|
||||
|
||||
int ret = OB_SUCCESS;
|
||||
VectorFormat left_format = left.get_format(ctx);
|
||||
VectorFormat right_format = right.get_format(ctx);
|
||||
VectorFormat res_format = expr.get_format(ctx);
|
||||
LOG_DEBUG("eval vector cmp", K(expr), K(l_tc), K(r_tc), K(bound),
|
||||
K(left_format), K(right_format), K(res_format));
|
||||
if (is_valid_format(left_format) && is_valid_format(right_format)
|
||||
&& is_valid_format(res_format)) {
|
||||
switch (CALC_FORMAT(left_format, right_format, res_format)) {
|
||||
VECTOR_BETWEEN_CMP_CASE(VEC_FIXED, VEC_FIXED, VEC_FIXED);
|
||||
VECTOR_BETWEEN_CMP_CASE(VEC_FIXED, VEC_UNIFORM, VEC_FIXED);
|
||||
VECTOR_BETWEEN_CMP_CASE(VEC_DISCRETE, VEC_DISCRETE, VEC_FIXED);
|
||||
VECTOR_BETWEEN_CMP_CASE(VEC_DISCRETE, VEC_UNIFORM, VEC_FIXED);
|
||||
VECTOR_BETWEEN_CMP_CASE(VEC_UNIFORM, VEC_FIXED, VEC_FIXED);
|
||||
VECTOR_BETWEEN_CMP_CASE(VEC_UNIFORM, VEC_DISCRETE, VEC_FIXED);
|
||||
VECTOR_BETWEEN_CMP_CASE(VEC_UNIFORM, VEC_UNIFORM, VEC_FIXED);
|
||||
default: {
|
||||
DO_VECTOR_BETWEEN_CMP(ObVectorBase, ObVectorBase, ObVectorBase);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("invalid format", K(left_format), K(right_format), K(res_format));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#undef VECTOR_BETWEEN_CMP_CASE
|
||||
};
|
||||
#undef CALC_FORMAT
|
||||
|
||||
static sql::ObExpr::EvalVectorFunc EVAL_VECTOR_EXPR_CMP_FUNCS[MAX_VEC_TC][MAX_VEC_TC][CO_MAX];
|
||||
static sql::ObExprBetween::EvalVectorBetweenFunc EVAL_VECTOR_BETWEEN_EXPR_CMP_FUNCS[MAX_VEC_TC][MAX_VEC_TC][ObExprBetween::EvalBetweenStage::BETWEEN_MAX];
|
||||
|
||||
template<int X, int Y, bool defined>
|
||||
struct VectorExprCmpFuncIniter
|
||||
@ -518,9 +382,6 @@ struct VectorExprCmpFuncIniter<X, Y, true>
|
||||
template <ObCmpOp cmp_op>
|
||||
using EvalFunc =
|
||||
EvalVectorCmp<static_cast<VecValueTypeClass>(X), static_cast<VecValueTypeClass>(Y), cmp_op>;
|
||||
template <ObExprBetween::EvalBetweenStage stage>
|
||||
using EvalBetweenFunc =
|
||||
EvalVectorBetweenCmp<static_cast<VecValueTypeClass>(X), static_cast<VecValueTypeClass>(Y), stage>;
|
||||
static void init_array()
|
||||
{
|
||||
auto &funcs = EVAL_VECTOR_EXPR_CMP_FUNCS;
|
||||
@ -531,12 +392,6 @@ struct VectorExprCmpFuncIniter<X, Y, true>
|
||||
funcs[X][Y][CO_NE] = &EvalFunc<CO_NE>::eval_vector;
|
||||
funcs[X][Y][CO_EQ] = &EvalFunc<CO_EQ>::eval_vector;
|
||||
funcs[X][Y][CO_CMP] = &EvalFunc<CO_CMP>::eval_vector;
|
||||
|
||||
auto &between_funcs = EVAL_VECTOR_BETWEEN_EXPR_CMP_FUNCS;
|
||||
between_funcs[X][Y][ObExprBetween::EvalBetweenStage::BETWEEN_LEFT] =
|
||||
&EvalBetweenFunc<ObExprBetween::EvalBetweenStage::BETWEEN_LEFT>::eval_between_vector;
|
||||
between_funcs[X][Y][ObExprBetween::EvalBetweenStage::BETWEEN_RIGHT] =
|
||||
&EvalBetweenFunc<ObExprBetween::EvalBetweenStage::BETWEEN_RIGHT>::eval_between_vector;
|
||||
}
|
||||
};
|
||||
|
||||
@ -557,48 +412,35 @@ sql::ObExpr::EvalVectorFunc VectorCmpExprFuncsHelper::get_eval_vector_expr_cmp_f
|
||||
return EVAL_VECTOR_EXPR_CMP_FUNCS[l_tc][r_tc][cmp_op];
|
||||
}
|
||||
|
||||
sql::ObExprBetween::EvalVectorBetweenFunc VectorCmpExprFuncsHelper::get_eval_vector_between_expr_cmp_func(
|
||||
const sql::ObDatumMeta &l_meta, const sql::ObDatumMeta &r_meta,
|
||||
sql::ObExprBetween::EvalBetweenStage stage)
|
||||
{
|
||||
LOG_DEBUG("eval vector between_expr_cmp_func", K(l_meta), K(r_meta), K(stage));
|
||||
VecValueTypeClass l_tc = get_vec_value_tc(l_meta.type_, l_meta.scale_, l_meta.precision_);
|
||||
VecValueTypeClass r_tc = get_vec_value_tc(r_meta.type_, r_meta.scale_, r_meta.precision_);
|
||||
return EVAL_VECTOR_BETWEEN_EXPR_CMP_FUNCS[l_tc][r_tc][stage];
|
||||
}
|
||||
|
||||
} // end namespace common
|
||||
|
||||
namespace sql
|
||||
{
|
||||
void *g_ser_eval_vector_expr_cmp_funcs[MAX_VEC_TC * MAX_VEC_TC * 7];
|
||||
void *g_ser_eval_vector_between_expr_cmp_funcs[MAX_VEC_TC * MAX_VEC_TC * 2];
|
||||
void *g_ser_nullsafe_rowcmp_funcs[MAX_VEC_TC * MAX_VEC_TC * 2];
|
||||
void *g_ser_rowcmp_funcs[MAX_VEC_TC * MAX_VEC_TC];
|
||||
|
||||
static_assert(sizeof(g_ser_eval_vector_expr_cmp_funcs) == sizeof(EVAL_VECTOR_EXPR_CMP_FUNCS),
|
||||
"unexpected size");
|
||||
static_assert(sizeof(g_ser_eval_vector_between_expr_cmp_funcs) == sizeof(EVAL_VECTOR_BETWEEN_EXPR_CMP_FUNCS),
|
||||
"unexpected size");
|
||||
static_assert(sizeof(g_ser_nullsafe_rowcmp_funcs) == sizeof(NULLSAFE_ROW_CMP_FUNCS),
|
||||
"unexpected size");
|
||||
static_assert(sizeof(g_ser_rowcmp_funcs) == sizeof(ROW_CMP_FUNCS),
|
||||
"unexpected size");
|
||||
bool g_ser_eval_vector_expr_cmp_funcs_init = ObFuncSerialization::convert_NxN_array(
|
||||
g_ser_eval_vector_expr_cmp_funcs, reinterpret_cast<void **>(EVAL_VECTOR_EXPR_CMP_FUNCS),
|
||||
MAX_VEC_TC, 7, 0, 7);
|
||||
bool g_ser_eval_vector_between_expr_cmp_funcs_init = ObFuncSerialization::convert_NxN_array(
|
||||
g_ser_eval_vector_between_expr_cmp_funcs, reinterpret_cast<void **>(EVAL_VECTOR_BETWEEN_EXPR_CMP_FUNCS),
|
||||
MAX_VEC_TC, 2, 0, 2);
|
||||
|
||||
bool g_ser_nullsafe_rowcmp_funcs_init = ObFuncSerialization::convert_NxN_array(
|
||||
g_ser_nullsafe_rowcmp_funcs, reinterpret_cast<void **>(NULLSAFE_ROW_CMP_FUNCS),
|
||||
MAX_VEC_TC, 2, 0, 2);
|
||||
|
||||
bool g_ser_rowcmp_funcs_init = ObFuncSerialization::convert_NxN_array(
|
||||
g_ser_rowcmp_funcs, reinterpret_cast<void **>(ROW_CMP_FUNCS),
|
||||
MAX_VEC_TC, 1, 0, 1);
|
||||
REG_SER_FUNC_ARRAY(OB_SFA_CMP_EXPR_EVAL_VECTOR, g_ser_eval_vector_expr_cmp_funcs,
|
||||
sizeof(g_ser_eval_vector_expr_cmp_funcs) / sizeof(void *));
|
||||
|
||||
REG_SER_FUNC_ARRAY(OB_SFA_CMP_BETWEEN_EXPR_EVAL_VECTOR, g_ser_eval_vector_between_expr_cmp_funcs,
|
||||
sizeof(g_ser_eval_vector_between_expr_cmp_funcs) / sizeof(void *));
|
||||
|
||||
REG_SER_FUNC_ARRAY(OB_SFA_VECTOR_NULLSAFE_CMP, g_ser_nullsafe_rowcmp_funcs,
|
||||
sizeof(g_ser_nullsafe_rowcmp_funcs) / sizeof(void *));
|
||||
REG_SER_FUNC_ARRAY(OB_SFA_VECTOR_CMP, g_ser_rowcmp_funcs,
|
||||
sizeof(g_ser_rowcmp_funcs) / sizeof(void *));
|
||||
} // end namespace sql
|
||||
} // end namespace oceanabse
|
||||
|
@ -39,15 +39,6 @@ struct VectorCmpExprFuncsHelper
|
||||
static sql::ObExpr::EvalVectorFunc get_eval_vector_expr_cmp_func(const sql::ObDatumMeta &l_meta,
|
||||
const sql::ObDatumMeta &r_meta,
|
||||
const common::ObCmpOp cmp_op);
|
||||
// Compared to get_eval_vector_expr_cmp_func,
|
||||
// the obtained function has two additional expr arguments: left and right.
|
||||
// Among the EvalVectorFunc functions,
|
||||
// they directly use the first two arguments of the expr as left and right.
|
||||
// However, in some scenarios, this may not be the case,
|
||||
// so the following functions have been added.
|
||||
static sql::ObExprBetween::EvalVectorBetweenFunc get_eval_vector_between_expr_cmp_func(const sql::ObDatumMeta &l_meta,
|
||||
const sql::ObDatumMeta &r_meta,
|
||||
sql::ObExprBetween::EvalBetweenStage stage);
|
||||
};
|
||||
|
||||
} // end namespace common
|
||||
|
@ -78,92 +78,99 @@ int calc_between_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res_datum)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// eval_left_and_right_operand
|
||||
template <typename ValVec, typename ResVec>
|
||||
static int eval_lr_operand(const ObExpr &expr, ObEvalCtx &ctx,
|
||||
ObBitVector &skip, const EvalBound &bound)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const ObExpr &val_expr = *expr.args_[0];
|
||||
const ObExpr &left_expr = *expr.args_[1];
|
||||
const ObExpr &right_expr = *expr.args_[2];
|
||||
ValVec *val_vec = static_cast<ValVec *>(val_expr.get_vector(ctx));
|
||||
ResVec *res_vec = static_cast<ResVec *>(expr.get_vector(ctx));
|
||||
if (val_vec->has_null()) {
|
||||
for (int i = bound.start(); i < bound.end(); ++i) {
|
||||
if (!skip.at(i) && val_vec->is_null(i)) {
|
||||
res_vec->set_null(i);
|
||||
skip.set(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if skip is all true, `eval_vector` still needs to be called, for that expr format may not be inited.
|
||||
if (OB_FAIL(left_expr.eval_vector(ctx, skip, bound))) {
|
||||
LOG_WARN("eval left operand failed", K(ret));
|
||||
} else if (OB_FAIL(right_expr.eval_vector(ctx, skip, bound))) {
|
||||
LOG_WARN("eval right operand failed", K(ret));
|
||||
}
|
||||
return ret;
|
||||
#define BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, right_vec, res_vec) \
|
||||
switch (l_format) { \
|
||||
case VEC_FIXED: { \
|
||||
ret = func_name<ObFixedLengthBase, right_vec, res_vec, stage>( \
|
||||
expr, ctx, my_skip, bound); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_DISCRETE: { \
|
||||
ret = func_name<ObDiscreteFormat, right_vec, res_vec, stage>( \
|
||||
expr, ctx, my_skip, bound); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_CONTINUOUS: { \
|
||||
ret = func_name<ObContinuousFormat, right_vec, res_vec, stage>( \
|
||||
expr, ctx, my_skip, bound); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_UNIFORM: { \
|
||||
ret = func_name<ObUniformFormat<false>, right_vec, res_vec, stage>( \
|
||||
expr, ctx, my_skip, bound); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_UNIFORM_CONST: { \
|
||||
ret = func_name<ObUniformFormat<true>, right_vec, res_vec, stage>( \
|
||||
expr, ctx, my_skip, bound); \
|
||||
break; \
|
||||
} \
|
||||
default: { \
|
||||
ret = func_name<ObVectorBase, right_vec, res_vec, stage>( \
|
||||
expr, ctx, my_skip, bound); \
|
||||
} \
|
||||
}
|
||||
|
||||
template <typename ValVec>
|
||||
static int dispatch_eval_between_operands(const ObExpr &expr, ObEvalCtx &ctx,
|
||||
ObBitVector &skip, const EvalBound &bound)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
VectorFormat res_format = expr.get_format(ctx);
|
||||
switch (res_format) {
|
||||
case VEC_FIXED: {
|
||||
ret = eval_lr_operand<ValVec, ObBitmapNullVectorBase>(expr, ctx, skip, bound);
|
||||
break;
|
||||
}
|
||||
case VEC_UNIFORM: {
|
||||
ret = eval_lr_operand<ValVec, ObUniformFormat<false>>(expr, ctx, skip, bound);
|
||||
break;
|
||||
}
|
||||
case VEC_UNIFORM_CONST: {
|
||||
ret = eval_lr_operand<ValVec, ObUniformFormat<true>>(expr, ctx, skip, bound);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ret = eval_lr_operand<ValVec, ObVectorBase>(expr, ctx, skip, bound);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
#define BETWEEN_DISPATCH_VECTOR_IN_RIGHT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, r_format, res_vec) \
|
||||
switch (r_format) { \
|
||||
case VEC_FIXED: { \
|
||||
BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, ObFixedLengthBase, res_vec); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_DISCRETE: { \
|
||||
BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, ObDiscreteFormat, res_vec); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_CONTINUOUS: { \
|
||||
BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, ObContinuousFormat, res_vec); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_UNIFORM: { \
|
||||
BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, ObUniformFormat<false>, res_vec); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_UNIFORM_CONST: { \
|
||||
BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, ObUniformFormat<true>, res_vec); \
|
||||
break; \
|
||||
} \
|
||||
default: { \
|
||||
BETWEEN_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, ObVectorBase, res_vec); \
|
||||
} \
|
||||
}
|
||||
|
||||
static int eval_between_operands(const ObExpr &expr, ObEvalCtx &ctx,
|
||||
ObBitVector &skip, const EvalBound &bound)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const ObExpr &val_expr = *expr.args_[0];
|
||||
if (OB_FAIL(val_expr.eval_vector(ctx, skip, bound))) {
|
||||
LOG_WARN("eval left operand failed", K(ret));
|
||||
} else {
|
||||
VectorFormat val_format = val_expr.get_format(ctx);
|
||||
switch (val_format) {
|
||||
case VEC_DISCRETE:
|
||||
case VEC_CONTINUOUS:
|
||||
case VEC_FIXED: {
|
||||
ret = dispatch_eval_between_operands<ObBitmapNullVectorBase>(expr, ctx, skip, bound);
|
||||
break;
|
||||
}
|
||||
case VEC_UNIFORM: {
|
||||
ret = dispatch_eval_between_operands<ObUniformFormat<false>>(expr, ctx, skip, bound);
|
||||
break;
|
||||
}
|
||||
case VEC_UNIFORM_CONST: {
|
||||
ret = dispatch_eval_between_operands<ObUniformFormat<true>>(expr, ctx, skip, bound);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ret = dispatch_eval_between_operands<ObVectorBase>(expr, ctx, skip, bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
#define BETWEEN_DISPATCH_VECTOR_IN_RES_ARG_FORMAT( \
|
||||
func_name, stage, l_format, r_format) \
|
||||
switch (res_format) { \
|
||||
case VEC_FIXED: { \
|
||||
BETWEEN_DISPATCH_VECTOR_IN_RIGHT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, r_format, IntegerFixedVec); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_UNIFORM: { \
|
||||
BETWEEN_DISPATCH_VECTOR_IN_RIGHT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, r_format, IntegerUniVec); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_UNIFORM_CONST: { \
|
||||
BETWEEN_DISPATCH_VECTOR_IN_RIGHT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, r_format, IntegerUniCVec); \
|
||||
break; \
|
||||
} \
|
||||
default: { \
|
||||
BETWEEN_DISPATCH_VECTOR_IN_RIGHT_ARG_FORMAT( \
|
||||
func_name, stage, l_format, r_format, ObVectorBase); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
int ObExprBetween::eval_between_vector(const ObExpr &expr,
|
||||
ObEvalCtx &ctx,
|
||||
const ObBitVector &skip,
|
||||
@ -176,17 +183,33 @@ int ObExprBetween::eval_between_vector(const ObExpr &expr,
|
||||
const ObExpr &right_expr = *expr.args_[2];
|
||||
ObBitVector &my_skip = expr.get_pvt_skip(ctx);
|
||||
my_skip.deep_copy(skip, bound.start(), bound.end());
|
||||
if (OB_FAIL(eval_between_operands(expr, ctx, my_skip, bound))) {
|
||||
LOG_WARN("eval between operands failed", K(ret));
|
||||
} else if (OB_FAIL((reinterpret_cast<EvalVectorBetweenFunc>(expr.inner_functions_[2]))(
|
||||
expr, left_expr, val_expr, ctx, my_skip, bound))) { // eval left <= val
|
||||
LOG_WARN("compare left and val failed", K(ret));
|
||||
} else if (OB_FAIL((reinterpret_cast<EvalVectorBetweenFunc>(expr.inner_functions_[3]))(
|
||||
expr, val_expr, right_expr, ctx, my_skip, bound))) { // eval val <= right
|
||||
LOG_WARN("compare val and right failed", K(ret));
|
||||
if (OB_FAIL(val_expr.eval_vector(ctx, my_skip, bound))) {
|
||||
LOG_WARN("eval left operand failed", K(ret));
|
||||
} else if (OB_FAIL(left_expr.eval_vector(ctx, my_skip, bound))) {
|
||||
LOG_WARN("eval left operand failed", K(ret));
|
||||
} else if (OB_FAIL(right_expr.eval_vector(ctx, my_skip, bound))) {
|
||||
LOG_WARN("eval left operand failed", K(ret));
|
||||
} else {
|
||||
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx);
|
||||
eval_flags.bit_not(skip, bound);
|
||||
VectorFormat val_format = val_expr.get_format(ctx);
|
||||
VectorFormat left_format = left_expr.get_format(ctx);
|
||||
VectorFormat right_format = right_expr.get_format(ctx);
|
||||
VectorFormat res_format = expr.get_format(ctx);
|
||||
BETWEEN_DISPATCH_VECTOR_IN_RES_ARG_FORMAT(
|
||||
inner_eval_between_vector, BETWEEN_LEFT,
|
||||
left_format, val_format);
|
||||
if (OB_FAIL(ret)) {
|
||||
LOG_WARN("compare left and val failed", K(ret));
|
||||
} else {
|
||||
BETWEEN_DISPATCH_VECTOR_IN_RES_ARG_FORMAT(
|
||||
inner_eval_between_vector, BETWEEN_RIGHT,
|
||||
val_format, right_format);
|
||||
if (OB_FAIL(ret)) {
|
||||
LOG_WARN("compare val and right failed", K(ret));
|
||||
} else {
|
||||
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx);
|
||||
eval_flags.bit_not(skip, bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -206,8 +229,8 @@ int ObExprBetween::cg_expr(ObExprCGCtx &expr_cg_ctx,
|
||||
} else {
|
||||
DatumCmpFunc cmp_func_1 = NULL; // left <= val
|
||||
DatumCmpFunc cmp_func_2 = NULL; // val <= right
|
||||
EvalVectorBetweenFunc vec_cmp_func_1 = NULL; // left <= val
|
||||
EvalVectorBetweenFunc vec_cmp_func_2 = NULL; // val <= right
|
||||
RowCmpFunc vec_cmp_func_1 = NULL; // left <= val
|
||||
RowCmpFunc vec_cmp_func_2 = NULL; // val <= right
|
||||
const ObDatumMeta &val_meta = rt_expr.args_[0]->datum_meta_;
|
||||
const ObDatumMeta &left_meta = rt_expr.args_[1]->datum_meta_;
|
||||
const ObDatumMeta &right_meta = rt_expr.args_[2]->datum_meta_;
|
||||
@ -237,23 +260,22 @@ int ObExprBetween::cg_expr(ObExprCGCtx &expr_cg_ctx,
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get_datum_expr_cmp_func failed", K(ret), K(val_meta), K(right_meta),
|
||||
K(is_oracle_mode()), K(rt_expr));
|
||||
} else if (OB_ISNULL(vec_cmp_func_1 = VectorCmpExprFuncsHelper::get_eval_vector_between_expr_cmp_func(
|
||||
left_meta, val_meta, EvalBetweenStage::BETWEEN_LEFT))) {
|
||||
} else if (OB_ISNULL(vec_cmp_func_1 = VectorCmpExprFuncsHelper::get_row_cmp_func(
|
||||
left_meta, val_meta))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
VecValueTypeClass value_tc = get_vec_value_tc(val_meta.type_, val_meta.scale_, val_meta.precision_);
|
||||
VecValueTypeClass left_tc = get_vec_value_tc(left_meta.type_, left_meta.scale_, left_meta.precision_);
|
||||
LOG_WARN("The result of get_eval_vector_between_expr_cmp_func(left) is null.",
|
||||
K(ret), K(left_meta), K(val_meta), K(right_meta), K(value_tc), K(left_tc), K(rt_expr));
|
||||
} else if (OB_ISNULL(vec_cmp_func_2 = VectorCmpExprFuncsHelper::get_eval_vector_between_expr_cmp_func(
|
||||
val_meta, right_meta, EvalBetweenStage::BETWEEN_RIGHT))) {
|
||||
} else if (OB_ISNULL(vec_cmp_func_2 = VectorCmpExprFuncsHelper::get_row_cmp_func(
|
||||
val_meta, right_meta))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
VecValueTypeClass value_tc = get_vec_value_tc(val_meta.type_, val_meta.scale_, val_meta.precision_);
|
||||
VecValueTypeClass right_tc = get_vec_value_tc(right_meta.type_, right_meta.scale_, right_meta.precision_);
|
||||
LOG_WARN("The result of get_eval_vector_between_expr_cmp_func(right) is null.",
|
||||
K(ret), K(left_meta), K(val_meta), K(right_meta), K(value_tc), K(right_tc), K(rt_expr));
|
||||
} else if (OB_ISNULL(rt_expr.inner_functions_ = reinterpret_cast<void**>(
|
||||
expr_cg_ctx.allocator_->alloc(sizeof(DatumCmpFunc) * 2 +
|
||||
sizeof(EvalVectorBetweenFunc) * 2)))) {
|
||||
expr_cg_ctx.allocator_->alloc(sizeof(DatumCmpFunc) * 2 + sizeof(RowCmpFunc) * 2)))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("alloc memory for inner_functions_ failed", K(ret));
|
||||
} else {
|
||||
@ -269,5 +291,147 @@ int ObExprBetween::cg_expr(ObExprCGCtx &expr_cg_ctx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define DO_VECTOR_BETWEEN_ROW_CMP() \
|
||||
if (std::is_same<LVec, ObFixedLengthBase>::value) { \
|
||||
l_payload = fixed_base_l_payload + l_len * i; \
|
||||
} else if (!std::is_same<LVec, ObUniformFormat<true>>::value){ \
|
||||
l_vector->get_payload(i, l_payload, l_len); \
|
||||
} \
|
||||
if (std::is_same<RVec, ObFixedLengthBase>::value) { \
|
||||
r_payload = fixed_base_r_payload + r_len * i; \
|
||||
} else if (!std::is_same<RVec, ObUniformFormat<true>>::value){ \
|
||||
r_vector->get_payload(i, r_payload, r_len); \
|
||||
} \
|
||||
if (Stage == EvalBetweenStage::BETWEEN_LEFT) { \
|
||||
ret = (reinterpret_cast<RowCmpFunc>(expr.inner_functions_[2])) \
|
||||
(left->obj_meta_, right->obj_meta_, \
|
||||
(const void *)l_payload, l_len, \
|
||||
(const void *)r_payload, r_len, cmp_ret); \
|
||||
} else { /*BETWEEN_RIGHT*/ \
|
||||
ret = (reinterpret_cast<RowCmpFunc>(expr.inner_functions_[3])) \
|
||||
(left->obj_meta_, right->obj_meta_, \
|
||||
(const void *)l_payload, l_len, \
|
||||
(const void *)r_payload, r_len, cmp_ret); \
|
||||
}
|
||||
|
||||
#define DO_VECTOR_BETWEEN_SET_RES() \
|
||||
/* Result priority: false > null > true */ \
|
||||
if (OB_FAIL(ret)) { \
|
||||
} else if (Stage == EvalBetweenStage::BETWEEN_LEFT) { \
|
||||
/* If the current calculation is left<=val, any result is directly filled in. \
|
||||
If the result is false, the subsequent calculation results are meaningless, \
|
||||
and skip is set to true. */ \
|
||||
res_vec->set_int(i, (cmp_ret <= 0)); \
|
||||
if (cmp_ret > 0) { \
|
||||
skip.set(i); \
|
||||
} \
|
||||
} else if (cmp_ret > 0) { /*BETWEEN_RIGHT*/ \
|
||||
/* If currently calculating val<=right, \
|
||||
only when the result is false will it be filled in. */ \
|
||||
res_vec->set_int(i, 0); \
|
||||
}
|
||||
|
||||
|
||||
template <typename LVec, typename RVec, typename ResVec,
|
||||
ObExprBetween::EvalBetweenStage Stage>
|
||||
int ObExprBetween::inner_eval_between_vector(const ObExpr &expr,
|
||||
ObEvalCtx &ctx,
|
||||
ObBitVector &skip,
|
||||
const EvalBound &bound)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObExpr *left = nullptr;
|
||||
ObExpr *right = nullptr;
|
||||
if (Stage == EvalBetweenStage::BETWEEN_LEFT) {
|
||||
left = expr.args_[1];
|
||||
right = expr.args_[0];
|
||||
} else {
|
||||
left = expr.args_[0];
|
||||
right = expr.args_[2];
|
||||
}
|
||||
LVec *l_vector = static_cast<LVec *>(left->get_vector(ctx));
|
||||
RVec *r_vector = static_cast<RVec *>(right->get_vector(ctx));
|
||||
ResVec *res_vec = static_cast<ResVec *>(expr.get_vector(ctx));
|
||||
ObBitVector &eval_flags = expr.get_evaluated_flags(ctx);
|
||||
const char *l_payload = nullptr, *r_payload = nullptr;
|
||||
const char *fixed_base_l_payload = nullptr, *fixed_base_r_payload = nullptr;
|
||||
ObLength l_len = 0, r_len = 0;
|
||||
int cmp_ret = 0;
|
||||
bool l_has_null = l_vector->has_null();
|
||||
bool r_has_null = r_vector->has_null();
|
||||
// If a constant value exists and that constant value is null,
|
||||
// then set the entire res_vec to null.
|
||||
if (std::is_same<LVec, ObUniformFormat<true>>::value && l_has_null) {
|
||||
// If at this point the computation is val < right, and val is null,
|
||||
// then the result must have already been set to null previously,
|
||||
// and can be skipped directly.
|
||||
if (Stage == EvalBetweenStage::BETWEEN_LEFT) {
|
||||
for (int i = bound.start(); i < bound.end(); ++i) {
|
||||
if (skip.at(i) || eval_flags.at(i)) { continue; }
|
||||
res_vec->set_null(i);
|
||||
}
|
||||
}
|
||||
} else if (std::is_same<RVec, ObUniformFormat<true>>::value && r_has_null) {
|
||||
for (int i = bound.start(); i < bound.end(); ++i) {
|
||||
if (skip.at(i) || eval_flags.at(i)) { continue; }
|
||||
res_vec->set_null(i);
|
||||
}
|
||||
// For the case where both sides are constants, calculate only once,
|
||||
// then fill the values in a loop;
|
||||
// there is no need to consider the null situation,
|
||||
// as it has already been assessed previously.
|
||||
} else if (std::is_same<LVec, ObUniformFormat<true>>::value &&
|
||||
std::is_same<RVec, ObUniformFormat<true>>::value) {
|
||||
l_vector->get_payload(0, l_payload, l_len);
|
||||
r_vector->get_payload(0, r_payload, r_len);
|
||||
if (Stage == EvalBetweenStage::BETWEEN_LEFT) {
|
||||
ret = (reinterpret_cast<RowCmpFunc>(expr.inner_functions_[2]))
|
||||
(left->obj_meta_, right->obj_meta_,
|
||||
(const void *)l_payload, l_len,
|
||||
(const void *)r_payload, r_len, cmp_ret);
|
||||
} else { /*BETWEEN_RIGHT*/
|
||||
ret = (reinterpret_cast<RowCmpFunc>(expr.inner_functions_[3]))
|
||||
(left->obj_meta_, right->obj_meta_,
|
||||
(const void *)l_payload, l_len,
|
||||
(const void *)r_payload, r_len, cmp_ret);
|
||||
}
|
||||
for (int i = bound.start(); OB_SUCC(ret) && i < bound.end(); ++i) {
|
||||
if (skip.at(i) || eval_flags.at(i)) { continue; }
|
||||
DO_VECTOR_BETWEEN_SET_RES();
|
||||
}
|
||||
} else {
|
||||
if (std::is_same<LVec, ObFixedLengthBase>::value) {
|
||||
fixed_base_l_payload = (reinterpret_cast<ObFixedLengthBase *>(l_vector))->get_data();
|
||||
l_len = (reinterpret_cast<ObFixedLengthBase *>(l_vector))->get_length();
|
||||
} else if (std::is_same<LVec, ObUniformFormat<true>>::value) {
|
||||
l_vector->get_payload(0, l_payload, l_len);
|
||||
}
|
||||
if (std::is_same<RVec, ObFixedLengthBase>::value) {
|
||||
fixed_base_r_payload = (reinterpret_cast<ObFixedLengthBase *>(r_vector))->get_data();
|
||||
r_len = (reinterpret_cast<ObFixedLengthBase *>(r_vector))->get_length();
|
||||
} else if (std::is_same<RVec, ObUniformFormat<true>>::value) {
|
||||
r_vector->get_payload(0, r_payload, r_len);
|
||||
}
|
||||
if (!(l_has_null || r_has_null)) {
|
||||
for (int i = bound.start(); OB_SUCC(ret) && i < bound.end(); ++i) {
|
||||
if (skip.at(i) || eval_flags.at(i)) { continue; }
|
||||
DO_VECTOR_BETWEEN_ROW_CMP();
|
||||
DO_VECTOR_BETWEEN_SET_RES();
|
||||
}
|
||||
} else {
|
||||
for (int i = bound.start(); OB_SUCC(ret) && i < bound.end(); ++i) {
|
||||
if (skip.at(i) || eval_flags.at(i)) { continue; }
|
||||
if (l_vector->is_null(i) || r_vector->is_null(i)) {
|
||||
res_vec->set_null(i);
|
||||
} else {
|
||||
DO_VECTOR_BETWEEN_ROW_CMP();
|
||||
DO_VECTOR_BETWEEN_SET_RES();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,12 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
enum EvalBetweenStage {
|
||||
BETWEEN_LEFT,
|
||||
BETWEEN_RIGHT,
|
||||
BETWEEN_MAX
|
||||
};
|
||||
|
||||
virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr,
|
||||
ObExpr &rt_expr) const override;
|
||||
|
||||
@ -37,20 +43,13 @@ public:
|
||||
ObEvalCtx &ctx,
|
||||
const ObBitVector &skip,
|
||||
const EvalBound &bound);
|
||||
enum EvalBetweenStage {
|
||||
BETWEEN_LEFT,
|
||||
BETWEEN_RIGHT,
|
||||
BETWEEN_MAX
|
||||
};
|
||||
|
||||
struct EvalVectorBetweenCmp;
|
||||
|
||||
typedef int (*EvalVectorBetweenFunc) (const ObExpr &expr,
|
||||
const ObExpr &left,
|
||||
const ObExpr &right,
|
||||
ObEvalCtx &ctx,
|
||||
ObBitVector &skip,
|
||||
const EvalBound &bound);
|
||||
template <typename LVec, typename RVec, typename ResVec,
|
||||
EvalBetweenStage Stage>
|
||||
static int inner_eval_between_vector(const ObExpr &expr,
|
||||
ObEvalCtx &ctx,
|
||||
ObBitVector &skip,
|
||||
const EvalBound &bound);
|
||||
private:
|
||||
// types and constants
|
||||
private:
|
||||
|
@ -751,7 +751,7 @@ int ObExprFuncRound::calc_round_expr_numeric1_batch(const ObExpr &expr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, res_vec) \
|
||||
#define ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, res_vec) \
|
||||
switch (left_format) { \
|
||||
case VEC_FIXED: { \
|
||||
ret = func_name<ObFixedLengthBase, res_vec>(expr, ctx, skip, bound); \
|
||||
@ -778,31 +778,31 @@ switch (left_format) {
|
||||
} \
|
||||
}
|
||||
|
||||
#define ROUND_DISPATCH_VECTOR_IN_RES_ARG_FORMAT(func_name) \
|
||||
switch (res_format) { \
|
||||
case VEC_FIXED: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObFixedLengthBase); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_DISCRETE: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObDiscreteFormat); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_CONTINUOUS: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObContinuousFormat); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_UNIFORM: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObUniformFormat<false>); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_UNIFORM_CONST: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObUniformFormat<true>); \
|
||||
break; \
|
||||
} \
|
||||
default: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObVectorBase); \
|
||||
} \
|
||||
#define ROUND_DISPATCH_VECTOR_IN_RES_ARG_FORMAT(func_name) \
|
||||
switch (res_format) { \
|
||||
case VEC_FIXED: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObFixedLengthBase); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_DISCRETE: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObDiscreteFormat); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_CONTINUOUS: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObContinuousFormat); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_UNIFORM: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObUniformFormat<false>); \
|
||||
break; \
|
||||
} \
|
||||
case VEC_UNIFORM_CONST: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObUniformFormat<true>); \
|
||||
break; \
|
||||
} \
|
||||
default: { \
|
||||
ROUND_DISPATCH_VECTOR_IN_LEFT_ARG_FORMAT(func_name, ObVectorBase); \
|
||||
} \
|
||||
}
|
||||
|
||||
int ObExprFuncRound::calc_round_expr_numeric1_vector(const ObExpr &expr,
|
||||
|
@ -120,7 +120,7 @@ typedef void (*ser_eval_vector_function)(ObEvalVectorFuncTag &);
|
||||
OB_SFA_DECIMAL_INT_BASIC_PART1, \
|
||||
OB_SFA_DECIMAL_INT_BASIC_PART2, \
|
||||
OB_SFA_DECIMAL_INT_NULLSAFE_CMP, \
|
||||
OB_SFA_CMP_BETWEEN_EXPR_EVAL_VECTOR, \
|
||||
OB_SFA_VECTOR_CMP, \
|
||||
OB_SFA_SQL_EXPR_ABS_EVAL_VEC, \
|
||||
OB_SFA_VECTOR_CAST, \
|
||||
OB_SFA_VECTOR_EVAL_ARG_CAST, \
|
||||
|
Reference in New Issue
Block a user