263 lines
9.7 KiB
C++
263 lines
9.7 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 "lib/ob_name_def.h"
|
|
#include "sql/engine/expr/ob_expr_time_format.h"
|
|
#include "sql/session/ob_sql_session_info.h"
|
|
#include "sql/engine/expr/ob_datum_cast.h"
|
|
#include "sql/engine/ob_exec_context.h"
|
|
#include "sql/engine/expr/ob_expr_util.h"
|
|
|
|
namespace oceanbase
|
|
{
|
|
using namespace common;
|
|
namespace sql
|
|
{
|
|
|
|
ObExprTimeFormat::ObExprTimeFormat(ObIAllocator &alloc)
|
|
: ObStringExprOperator(alloc, T_FUN_SYS_TIME_FORMAT, N_TIME_FORMAT, 2)
|
|
{
|
|
}
|
|
|
|
ObExprTimeFormat::~ObExprTimeFormat()
|
|
{
|
|
}
|
|
|
|
int ObExprTimeFormat::calc_result_type2(ObExprResType &type,
|
|
ObExprResType &time,
|
|
ObExprResType &format,
|
|
common::ObExprTypeCtx &type_ctx) const
|
|
{
|
|
int ret = common::OB_SUCCESS;
|
|
calc_temporal_format_result_length(type, format);
|
|
type.set_collation_type(type_ctx.get_coll_type());
|
|
type.set_collation_level(common::CS_LEVEL_COERCIBLE);
|
|
|
|
time.set_calc_type(ObTimeType);
|
|
format.set_calc_type(ObVarcharType);
|
|
format.set_calc_collation_type(type.get_collation_type());
|
|
// result is null if cast first param to ObTimeType failed.
|
|
type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_NULL_ON_WARN);
|
|
return ret;
|
|
}
|
|
|
|
|
|
int ObExprTimeFormat::time_to_str_format(const int64_t &time_value, const ObString &format,
|
|
char *buf, int64_t buf_len, int64_t &pos, bool &res_null)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTime ob_time;
|
|
if (ObTimeConverter::time_to_ob_time(time_value, ob_time)) {
|
|
LOG_WARN("time to ob time failed", K(ret), K(time_value));
|
|
} else if (OB_ISNULL(format.ptr()) || OB_ISNULL(buf)
|
|
|| OB_UNLIKELY(format.length() <= 0 || buf_len <= 0)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("format or output string is invalid", K(ret), K(format), K(buf), K(buf_len));
|
|
} else if (IS_NEG_TIME(ob_time.mode_) && OB_FAIL(databuff_printf(buf, buf_len, pos, "-"))) {
|
|
LOG_WARN("print - failed", K(ret));
|
|
} else {
|
|
const char *format_ptr = format.ptr();
|
|
const char *end_ptr = format.ptr() + format.length();
|
|
const int32_t *parts = ob_time.parts_;
|
|
//used for am/pm conversation in order to avoid if-else tests.
|
|
int hour12 = ((parts[DT_HOUR] + 11) % 12) + 1;
|
|
while (format_ptr < end_ptr && OB_SUCCESS == ret && !res_null) {
|
|
if ('%' == *format_ptr) {
|
|
format_ptr++;
|
|
if (format_ptr >= end_ptr) {
|
|
if (pos >= buf_len) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
break;
|
|
}
|
|
buf[pos++] = '%';
|
|
break;
|
|
}
|
|
switch (*format_ptr) {
|
|
case 'f': { //Microseconds (000000..999999), include '-' if value is negative.
|
|
ret = ObTimeConverter::data_fmt_nd(buf, buf_len, pos, 6, parts[DT_USEC]);
|
|
break;
|
|
}
|
|
case 'h': //Hour (01..12)
|
|
case 'I': { //Hour (01..12)
|
|
int hour = hour12;
|
|
ret = ObTimeConverter::data_fmt_nd(buf, buf_len, pos, 2, hour);
|
|
break;
|
|
}
|
|
case 'i': { //Minutes, numeric (00..59)
|
|
ret = ObTimeConverter::data_fmt_nd(buf, buf_len, pos, 2, parts[DT_MIN]);
|
|
break;
|
|
}
|
|
case 'H': { //Hour
|
|
if (parts[DT_HOUR] < 100) {
|
|
ret = ObTimeConverter::data_fmt_nd(buf, buf_len, pos, 2, parts[DT_HOUR]);
|
|
} else {
|
|
ret = ObTimeConverter::data_fmt_nd(buf, buf_len, pos, 3, parts[DT_HOUR]);
|
|
}
|
|
break;
|
|
}
|
|
case 'k': { //Hour
|
|
ret = ObTimeConverter::data_fmt_d(buf, buf_len, pos, parts[DT_HOUR]);
|
|
break;
|
|
}
|
|
case 'l': { //Hour (1..12)
|
|
int hour = hour12;
|
|
ret = ObTimeConverter::data_fmt_d(buf, buf_len, pos, hour);
|
|
break;
|
|
}
|
|
case 'p': { //AM or PM
|
|
const char *ptr = (parts[DT_HOUR] % 24) < 12 ? "AM" : "PM";
|
|
ret = ObTimeConverter::data_fmt_s(buf, buf_len, pos, ptr);
|
|
break;
|
|
}
|
|
case 'r': { //Time, 12-hour (hh:mm:ss followed by AM or PM)
|
|
const char *ptr = (parts[DT_HOUR] % 24) < 12 ? "AM" : "PM";
|
|
ret = databuff_printf(buf, buf_len, pos, "%02d:%02d:%02d %s", hour12, parts[DT_MIN], parts[DT_SEC], ptr);
|
|
break;
|
|
}
|
|
case 'S': //Seconds (00..59)
|
|
case 's': { //Seconds (00..59)
|
|
ret = ObTimeConverter::data_fmt_nd(buf, buf_len, pos, 2, parts[DT_SEC]);
|
|
break;
|
|
}
|
|
case 'T': { //Time (hh:mm:ss)
|
|
if (parts[DT_HOUR] < 100) {
|
|
ret = ObTimeConverter::data_fmt_nd(buf, buf_len, pos, 2, parts[DT_HOUR]);
|
|
} else {
|
|
ret = ObTimeConverter::data_fmt_nd(buf, buf_len, pos, 3, parts[DT_HOUR]);
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
ret = databuff_printf(buf, buf_len, pos, ":%02d:%02d", parts[DT_MIN], parts[DT_SEC]);
|
|
}
|
|
break;
|
|
}
|
|
case 'c': //Month, numeric (0..12)
|
|
case 'e': { //Day of the month, numeric (0..31)
|
|
ret = databuff_printf(buf, buf_len, pos, "0");
|
|
break;
|
|
}
|
|
case 'd': //Day of the month, numeric (00..31)
|
|
case 'm': //Month, numeric (00..12)
|
|
case 'y': { //Year, numeric (two digits)
|
|
ret = databuff_printf(buf, buf_len, pos, "00");
|
|
break;
|
|
}
|
|
case 'Y': { //Year, numeric, four digits
|
|
ret = databuff_printf(buf, buf_len, pos, "0000");
|
|
break;
|
|
}
|
|
case 'a': //Abbreviated weekday name (Sun..Sat)
|
|
case 'b': //Abbreviated month name (Jan..Dec)
|
|
case 'D': //Day of the month with English suffix (0th, 1st, 2nd, 3rd...)
|
|
case 'j': //Day of year (001..366)
|
|
case 'M': //Month name (January..December)
|
|
case 'U': //Week (00..53), where Sunday is the first day of the week
|
|
case 'u': //Week (00..53), where Monday is the first day of the week
|
|
case 'V': //Week (01..53), where Sunday is the first day of the week; used with %X
|
|
case 'v': //Week (01..53), where Monday is the first day of the week; used with %x
|
|
case 'W': //Weekday name (Sunday..Saturday)
|
|
case 'w': //Day of the week (0=Sunday..6=Saturday)
|
|
case 'X': //Year for the week where Sunday is the first day of the week
|
|
case 'x': { //Year for the week, where Monday is the first day of the week
|
|
res_null = true;
|
|
break;
|
|
}
|
|
case '%': { //A literal "%" character
|
|
if (pos >= buf_len) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
break;
|
|
}
|
|
buf[pos++] = '%';
|
|
break;
|
|
}
|
|
default: {
|
|
if (pos >= buf_len) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
break;
|
|
}
|
|
buf[pos++] = *format_ptr;
|
|
break;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
format_ptr++;
|
|
} else {
|
|
LOG_WARN("print failed", K(ret), K(*format_ptr), K(time_value), K(ob_time));
|
|
}
|
|
} else if (pos >= buf_len) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
break;
|
|
} else {
|
|
buf[pos++] = *(format_ptr++);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObExprTimeFormat::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_ != 2) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("date_format expr should have two params", K(ret), K(rt_expr.arg_cnt_));
|
|
} else if (OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0])
|
|
|| OB_ISNULL(rt_expr.args_[1])) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("children of date_format expr is null", K(ret), K(rt_expr.args_));
|
|
} else {
|
|
rt_expr.eval_func_ = ObExprTimeFormat::calc_time_format;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObExprTimeFormat::calc_time_format(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &expr_datum)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
char *buf = NULL;
|
|
int64_t buf_len = 0;
|
|
int64_t pos = 0;
|
|
ObDatum *time = NULL;
|
|
ObDatum *format = NULL;
|
|
bool res_null = false;
|
|
if (OB_FAIL(expr.eval_param_value(ctx, time, format))) {
|
|
LOG_WARN("calc param failed", K(ret));
|
|
} else if (time->is_null() || format->is_null()) {
|
|
expr_datum.set_null();
|
|
} else if (OB_UNLIKELY(format->get_string().empty())) {
|
|
expr_datum.set_null();
|
|
} else if (FALSE_IT(buf_len = format->get_string().length() * OB_TEMPORAL_BUF_SIZE_RATIO)) {
|
|
} else if (OB_ISNULL(buf = expr.get_str_res_mem(ctx, buf_len))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("no more memory to alloc for buf", K(ret), K(buf_len));
|
|
} else if (OB_FAIL(time_to_str_format(time->get_time(),
|
|
format->get_string(),
|
|
buf,
|
|
buf_len,
|
|
pos,
|
|
res_null))) {
|
|
LOG_WARN("failed to convert ob time to str with format");
|
|
} else if (res_null) {
|
|
expr_datum.set_null();
|
|
} else {
|
|
expr_datum.set_string(buf, static_cast<int32_t>(pos));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
}
|
|
}
|