diff --git a/deps/oblib/src/lib/ob_name_def.h b/deps/oblib/src/lib/ob_name_def.h index 1b9970443..5fed7ef65 100644 --- a/deps/oblib/src/lib/ob_name_def.h +++ b/deps/oblib/src/lib/ob_name_def.h @@ -117,6 +117,7 @@ #define N_NUM "num" #define N_SINH "sinh" #define N_COSH "cosh" +#define N_DEGREES "degrees" #define N_TANH "tanh" #define N_RADIANS "radians" #define N_IS_JOIN "is_join" diff --git a/src/share/object/ob_obj_cast.cpp b/src/share/object/ob_obj_cast.cpp index 9947f872e..3d62652d6 100644 --- a/src/share/object/ob_obj_cast.cpp +++ b/src/share/object/ob_obj_cast.cpp @@ -2013,6 +2013,29 @@ static int double_time( return ret; } +static int double_year(const ObObjType expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out, const ObCastMode cast_mode) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() + || ObYearTC != ob_obj_type_class(expect_type))) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid input type", + K(ret), K(in), K(expect_type)); + } else { + uint8_t value = 0; + double in_val = in.get_double(); + in_val = in_val < 0 ? INT_MIN : in_val + 0.5; + uint64_t intvalue = static_cast(in_val); + if (CAST_FAIL(ObTimeConverter::int_to_year(intvalue, value))) { + } else { + SET_RES_YEAR(out); + } + } + SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_YEAR, DEFAULT_LENGTH_FOR_TEMPORAL); + return ret; +} + static int double_string( const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode) { @@ -2382,6 +2405,10 @@ static int number_year( if (OB_ISNULL(value)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null pointer", K(ret), K(value)); + } else if (in.get_number().is_negative()) { + uint8_t value = 0; + if (CAST_FAIL(ObTimeConverter::int_to_year(INT_MIN, value))) { + } } else { ObObj from; from.set_varchar(value, static_cast(strlen(value))); @@ -5772,7 +5799,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = { double_datetime, /*datetime*/ double_date, /*date*/ double_time, /*time*/ - cast_not_support, /*year*/ + double_year, /*year*/ double_string, /*string*/ cast_not_support, /*extend*/ cast_not_support, /*unknown*/ diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt index 0749eee12..634c3903a 100644 --- a/src/sql/CMakeLists.txt +++ b/src/sql/CMakeLists.txt @@ -354,6 +354,8 @@ ob_set_subtarget(ob_sql engine engine/expr/ob_expr_pi.cpp engine/expr/ob_expr_pi.h engine/expr/ob_expr_radians.cpp + engine/expr/ob_expr_degrees.cpp + engine/expr/ob_expr_degrees.h engine/expr/ob_expr_res_type_map.cpp engine/expr/ob_expr_result_type_util.cpp engine/expr/ob_expr_reverse.cpp diff --git a/src/sql/engine/expr/ob_datum_cast.cpp b/src/sql/engine/expr/ob_datum_cast.cpp index b1932a45e..9d6e04eaa 100644 --- a/src/sql/engine/expr/ob_datum_cast.cpp +++ b/src/sql/engine/expr/ob_datum_cast.cpp @@ -2230,7 +2230,14 @@ CAST_FUNC_NAME(number, year) if (OB_ISNULL(nmb_buf)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null pointer", K(ret), K(nmb_buf)); - } else if (OB_FAIL(common_string_year(expr, ObString(strlen(nmb_buf), nmb_buf), res_datum))) { + } else if (nmb.is_negative()) { + // the year shouldn't accept a negative number, if we use the common_string_year. + // number like -0.4 could be converted to year, which should raise error in mysql + if (OB_FAIL(common_int_year(expr, INT_MIN, res_datum))) { + LOG_WARN("common_int_year failed", K(ret)); + } + } else if (OB_FAIL(common_string_year(expr, ObString(strlen(nmb_buf), nmb_buf), + res_datum))) { LOG_WARN("common_string_year failed", K(ret)); } } @@ -2635,6 +2642,24 @@ CAST_FUNC_NAME(double, time) return ret; } +CAST_FUNC_NAME(double, year) +{ + EVAL_ARG() + { + // When we insert 999999999999999999999.9(larger than max int) into a year field in mysql + // Mysql raise the same error as we insert 100 into a year field (1264). + // So the cast from double to int won't raise extra error. That's why we directly use + // static_cast here. Mysql will convert the double to nearest int and insert it to the year field. + double in_val = child_res->get_double(); + in_val = in_val < 0 ? INT_MIN : in_val + 0.5; + int64_t val_int = static_cast(in_val); + if (OB_FAIL(common_int_year(expr, val_int, res_datum))) { + LOG_WARN("common_int_time failed", K(ret), K(val_int)); + } + } + return ret; +} + CAST_FUNC_NAME(double, string) { EVAL_ARG() @@ -5916,7 +5941,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = { cast_inconsistent_types, /*datetime*/ cast_not_expected, /*date*/ cast_not_expected, /*time*/ - cast_not_expected, /*year*/ + double_year, /*year*/ double_string, /*string*/ cast_not_expected, /*extend*/ cast_not_expected, /*unknown*/ diff --git a/src/sql/engine/expr/ob_expr_degrees.cpp b/src/sql/engine/expr/ob_expr_degrees.cpp new file mode 100644 index 000000000..8e308845e --- /dev/null +++ b/src/sql/engine/expr/ob_expr_degrees.cpp @@ -0,0 +1,86 @@ +// Copyright (c) 2014-2021 Alibaba Inc. All Right Reserved. +// Author: +// liuqifan.lqf@antgroup.com +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_degrees.h" +#include "lib/number/ob_number_v2.h" +#include "sql/engine/expr/ob_expr_util.h" +#include "sql/parser/ob_item_type.h" +#include "sql/session/ob_sql_session_info.h" +#include + +using namespace oceanbase::common; +using namespace oceanbase::sql; +namespace oceanbase { +namespace sql { + +const double ObExprDegrees::degrees_ratio_ = 180.0 / std::acos(-1); + +ObExprDegrees::ObExprDegrees(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_DEGREES, N_DEGREES, 1, NOT_ROW_DIMENSION) +{} + +ObExprDegrees::~ObExprDegrees() +{} + +int ObExprDegrees::calc_result_type1(ObExprResType &type, ObExprResType &radian, ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + int ret = OB_SUCCESS; + if (NOT_ROW_DIMENSION != row_dimension_ || ObMaxType == radian.get_type()) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + } else { + type.set_double(); + radian.set_calc_type(ObDoubleType); + ObExprOperator::calc_result_flag1(type, radian); + } + return ret; +} + +int ObExprDegrees::calc_result1(ObObj &result, const ObObj &radian_obj, ObExprCtx &expr_ctx) const +{ + int ret = OB_SUCCESS; + double val = 0.0; + if (OB_ISNULL(expr_ctx.calc_buf_)) { + ret = OB_NOT_INIT; + LOG_WARN("expr_ctx.calc_buf_ is NULL", K(ret)); + } else if (OB_FAIL(radian_obj.get_double(val))) { + LOG_WARN("get double from obj failed in degrees", K(ret), K(radian_obj), K(val)); + } else { + result.set_double(val * degrees_ratio_); + } + return ret; +} + +int ObExprDegrees::calc_degrees_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res_datum) +{ + int ret = OB_SUCCESS; + ObDatum *radian = NULL; + if (OB_FAIL(expr.args_[0]->eval(ctx, radian))) { + LOG_WARN("eval radian arg failed", K(ret), K(expr)); + } else if (radian->is_null()) { + res_datum.set_null(); + } else { + const double val = radian->get_double(); + // cal result; + res_datum.set_double(val * degrees_ratio_); + } + return ret; +} + +int ObExprDegrees::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + int ret = OB_SUCCESS; + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + if (OB_UNLIKELY(1 != rt_expr.arg_cnt_) || (ObDoubleType != rt_expr.args_[0]->datum_meta_.type_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid arg_cnt_ or res type is invalid", K(ret), K(rt_expr)); + } else { + rt_expr.eval_func_ = calc_degrees_expr; + } + return ret; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_degrees.h b/src/sql/engine/expr/ob_expr_degrees.h new file mode 100644 index 000000000..83cbd09cd --- /dev/null +++ b/src/sql/engine/expr/ob_expr_degrees.h @@ -0,0 +1,30 @@ +// +// Author: +// liuqifan.lqf@antgroup.com +// + +#ifndef OCEANBASE_SQL_ENGINE_EXPR_DEGREES_ +#define OCEANBASE_SQL_ENGINE_EXPR_DEGREES_ + +#include "sql/engine/expr/ob_expr_operator.h" + +namespace oceanbase { +namespace sql { + +class ObExprDegrees : public ObFuncExprOperator { +public: + explicit ObExprDegrees(common::ObIAllocator &alloc); + virtual ~ObExprDegrees(); + virtual int calc_result_type1(ObExprResType &type, ObExprResType &radian, common::ObExprTypeCtx &type_ctx) const; + virtual int calc_result1(common::ObObj &result, const common::ObObj &radian_obj, common::ObExprCtx &expr_ctx) const; + static int calc_degrees_expr(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res_datum); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + const static double degrees_ratio_; + DISALLOW_COPY_AND_ASSIGN(ObExprDegrees); +}; + +} // namespace sql +} // namespace oceanbase +#endif diff --git a/src/sql/engine/expr/ob_expr_eval_functions.cpp b/src/sql/engine/expr/ob_expr_eval_functions.cpp index 17f9c45d0..befda14fe 100644 --- a/src/sql/engine/expr/ob_expr_eval_functions.cpp +++ b/src/sql/engine/expr/ob_expr_eval_functions.cpp @@ -184,6 +184,7 @@ #include "ob_expr_to_single_byte.h" #include "ob_expr_to_multi_byte.h" #include "ob_expr_convert_tz.h" +#include "ob_expr_degrees.h" namespace oceanbase { using namespace common; @@ -671,7 +672,7 @@ static ObExpr::EvalFunc g_expr_eval_functions[] = { NULL, /* 411 */ NULL, /* 412 */ NULL, /* 413 */ - NULL, /* 414 */ + ObExprDegrees::calc_degrees_expr, /* 414 */ NULL, /* 415 */ NULL, /* 416 */ NULL, /* 417 */ @@ -717,7 +718,7 @@ static ObExpr::EvalFunc g_expr_eval_functions[] = { ObExprInet6Ntoa::calc_inet6_ntoa, /* 457 */ NULL, // ObExprWeightString::eval_weight_string, /* 458 */ ObExprConvertTZ::eval_convert_tz, /* 459 */ - ObExprCrc32::calc_crc32_expr, /* 460 */ + ObExprCrc32::calc_crc32_expr /* 460 */ }; REG_SER_FUNC_ARRAY(OB_SFA_SQL_EXPR_EVAL, g_expr_eval_functions, ARRAYSIZEOF(g_expr_eval_functions)); diff --git a/src/sql/engine/expr/ob_expr_operator_factory.cpp b/src/sql/engine/expr/ob_expr_operator_factory.cpp index 0835ea631..3b84eaf7b 100644 --- a/src/sql/engine/expr/ob_expr_operator_factory.cpp +++ b/src/sql/engine/expr/ob_expr_operator_factory.cpp @@ -268,6 +268,7 @@ #include "sql/engine/expr/ob_expr_quarter.h" #include "sql/engine/expr/ob_expr_bit_length.h" #include "sql/engine/expr/ob_expr_convert_tz.h" +#include "sql/engine/expr/ob_expr_degrees.h" using namespace oceanbase::common; namespace oceanbase { @@ -677,6 +678,7 @@ void ObExprOperatorFactory::register_expr_operators() REG_OP(ObExprLastDay); REG_OP(ObExprTimeFormat); REG_OP(ObExprTimestamp); + REG_OP(ObExprDegrees); // register oracle system function REG_OP_ORCL(ObExprSysConnectByPath); REG_OP_ORCL(ObExprTimestampNvl); diff --git a/src/sql/parser/ob_item_type.h b/src/sql/parser/ob_item_type.h index a31ae2639..faab53b5a 100644 --- a/src/sql/parser/ob_item_type.h +++ b/src/sql/parser/ob_item_type.h @@ -426,6 +426,7 @@ typedef enum ObItemType { T_FUN_SYS_QUARTER = 711, T_FUN_SYS_BIT_LENGTH = 712, T_FUN_SYS_PI = 713, + T_FUN_SYS_DEGREES = 715, T_FUN_SYS_EXPORT_SET = 721, T_FUN_SYS_INET6NTOA = 722,