Files
oceanbase/src/sql/engine/expr/ob_expr_from_unix_time.cpp
2023-04-27 11:11:24 +00:00

308 lines
11 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 "ob_expr_from_unix_time.h"
#include "lib/allocator/ob_allocator.h"
#include "lib/timezone/ob_time_convert.h"
#include "sql/session/ob_sql_session_info.h"
#include "sql/engine/ob_exec_context.h"
#include "sql/engine/expr/ob_datum_cast.h"
#include "share/config/ob_server_config.h"
namespace oceanbase
{
using namespace common;
namespace sql
{
ObExprFromUnixTime::ObExprFromUnixTime(ObIAllocator &alloc)
: ObFuncExprOperator(alloc, T_FUN_SYS_FROM_UNIX_TIME,
N_FROM_UNIX_TIME, ONE_OR_TWO, NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION)
{
}
ObExprFromUnixTime::~ObExprFromUnixTime()
{
}
int ObExprFromUnixTime::calc_result_typeN(ObExprResType &type,
ObExprResType *params,
int64_t params_count,
common::ObExprTypeCtx &type_ctx) const
{
int ret = OB_SUCCESS;
// ObCollationType collation_connection = CS_TYPE_INVALID;
if (OB_UNLIKELY(NULL == params ||
params_count <= 0 ||
params_count > 2)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Invalid argument!", K(ret), K(params), K(params_count));
} else if (1 == params_count) {
type.set_datetime();
ret = set_scale_for_single_param(type, params[0]);
ObObjType param_calc_type = calc_one_param_type(params);
params[0].set_calc_type(param_calc_type);
} else { //params_count == 2
type.set_varchar();
type.set_collation_type(type_ctx.get_coll_type());
type.set_collation_level(CS_LEVEL_COERCIBLE);
type.set_length(DATETIME_MAX_LENGTH);
params[0].set_calc_type(ObNumberType);
params[1].set_calc_type(ObVarcharType);
}
return ret;
}
OB_INLINE int ObExprFromUnixTime::set_scale_for_single_param(ObExprResType &type,
const ObExprResType &type1) const
{
int ret = OB_SUCCESS;
if (type1.is_integer_type()) {
type.set_scale(DEFAULT_SCALE_FOR_INTEGER);
} else if(type1.is_varchar() || type.is_enum_or_set()) {
// 这里是不是有bug,type1.is_enum_or_set() TODO @zongmei.zzm
type.set_scale(MAX_SCALE_FOR_TEMPORAL);
} else {
type.set_scale(static_cast<ObScale>(MIN(type1.get_scale(), MAX_SCALE_FOR_TEMPORAL)));
}
return ret;
}
int ObExprFromUnixTime::cg_expr(ObExprCGCtx &op_cg_ctx,
const ObRawExpr &raw_expr,
ObExpr &rt_expr) const
{
int ret = OB_SUCCESS;
UNUSED(op_cg_ctx);
UNUSED(raw_expr);
if (OB_UNLIKELY(rt_expr.arg_cnt_ != 1 && rt_expr.arg_cnt_ != 2)
|| OB_ISNULL(rt_expr.args_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else if (1 == rt_expr.arg_cnt_) {
if (OB_ISNULL(rt_expr.args_[0])) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid null arg", K(ret));
} else if (ObNumberType != rt_expr.args_[0]->datum_meta_.type_) {
rt_expr.eval_func_ = &eval_one_temporal_fromtime;
} else {
rt_expr.eval_func_ = &eval_one_param_fromtime;
}
} else {
if (OB_ISNULL(rt_expr.args_[0]) || OB_ISNULL(rt_expr.args_[1])) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid null args", K(ret), K(rt_expr.args_[0]), K(rt_expr.args_[1]));
} else if (0 == raw_expr.get_extra()) {
rt_expr.eval_func_ = &eval_fromtime_normal;
} else {
rt_expr.eval_func_ = &eval_fromtime_special;
}
}
return ret;
}
ObObjType ObExprFromUnixTime::calc_one_param_type(ObExprResType *params) const
{
ObObjType calc_param_type = params[0].get_type();
if (calc_param_type >= ObDateTimeType && calc_param_type <= ObYearType) {
// do nothing
} else {
calc_param_type = ObNumberType;
}
return calc_param_type;
}
int ObExprFromUnixTime::eval_one_temporal_fromtime(const ObExpr &expr,
ObEvalCtx &ctx,
ObDatum &expr_datum)
{
int ret = OB_SUCCESS;
UNUSED(expr);
UNUSED(ctx);
expr_datum.set_null();
return ret;
}
int ObExprFromUnixTime::eval_one_param_fromtime(const ObExpr &expr,
ObEvalCtx &ctx,
ObDatum &expr_datum)
{
int ret = OB_SUCCESS;
ObDatum *param_datum = NULL;
const ObSQLSessionInfo *session = ctx.exec_ctx_.get_my_session();
if (OB_UNLIKELY(expr.arg_cnt_ != 1)
|| OB_ISNULL(expr.args_)
|| OB_ISNULL(expr.args_[0])
|| OB_ISNULL(session)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else if (OB_FAIL(expr.args_[0]->eval(ctx, param_datum))) {
LOG_WARN("failed to eval", K(ret));
} else if (param_datum->is_null()) {
expr_datum.set_null();
} else {
int64_t usec_val;
ObEvalCtx::TempAllocGuard alloc_guard(ctx);
if (OB_FAIL(get_usec_from_datum(*param_datum, alloc_guard.get_allocator(), usec_val))) {
LOG_WARN("failed to get_usec_from_datum", K(ret));
// if warn on failed
ObCastMode cast_mode = CM_NONE;
ObSQLUtils::get_default_cast_mode(session->get_stmt_type(), session, cast_mode);
if (CM_IS_WARN_ON_FAIL(cast_mode)) {
ret = OB_SUCCESS;
expr_datum.set_null();
}
} else if (usec_val < 0) {
expr_datum.set_null();
} else if (OB_FAIL(ObTimeConverter::timestamp_to_datetime(
usec_val,
get_timezone_info(session),
usec_val))) {
LOG_WARN("failed to convert timestamp to datetime", K(ret));
} else if (OB_UNLIKELY(ObTimeConverter::is_valid_datetime(usec_val))) {
expr_datum.set_datetime(usec_val);
} else {
expr_datum.set_null();
}
}
return ret;
}
int ObExprFromUnixTime::eval_fromtime_normal(const ObExpr &expr,
ObEvalCtx &ctx,
ObDatum &expr_datum)
{
int ret = OB_SUCCESS;
ObDatum *param1 = NULL;
ObDatum *param2 = NULL;
bool res_null = false;
const ObSQLSessionInfo *session = ctx.exec_ctx_.get_my_session();
if (OB_ISNULL(session)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("session is null", K(ret));
} else if (OB_FAIL(expr.args_[0]->eval(ctx, param1))) {
LOG_WARN("failed to eval", K(ret));
} else if (OB_ISNULL(param1)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null param1", K(ret), K(param1));
} else if (param1->is_null()) { // mysql 模式 from_unixtime有短路逻辑
expr_datum.set_null();
} else if (OB_FAIL(expr.args_[1]->eval(ctx, param2))) {
LOG_WARN("failed to eval", K(ret));
} else if (OB_ISNULL(param2)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null param2", K(ret));
} else if (param2->is_null() || param2->get_string().empty()) { // 需要运行时cast
expr_datum.set_null();
} else {
int64_t usec_val;
ObEvalCtx::TempAllocGuard alloc_guard(ctx);
if (OB_FAIL(get_usec_from_datum(
*param1,
alloc_guard.get_allocator(),
usec_val))) {
LOG_WARN("failed to get_usec_from_datum", K(ret));
// warn on fail mode
ObCastMode cast_mode = CM_NONE;
int tmp_ret = OB_SUCCESS;
if (OB_UNLIKELY(OB_SUCCESS != (tmp_ret = ObSQLUtils::get_default_cast_mode(session->get_stmt_type(), session, cast_mode)))) {
LOG_WARN("get_default_cast_mode failed", K(tmp_ret), K(session->get_stmt_type()));
} else if (CM_IS_WARN_ON_FAIL(cast_mode)) {
ret = OB_SUCCESS;
}
expr_datum.set_null();
} else {
ObTime ob_time;
ObDatum tmp_val;
char *buf = NULL;
int64_t pos = 0;
const int64_t BUF_LEN = 1024;
// 这里先用expr_datum,最后输出结果的时候会调用set_string覆盖其结果
expr_datum.set_time(usec_val);
if (usec_val < 0) {
expr_datum.set_null();
} else if (OB_ISNULL(buf = expr.get_str_res_mem(ctx, BUF_LEN))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no more memory to alloc for buf", K(ret));
} else if (OB_FAIL(ob_datum_to_ob_time_with_date(
expr_datum, ObTimestampType,
get_timezone_info(session),
ob_time,
get_cur_time(ctx.exec_ctx_.get_physical_plan_ctx()), false, 0, false))) {
LOG_WARN("failed to cast datum to obtime with date", K(ret));
} else if (OB_FAIL(ObTimeConverter::ob_time_to_str_format(
ob_time,
param2->get_string(),
buf, BUF_LEN, pos, res_null))) {
LOG_WARN("failed to convert str", K(ret));
} else if (res_null) {
expr_datum.set_null();
} else {
expr_datum.set_string(buf, static_cast<int32_t>(pos));
}
}
}
return ret;
}
int ObExprFromUnixTime::eval_fromtime_special(const ObExpr &expr,
ObEvalCtx &ctx,
ObDatum &expr_datum)
{
int ret = OB_SUCCESS;
ObDatum *param1 = NULL;
ObDatum *param2 = NULL;
if (OB_FAIL(expr.args_[0]->eval(ctx, param1))) {
LOG_WARN("failed to eval", K(ret));
} else if (param1->is_null()) { // mysql 模式 from_unixtime有短路逻辑
expr_datum.set_null();
} else if (OB_FAIL(expr.args_[1]->eval(ctx, param2))) {
LOG_WARN("failed to eval", K(ret));
} else if (param2->is_null()) {
expr_datum.set_null();
} else {
// just use param as result
expr_datum.set_string(param2->get_string());
}
return ret;
}
int ObExprFromUnixTime::get_usec_from_datum(const common::ObDatum &param_datum,
common::ObIAllocator &alloc,
int64_t &usec_val)
{
int ret = OB_SUCCESS;
number::ObNumber param1;
number::ObNumber param2;
number::ObNumber res;
number::ObNumber param2_tmp(param_datum.get_number());
const int64_t usecs_per_sec = USECS_PER_SEC;
int64_t tmp = 0;
if (OB_FAIL(param1.from(usecs_per_sec, alloc))
|| OB_FAIL(param2.from(param2_tmp, alloc))) {
LOG_WARN("failed to get number", K(ret));
} else if (OB_FAIL(param1.mul(param2, res, alloc))) {
LOG_WARN("failed to mul", K(ret));
} else if (OB_LIKELY(res.is_valid_int64(tmp))) {
usec_val = tmp;
} else {
ret = OB_ERR_TRUNCATED_WRONG_VALUE;
}
return ret;
}
}
}