When sql_mode='ALLOW_INVALID_DATES', the align_date4cmp remains compatible with previous versions of OB

This commit is contained in:
obdev
2023-09-22 12:17:47 +00:00
committed by ob-robot
parent 05bb1a50da
commit 7ae7524d3b
2 changed files with 43 additions and 19 deletions

View File

@ -141,6 +141,7 @@ int ObExprAlignDate4Cmp::eval_align_date4cmp(const ObExpr &expr, ObEvalCtx &ctx,
const bool is_zero_on_warn = CM_IS_ZERO_ON_WARN(expr.extra_);
const bool is_no_zero_date = CM_IS_NO_ZERO_DATE(expr.extra_);
const bool is_warn_on_fail = CM_IS_WARN_ON_FAIL(expr.extra_);
const bool is_allow_invalid_dates = CM_IS_ALLOW_INVALID_DATES(expr.extra_);
if (OB_SUCC(ret)) {
switch(date_arg_type) {
case VALID_DATE: {
@ -155,30 +156,28 @@ int ObExprAlignDate4Cmp::eval_align_date4cmp(const ObExpr &expr, ObEvalCtx &ctx,
case INVALID_DATE: {
bool is_valid_time = false;
int cmp_type = cmp_type_datum->get_int();
// if cmp_type == T_OP_EQ or T_OP_NSEQ or T_OP_NE,
// return null or 0 depending on is_zero_on_warn.
if (cmp_type == T_OP_EQ || cmp_type == T_OP_NSEQ || cmp_type == T_OP_NE) {
if (OB_FAIL(set_res(res, ob_time, res_type, is_valid_time, offset,
is_zero_on_warn, is_no_zero_date, is_warn_on_fail))) {
LOG_WARN("set_res fail.", K(ret), K(ob_time), K(res_type),
K(date_arg_type), K(is_valid_time));
// Compatible with previous versions of ob, not with mysql
if (is_allow_invalid_dates) {
int32_t offset = get_day_over_limit(ob_time);
if (offset > 0) {
push_back_n_days(ob_time, offset);
is_valid_time = true;
}
}
} else {
if (day_over_limit(ob_time)) {
} else { // cmp_type is: >, >=, <, <=
// Compatible with mysql, not with previous versions of ob
if (is_day_over_limit(ob_time)) {
offset = (cmp_type == T_OP_GT || cmp_type == T_OP_LE) ? false : true;
set_valid_time_floor(ob_time);
is_valid_time = true;
if (OB_FAIL(set_res(res, ob_time, res_type, is_valid_time, offset,
is_zero_on_warn, is_no_zero_date, is_warn_on_fail))) {
LOG_WARN("set_res fail.", K(ret), K(ob_time), K(res_type),
K(date_arg_type), K(is_valid_time));
}
} else if (OB_FAIL(set_res(res, ob_time, res_type, is_valid_time, offset,
is_zero_on_warn, is_no_zero_date, is_warn_on_fail))) {
LOG_WARN("set_res fail.", K(ret), K(ob_time), K(res_type),
K(date_arg_type), K(is_valid_time));
}
}
if (OB_FAIL(set_res(res, ob_time, res_type, is_valid_time, offset,
is_zero_on_warn, is_no_zero_date, is_warn_on_fail))) {
LOG_WARN("set_res fail.", K(ret), K(ob_time), K(res_type),
K(date_arg_type), K(is_valid_time));
}
break;
}
case NON_DATE: {
@ -205,6 +204,17 @@ int ObExprAlignDate4Cmp::eval_align_date4cmp(const ObExpr &expr, ObEvalCtx &ctx,
return ret;
}
// Because the date greater than 31 will be considered as NON_DATE,
// the maximum number of days to be pushed back in this case is 31-28=3.
// For year and month, the maximum pushback is limited to 1.
void ObExprAlignDate4Cmp::push_back_n_days(ObTime &ob_time, int32_t offset)
{
ob_time.parts_[DT_YEAR] += ob_time.parts_[DT_MON] / MONTHS_PER_YEAR;
ob_time.parts_[DT_MON] = (ob_time.parts_[DT_MON] + 1) % MONTHS_PER_YEAR;
ob_time.parts_[DT_MDAY] = offset;
ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time);
}
void ObExprAlignDate4Cmp::set_valid_time_floor(ObTime &ob_time)
{
int ret = OB_SUCCESS;
@ -222,7 +232,7 @@ void ObExprAlignDate4Cmp::set_valid_time_floor(ObTime &ob_time)
ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time);
}
bool ObExprAlignDate4Cmp::day_over_limit(const ObTime &ob_time)
bool ObExprAlignDate4Cmp::is_day_over_limit(const ObTime &ob_time)
{
bool res = true;
if (ob_time.parts_[DT_MON] < 1 || ob_time.parts_[DT_MON] > 12) {
@ -235,6 +245,18 @@ bool ObExprAlignDate4Cmp::day_over_limit(const ObTime &ob_time)
return res;
}
int32_t ObExprAlignDate4Cmp::get_day_over_limit(const ObTime &ob_time)
{
int32_t res = 0;
if (ob_time.parts_[DT_MON] < 1 || ob_time.parts_[DT_MON] > 12) {
} else if(IS_LEAP_YEAR(ob_time.parts_[DT_YEAR])) {
res = ob_time.parts_[DT_MDAY] - DAYS_OF_MON[1][ob_time.parts_[DT_MON]];
} else {
res = ob_time.parts_[DT_MDAY] - DAYS_OF_MON[0][ob_time.parts_[DT_MON]];
}
return res > 0 ? res : 0;
}
ObExprAlignDate4Cmp::DateArgType ObExprAlignDate4Cmp::validate_time(ObTime &ob_time)
{
DateArgType date_arg_type = VALID_DATE;

View File

@ -59,8 +59,10 @@ private:
//disallow copy
DISALLOW_COPY_AND_ASSIGN(ObExprAlignDate4Cmp);
static bool day_over_limit(const ObTime &ob_time);
static bool is_day_over_limit(const ObTime &ob_time);
static int32_t get_day_over_limit(const ObTime &ob_time);
static void set_valid_time_floor(ObTime &ob_time);
static void push_back_n_days(ObTime &ob_time, int32_t offset);
static DateArgType validate_time(ObTime &ob_time);
static int integer_to_ob_time(const int64_t &date, DateArgType &date_arg_type, ObTime &ob_time);
static int double_to_ob_time(const double &date, DateArgType &date_arg_type, ObTime &ob_time);