364 lines
13 KiB
C++
364 lines
13 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#define USING_LOG_PREFIX SQL_ENG
|
|
#include "sql/engine/expr/ob_expr_time.h"
|
|
#include "lib/timezone/ob_time_convert.h"
|
|
#include "sql/engine/ob_exec_context.h"
|
|
#include "sql/engine/expr/ob_datum_cast.h"
|
|
#include "sql/engine/expr/ob_expr_day_of_func.h"
|
|
#include "sql/engine/expr/ob_expr_util.h"
|
|
|
|
using namespace oceanbase::common;
|
|
using namespace oceanbase::sql;
|
|
|
|
namespace oceanbase
|
|
{
|
|
namespace sql
|
|
{
|
|
|
|
ObExprTime::ObExprTime(ObIAllocator &alloc)
|
|
: ObFuncExprOperator(alloc, T_FUN_SYS_TIME, N_TIME, 1, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION)
|
|
{}
|
|
|
|
ObExprTime::~ObExprTime()
|
|
{
|
|
}
|
|
|
|
int ObExprTime::calc_result_type1(ObExprResType &type,
|
|
ObExprResType &type1,
|
|
ObExprTypeCtx &type_ctx) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
//param will be casted to ObTimeType before calculation
|
|
//see ObExprOperator::cast_operand_type for more details if necessary
|
|
type1.set_calc_type(ObTimeType);
|
|
type.set_type(ObTimeType);
|
|
//deduce scale now.
|
|
int16_t scale1 = MIN(type1.get_scale(), MAX_SCALE_FOR_TEMPORAL);
|
|
int16_t scale = (SCALE_UNKNOWN_YET == scale1) ? MAX_SCALE_FOR_TEMPORAL : scale1;
|
|
type.set_scale(scale);
|
|
type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NULL_ON_WARN);
|
|
return ret;
|
|
}
|
|
|
|
int ObExprTime::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_ != 1) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("time expr should have one param", K(ret), K(rt_expr.arg_cnt_));
|
|
} else if (OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0])) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("children of time expr is null", K(ret), K(rt_expr.args_));
|
|
} else {
|
|
rt_expr.eval_func_ = ObExprTime::calc_time;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObExprTime::calc_time(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObDatum *param_datum = NULL;
|
|
if (OB_FAIL(expr.args_[0]->eval(ctx, param_datum))) {
|
|
LOG_WARN("eval param value failed");
|
|
} else if (OB_UNLIKELY(param_datum->is_null())) {
|
|
expr_datum.set_null();
|
|
} else {
|
|
expr_datum.set_time(param_datum->get_time());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
ObExprTimeBase::ObExprTimeBase(ObIAllocator &alloc, int32_t date_type, ObExprOperatorType type,
|
|
const char *name, ObValidForGeneratedColFlag valid_for_generated_col)
|
|
: ObFuncExprOperator(alloc, type, name, 1, valid_for_generated_col, NOT_ROW_DIMENSION)
|
|
{
|
|
dt_type_ = date_type;
|
|
}
|
|
|
|
ObExprTimeBase::~ObExprTimeBase()
|
|
{
|
|
}
|
|
|
|
static const char* daynames[7] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
|
|
static const char* monthnames[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
|
|
int ObExprTimeBase::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_ != 1) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("hour/minute/second expr should have one param", K(ret), K(rt_expr.arg_cnt_));
|
|
} else if (OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0])) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("children of hour/minute/second expr is null", K(ret), K(rt_expr.args_));
|
|
} else {
|
|
if(get_type() == T_FUN_SYS_DAY_NAME) {
|
|
rt_expr.eval_func_ = ObExprDayName::calc_dayname;
|
|
} else {
|
|
switch (dt_type_) {
|
|
case DT_HOUR :
|
|
rt_expr.eval_func_ = ObExprHour::calc_hour;
|
|
break;
|
|
case DT_MIN :
|
|
rt_expr.eval_func_ = ObExprMinute::calc_minute;
|
|
break;
|
|
case DT_SEC :
|
|
rt_expr.eval_func_ = ObExprSecond::calc_second;
|
|
break;
|
|
case DT_USEC :
|
|
rt_expr.eval_func_ = ObExprMicrosecond::calc_microsecond;
|
|
break;
|
|
case DT_MDAY :
|
|
rt_expr.eval_func_ = ObExprDayOfMonth::calc_dayofmonth;
|
|
break;
|
|
case DT_WDAY :
|
|
rt_expr.eval_func_ = ObExprDayOfWeek::calc_dayofweek;
|
|
break;
|
|
case DT_YDAY :
|
|
rt_expr.eval_func_ = ObExprDayOfYear::calc_dayofyear;
|
|
break;
|
|
case DT_YEAR :
|
|
rt_expr.eval_func_ = ObExprYear::calc_year;
|
|
break;
|
|
case DT_MON :
|
|
rt_expr.eval_func_ = ObExprMonth::calc_month;
|
|
break;
|
|
case DT_MON_NAME :
|
|
rt_expr.eval_func_ = ObExprMonthName::calc_month_name;
|
|
break;
|
|
default:
|
|
LOG_WARN("ObExprTimeBase cg_expr switch default", K(dt_type_));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int ob_expr_convert_to_time(const ObDatum &datum,
|
|
ObObjType type,
|
|
bool with_date,
|
|
bool is_dayofmonth,
|
|
ObEvalCtx &ctx,
|
|
ObTime &ot,
|
|
bool has_lob_header)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObSQLSessionInfo *session = ctx.exec_ctx_.get_my_session();
|
|
if (OB_ISNULL(session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("session is null", K(ret));
|
|
} else if (with_date) {
|
|
ObTime ot2;
|
|
ObDateSqlMode date_sql_mode;
|
|
date_sql_mode.init(session->get_sql_mode());
|
|
if (OB_FAIL(ob_datum_to_ob_time_with_date(datum, type, get_timezone_info(session),
|
|
ot2, get_cur_time(ctx.exec_ctx_.get_physical_plan_ctx()), is_dayofmonth, date_sql_mode,
|
|
has_lob_header))) {
|
|
LOG_WARN("cast to ob time failed", K(ret));
|
|
} else {
|
|
ot = ot2;
|
|
}
|
|
} else {
|
|
ObTime ot2(DT_TYPE_TIME);
|
|
if (OB_FAIL(ob_datum_to_ob_time_without_date(datum, type, get_timezone_info(session), ot2, has_lob_header))) {
|
|
LOG_WARN("cast to ob time failed", K(ret));
|
|
} else {
|
|
ot = ot2;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObExprTimeBase::calc(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum,
|
|
int32_t type, bool with_date, bool is_dayofmonth /* false */)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObDatum *param_datum = NULL;
|
|
const ObSQLSessionInfo *session = NULL;
|
|
if (OB_ISNULL(session = ctx.exec_ctx_.get_my_session())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("session is null", K(ret));
|
|
} else if (OB_FAIL(expr.args_[0]->eval(ctx, param_datum))) {
|
|
LOG_WARN("eval param value failed");
|
|
} else if (OB_UNLIKELY(param_datum->is_null())) {
|
|
expr_datum.set_null();
|
|
} else {
|
|
ObTime ot;
|
|
if (OB_FAIL(ob_expr_convert_to_time(*param_datum, expr.args_[0]->datum_meta_.type_, with_date,
|
|
is_dayofmonth, ctx, ot, expr.args_[0]->obj_meta_.has_lob_header()))) {
|
|
LOG_WARN("cast to ob time failed", K(ret), K(lbt()), K(session->get_stmt_type()));
|
|
LOG_USER_WARN(OB_ERR_CAST_VARCHAR_TO_TIME);
|
|
uint64_t cast_mode = 0;
|
|
ObSQLUtils::get_default_cast_mode(session->get_stmt_type(), session, cast_mode);
|
|
if (CM_IS_WARN_ON_FAIL(cast_mode) || CM_IS_WARN_ON_FAIL(expr.args_[0]->extra_)) {
|
|
ret = OB_SUCCESS;
|
|
expr_datum.set_null();
|
|
}
|
|
} else if (expr.type_ == T_FUN_SYS_DAY_NAME) {
|
|
if(!ot.parts_[DT_YEAR] && !ot.parts_[DT_MON] && !ot.parts_[DT_MDAY]) {
|
|
expr_datum.set_null();
|
|
} else {
|
|
int idx = ot.parts_[type] - 1;
|
|
if(0 <= idx && idx < 7) {
|
|
const ObString &name = daynames[idx];
|
|
if (OB_FAIL(ObExprUtil::set_expr_ascii_result(expr, ctx, expr_datum, name))) {
|
|
LOG_WARN("failed to exec set_expr_ascii_result", K(expr), K(ctx), K(expr_datum), K(name));
|
|
}
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("the parameter idx should be within a reasonable range", K(idx));
|
|
}
|
|
}
|
|
} else if (expr.type_ == T_FUN_SYS_MONTH_NAME) {
|
|
if(!ot.parts_[DT_MON]) {
|
|
expr_datum.set_null();
|
|
} else {
|
|
int idx = ot.parts_[type] - 1;
|
|
if(0 <= idx && idx < 12) {
|
|
const ObString &month_name = monthnames[idx];
|
|
if (OB_FAIL(ObExprUtil::set_expr_ascii_result(expr, ctx, expr_datum, month_name))) {
|
|
LOG_WARN("failed to exec set_expr_ascii_result", K(expr), K(ctx), K(expr_datum), K(month_name));
|
|
}
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("the parameter idx should be within a reasonable range", K(idx));
|
|
}
|
|
}
|
|
} else if (with_date && !is_dayofmonth && ot.parts_[DT_DATE] + DAYS_FROM_ZERO_TO_BASE < 0) {
|
|
expr_datum.set_null();
|
|
} else {
|
|
expr_datum.set_int32(ot.parts_[type]);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObExprTimeBase::is_valid_for_generated_column(const ObRawExpr*expr, const common::ObIArray<ObRawExpr *> &exprs, bool &is_valid) const {
|
|
int ret = OB_SUCCESS;
|
|
if (is_valid_for_generated_col_) {
|
|
is_valid = is_valid_for_generated_col_;
|
|
} else if (OB_FAIL(check_first_param_not_time(exprs, is_valid))) {
|
|
LOG_WARN("fail to check if first param is time", K(ret), K(exprs));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
ObExprHour::ObExprHour(ObIAllocator &alloc)
|
|
: ObExprTimeBase(alloc, DT_HOUR, T_FUN_SYS_HOUR, N_HOUR, VALID_FOR_GENERATED_COL) {};
|
|
|
|
ObExprHour::~ObExprHour() {}
|
|
|
|
int ObExprHour::calc_hour(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
return ObExprTimeBase::calc(expr, ctx, expr_datum, DT_HOUR, false);
|
|
}
|
|
|
|
ObExprMinute::ObExprMinute(ObIAllocator &alloc)
|
|
: ObExprTimeBase(alloc, DT_MIN, T_FUN_SYS_MINUTE, N_MINUTE, VALID_FOR_GENERATED_COL) {};
|
|
|
|
ObExprMinute::~ObExprMinute() {}
|
|
|
|
int ObExprMinute::calc_minute(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
return ObExprTimeBase::calc(expr, ctx, expr_datum, DT_MIN, false);
|
|
}
|
|
|
|
ObExprSecond::ObExprSecond(ObIAllocator &alloc)
|
|
: ObExprTimeBase(alloc, DT_SEC, T_FUN_SYS_SECOND, N_SECOND, VALID_FOR_GENERATED_COL) {};
|
|
|
|
ObExprSecond::~ObExprSecond() {}
|
|
|
|
int ObExprSecond::calc_second(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
return ObExprTimeBase::calc(expr, ctx, expr_datum, DT_SEC, false);
|
|
}
|
|
|
|
ObExprMicrosecond::ObExprMicrosecond(ObIAllocator &alloc)
|
|
: ObExprTimeBase(alloc, DT_USEC, T_FUN_SYS_MICROSECOND, N_MICROSECOND, VALID_FOR_GENERATED_COL) {};
|
|
|
|
ObExprMicrosecond::~ObExprMicrosecond() {}
|
|
|
|
int ObExprMicrosecond::calc_microsecond(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
return ObExprTimeBase::calc(expr, ctx, expr_datum, DT_USEC, false);
|
|
}
|
|
|
|
ObExprYear::ObExprYear(ObIAllocator &alloc)
|
|
: ObExprTimeBase(alloc, DT_YEAR, T_FUN_SYS_YEAR, N_YEAR, NOT_VALID_FOR_GENERATED_COL) {};
|
|
|
|
ObExprYear::~ObExprYear() {}
|
|
|
|
int ObExprYear::calc_year(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
return ObExprTimeBase::calc(expr, ctx, expr_datum, DT_YEAR, true, true);
|
|
}
|
|
|
|
ObExprMonth::ObExprMonth(ObIAllocator &alloc)
|
|
: ObExprTimeBase(alloc, DT_MON, T_FUN_SYS_MONTH, N_MONTH, NOT_VALID_FOR_GENERATED_COL) {};
|
|
|
|
ObExprMonth::~ObExprMonth() {}
|
|
|
|
int ObExprMonth::calc_month(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
// 对于MONTH('2020-00-00')场景,为了完全兼容mysql,也需要容忍月和日为0
|
|
return ObExprTimeBase::calc(expr, ctx, expr_datum, DT_MON, true, true);
|
|
}
|
|
|
|
ObExprMonthName::ObExprMonthName(ObIAllocator &alloc)
|
|
: ObExprTimeBase(alloc, DT_MON_NAME, T_FUN_SYS_MONTH_NAME, N_MONTH_NAME, NOT_VALID_FOR_GENERATED_COL) {};
|
|
|
|
ObExprMonthName::~ObExprMonthName() {}
|
|
|
|
int ObExprMonthName::calc_month_name(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// NOTE: the last param should be true otherwise '2020-09-00' will not work
|
|
if (OB_FAIL(calc(expr, ctx, expr_datum, DT_MON, true, true))) {
|
|
LOG_WARN("eval month in monthname failed", K(ret), K(expr));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObExprMonthName::calc_result_type1(ObExprResType &type,
|
|
ObExprResType &type1,
|
|
common::ObExprTypeCtx &type_ctx) const
|
|
{
|
|
ObCollationType cs_type = type_ctx.get_coll_type();
|
|
type.set_varchar();
|
|
type.set_collation_type(cs_type);
|
|
type.set_collation_level(CS_LEVEL_IMPLICIT);
|
|
type.set_full_length(MONTHNAME_MAX_LENGTH, type1.get_length_semantics());
|
|
common::ObObjTypeClass tc1 = ob_obj_type_class(type1.get_type());
|
|
if (common::ObEnumSetTC == tc1) {
|
|
type1.set_calc_type(common::ObVarcharType);
|
|
type1.set_collation_type(cs_type);
|
|
type1.set_collation_level(CS_LEVEL_IMPLICIT);
|
|
} else if ((common::ObFloatTC == tc1) || (common::ObDoubleTC == tc1)) {
|
|
type1.set_calc_type(common::ObIntType);
|
|
}
|
|
|
|
return OB_SUCCESS;
|
|
}
|
|
|
|
} //namespace sql
|
|
} //namespace oceanbase
|