support last_day in mysql mode

This commit is contained in:
jg0
2021-07-27 21:39:15 +08:00
committed by wangzelin.wzl
parent 09edba0ff6
commit 74d0236609
45 changed files with 26893 additions and 25079 deletions

View File

@ -45,6 +45,28 @@ int ObExprPeriodDiff::calc_result2(ObObj& result, const ObObj& left, const ObObj
return ret;
}
int get_year_month(const uint64_t value, uint64_t &year, uint64_t &month)
{
int ret = OB_SUCCESS;
const uint64_t YEAR_BASE_YEAR = 1900;
const uint64_t YEAR_VALUE_FACTOR = 100;
const uint64_t YEAR_ADJUST_THRESHOLD = 70;
const uint64_t YEAR_ADJUST_OFFSET = 2000;
year = value / YEAR_VALUE_FACTOR;
uint64_t tmp = year;
/*
*11(uint) will be treat as 11 + YEAR_ADJUST_OFFSET = 2011(year)
*68(uint) will be treat as 68 + YEAR_BASE_YEAR = 1968(year)
*1234(uint) will be treat as 1234(year)
*/
if (year < YEAR_ADJUST_THRESHOLD)
year += YEAR_ADJUST_OFFSET;
else if (tmp < YEAR_VALUE_FACTOR)
year += YEAR_BASE_YEAR;
month = value - tmp * YEAR_VALUE_FACTOR; // % operation ? too expensive !
return ret;
}
template <typename T>
int ObExprPeriodDiff::calc(T& result, const T& left, const T& right)
{
@ -67,28 +89,6 @@ int ObExprPeriodDiff::calc(T& result, const T& left, const T& right)
return ret;
}
int ObExprPeriodDiff::get_year_month(const uint64_t value, uint64_t& year, uint64_t& month)
{
int ret = OB_SUCCESS;
const uint64_t YEAR_BASE_YEAR = 1900;
const uint64_t YEAR_VALUE_FACTOR = 100;
const uint64_t YEAR_ADJUST_THRESHOLD = 70;
const uint64_t YEAR_ADJUST_OFFSET = 2000;
year = value / YEAR_VALUE_FACTOR;
uint64_t tmp = year;
/*
*11(uint) will be treat as 11 + YEAR_ADJUST_OFFSET = 2011(year)
*68(uint) will be treat as 68 + YEAR_BASE_YEAR = 1968(year)
*1234(uint) will be treat as 1234(year)
*/
if (year < YEAR_ADJUST_THRESHOLD)
year += YEAR_ADJUST_OFFSET;
else if (tmp < YEAR_VALUE_FACTOR)
year += YEAR_BASE_YEAR;
month = value - tmp * YEAR_VALUE_FACTOR; // % operation ? too expensive !
return ret;
}
int ObExprPeriodDiff::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const
{
UNUSED(op_cg_ctx);
@ -124,5 +124,119 @@ int ObExprPeriodDiff::calc_perioddiff(const ObExpr& expr, ObEvalCtx& ctx, ObDatu
return ret;
}
ObExprPeriodAdd::ObExprPeriodAdd(ObIAllocator &alloc)
: ObFuncExprOperator(alloc, T_FUN_SYS_PERIOD_ADD, N_PERIOD_ADD, 2, NOT_ROW_DIMENSION)
{
}
ObExprPeriodAdd::~ObExprPeriodAdd()
{
}
int ObExprPeriodAdd::calc_result_type2(ObExprResType &type,
ObExprResType &left,
ObExprResType &right,
common::ObExprTypeCtx &type_ctx) const
{
type.set_int();
type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_);
type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_);
left.set_calc_type(common::ObIntType);
right.set_calc_type(common::ObIntType);
type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_STRING_INTEGER_TRUNC);
return common::OB_SUCCESS;
}
int ObExprPeriodAdd::calc_result2(ObObj &result,
const ObObj &left,
const ObObj &right,
ObExprCtx &expr_ctx) const
{
UNUSED(expr_ctx);
int ret = OB_SUCCESS;
if (OB_UNLIKELY(left.is_null() || right.is_null())) {
result.set_null();
} else {
TYPE_CHECK(left, ObIntType);
TYPE_CHECK(right, ObIntType);
if (OB_SUCC(ret)) {
ret = calc(result, left, right);
}
}
return ret;
}
template <typename T>
int ObExprPeriodAdd::calc(
T &result,
const T &left,
const T &right)
{
int ret = OB_SUCCESS;
int64_t lvalue = left.get_int();
int64_t rvalue = right.get_int();
uint64_t lyear = 0;
uint64_t lmonth = 0;
if (OB_UNLIKELY(lvalue <= 0)) {
// not consistent with Mysql, by design.
result.set_int(0);
} else if (OB_FAIL(get_year_month(static_cast<uint64_t>(lvalue), lyear, lmonth))) {
LOG_WARN("get_year_month failed", K(ret), K(lvalue), K(lyear), K(lmonth));
} else {
int64_t res_months = lyear * MONS_PER_YEAR + lmonth + rvalue;
int64_t year = (res_months - 1) / MONS_PER_YEAR;
int64_t month = ((res_months - 1) % MONS_PER_YEAR) + 1;
if (OB_UNLIKELY(res_months <= 0 )) {
result.set_int(0);
} else {
if (year < 70) {
year += 2000;
} else if (year < 100) {
year += 1900;
}
result.set_int(year * 100 + month);
}
}
return ret;
}
int ObExprPeriodAdd::cg_expr(ObExprCGCtx &op_cg_ctx,
const ObRawExpr &raw_expr,
ObExpr &rt_expr) const
{
UNUSED(op_cg_ctx);
UNUSED(raw_expr);
int ret = OB_SUCCESS;
if (rt_expr.arg_cnt_ != 2) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("periodadd expr should have two params", K(ret), K(rt_expr.arg_cnt_));
} else if (OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0])
|| OB_ISNULL(rt_expr.args_[1])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("children of periodadd expr is null", K(ret), K(rt_expr.args_));
} else {
CK(ObIntType == rt_expr.args_[0]->datum_meta_.type_);
CK(ObIntType == rt_expr.args_[1]->datum_meta_.type_);
rt_expr.eval_func_ = ObExprPeriodAdd::calc_periodadd;
}
return ret;
}
int ObExprPeriodAdd::calc_periodadd(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
{
int ret = OB_SUCCESS;
ObDatum *param_datum1 = NULL;
ObDatum *param_datum2 = NULL;
if (OB_FAIL(expr.eval_param_value(ctx, param_datum1, param_datum2))) {
LOG_WARN("eval param value failed", K(ret));
} else if (OB_UNLIKELY(param_datum1->is_null() || param_datum2->is_null())) {
expr_datum.set_null();
} else {
ObDatum *res_datum = static_cast<ObDatum *>(&expr_datum);
ret = calc(*res_datum, *param_datum1, *param_datum2);
}
return ret;
}
} // namespace sql
} // namespace oceanbase
} // namespace oceanbase