diff --git a/src/sql/engine/expr/ob_expr_align_date4cmp.cpp b/src/sql/engine/expr/ob_expr_align_date4cmp.cpp index 20a1a61f46..413d211c6e 100644 --- a/src/sql/engine/expr/ob_expr_align_date4cmp.cpp +++ b/src/sql/engine/expr/ob_expr_align_date4cmp.cpp @@ -17,6 +17,8 @@ #include "common/object/ob_obj_compare.h" #include "lib/timezone/ob_time_convert.h" #include "sql/resolver/expr/ob_raw_expr.h" +#include "sql/engine/expr/ob_expr_util.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" namespace oceanbase { @@ -105,6 +107,7 @@ int ObExprAlignDate4Cmp::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_ LOG_WARN("the arg of expr_align_date4cmp is null.", K(ret), K(rt_expr)); } else { rt_expr.eval_func_ = eval_align_date4cmp; + rt_expr.extra_ = raw_expr.get_extra(); } return ret; } @@ -129,18 +132,21 @@ int ObExprAlignDate4Cmp::eval_align_date4cmp(const ObExpr &expr, ObEvalCtx &ctx, } else { date_arg_obj_type = expr.args_[0]->datum_meta_.type_; res_type = ObObjType(res_type_datum->get_int()); - if(OB_FAIL(datum_to_ob_time(date_datum, date_arg_obj_type, date_arg_type, ob_time))) { + if(OB_FAIL(datum_to_ob_time(expr, date_datum, date_arg_obj_type, date_arg_type, ob_time))) { LOG_WARN("datum_to_ob_time fail.", K(ret), K(date_datum), K(date_arg_obj_type)); } } bool offset = false; 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_); if (OB_SUCC(ret)) { switch(date_arg_type) { case VALID_DATE: { const bool is_valid_time = true; - if (OB_FAIL(set_res(res, ob_time, res_type, is_valid_time, offset, is_zero_on_warn))) { + 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)); } break; @@ -151,7 +157,8 @@ int ObExprAlignDate4Cmp::eval_align_date4cmp(const ObExpr &expr, ObEvalCtx &ctx, // 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))) { + 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)); } } else { @@ -159,10 +166,12 @@ int ObExprAlignDate4Cmp::eval_align_date4cmp(const ObExpr &expr, ObEvalCtx &ctx, 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))) { + 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)); } - } else if (OB_FAIL(set_res(res, ob_time, res_type, is_valid_time, offset, is_zero_on_warn))) { + } 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)); } } @@ -170,7 +179,8 @@ int ObExprAlignDate4Cmp::eval_align_date4cmp(const ObExpr &expr, ObEvalCtx &ctx, } case NON_DATE: { const bool is_valid_time = false; - if (OB_FAIL(set_res(res, ob_time, res_type, is_valid_time, offset, is_zero_on_warn))) { + 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)); } break; @@ -179,14 +189,18 @@ int ObExprAlignDate4Cmp::eval_align_date4cmp(const ObExpr &expr, ObEvalCtx &ctx, res.set_null(); break; } + case ZERO_DATE: { + if (OB_FAIL(set_zero_res(res, ob_time, res_type, is_no_zero_date))) { + LOG_WARN("set_zero_res fail.", K(ret), K(ob_time), K(res_type)); + } + } } } return ret; } - -void ObExprAlignDate4Cmp::set_valid_time_floor(ObTime& ob_time) +void ObExprAlignDate4Cmp::set_valid_time_floor(ObTime &ob_time) { int ret = OB_SUCCESS; if(IS_LEAP_YEAR(ob_time.parts_[DT_YEAR])) { @@ -203,7 +217,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::day_over_limit(const ObTime &ob_time) { bool res = true; if(IS_LEAP_YEAR(ob_time.parts_[DT_YEAR])) { @@ -214,51 +228,109 @@ bool ObExprAlignDate4Cmp::day_over_limit(const ObTime& ob_time) return res; } -int ObExprAlignDate4Cmp::integer_to_ob_time(const int64_t& date, - DateArgType& date_arg_type, - ObTime& ob_time) +ObExprAlignDate4Cmp::DateArgType ObExprAlignDate4Cmp::validate_time(ObTime &ob_time) +{ + DateArgType date_arg_type = VALID_DATE; + const int32_t *parts = ob_time.parts_; + if (!HAS_TYPE_ORACLE(ob_time.mode_) + && 0 == parts[DT_YEAR] && 0 == parts[DT_MON] && 0 == parts[DT_MDAY] && 0 == parts[DT_HOUR] + && 0 == parts[DT_MIN] && 0 == parts[DT_SEC] && 0 == parts[DT_USEC]) { + date_arg_type = ZERO_DATE; + } else { + const int64_t *part_min = (HAS_TYPE_ORACLE(ob_time.mode_) ? TZ_PART_MIN : DT_PART_MIN); + const int64_t *part_max = (HAS_TYPE_ORACLE(ob_time.mode_) ? TZ_PART_MAX : DT_PART_MAX); + for (int i = 0; i < DATETIME_PART_CNT; ++i) { + if (!(part_min[i] <= parts[i] && parts[i] <= part_max[i])) { + date_arg_type = INVALID_DATE; + } + } + int is_leap = IS_LEAP_YEAR(parts[DT_YEAR]); + if (parts[DT_MDAY] > 31 || + parts[DT_MDAY] > DAYS_OF_MON[is_leap][parts[DT_MON]]) { + date_arg_type = INVALID_DATE; + } + } + return date_arg_type; +} + +int ObExprAlignDate4Cmp::integer_to_ob_time(const int64_t &date, + DateArgType &date_arg_type, + ObTime &ob_time) { int ret = OB_SUCCESS; - ObDateSqlMode date_sql_mode; - // First try to perform a lenient type conversion. - // If it fails, it means the value is not convertible to time. - date_sql_mode.allow_invalid_dates_ = true; - date_sql_mode.no_zero_date_ = false; - if (OB_FAIL(ObTimeConverter::int_to_ob_time_with_date(date, ob_time, true, date_sql_mode))) { - date_arg_type = NON_DATE; - ret = OB_SUCCESS; + if (date == 0) { + date_arg_type = ZERO_DATE; } else { - // Then perform a strict type conversion check. - // If successful, it indicates a VALID_DATE; - // if unsuccessful, it indicates an INVALID_DATE. - date_sql_mode.allow_invalid_dates_ = false; - date_sql_mode.no_zero_date_ = true; - if (OB_SUCC(ObTimeConverter::validate_datetime(ob_time, false, date_sql_mode))) { - date_arg_type = VALID_DATE; - } else { - date_arg_type = INVALID_DATE; + ObDateSqlMode date_sql_mode; + // First try to perform a lenient type conversion. + // If it fails, it means the value is not convertible to time. + date_sql_mode.allow_invalid_dates_ = true; + date_sql_mode.no_zero_date_ = false; + if (OB_FAIL(ObTimeConverter::int_to_ob_time_with_date(date, ob_time, true, date_sql_mode))) { + date_arg_type = NON_DATE; ret = OB_SUCCESS; + } else { + // Then perform a strict type conversion check. + date_arg_type = validate_time(ob_time); } } return ret; } -int ObExprAlignDate4Cmp::double_to_ob_time(const double& date, DateArgType& date_arg_type, ObTime& ob_time) { - return integer_to_ob_time((int64_t)date, date_arg_type, ob_time); +static const int64_t MAX_DOUBLE_STRICT_PRINT_SIZE = 512; + +template +static int common_floating_number(const IN_TYPE in_val, + const ob_gcvt_arg_type arg_type, + ObIAllocator &alloc, + number::ObNumber &number) +{ + int ret = OB_SUCCESS; + char buf[MAX_DOUBLE_STRICT_PRINT_SIZE]; + MEMSET(buf, 0, MAX_DOUBLE_STRICT_PRINT_SIZE); + int64_t length = 0; + if (OB_GCVT_ARG_DOUBLE == arg_type) { + length = ob_gcvt_opt(in_val, arg_type, static_cast(sizeof(buf) - 1), + buf, NULL, lib::is_oracle_mode(), TRUE); + } else { + length = ob_gcvt(in_val, OB_GCVT_ARG_DOUBLE, sizeof(buf) - 1, buf, NULL); + } + ObString str(sizeof(buf), static_cast(length), buf); + ObScale res_scale; // useless + ObPrecision res_precision; + ret = number.from_sci_opt(str.ptr(), str.length(), alloc, + &res_precision, &res_scale); + return ret; } -int ObExprAlignDate4Cmp::number_to_ob_time(const number::ObNumber& date, DateArgType& date_arg_type, ObTime& ob_time) { +int ObExprAlignDate4Cmp::double_to_ob_time(const double &date, DateArgType &date_arg_type, ObTime &ob_time) { int ret = OB_SUCCESS; - int64_t date_int = 0; - if (OB_FAIL(date.extract_valid_int64_with_trunc(date_int))) { - LOG_WARN("extract_valid_int64_with_trunc fail.", K(ret), K(date)); - } else if (OB_FAIL(integer_to_ob_time(date_int, date_arg_type, ob_time))) { - LOG_WARN("cast integer to ob_time fail.", K(ret), K(date_int)); + ObNumStackOnceAlloc tmp_alloc; + number::ObNumber number; + if (OB_FAIL(common_floating_number(date, OB_GCVT_ARG_DOUBLE, tmp_alloc, number))) { + ret = OB_SUCCESS; + date_arg_type = NON_DATE; + } else if (OB_FAIL(number_to_ob_time(number, date_arg_type, ob_time))) { + LOG_WARN("number to ob_time failed", K(ret), K(number)); } return ret; } -int ObExprAlignDate4Cmp::str_to_ob_time(const ObString& date, DateArgType& date_arg_type, ObTime& ob_time) { +int ObExprAlignDate4Cmp::number_to_ob_time(const number::ObNumber &date, DateArgType &date_arg_type, ObTime &ob_time) { + int ret = OB_SUCCESS; + int64_t int_part = 0; + int64_t dec_part = 0; + if (!date.is_int_parts_valid_int64(int_part, dec_part)) { + date_arg_type = NON_DATE; + } else if (OB_FAIL(integer_to_ob_time(int_part, date_arg_type, ob_time))) { + LOG_WARN("cast integer to ob_time fail.", K(ret), K(int_part)); + } else { + ob_time.parts_[DT_USEC] = (dec_part + 500) / 1000; + } + return ret; +} + +int ObExprAlignDate4Cmp::str_to_ob_time(const ObString &date, DateArgType &date_arg_type, ObTime &ob_time) { int ret = OB_SUCCESS; ObDateSqlMode date_sql_mode; date_sql_mode.allow_invalid_dates_ = true; @@ -267,28 +339,30 @@ int ObExprAlignDate4Cmp::str_to_ob_time(const ObString& date, DateArgType& date_ date_arg_type = NON_DATE; ret = OB_SUCCESS; } else { - date_sql_mode.allow_invalid_dates_ = false; - date_sql_mode.no_zero_date_ = true; - if (OB_SUCC(ObTimeConverter::validate_datetime(ob_time, false, date_sql_mode))) { - date_arg_type = VALID_DATE; - } else { - date_arg_type = INVALID_DATE; - ret = OB_SUCCESS; - } + date_arg_type = validate_time(ob_time); } return ret; } -int ObExprAlignDate4Cmp::datum_to_ob_time(const ObDatum* date_datum, const ObObjType& date_arg_obj_type, DateArgType& date_arg_type, ObTime& ob_time) +int ObExprAlignDate4Cmp::datum_to_ob_time(const ObExpr &expr, + const ObDatum* date_datum, + const ObObjType& date_arg_obj_type, + DateArgType &date_arg_type, + ObTime &ob_time) { int ret = OB_SUCCESS; if (date_datum->is_null()) { date_arg_type = NULL_DATE; } else if (ob_is_string_type(date_arg_obj_type)) { - if (OB_FAIL(str_to_ob_time(date_datum->get_string(), date_arg_type, ob_time))) { + ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObString str = date_datum->get_string(); + if (OB_FAIL(ObTextStringHelper::read_real_string_data(&lob_allocator, date_arg_obj_type, + CS_TYPE_BINARY, expr.args_[0]->obj_meta_.has_lob_header(), str))) { + LOG_WARN("fail to get real string data", K(ret), K(date_datum)); + } else if (OB_FAIL(str_to_ob_time(str, date_arg_type, ob_time))) { LOG_WARN("str_to_ob_time fail.", K(ret), K(date_datum)); } - } else { + } else { // numeric switch(date_arg_obj_type) { case ObNullType: { date_arg_type = NULL_DATE; @@ -299,8 +373,7 @@ int ObExprAlignDate4Cmp::datum_to_ob_time(const ObDatum* date_datum, const ObObj case ObMediumIntType: case ObInt32Type: case ObIntType: { - if (OB_FAIL(integer_to_ob_time(static_cast(date_datum->get_uint()), - date_arg_type, ob_time))) { + if (OB_FAIL(integer_to_ob_time(date_datum->get_int(), date_arg_type, ob_time))) { LOG_WARN("integer_to_ob_time fail.", K(ret), K(date_datum)); } break; @@ -310,7 +383,8 @@ int ObExprAlignDate4Cmp::datum_to_ob_time(const ObDatum* date_datum, const ObObj case ObUMediumIntType: case ObUInt32Type: case ObUInt64Type: { - if (OB_FAIL(integer_to_ob_time(date_datum->get_int(), date_arg_type, ob_time))) { + if (OB_FAIL(integer_to_ob_time(static_cast(date_datum->get_uint()), + date_arg_type, ob_time))) { LOG_WARN("integer_to_ob_time fail.", K(ret), K(date_datum)); } break; @@ -344,7 +418,6 @@ int ObExprAlignDate4Cmp::datum_to_ob_time(const ObDatum* date_datum, const ObObj } } } - return ret; } @@ -352,7 +425,9 @@ int ObExprAlignDate4Cmp::set_res(ObDatum &res, ObTime &ob_time, const ObObjType &res_type, const bool is_valid_time, const bool offset, - const bool is_zero_on_warn) + const bool is_zero_on_warn, + const bool is_no_zero_date, + const bool is_warn_on_fail) { int ret = OB_SUCCESS; switch(res_type) { @@ -362,8 +437,10 @@ int ObExprAlignDate4Cmp::set_res(ObDatum &res, ObTime &ob_time, } case ObDateTimeType: { if (!is_valid_time) { - if (is_zero_on_warn) { - res.set_datetime(0); + if (!is_warn_on_fail) { + ret = OB_INVALID_DATE_FORMAT; + } else if (is_zero_on_warn && !is_no_zero_date) { + res.set_datetime(ObTimeConverter::ZERO_DATETIME); } else { res.set_null(); } @@ -380,8 +457,10 @@ int ObExprAlignDate4Cmp::set_res(ObDatum &res, ObTime &ob_time, } case ObDateType: { if (!is_valid_time) { - if (is_zero_on_warn) { - res.set_date(0); + if (!is_warn_on_fail) { + ret = OB_INVALID_DATE_FORMAT; + } else if (is_zero_on_warn && !is_no_zero_date) { + res.set_date(ObTimeConverter::ZERO_DATE); } else { res.set_null(); } @@ -397,11 +476,45 @@ int ObExprAlignDate4Cmp::set_res(ObDatum &res, ObTime &ob_time, break; } } - return ret; } -bool ObExprAlignDate4Cmp::is_align_date4cmp_support_obj_type(const ObObjType& obj_type) { +int ObExprAlignDate4Cmp::set_zero_res(ObDatum &res, ObTime &ob_time, + const ObObjType &res_type, + bool is_no_zero_date) +{ + int ret = OB_SUCCESS; + switch(res_type) { + case ObNullType: { + res.set_null(); + break; + } + case ObDateTimeType: { + if (is_no_zero_date) { + res.set_null(); + } else { + res.set_datetime(ObTimeConverter::ZERO_DATETIME + ob_time.parts_[DT_USEC]); + } + break; + } + case ObDateType: { + if (is_no_zero_date) { + res.set_null(); + } else { + res.set_date(ObTimeConverter::ZERO_DATE); + } + break; + } + default: { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("unexpected res type.", K(ret), K(res_type)); + break; + } + } + return ret; +} + +bool ObExprAlignDate4Cmp::is_align_date4cmp_support_obj_type(const ObObjType &obj_type) { bool res = false; if (ObNullType <= obj_type && obj_type <= ObUNumberType) { res = true; diff --git a/src/sql/engine/expr/ob_expr_align_date4cmp.h b/src/sql/engine/expr/ob_expr_align_date4cmp.h index 9a86b435ca..4625654532 100644 --- a/src/sql/engine/expr/ob_expr_align_date4cmp.h +++ b/src/sql/engine/expr/ob_expr_align_date4cmp.h @@ -52,6 +52,7 @@ public: INVALID_DATE = 2, NON_DATE = 3, NULL_DATE = 4, + ZERO_DATE = 5, }; private: @@ -60,19 +61,27 @@ private: static bool day_over_limit(const ObTime &ob_time); static void set_valid_time_floor(ObTime &ob_time); + 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); static int number_to_ob_time(const number::ObNumber &date, DateArgType &date_arg_type, ObTime &ob_time); static int str_to_ob_time(const ObString &date, DateArgType &date_arg_type, ObTime &ob_time); - static int datum_to_ob_time(const ObDatum *date_datum, + static int datum_to_ob_time(const ObExpr &expr, + const ObDatum *date_datum, const ObObjType &date_arg_obj_type, DateArgType &date_arg_type, ObTime &ob_time); + static bool is_zero_time(ObTime &ob_time); static int set_res(ObDatum &res, ObTime &ob_time, const ObObjType &res_type, const bool is_valid_time, const bool offset, - const bool is_zero_on_warn); + const bool is_zero_on_warn, + const bool is_no_zero_date, + const bool is_warn_on_fail); + static int set_zero_res(ObDatum &res, ObTime &ob_time, + const ObObjType &res_type, + bool is_no_zero_date); }; } }