From 7ae7524d3bfd41546ed26d94ef8faef8e3d57f51 Mon Sep 17 00:00:00 2001 From: obdev Date: Fri, 22 Sep 2023 12:17:47 +0000 Subject: [PATCH] When sql_mode='ALLOW_INVALID_DATES', the align_date4cmp remains compatible with previous versions of OB --- .../engine/expr/ob_expr_align_date4cmp.cpp | 58 +++++++++++++------ src/sql/engine/expr/ob_expr_align_date4cmp.h | 4 +- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/sql/engine/expr/ob_expr_align_date4cmp.cpp b/src/sql/engine/expr/ob_expr_align_date4cmp.cpp index bbcea675aa..a0dfa5c5a9 100644 --- a/src/sql/engine/expr/ob_expr_align_date4cmp.cpp +++ b/src/sql/engine/expr/ob_expr_align_date4cmp.cpp @@ -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; diff --git a/src/sql/engine/expr/ob_expr_align_date4cmp.h b/src/sql/engine/expr/ob_expr_align_date4cmp.h index 4625654532..eef7f245f7 100644 --- a/src/sql/engine/expr/ob_expr_align_date4cmp.h +++ b/src/sql/engine/expr/ob_expr_align_date4cmp.h @@ -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);