/**
 * 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 COMMON

#include "share/object/ob_obj_cast.h"
#include <math.h>
#include <float.h>
#include "lib/charset/ob_dtoa.h"
#include "lib/string/ob_sql_string.h"
#include "rpc/obmysql/ob_mysql_util.h"
#include "share/ob_worker.h"
#include "share/object/ob_obj_cast_util.h"

// from sql_parser_base.h
#define DEFAULT_STR_LENGTH -1
namespace oceanbase {
using namespace lib;
using namespace share;
namespace common {
using namespace number;

static const int64_t MAX_DOUBLE_STRICT_PRINT_SIZE = 512;

static int cast_identity(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(expect_type);
  UNUSED(params);
  UNUSED(cast_mode);
  if (&in != &out) {
    out = in;
  }
  return OB_SUCCESS;
}

static int cast_not_support(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(params);
  LOG_WARN("not supported obj type convert", K(expect_type), K(in), K(out), K(cast_mode));
  return OB_NOT_SUPPORTED;
}

static int cast_not_expected(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(params);
  LOG_WARN("not expected obj type convert", K(expect_type), K(in), K(out), K(cast_mode));
  return OB_ERR_UNEXPECTED;
}

static int cast_inconsistent_types(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(params);
  UNUSED(out);
  UNUSED(cast_mode);
  LOG_WARN("inconsistent datatypes", "expected", expect_type, "got", in.get_type());
  return OB_ERR_INVALID_TYPE_FOR_OP;
}

static int cast_not_support_enum_set(
    const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  UNUSED(params);
  LOG_WARN("not supported obj type convert", K(expect_type), K(in), K(out));
  return OB_NOT_SUPPORTED;
}

static int cast_identity_enum_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  UNUSED(expect_type);
  UNUSED(params);
  if (&in != &out) {
    out = in;
  }
  return OB_SUCCESS;
}

static int cast_not_expected_enum_set(
    const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  UNUSED(params);
  LOG_WARN("not expected obj type convert", K(expect_type), K(in), K(out));
  return OB_ERR_UNEXPECTED;
}

static int unknown_other(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  return cast_not_support(expect_type, params, in, out, cast_mode);
}

////////////////////////////////////////////////////////////////
// Utility func

// %align_offset is used in mysql mode to align blob to other charset.
static int copy_string(const ObObjCastParams& params, const ObObjType type, const char* str, int64_t len, ObObj& obj,
    int64_t align_offset = 0)
{
  int ret = OB_SUCCESS;
  char* buf = NULL;
  if (OB_LIKELY(len > 0 && NULL != str)) {
    if (OB_LIKELY(NULL != params.zf_info_) && params.zf_info_->need_zerofill_) {
      int64_t str_len = std::max(len, static_cast<int64_t>(params.zf_info_->max_length_));
      if (OB_UNLIKELY(NULL == (buf = static_cast<char*>(params.alloc(str_len))))) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
      } else {
        int64_t zf = params.zf_info_->max_length_ - len;
        if (zf > 0) {
          MEMSET(buf, '0', zf);
          MEMCPY(buf + zf, str, len);
          len = str_len;  // set string length
        } else {
          MEMCPY(buf, str, len);
        }
      }
    } else {
      len += align_offset;
      if (OB_UNLIKELY(NULL == (buf = static_cast<char*>(params.alloc(len))))) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
      } else {
        MEMSET(buf, 0, align_offset);
        MEMCPY(buf + align_offset, str, len - align_offset);
      }
    }
  }
  if (OB_SUCC(ret)) {
    if (ob_is_text_tc(type)) {
      obj.set_lob_value(type, buf, static_cast<int32_t>(len));
    } else if (ob_is_raw(type)) {
      obj.set_raw(buf, static_cast<int32_t>(len));
    } else {
      obj.set_string(type, buf, static_cast<int32_t>(len));
    }
  }
  return ret;
}

static int copy_string(
    const ObObjCastParams& params, const ObObjType type, const ObString& str, ObObj& obj, int64_t align_offset = 0)
{
  return copy_string(params, type, str.ptr(), str.length(), obj, align_offset);
}

/*
 * check err when a string cast to int/uint/double/float according to endptr
 *@str input string
 *@endptr result pointer to end of converted string
 *@len length of str
 *@err
 * incorrect -> "a232"->int or "a2323.23"->double
 * truncated -> "23as" -> int or "as2332.a"->double
 * @note
 *  This is called after one has called strntoull10rnd() or strntod function.
 */
int check_convert_str_err(const char* str, const char* endptr, const int32_t len, const int err)
{
  int ret = OB_SUCCESS;
  // 1. only one of str and endptr is null, it is invalid input.
  if ((OB_ISNULL(str) || OB_ISNULL(endptr)) && str != endptr) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("null pointer(s)", K(ret), KP(str), KP(endptr));
  } else if (is_oracle_mode() && 0 != err) {
    ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
  } else
      // 2. str == endptr include NULL == NULL.
      if (OB_UNLIKELY(str == endptr) || OB_UNLIKELY(EDOM == err)) {
    ret = OB_ERR_TRUNCATED_WRONG_VALUE_FOR_FIELD;  // 1366
  } else {
    // 3. so here we are sure that both str and endptr are not NULL.
    endptr += ObCharset::scan_str(endptr, str + len, OB_SEQ_SPACES);
    endptr += ObCharset::scan_str(endptr, str + len, OB_SEQ_INTTAIL);
    if (endptr < str + len) {
      ret = OB_ERR_DATA_TRUNCATED;  // 1265
      LOG_DEBUG("check_convert_str_err", K(len), K(str - endptr));
    }
  }
  return ret;
}

static int convert_string_collation(const ObString& in, const ObCollationType in_collation, ObString& out,
    const ObCollationType out_collation, ObObjCastParams& params)
{
  int ret = OB_SUCCESS;
  if (!ObCharset::is_valid_collation(in_collation) || !ObCharset::is_valid_collation(out_collation) ||
      ObCharset::charset_type_by_coll(in_collation) == CHARSET_BINARY ||
      ObCharset::charset_type_by_coll(out_collation) == CHARSET_BINARY ||
      (ObCharset::charset_type_by_coll(in_collation) == ObCharset::charset_type_by_coll(out_collation))) {
    out = in;
  } else if (in.empty()) {
    out.reset();
  } else {
    char* buf = NULL;
    const int32_t CharConvertFactorNum = 4;
    int32_t buf_len = in.length() * CharConvertFactorNum;
    uint32_t result_len = 0;
    if (OB_ISNULL(buf = static_cast<char*>(params.alloc(buf_len)))) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_ERROR("alloc memory failed", K(ret));
    } else if (OB_FAIL(ObCharset::charset_convert(
                   in_collation, in.ptr(), in.length(), out_collation, buf, buf_len, result_len))) {
      LOG_WARN("charset convert failed", K(ret));
    } else {
      out.assign_ptr(buf, result_len);
    }
  }
  LOG_DEBUG("convert_string_collation", K(in.length()), K(in_collation), K(out.length()), K(out_collation));
  return ret;
}

////////////////////////////////////////////////////////////////

OB_INLINE int get_cast_ret(const ObCastMode cast_mode, int ret, int& warning)
{
  // compatibility for old ob
  if (OB_UNLIKELY(OB_ERR_UNEXPECTED_TZ_TRANSITION == ret) || OB_UNLIKELY(OB_ERR_UNKNOWN_TIME_ZONE == ret)) {
    ret = OB_INVALID_DATE_VALUE;
  } else if (OB_SUCCESS != ret &&
             // OB_ERR_UNEXPECTED != ret &&
             CM_IS_WARN_ON_FAIL(cast_mode)) {
    warning = ret;
    ret = OB_SUCCESS;
  }
  return ret;
}

#define CAST_FAIL(stmt) (OB_UNLIKELY((OB_SUCCESS != (ret = get_cast_ret(cast_mode, (stmt), params.warning_)))))

#define CAST_RET(stmt) (ret = get_cast_ret(cast_mode, (stmt), params.warning_))

#define SET_RES_OBJ(res, func_val, obj_type, comma, val, zero_val)                                                   \
  do {                                                                                                               \
    if (OB_SUCC(ret)) {                                                                                              \
      if (OB_SUCCESS == params.warning_ || OB_ERR_TRUNCATED_WRONG_VALUE == params.warning_ ||                        \
          OB_DATA_OUT_OF_RANGE == params.warning_ || OB_ERR_DATA_TRUNCATED == params.warning_ ||                     \
          OB_ERR_DOUBLE_TRUNCATED == params.warning_ || OB_ERR_TRUNCATED_WRONG_VALUE_FOR_FIELD == params.warning_) { \
        res.set_##func_val(obj_type comma val);                                                                      \
      } else if (CM_IS_ZERO_ON_WARN(cast_mode)) {                                                                    \
        res.set_##func_val(obj_type comma zero_val);                                                                 \
      } else {                                                                                                       \
        res.set_null();                                                                                              \
      }                                                                                                              \
    } else {                                                                                                         \
      res.set_##func_val(obj_type comma val);                                                                        \
    }                                                                                                                \
  } while (0)

#define COMMA ,
#define SET_RES_INT(res) SET_RES_OBJ(res, int, expect_type, COMMA, value, 0)
#define SET_RES_UINT(res) SET_RES_OBJ(res, uint, expect_type, COMMA, value, 0)
#define SET_RES_FLOAT(res) SET_RES_OBJ(res, float, expect_type, COMMA, value, 0.0)
#define SET_RES_DOUBLE(res) SET_RES_OBJ(res, double, expect_type, COMMA, value, 0.0)
#define SET_RES_NUMBER(res) SET_RES_OBJ(res, number, expect_type, COMMA, value, (value.set_zero(), value))
#define SET_RES_DATETIME(res) SET_RES_OBJ(res, datetime, expect_type, COMMA, value, ObTimeConverter::ZERO_DATETIME)
#define SET_RES_DATE(res) SET_RES_OBJ(res, date, , , value, ObTimeConverter::ZERO_DATE)
#define SET_RES_TIME(res) SET_RES_OBJ(res, time, , , value, ObTimeConverter::ZERO_TIME)
#define SET_RES_YEAR(res) SET_RES_OBJ(res, year, , , value, ObTimeConverter::ZERO_YEAR)
#define SET_RES_BIT(res) SET_RES_OBJ(res, bit, , , value, 0)
#define SET_RES_ENUM(res) SET_RES_OBJ(res, enum, , , value, 0)
#define SET_RES_SET(res) SET_RES_OBJ(res, set, , , value, 0)
#define SET_RES_OTIMESTAMP(res) SET_RES_OBJ(res, otimestamp_value, expect_type, COMMA, value, ObOTimestampData())
#define SET_RES_INTERVAL_YM(res) SET_RES_OBJ(res, interval_ym, , , value, ObIntervalYMValue())
#define SET_RES_INTERVAL_DS(res) SET_RES_OBJ(res, interval_ds, , , value, ObIntervalDSValue())
#define SET_RES_UROWID(res) SET_RES_OBJ(res, urowid, , , value, ObURowIDData());

#define SET_RES_ACCURACY(res_precision, res_scale, res_length) \
  if (params.res_accuracy_ != NULL && OB_SUCCESS == ret) {     \
    params.res_accuracy_->set_scale(res_scale);                \
    params.res_accuracy_->set_precision(res_precision);        \
    params.res_accuracy_->set_length(res_length);              \
  }

#define SET_RES_ACCURACY_STRING(type, res_precision, res_length) \
  if (params.res_accuracy_ != NULL && OB_SUCCESS == ret) {       \
    params.res_accuracy_->set_precision(res_precision);          \
    params.res_accuracy_->set_length(res_length);                \
    if (ob_is_text_tc(type)) {                                   \
      params.res_accuracy_->set_scale(DEFAULT_SCALE_FOR_TEXT);   \
    } else {                                                     \
      params.res_accuracy_->set_scale(DEFAULT_SCALE_FOR_STRING); \
    }                                                            \
  }
////////////////////////////////////////////////////////////////
// range check function templates.

////////////////////////////////////////////////////////////////////////////////////////////////////

ObNumber ObNumberConstValue::MYSQL_MIN[ObNumber::MAX_PRECISION + 1][ObNumber::MAX_SCALE + 1] = {};
ObNumber ObNumberConstValue::MYSQL_MAX[ObNumber::MAX_PRECISION + 1][ObNumber::MAX_SCALE + 1] = {};
ObNumber ObNumberConstValue::MYSQL_CHECK_MIN[ObNumber::MAX_PRECISION + 1][ObNumber::MAX_SCALE + 1] = {};
ObNumber ObNumberConstValue::MYSQL_CHECK_MAX[ObNumber::MAX_PRECISION + 1][ObNumber::MAX_SCALE + 1] = {};
ObNumber ObNumberConstValue::ORACLE_CHECK_MIN[OB_MAX_NUMBER_PRECISION + 1]
                                             [ObNumberConstValue::MAX_ORACLE_SCALE_SIZE + 1] = {};
ObNumber ObNumberConstValue::ORACLE_CHECK_MAX[OB_MAX_NUMBER_PRECISION + 1]
                                             [ObNumberConstValue::MAX_ORACLE_SCALE_SIZE + 1] = {};

int ObNumberConstValue::init(ObIAllocator& allocator, const lib::ObMemAttr& attr)
{
  int ret = OB_SUCCESS;
  int64_t total_alloc_size = 0;
  const int64_t BUFFER_SIZE = 2 * (ObNumber::MAX_SCALE + ObNumber::MAX_PRECISION);
  char buf[BUFFER_SIZE];
  buf[BUFFER_SIZE - 1] = '\0';
  // prepare string like "99.999".
  int pos = 0;
  buf[pos++] = '-';

  {
    CompatModeGuard tmp_mode(ObWorker::CompatMode::MYSQL);
    for (int16_t precision = OB_MIN_DECIMAL_PRECISION; OB_SUCC(ret) && precision <= ObNumber::MAX_PRECISION;
         ++precision) {
      for (int16_t scale = 0; OB_SUCC(ret) && precision >= scale && scale <= ObNumber::MAX_SCALE; ++scale) {
        pos = 1;
        MEMSET(buf + pos, 0, BUFFER_SIZE - pos);
        if (precision == scale) {
          buf[pos++] = '0';
        }
        MEMSET(buf + pos, '9', precision + 1);
        buf[pos + precision + 1] = '5';
        buf[pos + precision - scale] = '.';
        // make min and max numbers.
        ObNumber& min_check_num = MYSQL_CHECK_MIN[precision][scale];
        ObNumber& max_check_num = MYSQL_CHECK_MAX[precision][scale];
        ObString tmp_string(pos + precision + 1 + 1, buf);
        if (OB_FAIL(min_check_num.from(tmp_string.ptr(), tmp_string.length(), allocator, attr))) {
          LOG_ERROR("fail to call from", K(precision), K(scale), K(tmp_string), K(pos), K(ret));
        } else if (OB_FAIL(max_check_num.from(tmp_string.ptr() + 1, tmp_string.length() - 1, allocator, attr))) {
          LOG_ERROR("fail to call from", K(precision), K(scale), K(tmp_string), K(pos), K(ret));
        } else {
          total_alloc_size += sizeof(uint32_t) * (min_check_num.get_length() + max_check_num.get_length());
          LOG_DEBUG("succ to build mysql min max check number",
              K(precision),
              K(scale),
              K(tmp_string),
              K(total_alloc_size),
              K(min_check_num),
              K(max_check_num));
        }

        if (OB_SUCC(ret)) {
          buf[pos + precision + 1] = '0';
          // make min and max numbers.
          ObNumber& min_num = MYSQL_MIN[precision][scale];
          ObNumber& max_num = MYSQL_MAX[precision][scale];
          if (OB_FAIL(min_num.from(tmp_string.ptr(), tmp_string.length(), allocator, attr))) {
            LOG_ERROR("fail to call from", K(precision), K(scale), K(tmp_string), K(pos), K(ret));
          } else if (OB_FAIL(max_num.from(tmp_string.ptr() + 1, tmp_string.length() - 1, allocator, attr))) {
            LOG_ERROR("fail to call from", K(precision), K(scale), K(tmp_string), K(pos), K(ret));
          } else {
            total_alloc_size += sizeof(uint32_t) * (min_num.get_length() + max_num.get_length());
            LOG_DEBUG("succ to build mysql min max number",
                K(precision),
                K(scale),
                K(tmp_string),
                K(total_alloc_size),
                K(min_num),
                K(max_num));
          }
        }
      }
    }
  }

  {
    CompatModeGuard tmp_mode(ObWorker::CompatMode::ORACLE);
    for (int16_t precision = OB_MIN_NUMBER_PRECISION; OB_SUCC(ret) && precision <= OB_MAX_NUMBER_PRECISION;
         ++precision) {
      for (int16_t scale = ObNumber::MIN_SCALE; OB_SUCC(ret) && scale <= ObNumber::MAX_SCALE; ++scale) {
        pos = 1;
        MEMSET(buf + pos, 0, BUFFER_SIZE - pos);
        ObNumber& min_check_num = ORACLE_CHECK_MIN[precision][scale + MAX_ORACLE_SCALE_DELTA];
        ObNumber& max_check_num = ORACLE_CHECK_MAX[precision][scale + MAX_ORACLE_SCALE_DELTA];
        ObString tmp_string;

        if (precision >= scale && scale >= 0) {
          /* number(3, 1) => legal range(-99.95, 99.95) */
          if (precision == scale) {
            buf[pos++] = '0';
          }
          MEMSET(buf + pos, '9', precision + 1);
          buf[pos + precision - scale] = '.';
          buf[pos + precision + 1] = '5';
          tmp_string.assign_ptr(buf, pos + precision + 1 + 1);
        } else if (scale < 0) {
          /* number(2, -3) => legal range: (-99500, 99500) */
          MEMSET(buf + pos, '9', precision);
          buf[pos + precision] = '5';
          MEMSET(buf + pos + precision + 1, '0', 0 - scale - 1);
          tmp_string.assign_ptr(buf, pos + precision - scale);
        } else {
          // number(2, 3) => legal range:(-0.0995, 0.0995)
          buf[pos++] = '0';
          buf[pos++] = '.';
          MEMSET(buf + pos, '0', scale - precision);
          MEMSET(buf + pos + scale - precision, '9', precision);
          buf[pos + scale] = '5';
          tmp_string.assign_ptr(buf, pos + scale + 1);
        }

        // make min and max numbers.
        if (OB_FAIL(min_check_num.from(tmp_string.ptr(), tmp_string.length(), allocator, attr))) {
          LOG_ERROR("fail to call from", K(precision), K(scale), K(tmp_string), K(ret));
        } else if (OB_FAIL(max_check_num.from(tmp_string.ptr() + 1, tmp_string.length() - 1, allocator, attr))) {
          LOG_ERROR("fail to call from", K(precision), K(scale), K(tmp_string), K(ret));
        } else {
          total_alloc_size += sizeof(uint32_t) * (min_check_num.get_length() + max_check_num.get_length());
          LOG_DEBUG("succ to build min max number",
              K(precision),
              K(scale),
              K(tmp_string),
              K(total_alloc_size),
              K(min_check_num),
              K(max_check_num));
        }
      }
    }
  }
  return ret;
}

// Type is float/double
template <typename Type>
int real_range_check_only(const ObAccuracy& accuracy, Type value)
{
  int ret = OB_SUCCESS;
  const ObPrecision precision = accuracy.get_precision();
  const ObScale scale = accuracy.get_scale();
  if (OB_LIKELY(precision > 0) && OB_LIKELY(scale >= 0) && OB_LIKELY(precision >= scale)) {
    Type integer_part = static_cast<Type>(pow(10.0, static_cast<double>(precision - scale)));
    Type decimal_part = static_cast<Type>(pow(10.0, static_cast<double>(scale)));
    Type max_value = integer_part - 1 / decimal_part;
    Type min_value = -max_value;
    if (OB_FAIL(numeric_range_check(value, min_value, max_value, value))) {}
  }
  return ret;
}

#define BOUND_INFO_START_POS 18

template <typename T>
ObPrecision get_precision_for_integer(T value)
{
  static const uint64_t bound_info[] = {
      INT64_MAX + 1ULL,
      999999999999999999ULL,
      99999999999999999ULL,
      9999999999999999ULL,
      999999999999999ULL,
      99999999999999ULL,
      9999999999999ULL,
      999999999999ULL,
      99999999999ULL,
      9999999999ULL,
      999999999ULL,
      99999999ULL,
      9999999ULL,
      999999ULL,
      99999ULL,
      9999ULL,
      999ULL,
      99ULL,
      9ULL,
      99ULL,
      999ULL,
      9999ULL,
      99999ULL,
      999999ULL,
      9999999ULL,
      99999999ULL,
      999999999ULL,
      9999999999ULL,
      99999999999ULL,
      999999999999ULL,
      9999999999999ULL,
      99999999999999ULL,
      999999999999999ULL,
      9999999999999999ULL,
      99999999999999999ULL,
      999999999999999999ULL,
      9999999999999999999ULL,
      UINT64_MAX,
  };
  int64_t flag = std::less<T>()(value, 0) ? -1 : 1;
  uint64_t abs_value = value * flag;
  const uint64_t* iter = bound_info + BOUND_INFO_START_POS;
  while (abs_value > *iter) {
    iter += flag;
  }
  // *(iter - 1) < abs <= *iter
  return static_cast<ObPrecision>((iter - (bound_info + BOUND_INFO_START_POS)) * flag + 1);
}

int ObHexUtils::unhex(const ObString& text, ObCastCtx& cast_ctx, ObObj& result)
{
  int ret = OB_SUCCESS;
  ObString str_result;
  char* buf = NULL;
  const bool need_fill_zero = (1 == text.length() % 2);
  const int32_t tmp_length = text.length() / 2 + need_fill_zero;
  int32_t alloc_length = (0 == tmp_length ? 1 : tmp_length);
  if (OB_ISNULL(cast_ctx.allocator_v2_)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("allocator in cast ctx is NULL", K(ret), K(text));
  } else if (OB_ISNULL(buf = static_cast<char*>(cast_ctx.allocator_v2_->alloc(alloc_length)))) {
    result.set_null();
    ret = OB_ALLOCATE_MEMORY_FAILED;
    LOG_ERROR("alloc memory failed", K(alloc_length), K(ret));
  } else {
    int32_t i = 0;
    char c1 = 0;
    char c2 = 0;
    if (text.length() > 0) {
      if (need_fill_zero) {
        c1 = '0';
        c2 = text[0];
        i = 0;
      } else {
        c1 = text[0];
        c2 = text[1];
        i = 1;
      }
    }
    while (OB_SUCC(ret) && i < text.length()) {
      if (isxdigit(c1) && isxdigit(c2)) {
        buf[i / 2] = (char)((get_xdigit(c1) << 4) | get_xdigit(c2));
        c1 = text[++i];
        c2 = text[++i];
      } else {
        ret = OB_ERR_INVALID_HEX_NUMBER;
        LOG_WARN("invalid hex number", K(ret), K(c1), K(c2), K(text));
      }
    }

    if (OB_SUCC(ret)) {
      str_result.assign_ptr(buf, tmp_length);
      result.set_varchar(str_result);
    }
  }
  return ret;
}

int ObHexUtils::hex(const ObString& text, ObCastCtx& cast_ctx, ObObj& result)
{
  int ret = OB_SUCCESS;
  ObString str_result;
  char* buf = NULL;
  const int32_t alloc_length = text.empty() ? 1 : text.length() * 2;
  if (OB_ISNULL(cast_ctx.allocator_v2_)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("allocator in cast ctx is NULL", K(ret), K(text));
  } else if (OB_ISNULL(buf = static_cast<char*>(cast_ctx.allocator_v2_->alloc(alloc_length)))) {
    result.set_null();
    ret = OB_ALLOCATE_MEMORY_FAILED;
    LOG_ERROR("alloc memory failed", K(ret), K(alloc_length));
  } else {
    static const char* HEXCHARS = "0123456789ABCDEF";
    int32_t pos = 0;
    for (int32_t i = 0; i < text.length(); ++i) {
      buf[pos++] = HEXCHARS[text[i] >> 4 & 0xF];
      buf[pos++] = HEXCHARS[text[i] & 0xF];
    }
    str_result.assign_ptr(buf, pos);
    result.set_varchar(str_result);
    LOG_DEBUG("succ to hex", K(text), "length", text.length(), K(str_result));
  }
  return ret;
}

int ObHexUtils::hex_for_mysql(const uint64_t uint_val, common::ObCastCtx& cast_ctx, common::ObObj& result)
{

  int ret = OB_SUCCESS;
  char* buf = NULL;
  const int32_t MAX_INT64_LEN = 20;
  if (OB_ISNULL(cast_ctx.allocator_v2_)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("allocator in cast ctx is NULL", K(ret), K(uint_val));
  } else if (OB_ISNULL(buf = static_cast<char*>(cast_ctx.allocator_v2_->alloc(MAX_INT64_LEN)))) {
    result.set_null();
    ret = OB_ALLOCATE_MEMORY_FAILED;
    LOG_ERROR("alloc memory failed", K(ret));
  } else {
    int pos = snprintf(buf, MAX_INT64_LEN, "%lX", uint_val);
    if (OB_UNLIKELY(pos <= 0) || OB_UNLIKELY(pos >= MAX_INT64_LEN)) {
      ret = OB_SIZE_OVERFLOW;
      LOG_ERROR("size is overflow", K(ret), K(uint_val));
    } else {
      ObString str_result(pos, buf);
      result.set_varchar(str_result);
    }
  }
  return ret;
}

// https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/RAWTOHEX.html
// As a SQL built-in function, RAWTOHEX accepts an argument of any scalar data type other than LONG,
// LONG RAW, CLOB, NCLOB, BLOB, or BFILE. If the argument is of a data type other than RAW,
// then this function converts the argument value, which is represented using some number of data bytes,
// into a RAW value with the same number of data bytes. The data itself is not modified in any way,
// but the data type is recast to a RAW data type.
int ObHexUtils::rawtohex(const ObObj& text, ObCastCtx& cast_ctx, ObObj& result)
{
  int ret = OB_SUCCESS;

  if (text.is_null()) {
    result.set_null();
  } else {
    ObString str;
    ObObj num_obj;
    char* splice_num_str = NULL;  // for splice Desc and degits_ of number.
    ObOTimestampData time_value;
    switch (text.get_type()) {
      // TODO::this should same as oracle, and support dump func
      case ObTinyIntType:
      case ObSmallIntType:
      case ObInt32Type:
      case ObIntType: {
        int64_t int_value = text.get_int();
        number::ObNumber nmb;
        if (OB_FAIL(nmb.from(int_value, cast_ctx))) {
          LOG_WARN("fail to int_number", K(ret), K(int_value), "type", text.get_type());
        } else {
          num_obj.set_number(ObNumberType, nmb);
          int32_t alloc_len =
              static_cast<int32_t>(sizeof(num_obj.get_number_desc()) + num_obj.get_number_byte_length());
          if (OB_ISNULL(cast_ctx.allocator_v2_)) {
            ret = OB_INVALID_ARGUMENT;
            LOG_WARN("allocator in cast ctx is NULL", K(ret));
          } else if (OB_ISNULL(splice_num_str = static_cast<char*>(cast_ctx.allocator_v2_->alloc(alloc_len)))) {
            result.set_null();
            ret = OB_ALLOCATE_MEMORY_FAILED;
            LOG_ERROR("alloc memory failed", K(ret), K(alloc_len));
          } else {
            MEMCPY(splice_num_str, &(num_obj.get_number_desc()), sizeof(num_obj.get_number_desc()));
            MEMCPY(splice_num_str + sizeof(num_obj.get_number_desc()),
                num_obj.get_data_ptr(),
                num_obj.get_number_byte_length());
            str.assign_ptr(static_cast<const char*>(splice_num_str), alloc_len);
          }
          LOG_DEBUG("succ to int_number", K(ret), K(int_value), "type", num_obj.get_type(), K(nmb), K(str));
        }
        break;
      }
      case ObNumberFloatType:
      case ObNumberType: {
        int32_t alloc_len = static_cast<int32_t>(sizeof(text.get_number_desc()) + text.get_number_byte_length());
        if (OB_ISNULL(cast_ctx.allocator_v2_)) {
          ret = OB_INVALID_ARGUMENT;
          LOG_WARN("allocator in cast ctx is NULL", K(ret));
        } else if (OB_ISNULL(splice_num_str = static_cast<char*>(cast_ctx.allocator_v2_->alloc(alloc_len)))) {
          result.set_null();
          ret = OB_ALLOCATE_MEMORY_FAILED;
          LOG_ERROR("alloc memory failed", K(ret), K(alloc_len));
        } else {
          MEMCPY(splice_num_str, &(text.get_number_desc()), sizeof(text.get_number_desc()));
          MEMCPY(splice_num_str + sizeof(text.get_number_desc()), text.get_data_ptr(), text.get_number_byte_length());
          str.assign_ptr(static_cast<const char*>(splice_num_str), alloc_len);
        }
        break;
      }
      case ObDateTimeType: {
        str.assign_ptr(static_cast<const char*>(text.get_data_ptr()), static_cast<int32_t>(sizeof(int64_t)));
        break;
      }
      case ObNVarchar2Type:
      case ObNCharType:
      case ObVarcharType:
      case ObCharType:
      case ObLongTextType:
      case ObRawType: {
        // https://www.techonthenet.com/oracle/functions/rawtohex.php
        // NOTE:: when convert string to raw, Oracle use utl_raw.cast_to_raw(), while PL/SQL use hextoraw()
        //       here we use utl_raw.cast_to_raw(), as we can not distinguish in which SQL
        str = text.get_varbinary();
        break;
      }
      case ObTimestampTZType:
      case ObTimestampLTZType:
      case ObTimestampNanoType: {
        time_value = text.get_otimestamp_value();
        str.assign_ptr(reinterpret_cast<char*>(&time_value), static_cast<int32_t>(text.get_otimestamp_store_size()));
        break;
      }
      case ObLobType: {
        const ObLobLocator* lob_locator = text.get_lob_locator();
        if (OB_ISNULL(lob_locator)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("lob_locator is null", K(ret));
        } else if (OB_FAIL(lob_locator->get_payload(str))) {
          LOG_WARN("get payload from lob_locator failed", K(ret), K(*lob_locator));
        }
        break;
      }
      default: {
        ret = OB_ERR_INVALID_HEX_NUMBER;
        LOG_WARN("invalid hex number", K(ret), K(text), "type", text.get_type());
      }
    }
    if (OB_SUCC(ret)) {
      if (OB_FAIL(hex(str, cast_ctx, result))) {
        LOG_WARN("fail to convert to hex", K(ret), K(str));
      } else {
        result.set_default_collation_type();
      }
    }
  }
  LOG_DEBUG("succ to rawtohex", "type", text.get_type(), K(text), K(result), K(lbt()));
  return ret;
}

int ObHexUtils::hextoraw(const ObObj& text, ObCastCtx& cast_ctx, ObObj& result)
{
  int ret = OB_SUCCESS;
  if (text.is_null()) {
    result.set_null();
  } else if (text.is_numeric_type()) {
    number::ObNumber nmb_val;
    if (OB_FAIL(get_uint(text, cast_ctx, nmb_val))) {
      LOG_WARN("fail to get uint64", K(ret), K(text));
    } else if (OB_FAIL(uint_to_raw(nmb_val, cast_ctx, result))) {
      LOG_WARN("fail to convert to hex", K(ret), K(nmb_val));
    }
  } else if (text.is_raw()) {
    // fast path
    if (OB_FAIL(copy_raw(text, cast_ctx, result))) {
      LOG_WARN("fail to convert to hex", K(ret), K(text));
    }
  } else if (text.is_character_type() || text.is_varbinary_or_binary()) {
    ObString utf8_string;
    if (OB_FAIL(convert_string_collation(
            text.get_string(), text.get_collation_type(), utf8_string, ObCharset::get_system_collation(), cast_ctx))) {
      LOG_WARN("convert_string_collation", K(ret));
    } else if (OB_FAIL(unhex(utf8_string, cast_ctx, result))) {
      LOG_WARN("fail to convert to hex", K(ret), K(text));
    } else {
      result.set_raw(result.get_raw());
    }
  } else {
    ret = OB_ERR_INVALID_HEX_NUMBER;
    LOG_WARN("invalid hex number", K(ret), K(text));
  }
  LOG_DEBUG("succ to hextoraw", "type", text.get_type(), K(text), K(result.get_raw()), K(result), K(lbt()));
  return ret;
}

int ObHexUtils::get_uint(const ObObj& obj, ObCastCtx& cast_ctx, number::ObNumber& out)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(!ob_is_accurate_numeric_type(obj.get_type()))) {
    ret = OB_ERR_INVALID_HEX_NUMBER;
    LOG_WARN("invalid hex number", K(ret), K(obj));
  } else if (obj.is_number() || obj.is_unumber()) {
    const number::ObNumber& value = obj.get_number();
    if (OB_FAIL(out.from(value, cast_ctx))) {
      LOG_WARN("deep copy failed", K(ret), K(obj));
    } else if (OB_UNLIKELY(!out.is_integer()) || OB_UNLIKELY(out.is_negative())) {
      ret = OB_ERR_INVALID_HEX_NUMBER;
      LOG_WARN("invalid hex number", K(ret), K(out));
    } else if (OB_FAIL(out.round(0))) {
      LOG_WARN("round failed", K(ret), K(out));
    }
  } else {
    if (OB_UNLIKELY(obj.get_int() < 0)) {
      ret = OB_ERR_INVALID_HEX_NUMBER;
      LOG_WARN("invalid hex number", K(ret), K(obj));
    } else if (OB_FAIL(out.from(obj.get_int(), cast_ctx))) {
      LOG_WARN("deep copy failed", K(ret), K(obj));
    }
  }
  return ret;
}

int ObHexUtils::uint_to_raw(const number::ObNumber& uint_num, ObCastCtx& cast_ctx, ObObj& result)
{
  int ret = OB_SUCCESS;
  const int64_t oracle_max_avail_len = 40;
  char uint_buf[number::ObNumber::MAX_TOTAL_SCALE] = {0};
  int64_t uint_pos = 0;
  ObString uint_str;
  if (OB_FAIL(uint_num.format(uint_buf, number::ObNumber::MAX_TOTAL_SCALE, uint_pos, 0))) {
    LOG_WARN("fail to format ", K(ret), K(uint_num));
  } else if (uint_pos > oracle_max_avail_len) {
    ret = OB_ERR_INVALID_HEX_NUMBER;
    LOG_WARN("invalid hex number", K(ret), K(uint_pos), K(oracle_max_avail_len), K(uint_num));
  } else {
    uint_str.assign_ptr(uint_buf, static_cast<int32_t>(uint_pos));
    if (OB_FAIL(unhex(uint_str, cast_ctx, result))) {
      LOG_WARN("fail to str_to_raw", K(ret), K(result));
    } else {
      result.set_raw(result.get_raw());
    }
  }
  return ret;
}

int ObHexUtils::copy_raw(const common::ObObj& obj, common::ObCastCtx& cast_ctx, common::ObObj& result)
{
  int ret = OB_SUCCESS;
  char* buf = NULL;
  const ObString& value = obj.get_raw();
  const int32_t alloc_length = value.empty() ? 1 : value.length();
  if (OB_ISNULL(cast_ctx.allocator_v2_)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("allocator in cast ctx is NULL", K(ret));
  } else if (OB_ISNULL(buf = static_cast<char*>(cast_ctx.allocator_v2_->alloc(alloc_length)))) {
    result.set_null();
    ret = OB_ALLOCATE_MEMORY_FAILED;
    LOG_ERROR("alloc memory failed", K(ret), K(alloc_length));
  } else {
    MEMCPY(buf, value.ptr(), value.length());
    result.set_raw(buf, value.length());
  }
  return ret;
}

static int check_convert_string(const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  // UNUSED(expect_type);
  // UNUSED(params);
  //  if (lib::is_oracle_mode()) {
  //    //varchar2 --> raw
  //    if (in.is_varchar_or_char() && ob_is_varbinary_type(expect_type, params.expect_obj_collation_)) {
  //      if (OB_FAIL(ObHexUtils::hextoraw(in, params, out))) {
  //        LOG_WARN("fail to hextoraw", K(ret), K(in));
  //      }
  //    //raw --> varchar2
  //    } else if (in.is_varbinary() && ob_is_varchar_char_type(expect_type, params.expect_obj_collation_)) {
  //      if (OB_FAIL(ObHexUtils::rawtohex(in, params, out))) {
  //        LOG_WARN("fail to rawtohex", K(ret), K(in));
  //      }
  //    } else {
  //      //TODO::for lob, for long raw ,
  //      out = in;
  //      LOG_DEBUG("do nothing");
  //    }
  //    LOG_DEBUG("finish check_convert_string", K(ret), "in_type", in.get_type(), "in_cs_type",
  //    in.get_collation_type(), K(in), K(expect_type), "expect_cs_type", params.dest_collation_, K(out));
  if (lib::is_oracle_mode() && ob_is_blob(expect_type, params.expect_obj_collation_) && !in.is_blob() && !in.is_raw()) {
    if (in.is_varchar_or_char()) {
      if (OB_FAIL(ObHexUtils::hextoraw(in, params, out))) {
        LOG_WARN("fail to hextoraw for blob", K(ret), K(in));
      }
    } else {
      ret = OB_NOT_SUPPORTED;
      LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
    }
  } else {
    out = in;
  }
  return ret;
}

static int check_convert_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObString& in_string, ObObj& out)
{
  ObObj tmp_obj;
  tmp_obj.set_varchar(in_string);
  return check_convert_string(expect_type, params, tmp_obj, out);
}

static int check_convert_string(
    const ObObjType expect_type, ObObjCastParams& params, const char* in_str, const int64_t len, ObObj& out)
{
  ObObj tmp_obj;
  tmp_obj.set_varchar(in_str, static_cast<ObString::obstr_size_t>(len));
  return check_convert_string(expect_type, params, tmp_obj, out);
}

////////////////////////////////////////////////////////////////
// Int -> XXX

static const double ROUND_DOUBLE = 0.5;

static int int_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    int64_t value = in.get_int();
    if (in.get_type() > expect_type && CAST_FAIL(int_range_check(expect_type, value, value))) {
    } else {
      out.set_int(expect_type, value);
      res_precision = get_precision_for_integer(value);
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int int_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (CM_SKIP_CAST_INT_UINT(cast_mode)) {
    out = in;
    res_precision = get_precision_for_integer(out.get_uint64());
  } else {
    uint64_t value = static_cast<uint64_t>(in.get_int());
    if (CM_NEED_RANGE_CHECK(cast_mode) && CAST_FAIL(uint_range_check(expect_type, in.get_int(), value))) {
    } else {
      out.set_uint(expect_type, value);
      res_precision = get_precision_for_integer(out.get_uint64());
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int int_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    double value = static_cast<double>(in.get_int());
    if (ObUFloatType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
    } else {
      out.set_float(expect_type, static_cast<float>(value));
    }
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int int_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    double value = static_cast<double>(in.get_int());
    if (ObUDoubleType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
    } else {
      out.set_double(expect_type, value);
    }
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int int_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    int64_t value = in.get_int();
    number::ObNumber nmb;
    if (ObUNumberType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
    } else if (OB_FAIL(nmb.from(value, params))) {
    } else {
      out.set_number(expect_type, nmb);
      res_precision = get_precision_for_integer(in.get_int());
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int int_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    ObTimeConvertCtx cvrt_ctx(params.dtc_params_.tz_info_, ObTimestampType == expect_type);
    int64_t value = 0;
    if (in.get_int() < 0) {
      ret = OB_INVALID_DATE_FORMAT;
    } else {
      ret = ObTimeConverter::int_to_datetime(in.get_int(), 0, cvrt_ctx, value);
    }
    if (CAST_FAIL(ret)) {
    } else {
      SET_RES_DATETIME(out);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, MIN_SCALE_FOR_TEMPORAL, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int int_datetime_interval(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class()) || OB_UNLIKELY(ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {

    // oracle treate int as day
    int64_t value = in.get_int() * USECS_PER_DAY;
    SET_RES_DATETIME(out);
    LOG_DEBUG("succ to int_datetime_interval", K(ret), K(in), K(value), K(expect_type));
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, MIN_SCALE_FOR_TEMPORAL, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}
static int int_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class() || ObDateTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    int32_t value = 0;
    if (CAST_FAIL(ObTimeConverter::int_to_date(in.get_int(), value))) {
    } else {
      SET_RES_DATE(out);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_DATE, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int int_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class() || ObTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    int64_t value = 0;
    if (CAST_FAIL(ObTimeConverter::int_to_time(in.get_int(), value))) {
    } else {
      SET_RES_TIME(out);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, MIN_SCALE_FOR_TEMPORAL, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int int_year(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObIntTC != 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;
    if (CAST_FAIL(ObTimeConverter::int_to_year(in.get_int(), 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 int_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class() ||
                  (ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    ObObj tmp_out;
    ObFastFormatInt ffi(in.get_int());
    ObString tmp_str;
    if (OB_FAIL(convert_string_collation(ObString(ffi.length(), ffi.ptr()),
            ObCharset::get_system_collation(),
            tmp_str,
            params.dest_collation_,
            params))) {
      LOG_WARN("fail to convert string collation", K(ret));
    } else if (OB_FAIL(check_convert_string(expect_type, params, tmp_str.ptr(), tmp_str.length(), tmp_out))) {
      LOG_WARN("fail to check_convert_string", K(ret), K(in), K(expect_type));
    } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out))) {
    } else {
      res_length = static_cast<ObLength>(out.get_string_len());
    }
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  UNUSED(cast_mode);
  return ret;
}

static int int_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  uint64_t value = static_cast<uint64_t>(in.get_int());
  int32_t bit_len = 0;
  if (OB_UNLIKELY(ObIntTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_bit_len(value, bit_len))) {
    LOG_WARN("fail to get bit len", K(ret), K(value), K(bit_len));
  } else {
    SET_RES_BIT(out);
    SET_RES_ACCURACY(static_cast<ObPrecision>(bit_len), DEFAULT_SCALE_FOR_BIT, DEFAULT_LENGTH_FOR_NUMERIC);
  }
  return ret;
}

static int uint_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out);
static int int_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) || OB_UNLIKELY(ObIntTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else {
    uint64_t value = static_cast<uint64_t>(in.get_int());
    ObObj uint_val;
    uint_val.set_uint64(value);
    if (OB_FAIL(uint_enum(expect_type, params, uint_val, out))) {
      LOG_WARN("fail to cast uint to enum", K(expect_type), K(in), K(uint_val), K(out), K(ret));
    }
  }
  return ret;
}

static int uint_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out);
static int int_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) || OB_UNLIKELY(ObIntTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else {
    uint64_t value = static_cast<uint64_t>(in.get_int());
    ObObj uint_val;
    uint_val.set_uint64(value);
    if (OB_FAIL(uint_set(expect_type, params, uint_val, out))) {
      LOG_WARN("fail to cast uint to enum", K(expect_type), K(in), K(uint_val), K(out), K(ret));
    }
  }
  return ret;
}
static int string_lob(const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out,
    const ObCastMode cast_mode, const ObLobLocator* lob_locator);
static int string_lob(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  return string_lob(expect_type, params, in, out, cast_mode, NULL);
}

#define CAST_TO_LOB_METHOD(TYPE, TYPE_CLASS)                                                                         \
  static int TYPE##_lob(                                                                                             \
      const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode) \
  {                                                                                                                  \
    int ret = OB_SUCCESS;                                                                                            \
    ObObj tmp_val;                                                                                                   \
    if (OB_UNLIKELY(TYPE_CLASS != in.get_type_class() || ObLobTC != ob_obj_type_class(expect_type))) {               \
      ret = OB_ERR_UNEXPECTED;                                                                                       \
      LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));                                                \
    } else if (OB_FAIL(TYPE##_string(ObLongTextType, params, in, tmp_val, cast_mode))) {                             \
      LOG_WARN("fail to cast" #TYPE "to string", K(ret), K(expect_type), K(in), K(tmp_val));                         \
    } else if (OB_FAIL(string_lob(expect_type, params, tmp_val, out, cast_mode))) {                                  \
      LOG_WARN("fail to cast string to lob", K(ret), K(expect_type), K(in), K(tmp_val));                             \
    }                                                                                                                \
    return ret;                                                                                                      \
  }

CAST_TO_LOB_METHOD(int, ObIntTC);

////////////////////////////////////////////////////////////////
// UInt -> XXX

static int uint_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObUIntTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (CM_IS_EXTERNAL_CALL(cast_mode) && CM_SKIP_CAST_INT_UINT(cast_mode)) {
    out = in;
    res_precision = get_precision_for_integer(out.get_int());
  } else {
    int64_t value = static_cast<int64_t>(in.get_uint64());
    if (CM_NEED_RANGE_CHECK(cast_mode) && CAST_FAIL(int_upper_check(expect_type, in.get_uint64(), value))) {
    } else {
      out.set_int(expect_type, value);
      res_precision = get_precision_for_integer(value);
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int uint_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObUIntTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    uint64_t value = in.get_uint64();
    if (in.get_type() > expect_type && CAST_FAIL(uint_upper_check(expect_type, value))) {
    } else {
      out.set_uint(expect_type, value);
      res_precision = get_precision_for_integer(value);
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int uint_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObUIntTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    // for compatibility with mysql, we cast uint to double first, then to float.
    double value = static_cast<double>(in.get_uint64());
    out.set_float(expect_type, static_cast<float>(value));
  }
  UNUSED(cast_mode);
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int uint_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObUIntTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    out.set_double(expect_type, static_cast<double>(in.get_uint64()));
  }
  UNUSED(cast_mode);
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int uint_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  number::ObNumber nmb;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObUIntTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(nmb.from(in.get_uint64(), params))) {
  } else {
    out.set_number(expect_type, nmb);
    res_precision = get_precision_for_integer(in.get_uint64());
  }
  UNUSED(cast_mode);
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int uint_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj int64;
  if (OB_UNLIKELY(ObUIntTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(uint_int(ObIntType, params, in, int64, CM_UNSET_NO_CAST_INT_UINT(cast_mode)))) {
  } else if (OB_FAIL(int_datetime(expect_type, params, int64, out, cast_mode))) {
  }
  // has set the accuracy in prev int_datetime call
  return ret;
}

static int uint_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj int64;
  if (OB_UNLIKELY(ObUIntTC != in.get_type_class() || ObDateTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(uint_int(ObIntType, params, in, int64, CM_UNSET_NO_CAST_INT_UINT(cast_mode)))) {
  } else if (OB_FAIL(int_date(expect_type, params, int64, out, cast_mode))) {
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_DATE, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int uint_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj int64;
  if (OB_UNLIKELY(ObUIntTC != in.get_type_class() || ObTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(uint_int(ObIntType, params, in, int64, CM_UNSET_NO_CAST_INT_UINT(cast_mode)))) {
  } else if (OB_FAIL(int_time(expect_type, params, int64, out, cast_mode))) {
  }
  // accuracy has been set in prev int_time call
  return ret;
}

static int uint_year(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj int64;
  if (OB_UNLIKELY(ObUIntTC != 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 if (OB_FAIL(uint_int(ObIntType, params, in, int64, CM_UNSET_NO_CAST_INT_UINT(cast_mode)))) {
  } else if (OB_FAIL(int_year(expect_type, params, int64, out, cast_mode))) {
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_YEAR, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int uint_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObUIntTC != in.get_type_class() ||
                  (ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    ObObj tmp_out;
    ObFastFormatInt ffi(in.get_uint64());
    ObString tmp_str;
    if (OB_FAIL(convert_string_collation(ObString(ffi.length(), ffi.ptr()),
            ObCharset::get_system_collation(),
            tmp_str,
            params.dest_collation_,
            params))) {
      LOG_WARN("fail to convert string collation", K(ret));
    } else if (OB_FAIL(check_convert_string(expect_type, params, tmp_str.ptr(), tmp_str.length(), tmp_out))) {
      LOG_WARN("fail to check_convert_string", K(ret), K(in), K(expect_type));
    } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out))) {
    } else {
      res_length = static_cast<ObLength>(out.get_string_len());
    }
  }

  UNUSED(cast_mode);
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  return ret;
}

static int uint_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  uint64_t value = in.get_uint64();
  int32_t bit_len = 0;
  if (OB_UNLIKELY(ObUIntTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_bit_len(value, bit_len))) {
    LOG_WARN("fail to get bit len", K(ret), K(value), K(bit_len));
  } else {
    SET_RES_BIT(out);
    SET_RES_ACCURACY(static_cast<ObPrecision>(bit_len), DEFAULT_SCALE_FOR_BIT, DEFAULT_LENGTH_FOR_NUMERIC);
  }
  return ret;
}

static int uint_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObCastMode cast_mode = params.cast_mode_;
  const ObIArray<ObString>* type_infos = NULL;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) || OB_UNLIKELY(ObUIntTC != in.get_type_class()) ||
      OB_ISNULL(type_infos = expect_type.get_type_infos())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else {
    uint64_t value = in.get_uint64();
    if (OB_UNLIKELY(0 == value || value > type_infos->count())) {
      value = 0;
      ret = OB_ERR_DATA_TRUNCATED;
      LOG_WARN("input value out of range", K(in), K(expect_type), K(ret));
    }

    if (OB_FAIL(ret) && CM_IS_WARN_ON_FAIL(cast_mode)) {
      params.warning_ = OB_ERR_DATA_TRUNCATED;
      ret = OB_SUCCESS;
    }
    LOG_DEBUG("finish uint_enum", K(ret), K(expect_type), K(in), K(out), KPC(type_infos), K(lbt()));
    SET_RES_ENUM(out);
  }
  return ret;
}

static int uint_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObCastMode cast_mode = params.cast_mode_;
  const ObIArray<ObString>* type_infos = NULL;
  int64_t val_cnt = 0;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) || OB_UNLIKELY(ObUIntTC != in.get_type_class()) ||
      OB_ISNULL(type_infos = expect_type.get_type_infos())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else {
    uint64_t value = in.get_uint64();
    val_cnt = type_infos->count();
    if (OB_UNLIKELY(val_cnt <= 0)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("unexpect val_cnt", K(in), K(out), K(expect_type), K(ret));
    } else if (val_cnt >= 64) {  // do nothing
    } else if (val_cnt < 64 && value > ((1ULL << val_cnt) - 1)) {
      value = value & ((1ULL << val_cnt) - 1);
      ret = OB_ERR_DATA_TRUNCATED;
      LOG_WARN("input value out of range", K(in), K(val_cnt), K(ret));
    }

    if (OB_FAIL(ret) && CM_IS_WARN_ON_FAIL(cast_mode)) {
      params.warning_ = OB_ERR_DATA_TRUNCATED;
      ret = OB_SUCCESS;
    }
    LOG_DEBUG("finish uint_set", K(ret), K(expect_type), K(in), K(out), KPC(type_infos), K(lbt()));
    SET_RES_SET(out);
  }
  return ret;
}

CAST_TO_LOB_METHOD(uint, ObUIntTC);

////////////////////////////////////////////////////////////////
// Float -> XXX

// directly stacit cast from float to int or uint:
// case 1: float = -99999896450971467776.000000, int64 = -9223372036854775808, uint64 = 9223372036854775808.
// case 2: float = 99999896450971467776.000000, int64 = -9223372036854775808, uint64 = 0.
// case 3: float = -99999904.000000, int64 = -99999904, uint64 = 18446744073609551712.
// case 4: float = 99999904.000000, int64 = 99999904, uint64 = 99999904.
// we can see that if float value is out of range of int or uint value, the casted int or uint
// value can't be used to compare with INT64_MAX and so on, see case 2.
// so we should use float value to determine weither it is in range of int or uint.

int common_double_int(const double in, int64_t& out, const int64_t trunc_min_value, const int64_t trunc_max_value)
{
  int ret = OB_SUCCESS;
  out = 0;
  if (in <= static_cast<double>(LLONG_MIN)) {
    out = trunc_min_value;
    if (in < static_cast<double>(LLONG_MIN)) {
      ret = OB_DATA_OUT_OF_RANGE;
    }
  } else if (in >= static_cast<double>(LLONG_MAX)) {
    out = trunc_max_value;
    if (in > static_cast<double>(LLONG_MAX)) {
      ret = OB_DATA_OUT_OF_RANGE;
    }
  } else {
    out = static_cast<int64_t>(rint(in));
  }
  return ret;
}

static int float_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t value = 0;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    if (CAST_FAIL(common_double_int(
            in.get_float(), value, LLONG_MIN, CM_IS_COLUMN_CONVERT(cast_mode) ? LLONG_MAX : LLONG_MIN))) {
      LOG_WARN("cast float to int failed", K(ret), K(in), K(value));
    } else if (CAST_FAIL(int_range_check(expect_type, value, value))) {
    } else {
      out.set_int(expect_type, value);
    }
    if (OB_SUCC(ret)) {
      res_precision = get_precision_for_integer(value);
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int float_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  uint64_t value = 0;
  ObPrecision res_precision = -1;
  double in_value = static_cast<double>(in.get_float());
  bool is_column_convert = CM_IS_COLUMN_CONVERT(cast_mode);
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    if (in_value <= static_cast<double>(LLONG_MIN) || in_value >= static_cast<double>(ULLONG_MAX)) {
      value = static_cast<uint64_t>(LLONG_MIN);
      ret = OB_DATA_OUT_OF_RANGE;
    } else {
      if (is_column_convert) {
        value = static_cast<uint64_t>(rint(in_value));
      } else {
        value = static_cast<uint64_t>(static_cast<int64_t>(rint(in_value)));
      }
      if (in_value < 0 && value != 0) {
        ret = OB_DATA_OUT_OF_RANGE;
      }
    }
    if (CAST_FAIL(ret)) {
      LOG_WARN("cast float to uint failed", K(ret), K(in), K(value));
    }
  }

  if (OB_FAIL(ret)) {
  } else if (CM_NEED_RANGE_CHECK(cast_mode) && CAST_FAIL(uint_range_check(expect_type, value, value))) {
  } else {
    out.set_uint(expect_type, value);
  }
  if (OB_SUCC(ret)) {
    res_precision = get_precision_for_integer(value);
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int float_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  float value = in.get_float();
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (ObUFloatType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
  } else {
    out.set_float(expect_type, value);
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int float_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  double value = static_cast<double>(in.get_float());
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (ObUDoubleType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
  } else {
    out.set_double(expect_type, value);
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int float_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  float value = in.get_float();
  ObPrecision res_precision = -1;
  ObScale res_scale = -1;
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (isnan(value)) {
    ret = OB_INVALID_NUMERIC;
    LOG_WARN("float_number failed ", K(ret), K(value));
  } else if (isinf(value)) {
    ret = OB_NUMERIC_OVERFLOW;
    LOG_WARN("float_number failed", K(ret), K(value));
  } else if (ObUNumberType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
  } else {
    char buf[MAX_DOUBLE_STRICT_PRINT_SIZE];
    MEMSET(buf, 0, MAX_DOUBLE_STRICT_PRINT_SIZE);
    int64_t length = 0;
    if (lib::is_oracle_mode()) {
      length = ob_gcvt_opt(in.get_float(), OB_GCVT_ARG_FLOAT, sizeof(buf) - 1, buf, NULL, TRUE);
    } else {
      length = ob_gcvt(in.get_float(), OB_GCVT_ARG_DOUBLE, sizeof(buf) - 1, buf, NULL);
    }
    ObString str(sizeof(buf), static_cast<int32_t>(length), buf);
    number::ObNumber nmb;
    if (OB_FAIL(nmb.from_sci_opt(str.ptr(), str.length(), params, &res_precision, &res_scale))) {
      LOG_WARN("fail to from str to number", K(ret), K(str));
    } else {
      out.set_number(expect_type, nmb);
    }
    LOG_DEBUG("finish float to number", K(ret), K(str), K(length), K(in), K(expect_type), K(nmb), K(out), K(lbt()));
  }
  SET_RES_ACCURACY(res_precision, res_scale, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int double_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int float_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj dbl;
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(float_double(ObDoubleType, params, in, dbl, cast_mode))) {
  } else if (OB_FAIL(double_datetime(expect_type, params, dbl, out, cast_mode))) {
  }
  // has set accuracy in prev double_datetime call
  return ret;
}

static int double_datetime_interval(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int float_datetime_interval(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj dbl;
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(float_double(ObDoubleType, params, in, dbl, cast_mode))) {
  } else if (OB_FAIL(double_datetime_interval(expect_type, params, dbl, out, cast_mode))) {
  }
  return ret;
}

static int double_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int float_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj dbl;
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() || ObDateTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(float_double(ObDoubleType, params, in, dbl, cast_mode))) {
  } else if (OB_FAIL(double_date(expect_type, params, dbl, out, cast_mode))) {
  }
  // has set accuracy in prev double_date call
  return ret;
}

static int double_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int float_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj dbl;
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() || ObTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(float_double(ObDoubleType, params, in, dbl, cast_mode))) {
  } else if (OB_FAIL(double_time(expect_type, params, dbl, out, cast_mode))) {
  }
  // has set accuracy in prev double_time call
  return ret;
}

static int float_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
  ObScale scale = in.get_scale();
  int64_t length = 0;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() ||
                  (ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    if (0 <= scale) {
      length = ob_fcvt(in.get_float(), scale, sizeof(buf) - 1, buf, NULL);
    } else {
      length = ob_gcvt_opt(in.get_float(), OB_GCVT_ARG_FLOAT, sizeof(buf) - 1, buf, NULL, lib::is_oracle_mode());
    }
    ObString str(sizeof(buf), static_cast<int32_t>(length), buf);
    LOG_DEBUG("finish float_string", K(ret), K(in), K(expect_type), K(str));
    ObObj tmp_out;
    ObString tmp_str;
    if (OB_FAIL(convert_string_collation(
            str, ObCharset::get_system_collation(), tmp_str, params.dest_collation_, params))) {
      LOG_WARN("fail to convert string collation", K(ret));
    } else if (OB_FAIL(check_convert_string(expect_type, params, tmp_str.ptr(), tmp_str.length(), tmp_out))) {
      LOG_WARN("fail to check_convert_string", K(ret), K(in), K(expect_type));
    } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out))) {
    } else {
      res_length = static_cast<ObLength>(out.get_string_len());
    }
  }
  UNUSED(cast_mode);
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  return ret;
}

static int float_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  uint64_t value = static_cast<uint64_t>(in.get_float());
  int32_t bit_len = 0;
  if (OB_UNLIKELY(ObFloatTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_bit_len(value, bit_len))) {
    LOG_WARN("fail to get bit len", K(ret), K(value), K(bit_len));
  } else {
    SET_RES_BIT(out);
    SET_RES_ACCURACY(static_cast<ObPrecision>(bit_len), DEFAULT_SCALE_FOR_BIT, DEFAULT_LENGTH_FOR_NUMERIC);
  }

  return ret;
}

static int float_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) || OB_UNLIKELY(ObFloatTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else {
    int64_t value = static_cast<int64_t>(in.get_float());
    ObObj int_val(value);
    if (OB_FAIL(int_enum(expect_type, params, int_val, out))) {
      LOG_WARN("fail to cast int to enum", K(expect_type), K(in), K(int_val), K(out), K(ret));
    }
  }
  return ret;
}

static int float_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) || OB_UNLIKELY(ObFloatTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else {
    int64_t value = static_cast<int64_t>(in.get_float());
    ObObj int_val(value);
    if (OB_FAIL(int_set(expect_type, params, int_val, out))) {
      LOG_WARN("fail to cast int to enum", K(expect_type), K(in), K(int_val), K(out), K(ret));
    }
  }
  return ret;
}

CAST_TO_LOB_METHOD(float, ObFloatTC);

////////////////////////////////////////////////////////////////
// Double -> XXX

static int double_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t value = 0;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    if (CAST_FAIL(common_double_int(in.get_double(), value, LLONG_MIN, LLONG_MAX))) {
      LOG_WARN("common double to in failed", K(ret), K(in), K(cast_mode));
    } else if (CAST_FAIL(int_range_check(expect_type, value, value))) {
      LOG_WARN("int range check failed", K(ret), K(value));
    } else {
      out.set_int(expect_type, value);
    }
    if (OB_SUCC(ret)) {
      res_precision = get_precision_for_integer(value);
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int double_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  uint64_t value = 0;
  ObPrecision res_precision = -1;
  double in_value = in.get_double();
  bool is_column_convert = CM_IS_COLUMN_CONVERT(cast_mode);
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    if (in_value <= static_cast<double>(LLONG_MIN)) {
      value = static_cast<uint64_t>(LLONG_MIN);
      ret = OB_DATA_OUT_OF_RANGE;
    } else if (in_value >= static_cast<double>(ULLONG_MAX)) {
      value = static_cast<uint64_t>(LLONG_MAX);
      ret = OB_DATA_OUT_OF_RANGE;
    } else {
      if (is_column_convert) {
        value = static_cast<uint64_t>(rint(in_value));
      } else if (in_value >= static_cast<double>(LLONG_MAX)) {
        value = static_cast<uint64_t>(LLONG_MAX);
      } else {
        value = static_cast<uint64_t>(static_cast<int64_t>(rint(in_value)));
      }
      if (in_value < 0 && value != 0) {
        ret = OB_DATA_OUT_OF_RANGE;
      }
    }
    if (CAST_FAIL(ret)) {
      LOG_WARN("cast float to uint failed", K(ret), K(in), K(value));
    }
  }

  if (OB_FAIL(ret)) {
  } else if (CM_NEED_RANGE_CHECK(cast_mode) && CAST_FAIL(uint_range_check(expect_type, value, value))) {
  } else {
    out.set_uint(expect_type, value);
  }
  if (OB_SUCC(ret)) {
    res_precision = get_precision_for_integer(value);
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int double_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  float value = static_cast<float>(in.get_double());
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (CAST_FAIL(real_range_check(expect_type, in.get_double(), value))) {
  } else {
    out.set_float(expect_type, value);
    LOG_DEBUG("succ to double_float", K(ret), K(in), K(value), K(out));
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int double_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  double value = in.get_double();
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (ObUDoubleType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
  } else {
    out.set_double(expect_type, value);
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int double_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  double value = in.get_double();
  ObPrecision res_precision = -1;
  ObScale res_scale = -1;
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (isnan(value) && lib::is_oracle_mode()) {
    ret = OB_INVALID_NUMERIC;
    LOG_WARN("float_number failed ", K(ret), K(value));
  } else if (isinf(value) && lib::is_oracle_mode()) {
    ret = OB_NUMERIC_OVERFLOW;
    LOG_WARN("float_number failed", K(ret), K(value));
  } else if (ObUNumberType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
  } else {
    char buf[MAX_DOUBLE_STRICT_PRINT_SIZE];
    MEMSET(buf, 0, MAX_DOUBLE_STRICT_PRINT_SIZE);
    int64_t length =
        ob_gcvt_opt(in.get_double(), OB_GCVT_ARG_DOUBLE, sizeof(buf) - 1, buf, NULL, lib::is_oracle_mode());
    ObString str(sizeof(buf), static_cast<int32_t>(length), buf);
    number::ObNumber nmb;
    if (OB_FAIL(nmb.from_sci_opt(str.ptr(), str.length(), params, &res_precision, &res_scale))) {
    } else {
      out.set_number(expect_type, nmb);
    }
    LOG_DEBUG("finish double to number", K(ret), K(str), K(length), K(in), K(expect_type), K(nmb), K(out), K(lbt()));
  }
  SET_RES_ACCURACY(res_precision, res_scale, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}
static int number_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int double_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // double to datetime must cast to number first, then cast string to datetime.
  // because double 20151016153421.8 may actually 20151016153421.801 in memory,
  // so we will get '2015-10-16 15:34:21.801' instead of '2015-10-16 15:34:21.8'.
  // this problem can be resolved by cast double to number.
  int ret = OB_SUCCESS;
  ObScale res_scale = -1;
  int64_t value = 0;
  ObTimeConvertCtx cvrt_ctx(params.dtc_params_.tz_info_, ObTimestampType == expect_type);
  ObObj tmp_num_obj;
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(double_number(ObNumberType, params, in, tmp_num_obj, cast_mode))) {
    LOG_WARN("cast double to number failed", K(ret), K(cast_mode));
    if (CM_IS_WARN_ON_FAIL(cast_mode)) {
      ret = OB_SUCCESS;
      if (CM_IS_ZERO_ON_WARN(cast_mode)) {
        out.set_datetime(expect_type, ObTimeConverter::ZERO_DATETIME);
      } else {
        out.set_null();
      }
    } else {
      ret = OB_INVALID_DATE_VALUE;
    }
  } else if (CAST_FAIL(number_datetime(expect_type, params, tmp_num_obj, out, cast_mode))) {
    LOG_WARN("number to datetime failed", K(ret));
  }
  return ret;
}

static int double_datetime_interval(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObScale res_scale = -1;
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class()) || OB_UNLIKELY(ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const int64_t value = static_cast<int64_t>(in.get_double() * static_cast<double>(USECS_PER_DAY));
    LOG_DEBUG("succ to double_datetime_interval", K(ret), K(in), K(value), K(expect_type));
    SET_RES_DATETIME(out);
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, res_scale, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int double_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // TODO In datediff,mysql does truncate NOT round
  // So,we have to revise double 2 int which act as round (right now) to truncation
  int ret = OB_SUCCESS;
  ObObj int64;
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() || ObDateTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(double_int(ObIntType, params, in, int64, cast_mode))) {
  } else if (OB_FAIL(int_date(expect_type, params, int64, out, cast_mode))) {
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_DATE, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int double_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // double to time must cast to string first, then cast string to time.
  // see comment in double_datetime.
  int ret = OB_SUCCESS;
  ObScale res_scale = -1;
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() || ObTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    int64_t value = 0;
    char buf[MAX_DOUBLE_PRINT_SIZE];
    MEMSET(buf, 0, MAX_DOUBLE_PRINT_SIZE);
    int64_t length = ob_gcvt(in.get_double(), OB_GCVT_ARG_DOUBLE, sizeof(buf) - 1, buf, NULL);
    ObString str(sizeof(buf), static_cast<int32_t>(length), buf);
    if (CAST_FAIL(ObTimeConverter::str_to_time(str, value, &res_scale))) {
    } else {
      SET_RES_TIME(out);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, res_scale, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int double_year(const ObObjType expect_type, ObObjCastParams &params,
                       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<uint64_t>(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)
{
  int ret = OB_SUCCESS;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() ||
                  (ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
    ObScale scale = in.get_scale();
    int64_t length = 0;
    if (0 <= scale) {
      length = ob_fcvt(in.get_double(), scale, sizeof(buf) - 1, buf, NULL);
    } else {
      length = ob_gcvt_opt(in.get_double(), OB_GCVT_ARG_DOUBLE, sizeof(buf) - 1, buf, NULL, lib::is_oracle_mode());
    }
    ObString str(sizeof(buf), static_cast<int32_t>(length), buf);
    LOG_DEBUG("finish double_string", K(ret), K(in), K(expect_type), K(str));
    ObObj tmp_out;
    ObString tmp_str;
    if (OB_FAIL(convert_string_collation(
            str, ObCharset::get_system_collation(), tmp_str, params.dest_collation_, params))) {
      LOG_WARN("fail to convert string collation", K(ret));
    } else if (OB_FAIL(check_convert_string(expect_type, params, tmp_str, tmp_out))) {
      LOG_WARN("fail to check_convert_string", K(ret), K(in), K(expect_type));
    } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out))) {
    } else {
      res_length = static_cast<ObLength>(out.get_string_len());
    }
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  UNUSED(cast_mode);
  return ret;
}

static int double_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  uint64_t value = static_cast<uint64_t>(in.get_double());
  int32_t bit_len = 0;
  if (OB_UNLIKELY(ObDoubleTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_bit_len(value, bit_len))) {
    LOG_WARN("fail to get bit len", K(ret), K(value), K(bit_len));
  } else {
    SET_RES_BIT(out);
    SET_RES_ACCURACY(static_cast<ObPrecision>(bit_len), DEFAULT_SCALE_FOR_BIT, DEFAULT_LENGTH_FOR_NUMERIC);
  }
  return ret;
}

static int double_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) || OB_UNLIKELY(ObDoubleTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else {
    int64_t value = static_cast<int64_t>(in.get_double());
    ObObj int_val(value);
    if (OB_FAIL(int_enum(expect_type, params, int_val, out))) {
      LOG_WARN("fail to cast int to enum", K(expect_type), K(in), K(int_val), K(out), K(ret));
    }
  }
  return ret;
}

static int double_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) || OB_UNLIKELY(ObDoubleTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else {
    int64_t value = static_cast<int64_t>(in.get_double());
    ObObj int_val(value);
    if (OB_FAIL(int_set(expect_type, params, int_val, out))) {
      LOG_WARN("fail to cast int to enum", K(expect_type), K(in), K(int_val), K(out), K(ret));
    }
  }
  return ret;
}

CAST_TO_LOB_METHOD(double, ObDoubleTC);

////////////////////////////////////////////////////////////////
// Number -> XXX

static int string_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int number_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const number::ObNumber& nmb = in.get_number();
    const char* value = nmb.format();
    if (OB_ISNULL(value)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("null pointer", K(ret), K(value));
    } else {
      ObObj from;
      from.set_varchar(value, static_cast<ObString::obstr_size_t>(strlen(value)));
      ret = string_int(expect_type, params, from, out, CM_UNSET_STRING_INTEGER_TRUNC(cast_mode));
    }
  }
  if (OB_SUCC(ret)) {
    res_precision = get_precision_for_integer(out.get_int());
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int string_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int number_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const number::ObNumber& nmb = in.get_number();
    const char* value = nmb.format();
    if (OB_ISNULL(value)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("null pointer", K(ret), K(value));
    } else {
      ObObj from;
      from.set_varchar(value, static_cast<ObString::obstr_size_t>(strlen(value)));
      ret = string_uint(expect_type, params, from, out, CM_UNSET_STRING_INTEGER_TRUNC(cast_mode));
    }
  }
  if (OB_SUCC(ret)) {
    res_precision = get_precision_for_integer(out.get_uint64());
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int string_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int number_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const char* value = in.get_number().format();
    if (OB_ISNULL(value)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("null pointer", K(ret), K(value));
    } else {
      ObObj from;
      from.set_varchar(value, static_cast<ObString::obstr_size_t>(strlen(value)));
      ret = string_float(expect_type, params, from, out, cast_mode);
    }
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int string_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int number_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const char* value = in.get_number().format();
    if (OB_ISNULL(value)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("null pointer", K(ret), K(value));
    } else {
      ObObj from;
      from.set_varchar(value, static_cast<ObString::obstr_size_t>(strlen(value)));
      ret = string_double(expect_type, params, from, out, cast_mode);
    }
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int number_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const number::ObNumber& nmb = in.get_number();
    number::ObNumber value;
    if (OB_FAIL(value.from(nmb, params))) {
    } else if (ObUNumberType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
    } else {
      out.set_number(expect_type, value);
    }
  }
  // todo maybe we can do some dirty work to get better result.
  // for now, just set it to unknown....
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, NUMBER_SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int string_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int number_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  const int64_t three_digit_min = 100;
  const int64_t eight_digit_max = 99999999;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    ObTimeConvertCtx cvrt_ctx(params.dtc_params_.tz_info_, ObTimestampType == expect_type);
    int64_t value = 0;
    int64_t int_part = 0;
    int64_t dec_part = 0;
    if (in.get_number().is_negative()) {
      ret = OB_INVALID_DATE_FORMAT;
      LOG_WARN("invalid date format", K(ret), K(in), K(cast_mode));
    } else if (!in.get_number().is_int_parts_valid_int64(int_part,dec_part)) {
      ret = OB_INVALID_DATE_FORMAT;
      LOG_WARN("invalid date format", K(ret), K(in), K(cast_mode));
    } else if (OB_UNLIKELY(dec_part != 0
              && ((0 == int_part && ObTimestampType == expect_type)
                  || (int_part >= three_digit_min && int_part <= eight_digit_max)))) {
      if (CM_IS_COLUMN_CONVERT(cast_mode) && !CM_IS_WARN_ON_FAIL(cast_mode)) {
        ret = OB_INVALID_DATE_VALUE;
        LOG_WARN("invalid date value", K(ret));
      } else {
        dec_part = 0;
      }
    }
    if (OB_SUCC(ret)) {
      ret = ObTimeConverter::int_to_datetime(int_part, dec_part, cvrt_ctx, value);
      LOG_DEBUG("succ to number_datetime", K(ret), K(in), K(value), K(expect_type), K(int_part), K(dec_part));
    }
    if (CAST_FAIL(ret)) {
    } else {
      SET_RES_DATETIME(out);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, MIN_SCALE_FOR_TEMPORAL, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int number_datetime_interval(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class()) || OB_UNLIKELY(ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    int64_t int_part = 0;
    int64_t dec_part = 0;
    if (!in.get_number().is_int_parts_valid_int64(int_part, dec_part)) {
      ret = OB_INVALID_DATE_FORMAT;
      LOG_WARN("invalid date format", K(ret), K(in), K(cast_mode));
    } else {
      const int64_t value =
          static_cast<int64_t>(int_part * USECS_PER_DAY) +
          (in.is_negative_number() ? -1 : 1) *
              static_cast<int64_t>(static_cast<double>(dec_part) / NSECS_PER_SEC * static_cast<double>(USECS_PER_DAY));
      LOG_DEBUG("succ to number_datetime_interval", K(ret), K(in), K(value), K(expect_type), K(int_part), K(dec_part));
      SET_RES_DATETIME(out);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, MIN_SCALE_FOR_TEMPORAL, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int string_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int number_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj int64;
  int32_t value = 0;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class() || ObDateTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type",
        K(ret), K(in), K(expect_type));
  } else {
    int64_t int_part = 0;
    int64_t dec_part = 0;
    const number::ObNumber nmb = in.get_number();
    if (nmb.is_negative()) {
      ret = OB_INVALID_DATE_VALUE;
      LOG_WARN("invalid date value", K(ret), K(nmb));
    } else if (!nmb.is_int_parts_valid_int64(int_part, dec_part)) {
      ret = OB_INVALID_DATE_VALUE;
      LOG_WARN("invalid date format", K(ret), K(nmb));
    } else {
      ret = ObTimeConverter::int_to_date(int_part, value);
      if (OB_SUCC(ret) && OB_UNLIKELY(dec_part > 0)) {
        if (CM_IS_COLUMN_CONVERT(cast_mode) && !CM_IS_WARN_ON_FAIL(cast_mode)) {
          ret = OB_INVALID_DATE_VALUE;
          LOG_WARN("invalid date value with decimal part", K(ret));
        }
      }
    }
    if (CAST_FAIL(ret)) {
    } else {
      SET_RES_DATE(out);
    }
  }
  return ret;
}

static int string_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int number_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class() || ObTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const char* value = in.get_number().format();
    if (OB_ISNULL(value)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("null pointer", K(ret), K(value));
    } else {
      ObObj from;
      from.set_varchar(value, static_cast<ObString::obstr_size_t>(strlen(value)));
      ret = string_time(expect_type, params, from, out, cast_mode);
    }
  }
  // has set accuracy in prev string_time call
  return ret;
}

static int string_year(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int number_year(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObNumberTC != 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 {
    const char* value = in.get_number().format();
    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<ObString::obstr_size_t>(strlen(value)));
      ret = string_year(expect_type, params, from, out, cast_mode);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_YEAR, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int number_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
  int64_t len = 0;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class() ||
                  (ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (is_oracle_mode() && ob_is_blob(expect_type, params.dest_collation_)) {
    ret = OB_ERR_INVALID_TYPE_FOR_OP;
    LOG_WARN("cast number to blob not allowed", K(ret));
  } else {
    if (lib::is_oracle_mode() && params.format_number_with_limit_) {
      if (OB_FAIL(in.get_number().format_with_oracle_limit(buf, sizeof(buf), len, in.get_scale()))) {
        LOG_WARN("fail to format", K(ret), K(in.get_number()));
      }
    } else {
      if (OB_FAIL(in.get_number().format(buf, sizeof(buf), len, in.get_scale()))) {
        LOG_WARN("fail to format", K(ret), K(in.get_number()));
      }
    }

    if (OB_SUCC(ret)) {
      ObString tmp_str;
      ObObj tmp_out;
      if (OB_FAIL(convert_string_collation(
              ObString(len, buf), ObCharset::get_system_collation(), tmp_str, params.dest_collation_, params))) {
        LOG_WARN("fail to convert string collation", K(ret));
      } else if (OB_FAIL(check_convert_string(expect_type, params, tmp_str, tmp_out))) {
        LOG_WARN("fail to check_convert_string", K(ret), K(in), K(expect_type));
      } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out))) {
      } else {
        res_length = static_cast<ObLength>(out.get_string_len());
      }
    }
  }
  UNUSED(cast_mode);
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  return ret;
}

static int number_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj tmp_val;
  if (OB_UNLIKELY(ObNumberTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(number_uint(ObUInt64Type, params, in, tmp_val, cast_mode))) {
    LOG_WARN("fail to cast number to uint", K(ret), K(expect_type), K(in), K(tmp_val));
  } else if (OB_FAIL(uint_bit(expect_type, params, tmp_val, out, cast_mode))) {
    LOG_WARN("fail to cast uint to bit", K(ret), K(expect_type), K(out), K(tmp_val));
  }
  return ret;
}

static int number_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObObj double_val;
  ObCastMode cast_mode = params.cast_mode_;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) || OB_UNLIKELY(ObNumberTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (OB_FAIL(number_double(ObDoubleType, params, in, double_val, cast_mode))) {
    LOG_WARN("fail to cast number to double", K(in), K(double_val), K(ret));
  } else if (OB_FAIL(double_enum(expect_type, params, double_val, out))) {
    LOG_WARN("fail to cast double to enum", K(expect_type), K(out), K(double_val), K(ret));
  }
  return ret;
}

static int number_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObObj double_val;
  ObCastMode cast_mode = params.cast_mode_;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) || OB_UNLIKELY(ObNumberTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (OB_FAIL(number_double(ObDoubleType, params, in, double_val, cast_mode))) {
    LOG_WARN("fail to cast number to double", K(in), K(double_val), K(ret));
  } else if (OB_FAIL(double_set(expect_type, params, double_val, out))) {
    LOG_WARN("fail to cast double to enum", K(expect_type), K(out), K(double_val), K(ret));
  }
  return ret;
}

CAST_TO_LOB_METHOD(number, ObNumberTC);

////////////////////////////////////////////////////////////
// Datetime -> XXX

static int datetime_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const ObTimeZoneInfo* tz_info = (ObTimestampType == in.get_type()) ? params.dtc_params_.tz_info_ : NULL;
    int64_t value = 0;
    if (OB_FAIL(ObTimeConverter::datetime_to_int(in.get_datetime(), tz_info, value))) {
    } else if (expect_type < ObIntType && CAST_FAIL(int_range_check(expect_type, value, value))) {
    } else {
      out.set_int(expect_type, value);
      res_precision = get_precision_for_integer(value);
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int datetime_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const ObTimeZoneInfo* tz_info = (ObTimestampType == in.get_type()) ? params.dtc_params_.tz_info_ : NULL;
    int64_t int64 = 0;
    if (OB_FAIL(ObTimeConverter::datetime_to_int(in.get_datetime(), tz_info, int64))) {
    } else {
      uint64_t value = static_cast<uint64_t>(int64);
      if (expect_type < ObUInt64Type && CAST_FAIL(uint_range_check(expect_type, int64, value))) {
      } else {
        out.set_uint(expect_type, value);
        res_precision = get_precision_for_integer(value);
      }
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int datetime_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const ObTimeZoneInfo* tz_info = (ObTimestampType == in.get_type()) ? params.dtc_params_.tz_info_ : NULL;
    double value = 0.0;
    if (OB_FAIL(ObTimeConverter::datetime_to_double(in.get_datetime(), tz_info, value))) {
    } else {
      // if datetime_to_double return OB_SUCCESS, double value must be in (0, INT64_MAX),
      // so we can static_cast to float without range check.
      out.set_float(expect_type, static_cast<float>(value));
    }
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  UNUSED(cast_mode);
  return ret;
}

static int datetime_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const ObTimeZoneInfo* tz_info = (ObTimestampType == in.get_type()) ? params.dtc_params_.tz_info_ : NULL;
    double value = 0.0;
    if (OB_FAIL(ObTimeConverter::datetime_to_double(in.get_datetime(), tz_info, value))) {
    } else {
      out.set_double(expect_type, value);
    }
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  UNUSED(cast_mode);
  return ret;
}

static int datetime_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  ObScale res_scale = -1;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const ObTimeZoneInfo* tz_info = (ObTimestampType == in.get_type()) ? params.dtc_params_.tz_info_ : NULL;
    ObString nls_format;
    char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
    int64_t len = 0;
    number::ObNumber value;
    if (OB_FAIL(ObTimeConverter::datetime_to_str(
            in.get_datetime(), tz_info, nls_format, in.get_scale(), buf, sizeof(buf), len, false))) {
      LOG_WARN("failed to convert datetime to string", K(ret));
    } else if (CAST_FAIL(value.from(buf, len, params, &res_precision, &res_scale))) {
      LOG_WARN("failed to convert string to number", K(ret));
    } else {
      out.set_number(expect_type, value);
    }
  }
  SET_RES_ACCURACY(res_precision, res_scale, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int datetime_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    int64_t value = in.get_datetime();
    if (ObDateTimeType == in.get_type() && ObTimestampType == expect_type) {
      ret = ObTimeConverter::datetime_to_timestamp(in.get_datetime(), params.dtc_params_.tz_info_, value);
      ret = OB_ERR_UNEXPECTED_TZ_TRANSITION == ret ? OB_INVALID_DATE_VALUE : ret;
    } else if (ObTimestampType == in.get_type() && ObDateTimeType == expect_type) {
      ret = ObTimeConverter::timestamp_to_datetime(in.get_datetime(), params.dtc_params_.tz_info_, value);
    }

    if (OB_FAIL(ret)) {
    } else {
      out.set_datetime(expect_type, value);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, in.get_scale(), DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

static int datetime_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class() || ObDateTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const ObTimeZoneInfo* tz_info = (ObTimestampType == in.get_type()) ? params.dtc_params_.tz_info_ : NULL;
    int32_t value = 0;
    if (OB_FAIL(ObTimeConverter::datetime_to_date(in.get_datetime(), tz_info, value))) {
    } else {
      out.set_date(value);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_DATE, DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

static int datetime_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class() || ObTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const ObTimeZoneInfo* tz_info = (ObTimestampType == in.get_type()) ? params.dtc_params_.tz_info_ : NULL;
    int64_t value = 0;
    if (OB_FAIL(ObTimeConverter::datetime_to_time(in.get_datetime(), tz_info, value))) {
    } else {
      out.set_time(value);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, in.get_scale(), DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

static int datetime_year(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObDateTimeTC != 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 {
    const ObTimeZoneInfo* tz_info = (ObTimestampType == in.get_type()) ? params.dtc_params_.tz_info_ : NULL;
    uint8_t value = 0;
    if (CAST_FAIL(ObTimeConverter::datetime_to_year(in.get_datetime(), tz_info, value))) {
    } else {
      SET_RES_YEAR(out);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_YEAR, DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

static int datetime_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class() ||
                  (ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    const ObTimeZoneInfo* tz_info = (ObTimestampType == in.get_type()) ? params.dtc_params_.tz_info_ : NULL;
    ObString nls_format;
    if (lib::is_oracle_mode() && !params.dtc_params_.force_use_standard_format_) {
      nls_format = params.dtc_params_.get_nls_format(ObDateTimeType);
    }
    char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
    int64_t len = 0;
    if (OB_FAIL(ObTimeConverter::datetime_to_str(
            in.get_datetime(), tz_info, nls_format, in.get_scale(), buf, sizeof(buf), len))) {
      LOG_WARN("failed to convert datetime to string", K(ret));
    } else {
      out.set_type(expect_type);
      ObString tmp_str;
      ObObj tmp_out;
      if (OB_FAIL(convert_string_collation(
              ObString(len, buf), ObCharset::get_system_collation(), tmp_str, params.dest_collation_, params))) {
        LOG_WARN("fail to convert string collation", K(ret));
      } else if (OB_FAIL(check_convert_string(expect_type, params, tmp_str, tmp_out))) {
        LOG_WARN("fail to check_convert_string", K(ret), K(in), K(expect_type));
      } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out))) {
      } else {
        res_length = static_cast<ObLength>(out.get_string_len());
      }
    }
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  UNUSED(cast_mode);
  return ret;
}

static int string_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int datetime_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj tmp_val;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(datetime_string(ObVarcharType, params, in, tmp_val, cast_mode))) {
    LOG_WARN("fail to cast datetime to string", K(ret), K(expect_type), K(in), K(tmp_val));
  } else if (OB_FAIL(string_bit(expect_type, params, tmp_val, out, cast_mode))) {
    LOG_WARN("fail to cast string to bit", K(ret), K(expect_type), K(in), K(tmp_val));
  }
  return ret;
}

static int string_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out);
static int datetime_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObObj str_val;
  ObCastMode cast_mode = params.cast_mode_;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) || OB_UNLIKELY(ObDateTimeTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (OB_FAIL(datetime_string(ObVarcharType, params, in, str_val, cast_mode))) {
    LOG_WARN("fail to cast number to double", K(in), K(str_val), K(ret));
  } else if (OB_FAIL(string_enum(expect_type, params, str_val, out))) {
    LOG_WARN("fail to cast double to enum", K(expect_type), K(out), K(str_val), K(ret));
  }
  return ret;
}
static int string_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out);
static int datetime_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObObj str_val;
  ObCastMode cast_mode = params.cast_mode_;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) || OB_UNLIKELY(ObDateTimeTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (OB_FAIL(datetime_string(ObVarcharType, params, in, str_val, cast_mode))) {
    LOG_WARN("fail to cast number to double", K(in), K(str_val), K(ret));
  } else if (OB_FAIL(string_set(expect_type, params, str_val, out))) {
    LOG_WARN("fail to cast double to enum", K(expect_type), K(out), K(str_val), K(ret));
  }
  return ret;
}

static int datetime_otimestamp(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObDateTimeTC != in.get_type_class()) ||
      OB_UNLIKELY(ObOTimestampTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    int64_t dt_value = 0;
    if (ObTimestampType == in.get_type()) {
      int64_t utc_value = in.get_timestamp();
      if (OB_FAIL(ObTimeConverter::timestamp_to_datetime(utc_value, params.dtc_params_.tz_info_, dt_value))) {
        LOG_WARN("failed to convert timestamp to datetime", K(ret));
      }
    } else {
      dt_value = in.get_datetime();
    }
    if (OB_SUCC(ret)) {
      int64_t odate_value = 0;
      ObOTimestampData value;
      ObTimeConverter::datetime_to_odate(dt_value, odate_value);
      if (OB_FAIL(ObTimeConverter::odate_to_otimestamp(odate_value, params.dtc_params_.tz_info_, expect_type, value))) {
        LOG_WARN("fail to timestamp_to_timestamp_tz", K(ret), K(in), K(expect_type));
      } else {
        SET_RES_OTIMESTAMP(out);
      }
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, in.get_scale(), DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

CAST_TO_LOB_METHOD(datetime, ObDateTimeTC);

////////////////////////////////////////////////////////////
// Date -> XXX

static int date_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t value = 0;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObDateTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::date_to_int(in.get_date(), value))) {
  } else if (expect_type < ObInt32Type && CAST_FAIL(int_range_check(expect_type, value, value))) {
  } else {
    out.set_int(expect_type, value);
    res_precision = get_precision_for_integer(value);
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int date_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  int64_t int64 = 0;
  uint64_t value = 0;
  if (OB_UNLIKELY(ObDateTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::date_to_int(in.get_date(), int64))) {
  } else {
    value = static_cast<uint64_t>(int64);
    if (expect_type < ObUInt32Type && CAST_FAIL(uint_range_check(expect_type, int64, value))) {
    } else {
      out.set_uint(expect_type, value);
      res_precision = get_precision_for_integer(value);
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int date_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t value = 0;
  if (OB_UNLIKELY(ObDateTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::date_to_int(in.get_date(), value))) {
  } else {
    out.set_float(expect_type, static_cast<float>(value));
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  UNUSED(cast_mode);
  return ret;
}

static int date_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t value = 0;
  if (OB_UNLIKELY(ObDateTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::date_to_int(in.get_date(), value))) {
  } else {
    out.set_double(expect_type, static_cast<double>(value));
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  UNUSED(cast_mode);
  return ret;
}

static int date_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj obj_int;
  if (OB_UNLIKELY(ObDateTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(date_int(ObIntType, params, in, obj_int, cast_mode))) {
  } else if (OB_FAIL(int_number(expect_type, params, obj_int, out, cast_mode))) {
  }
  // has set accuracy in prev int_number
  return ret;
}

static int date_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObDateTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    ObTimeConvertCtx cvrt_ctx(params.dtc_params_.tz_info_, ObTimestampType == expect_type);
    int64_t value = 0;
    if (OB_FAIL(ObTimeConverter::date_to_datetime(in.get_date(), cvrt_ctx, value))) {
    } else {
      out.set_datetime(expect_type, value);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, MIN_SCALE_FOR_TEMPORAL, DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

static int date_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObDateTC != in.get_type_class() || ObTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    out.set_time(ObTimeConverter::ZERO_TIME);
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, MIN_SCALE_FOR_TEMPORAL, DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return OB_SUCCESS;
}

static int date_year(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  uint8_t value = 0;
  if (OB_UNLIKELY(ObDateTC != 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 if (CAST_FAIL(ObTimeConverter::date_to_year(in.get_date(), value))) {
  } else {
    SET_RES_YEAR(out);
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_YEAR, DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

static int date_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
  int64_t len = 0;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObDateTC != in.get_type_class() ||
                  (ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::date_to_str(in.get_date(), buf, sizeof(buf), len))) {
  } else {
    out.set_type(expect_type);
    ret = copy_string(params, expect_type, buf, len, out);
    if (OB_SUCC(ret)) {
      res_length = static_cast<ObLength>(out.get_string_len());
    }
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  UNUSED(cast_mode);
  return ret;
}

static int date_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj tmp_val;
  if (OB_UNLIKELY(ObDateTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(date_string(ObVarcharType, params, in, tmp_val, cast_mode))) {
    LOG_WARN("fail to cast datetime to string", K(ret), K(expect_type), K(in), K(tmp_val));
  } else if (OB_FAIL(string_bit(expect_type, params, tmp_val, out, cast_mode))) {
    LOG_WARN("fail to cast string to bit", K(ret), K(expect_type), K(in), K(tmp_val));
  }
  return ret;
}

static int date_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObObj str_val;
  ObCastMode cast_mode = params.cast_mode_;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) || OB_UNLIKELY(ObDateTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (OB_FAIL(date_string(ObVarcharType, params, in, str_val, cast_mode))) {
    LOG_WARN("fail to cast number to double", K(in), K(str_val), K(ret));
  } else if (OB_FAIL(string_enum(expect_type, params, str_val, out))) {
    LOG_WARN("fail to cast double to enum", K(expect_type), K(out), K(str_val), K(ret));
  }
  return ret;
}

static int date_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObObj str_val;
  ObCastMode cast_mode = params.cast_mode_;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) || OB_UNLIKELY(ObDateTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (OB_FAIL(date_string(ObVarcharType, params, in, str_val, cast_mode))) {
    LOG_WARN("fail to cast number to double", K(in), K(str_val), K(ret));
  } else if (OB_FAIL(string_set(expect_type, params, str_val, out))) {
    LOG_WARN("fail to cast double to enum", K(expect_type), K(out), K(str_val), K(ret));
  }
  return ret;
}

CAST_TO_LOB_METHOD(date, ObDateTC);
////////////////////////////////////////////////////////////
// Time -> XXX

static int time_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t value = 0;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObTimeTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::time_to_int(in.get_time(), value))) {
  } else if (expect_type < ObInt32Type && CAST_FAIL(int_range_check(expect_type, value, value))) {
  } else {
    out.set_int(expect_type, value);
    res_precision = get_precision_for_integer(value);
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int time_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t int64 = 0;
  uint64_t value = 0;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObTimeTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::time_to_int(in.get_time(), int64))) {
  } else {
    value = static_cast<uint64_t>(int64);
    if (CM_NEED_RANGE_CHECK(cast_mode) && CAST_FAIL(uint_range_check(expect_type, int64, value))) {
    } else {
      out.set_uint(expect_type, value);
      res_precision = get_precision_for_integer(value);
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int time_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  double value = 0.0;
  if (OB_UNLIKELY(ObTimeTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::time_to_double(in.get_time(), value))) {
  } else if (ObUFloatType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
  } else {
    // if time_to_double return OB_SUCCESS, double value must be in (INT64_MIN, INT64_MAX),
    // so we can static_cast to float without range check.
    out.set_float(expect_type, static_cast<float>(value));
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int time_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  double value = 0.0;
  if (OB_UNLIKELY(ObTimeTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::time_to_double(in.get_time(), value))) {
  } else if (ObUDoubleType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
  } else {
    out.set_double(expect_type, value);
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  UNUSED(cast_mode);
  return ret;
}

static int time_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
  int64_t len = 0;
  number::ObNumber value;
  ObPrecision res_precision = -1;
  ObScale res_scale = -1;
  if (OB_UNLIKELY(ObTimeTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::time_to_str(in.get_time(), in.get_scale(), buf, sizeof(buf), len, false))) {
  } else if (CAST_FAIL(value.from(buf, len, params, &res_precision, &res_scale))) {
  } else {
    out.set_number(expect_type, value);
  }
  SET_RES_ACCURACY(res_precision, res_scale, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int time_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  const ObTimeZoneInfo* tz_info = params.dtc_params_.tz_info_;
  int64_t value = 0;
  if (OB_UNLIKELY(ObTimeTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::time_to_datetime(in.get_time(), params.cur_time_, tz_info, value, expect_type))) {
  } else {
    out.set_datetime(expect_type, value);
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, in.get_scale(), DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

static int time_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  const ObTimeZoneInfo* tz_info = params.dtc_params_.tz_info_;
  int32_t value = 0;
  if (OB_UNLIKELY(ObTimeTC != in.get_type_class() || ObDateTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type",
        K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::datetime_to_date(params.cur_time_, tz_info, value))) {
    LOG_WARN("datetime_to_date failed", K(ret), K(params.cur_time_));
  } else {
    out.set_date(value);
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_DATE, DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

static int time_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
  int64_t len = 0;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObTimeTC != in.get_type_class() ||
                  (ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::time_to_str(in.get_time(), in.get_scale(), buf, sizeof(buf), len))) {
  } else {
    out.set_type(expect_type);
    ret = copy_string(params, expect_type, buf, len, out);
    if (OB_SUCC(ret)) {
      res_length = static_cast<ObLength>(out.get_string_len());
    }
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  UNUSED(cast_mode);
  return ret;
}

static int time_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj tmp_val;
  if (OB_UNLIKELY(ObTimeTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(time_string(ObVarcharType, params, in, tmp_val, cast_mode))) {
    LOG_WARN("fail to cast datetime to string", K(ret), K(expect_type), K(in), K(tmp_val));
  } else if (OB_FAIL(string_bit(expect_type, params, tmp_val, out, cast_mode))) {
    LOG_WARN("fail to cast string to bit", K(ret), K(expect_type), K(in), K(tmp_val));
  }
  return ret;
}

static int time_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObObj str_val;
  ObCastMode cast_mode = params.cast_mode_;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) || OB_UNLIKELY(ObTimeTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (OB_FAIL(time_string(ObVarcharType, params, in, str_val, cast_mode))) {
    LOG_WARN("fail to cast number to double", K(in), K(str_val), K(ret));
  } else if (OB_FAIL(string_enum(expect_type, params, str_val, out))) {
    LOG_WARN("fail to cast double to enum", K(expect_type), K(out), K(str_val), K(ret));
  }
  return ret;
}

static int time_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObObj str_val;
  ObCastMode cast_mode = params.cast_mode_;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) || OB_UNLIKELY(ObTimeTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (OB_FAIL(time_string(ObVarcharType, params, in, str_val, cast_mode))) {
    LOG_WARN("fail to cast number to double", K(in), K(str_val), K(ret));
  } else if (OB_FAIL(string_set(expect_type, params, str_val, out))) {
    LOG_WARN("fail to cast double to enum", K(expect_type), K(out), K(str_val), K(ret));
  }
  return ret;
}

CAST_TO_LOB_METHOD(time, ObTimeTC);

////////////////////////////////////////////////////////////
// Year -> XXX

static int year_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t value = 0;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObYearTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::year_to_int(in.get_year(), value))) {
  } else if (expect_type < ObSmallIntType && CAST_FAIL(int_range_check(expect_type, value, value))) {
  } else {
    out.set_int(expect_type, value);
    res_precision = get_precision_for_integer(value);
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int year_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t int64 = 0;
  uint64_t value = 0;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObYearTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::year_to_int(in.get_year(), int64))) {
  } else {
    value = static_cast<uint64_t>(int64);
    if (expect_type < ObUSmallIntType && CAST_FAIL(uint_range_check(expect_type, int64, value))) {
    } else {
      out.set_uint(expect_type, value);
      res_precision = get_precision_for_integer(value);
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int year_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t value = 0;
  if (OB_UNLIKELY(ObYearTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::year_to_int(in.get_year(), value))) {
  } else {
    out.set_float(expect_type, static_cast<float>(value));
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  UNUSED(cast_mode);
  return ret;
}

static int year_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t value = 0;
  if (OB_UNLIKELY(ObYearTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::year_to_int(in.get_year(), value))) {
  } else {
    out.set_double(expect_type, static_cast<double>(value));
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  UNUSED(cast_mode);
  return ret;
}

static int year_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj obj_int;
  if (OB_UNLIKELY(ObYearTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(year_int(ObIntType, params, in, obj_int, cast_mode))) {
  } else if (OB_FAIL(int_number(expect_type, params, obj_int, out, cast_mode))) {
  }
  // has set accuracy in prev int_number
  return ret;
}

static int year_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t in_value = 0;
  if (OB_UNLIKELY(ObYearTC != in.get_type_class() || ObDateTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type",
        K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::year_to_int(in.get_year(), in_value))) {
  } else {
    int32_t value = 0;
    if (CAST_FAIL(ObTimeConverter::int_to_date(in_value, value))) {
    } else {
      SET_RES_DATE(out);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_DATE, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int year_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
  int64_t len = 0;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObYearTC != in.get_type_class() ||
                  (ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::year_to_str(in.get_year(), buf, sizeof(buf), len))) {
  } else {
    out.set_type(expect_type);
    ret = copy_string(params, expect_type, buf, len, out);
    if (OB_SUCC(ret)) {
      res_length = static_cast<ObLength>(out.get_string_len());
    }
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  UNUSED(cast_mode);
  return ret;
}

static int year_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj tmp_val;
  if (OB_UNLIKELY(ObYearTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(year_int(ObIntType, params, in, tmp_val, cast_mode))) {
    LOG_WARN("fail to cast datetime to int", K(ret), K(expect_type), K(in), K(tmp_val));
  } else if (OB_FAIL(int_bit(expect_type, params, tmp_val, out, cast_mode))) {
    LOG_WARN("fail to cast int to bit", K(ret), K(expect_type), K(in), K(tmp_val));
  }
  return ret;
}

static int year_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObObj uint_val;
  ObCastMode cast_mode = params.cast_mode_;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) || OB_UNLIKELY(ObYearTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (OB_FAIL(year_uint(ObUInt64Type, params, in, uint_val, cast_mode))) {
    LOG_WARN("fail to cast number to double", K(in), K(uint_val), K(ret));
  } else if (OB_FAIL(uint_enum(expect_type, params, uint_val, out))) {
    LOG_WARN("fail to cast double to enum", K(expect_type), K(out), K(uint_val), K(ret));
  }
  return ret;
}

static int year_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObObj uint_val;
  ObCastMode cast_mode = params.cast_mode_;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) || OB_UNLIKELY(ObYearTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (OB_FAIL(year_uint(ObUInt64Type, params, in, uint_val, cast_mode))) {
    LOG_WARN("fail to cast number to double", K(in), K(uint_val), K(ret));
  } else if (OB_FAIL(uint_set(expect_type, params, uint_val, out))) {
    LOG_WARN("fail to cast double to enum", K(expect_type), K(out), K(uint_val), K(ret));
  }
  return ret;
}

CAST_TO_LOB_METHOD(year, ObYearTC);

////////////////////////////////////////////////////////////
// String -> XXX

int common_string_unsigned_integer(const ObCastMode& cast_mode, const ObObjType& in_type, const ObString& in_str,
    const bool is_str_integer_cast, uint64_t& out_val)
{
  int ret = OB_SUCCESS;
  if (ObHexStringType == in_type) {
    out_val = hex_to_uint64(in_str);
  } else {
    int err = 0;
    char* endptr = NULL;
    if (is_str_integer_cast && CM_IS_STRING_INTEGER_TRUNC(cast_mode)) {
      out_val = ObCharset::strntoull(in_str.ptr(), in_str.length(), 10, &endptr, &err);
      if (ERANGE == err && (INT64_MIN == out_val || INT64_MAX == out_val)) {
        ret = OB_DATA_OUT_OF_RANGE;
      } else if (endptr == in_str.ptr() || endptr != in_str.ptr() + in_str.length()) {
        ret = OB_ERR_TRUNCATED_WRONG_VALUE;
        if (CM_IS_WARN_ON_FAIL(cast_mode)) {
          ObString tmp_msg("INTEGER");
          LOG_USER_WARN(OB_ERR_TRUNCATED_WRONG_VALUE, tmp_msg.length(), tmp_msg.ptr(), in_str.length(), in_str.ptr());
        }
      }
    } else {
      out_val = ObCharset::strntoullrnd(in_str.ptr(), in_str.length(), true, &endptr, &err);
      if (ERANGE == err && (0 == out_val || UINT64_MAX == out_val)) {
        ret = OB_DATA_OUT_OF_RANGE;
      } else {
        ret = check_convert_str_err(in_str.ptr(), endptr, in_str.length(), err);
      }
    }
  }
  return ret;
}

int common_string_integer(const ObCastMode& cast_mode, const ObObjType& in_type, const ObString& in_str,
    const bool is_str_integer_cast, int64_t& out_val)
{
  int ret = OB_SUCCESS;
  if (ObHexStringType == in_type) {
    out_val = static_cast<int64_t>(hex_to_uint64(in_str));
  } else {
    int err = 0;
    char* endptr = NULL;
    if (is_str_integer_cast && CM_IS_STRING_INTEGER_TRUNC(cast_mode)) {
      out_val = ObCharset::strntoll(in_str.ptr(), in_str.length(), 10, &endptr, &err);
      if (ERANGE == err && (INT64_MIN == out_val || INT64_MAX == out_val)) {
        ret = OB_DATA_OUT_OF_RANGE;
      } else if (endptr == in_str.ptr() || endptr != in_str.ptr() + in_str.length()) {
        ret = OB_ERR_TRUNCATED_WRONG_VALUE;
        if (CM_IS_WARN_ON_FAIL(cast_mode)) {
          ObString tmp_msg("INTEGER");
          LOG_USER_WARN(OB_ERR_TRUNCATED_WRONG_VALUE, tmp_msg.length(), tmp_msg.ptr(), in_str.length(), in_str.ptr());
        }
      }
    } else {
      out_val = static_cast<int64_t>(ObCharset::strntoullrnd(in_str.ptr(), in_str.length(), false, &endptr, &err));
      if (ERANGE == err && (INT64_MIN == out_val || INT64_MAX == out_val)) {
        ret = OB_DATA_OUT_OF_RANGE;
      } else {
        ret = check_convert_str_err(in_str.ptr(), endptr, in_str.length(), err);
      }
    }
  }
  return ret;
}

static int string_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
                  ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else {
    const ObString& str = in.get_string();
    int64_t value = 0;
    const bool is_str_int_cast = true;
    if (CAST_FAIL(common_string_integer(cast_mode, in.get_type(), str, is_str_int_cast, value))) {
    } else if (expect_type < ObIntType && CAST_FAIL(int_range_check(expect_type, value, value))) {
    } else {
      SET_RES_INT(out);
    }
  }
  if (OB_SUCC(ret)) {
    res_precision = get_precision_for_integer(out.get_int());
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int string_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
                  ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else {
    const ObString& str = in.get_string();
    uint64_t value = 0;
    const bool is_str_int_cast = true;
    if (CAST_FAIL(common_string_unsigned_integer(cast_mode, in.get_type(), str, is_str_int_cast, value))) {
    } else if (expect_type < ObUInt64Type && CM_NEED_RANGE_CHECK(cast_mode) &&
               CAST_FAIL(uint_upper_check(expect_type, value))) {
    } else {
      SET_RES_UINT(out);
    }
  }
  if (OB_SUCC(ret)) {
    res_precision = get_precision_for_integer(out.get_uint64());
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int string_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj dbl;
  if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
                  ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else if (OB_FAIL(string_double(ObDoubleType, params, in, dbl, cast_mode))) {
  } else if (OB_FAIL(double_float(expect_type, params, dbl, out, cast_mode))) {
  }
  // has set accuracy in prev double_float call
  return ret;
}

static int string_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
                  ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else {
    double value = 0.0;
    if (ObHexStringType == in.get_type()) {
      value = static_cast<double>(hex_to_uint64(in.get_string()));
    } else {
      int err = 0;
      char* endptr = NULL;
      ObString str_utf8;
      if (OB_FAIL(convert_string_collation(
              in.get_string(), in.get_collation_type(), str_utf8, ObCharset::get_system_collation(), params))) {
        LOG_WARN("convert_string_collation", K(ret), K(str_utf8), K(in.get_string()));
      } else {
        value = ObCharset::strntod(str_utf8.ptr(), str_utf8.length(), &endptr, &err);
        if (EOVERFLOW == err && (-DBL_MAX == value || DBL_MAX == value)) {
          ret = OB_DATA_OUT_OF_RANGE;
        } else {
          ObString trimed_str = str_utf8.trim();
          if (lib::is_mysql_mode() && 0 == trimed_str.length()) {
            if (!CM_IS_COLUMN_CONVERT(cast_mode)) {
              // skip
            } else {
              ret = OB_ERR_DOUBLE_TRUNCATED;
              LOG_WARN("convert string to double failed", K(ret), K(str_utf8));
            }
          } else if (OB_SUCCESS != (ret = check_convert_str_err(str_utf8.ptr(), endptr, str_utf8.length(), err))) {
            LOG_WARN("failed to check_convert_str_err", K(ret), K(str_utf8), K(value), K(err));
            ret = OB_ERR_DOUBLE_TRUNCATED;
            if (CM_IS_WARN_ON_FAIL(cast_mode)) {
              LOG_USER_WARN(OB_ERR_DOUBLE_TRUNCATED, str_utf8.length(), str_utf8.ptr());
            }
          }
        }
      }
    }

    if (CAST_FAIL(ret)) {
    } else if (ObUDoubleType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
    } else {
      SET_RES_DOUBLE(out);
    }
  }
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int string_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = PRECISION_UNKNOWN_YET;
  ObScale res_scale = NUMBER_SCALE_UNKNOWN_YET;
  ObString utf8_string;

  if (OB_ISNULL(params.allocator_v2_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid allocator", K(ret));
  } else if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
                         ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else {
    number::ObNumber value;
    if (ObHexStringType == in.get_type()) {
      ret = value.from(hex_to_uint64(in.get_string()), params);
    } else if (OB_UNLIKELY(0 == in.get_string().length())) {
      value.set_zero();
      ret = OB_ERR_TRUNCATED_WRONG_VALUE_FOR_FIELD;
    } else if (OB_FAIL(convert_string_collation(
                   in.get_string(), in.get_collation_type(), utf8_string, ObCharset::get_system_collation(), params))) {
      LOG_WARN("convert_string_collation", K(ret));
    } else {
      const ObString& str = utf8_string;
      ret = value.from_sci_opt(str.ptr(), str.length(), params, &res_precision, &res_scale);
      // select cast('1e500' as decimal);  -> max_val
      // select cast('-1e500' as decimal); -> min_val
      if (ret == OB_NUMERIC_OVERFLOW) {
        int64_t i = 0;
        while (i < str.length() && isspace(str[i])) {
          ++i;
        }
        bool is_neg = (str[i] == '-');
        int tmp_ret = OB_SUCCESS;
        const ObAccuracy& def_acc = ObAccuracy::DDL_DEFAULT_ACCURACY2[0][expect_type];
        const ObPrecision prec = def_acc.get_precision();
        const ObScale scale = def_acc.get_scale();
        const ObNumber* bound_num = NULL;
        if (is_neg) {
          bound_num = &(ObNumberConstValue::MYSQL_MIN[prec][scale]);
        } else {
          bound_num = &(ObNumberConstValue::MYSQL_MAX[prec][scale]);
        }
        if (OB_ISNULL(bound_num)) {
          tmp_ret = OB_ERR_UNEXPECTED;
          LOG_WARN("bound_num is NULL", K(tmp_ret), K(ret), K(is_neg));
        } else if (OB_SUCCESS != (tmp_ret = value.from(*bound_num, *params.allocator_v2_))) {
          LOG_WARN("copy min number failed", K(ret), K(tmp_ret), KPC(bound_num));
        }
      }
    }
    if (CAST_FAIL(ret)) {
    } else if (ObUNumberType == expect_type && CAST_FAIL(numeric_negative_check(value))) {
    } else {
      out.set_number(expect_type, value);
    }
  }
  SET_RES_ACCURACY(res_precision, res_scale, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int string_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObScale res_scale = -1;
  ObString utf8_string;

  if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
                  ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else if (OB_FAIL(convert_string_collation(
                 in.get_string(), in.get_collation_type(), utf8_string, ObCharset::get_system_collation(), params))) {
    LOG_WARN("convert_string_collation", K(ret));
  } else {
    int64_t value = 0;
    ObTimeConvertCtx cvrt_ctx(params.dtc_params_.tz_info_, ObTimestampType == expect_type);
    if (lib::is_oracle_mode()) {
      cvrt_ctx.oracle_nls_format_ = params.dtc_params_.get_nls_format(ObDateTimeType);
      CAST_RET(ObTimeConverter::str_to_date_oracle(utf8_string, cvrt_ctx, value));
    } else {
      CAST_RET(ObTimeConverter::str_to_datetime(utf8_string, cvrt_ctx, value, &res_scale));
    }

    if (OB_SUCC(ret)) {
      SET_RES_DATETIME(out);
    }
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, res_scale, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int string_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int32_t value = 0;
  if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
                  ObDateTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else if (CAST_FAIL(ObTimeConverter::str_to_date(in.get_string(), value))) {
  } else {
    SET_RES_DATE(out);
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_DATE, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int string_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t value = 0;
  ObScale res_scale = -1;
  if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
                  ObTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else if (CAST_FAIL(ObTimeConverter::str_to_time(in.get_string(), value, &res_scale))) {
  } else {
    SET_RES_TIME(out);
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, res_scale, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int string_year(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj int64;
  if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != 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 if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else if (OB_FAIL(string_int(
                 ObIntType, params, in, int64, CM_UNSET_STRING_INTEGER_TRUNC(CM_SET_WARN_ON_FAIL(cast_mode))))) {
  } else if (0 == int64.get_int()) {
    const uint8_t base_year = 100;
    uint8_t value = 4 == in.get_string().length() ? ObTimeConverter::ZERO_YEAR : base_year;
    SET_RES_YEAR(out);
  } else if (CAST_FAIL(int_year(ObYearType, params, int64, out, cast_mode))) {
  } else if (CAST_FAIL(params.warning_)) {
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_YEAR, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int string_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObLength res_length = -1;
  ObObj tmp_out;
  if (OB_UNLIKELY(
          (ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
          OB_UNLIKELY(ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && !(in.is_blob() && ob_is_blob(expect_type, params.expect_obj_collation_)) &&
             (in.is_blob())) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("invalid cast of blob type", K(ret), K(in), K(out.get_meta()), K(expect_type), K(cast_mode));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "cast to blob type");
  } else if (ObTextTC == in.get_type_class() && in.is_lob_outrow()) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("invalid cast of out row lob obj", K(ret), K(in), K(out.get_meta()), K(expect_type), K(cast_mode));
  } else if (lib::is_oracle_mode() && in.is_clob() && (0 == in.get_string().length()) &&
             !ob_is_clob(expect_type, params.expect_obj_collation_)) {
    out.set_null();
  } else {
    ObString str;
    in.get_string(str);
    if (0 != str.length() && CS_TYPE_BINARY != in.get_collation_type() && CS_TYPE_BINARY != params.dest_collation_ &&
        (ObCharset::charset_type_by_coll(in.get_collation_type()) !=
            ObCharset::charset_type_by_coll(params.dest_collation_))) {
      char* buf = NULL;
      // gbk and utf16 is fixed 2 btyes, utf8mb4 is 1 to 4 bytes,
      // so the factor should be 2.
      const int32_t CharConvertFactorNum = 2;
      int32_t buf_len = str.length() * CharConvertFactorNum;
      uint32_t result_len = 0;
      if (OB_UNLIKELY(NULL == (buf = static_cast<char*>(params.alloc(buf_len))))) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        LOG_ERROR("alloc memory failed", K(ret));
      } else if (OB_FAIL(ObCharset::charset_convert(in.get_collation_type(),
                     str.ptr(),
                     str.length(),
                     params.dest_collation_,
                     buf,
                     buf_len,
                     result_len))) {
        LOG_WARN("charset convert failed",
            K(ret),
            K(in.get_collation_type()),
            K(params.dest_collation_),
            K(params.is_ignore_));
        if (params.is_ignore_) {
          ObString question_mark = ObCharsetUtils::get_const_str(params.dest_collation_, '?');
          int32_t str_offset = 0;
          int64_t buf_offset = 0;
          while (str_offset < str.length() && buf_offset + question_mark.length() <= buf_len) {
            int64_t offset =
                ObCharset::charpos(in.get_collation_type(), str.ptr() + str_offset, str.length() - str_offset, 1);
            ret = ObCharset::charset_convert(in.get_collation_type(),
                str.ptr() + str_offset,
                offset,
                params.dest_collation_,
                buf + buf_offset,
                buf_len - buf_offset,
                result_len);
            str_offset += offset;
            if (OB_SUCCESS == ret) {
              buf_offset += result_len;
            } else {
              MEMCPY(buf + buf_offset, question_mark.ptr(), question_mark.length());
              buf_offset += question_mark.length();
            }
          }
          if (str_offset < str.length()) {
            ret = OB_SIZE_OVERFLOW;
            LOG_WARN("size overflow", K(ret), K(str), KPHEX(str.ptr(), str.length()));
          } else {
            result_len = buf_offset;
            ret = OB_SUCCESS;
            LOG_WARN("charset convert failed", K(ret), K(in.get_collation_type()), K(params.dest_collation_));
          }
        }
      }

      LOG_DEBUG("convert result", K(str), "result", ObHexEscapeSqlStr(ObString(result_len, buf)));

      if (OB_SUCC(ret)) {
        if (ObTextTC == ob_obj_type_class(expect_type)) {
          out.set_lob_value(expect_type, buf, static_cast<int32_t>(result_len));
        } else {
          out.set_string(expect_type, buf, static_cast<int32_t>(result_len));
        }
        if (CS_TYPE_INVALID != in.get_collation_type()) {
          out.set_collation_type(params.dest_collation_);
        }
      }
    } else {
      // When convert blob to other charset, need to align to mbminlen of destination charset
      // by add '\0' prefix in mysql mode. (see mysql String::copy)
      int64_t align_offset = 0;
      const ObCharsetInfo* cs = NULL;
      if (CS_TYPE_BINARY == in.get_collation_type() && is_mysql_mode() &&
          NULL != (cs = ObCharset::get_charset(params.dest_collation_))) {
        if (cs->mbminlen > 0 && in.get_string_len() % cs->mbminlen != 0) {
          align_offset = cs->mbminlen - in.get_string_len() % cs->mbminlen;
        }
      }
      if (OB_FAIL(check_convert_string(expect_type, params, in, tmp_out))) {
        LOG_WARN("failed to check_and_convert_string", K(ret), K(in), K(expect_type));
      } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out, align_offset))) {
      } else {
        if (CS_TYPE_INVALID != tmp_out.get_collation_type()) {
          out.set_collation_type(tmp_out.get_collation_type());
        }
        if (ObTextTC == ob_obj_type_class(expect_type)) {
          out.set_lob_inrow();
        }
      }
    }
  }
  if (OB_SUCC(ret)) {
    res_length = static_cast<ObLength>(out.get_string_len());
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  UNUSED(cast_mode);
  return ret;
}

static int string_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  uint64_t value = 0;
  if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
                  ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else {
    int32_t bit_len = 0;
    const ObString& str = in.get_string();
    if (OB_FAIL(get_bit_len(str, bit_len))) {
      LOG_WARN("fail to get bit length", K(ret), K(str));
    } else if (OB_UNLIKELY(bit_len <= 0)) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("bit length is less than or equal to zero", K(ret), K(str), K(bit_len));
    } else {
      if (ObHexStringType == in.get_type() && str.empty()) {
        value = 0;
        ret = OB_ERR_TRUNCATED_WRONG_VALUE_FOR_FIELD;
        LOG_WARN("hex string is empty, can't cast to bit", K(ret), K(in));
      } else if (OB_UNLIKELY(bit_len > OB_MAX_BIT_LENGTH)) {
        value = UINT64_MAX;
        ret = OB_ERR_DATA_TOO_LONG;
        LOG_WARN("bit type length is too long", K(ret), K(str), K(OB_MAX_BIT_LENGTH), K(bit_len));
      } else {
        value = hex_to_uint64(str);
      }
      if (OB_FAIL(ret) && CM_IS_WARN_ON_FAIL(cast_mode)) {
        params.warning_ = OB_DATA_OUT_OF_RANGE;
        ret = OB_SUCCESS;
      }
      if (OB_SUCC(ret)) {
        SET_RES_BIT(out);
        SET_RES_ACCURACY(static_cast<ObPrecision>(bit_len), DEFAULT_SCALE_FOR_BIT, DEFAULT_LENGTH_FOR_NUMERIC);
      }
    }
  }
  return ret;
}

static int string_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObCastMode cast_mode = params.cast_mode_;
  const ObIArray<ObString>* type_infos = NULL;
  const ObCollationType in_cs_type = ObCharset::is_valid_collation(in.get_collation_type())
                                         ? in.get_collation_type()
                                         : ObCharset::get_system_collation();
  ObCollationType cs_type = expect_type.get_collation_type();
  int32_t pos = 0;
  uint64_t value = 0;
  int32_t no_sp_len = 0;
  ObString no_sp_val;
  ObString in_str;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) ||
      OB_UNLIKELY(ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
      OB_ISNULL(type_infos = expect_type.get_type_infos())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else if (OB_FAIL(ObCharset::charset_convert(*params.allocator_v2_, in.get_string(), in_cs_type, cs_type, in_str))) {
    LOG_WARN("convert charset failed", K(ret), K(in), K(cs_type));
  } else {
    no_sp_len = static_cast<int32_t>(ObCharset::strlen_byte_no_sp(cs_type, in_str.ptr(), in_str.length()));
    no_sp_val.assign_ptr(in_str.ptr(), static_cast<ObString::obstr_size_t>(no_sp_len));
    if (OB_FAIL(find_type(*type_infos, cs_type, no_sp_val, pos))) {
      LOG_WARN("fail to find type", KPC(type_infos), K(cs_type), K(no_sp_val), K(in_str), K(pos), K(ret));
    } else if (OB_UNLIKELY(pos < 0)) {
      if (!in_str.is_numeric()) {
        ret = OB_ERR_DATA_TRUNCATED;
      } else {
        int err = 0;
        int64_t val_cnt = type_infos->count();
        value = ObCharset::strntoull(in_str.ptr(), in_str.length(), 10, &err);
        if (err != 0 || value > val_cnt) {
          value = 0;
          ret = OB_ERR_DATA_TRUNCATED;
          LOG_WARN("input value out of range", K(in), K(val_cnt), K(ret), K(err));
        }
      }
      if (OB_FAIL(ret) && CM_IS_WARN_ON_FAIL(cast_mode)) {
        params.warning_ = OB_ERR_DATA_TRUNCATED;
        ret = OB_SUCCESS;
      }
    } else {
      value = pos + 1;  // enum start from 1
    }
    LOG_DEBUG("finish string_enum", K(ret), K(expect_type), K(in), K(out), KPC(type_infos), K(lbt()));
    SET_RES_ENUM(out);
  }
  return ret;
}

static int string_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObCastMode cast_mode = params.cast_mode_;
  const ObIArray<ObString>* type_infos = NULL;
  const ObCollationType in_cs_type = ObCharset::is_valid_collation(in.get_collation_type())
                                         ? in.get_collation_type()
                                         : ObCharset::get_system_collation();
  ObCollationType cs_type = expect_type.get_collation_type();
  const ObString& sep = ObCharsetUtils::get_const_str(cs_type, ',');
  int32_t pos = 0;
  uint64_t value = 0;
  ObString in_str;
  ObString val_str;
  bool is_last_value = false;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) ||
      OB_UNLIKELY(ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
      OB_ISNULL(type_infos = expect_type.get_type_infos()) || !ObCharset::is_valid_collation(cs_type)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(cs_type), K(ret));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else if (in.get_string().empty()) {
    value = 0;
  } else if (OB_FAIL(ObCharset::charset_convert(*params.allocator_v2_, in.get_string(), in_cs_type, cs_type, in_str))) {
  } else {
    const char* remain = in_str.ptr();
    int64_t remain_len = ObCharset::strlen_byte_no_sp(cs_type, in_str.ptr(), in_str.length());
    do {
      pos = 0;
      const char* sep_loc = NULL;
      if (NULL == (sep_loc = static_cast<const char*>(memmem(remain, remain_len, sep.ptr(), sep.length())))) {
        is_last_value = true;
        val_str.assign_ptr(remain, remain_len);
        if (OB_FAIL(find_type(*type_infos, cs_type, val_str, pos))) {
          LOG_WARN("fail to find type", KPC(type_infos), K(cs_type), K(val_str), K(in_str), K(pos), K(ret));
        }
      } else {
        val_str.assign_ptr(remain, sep_loc - remain);
        remain_len = remain_len - (sep_loc - remain + sep.length());
        remain = sep_loc + sep.length();
        if (OB_FAIL(find_type(*type_infos, cs_type, val_str, pos))) {
          LOG_WARN("fail to find type", KPC(type_infos), K(cs_type), K(val_str), K(in_str), K(pos), K(ret));
        }
      }
      if (OB_FAIL(ret)) {
      } else if (pos < 0) {  // not found
        if (CM_IS_WARN_ON_FAIL(cast_mode)) {
          params.warning_ = OB_ERR_DATA_TRUNCATED;
          LOG_INFO(
              "input value out of range, and set out value zero", K(pos), K(in), K(val_str), K(in_str), K(expect_type));
        } else {
          ret = OB_ERR_DATA_TRUNCATED;
          LOG_WARN("data truncate", K(pos), K(in), K(val_str), K(in_str), K(expect_type), K(ret));
        }
      } else {
        pos %= 64;  // value_count can more than 64 if has duplicated values in mysql.
        value |= (1ULL << pos);
      }
    } while (OB_SUCC(ret) && !is_last_value);

    // Bug30666903: check implicit cast logic to handle number cases
    if (in_str.is_numeric() &&
        (OB_ERR_DATA_TRUNCATED == ret || (params.warning_ == OB_ERR_DATA_TRUNCATED && CM_IS_WARN_ON_FAIL(cast_mode)))) {
      int err = 0;
      value = ObCharset::strntoull(in_str.ptr(), in_str.length(), 10, &err);
      if (err == 0) {
        ret = OB_SUCCESS;
        uint32_t val_cnt = type_infos->count();
        if (OB_UNLIKELY(val_cnt <= 0)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("unexpect val_cnt", K(in), K(out), K(expect_type), K(ret));
        } else if (val_cnt >= 64) {  // do nothing
        } else if (val_cnt < 64 && value > ((1ULL << val_cnt) - 1)) {
          value = 0;
          ret = OB_ERR_DATA_TRUNCATED;
          LOG_WARN("input value out of range", K(in), K(val_cnt), K(ret));
        }
        if (OB_FAIL(ret) && CM_IS_WARN_ON_FAIL(cast_mode)) {
          params.warning_ = OB_ERR_DATA_TRUNCATED;
          ret = OB_SUCCESS;
        }
      } else {
        value = 0;
      }
    }
  }
  LOG_DEBUG("finish string_set", K(ret), K(expect_type), K(in), K(out), KPC(type_infos), K(lbt()));
  SET_RES_SET(out);
  return ret;
}

static int string_otimestamp(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  ObScale res_scale = -1;
  ObString utf8_string;

  if (OB_UNLIKELY(ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
      OB_UNLIKELY(ObOTimestampTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (lib::is_oracle_mode() && in.is_blob()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Cast to blob type");
  } else if (OB_FAIL(convert_string_collation(
                 in.get_string(), in.get_collation_type(), utf8_string, ObCharset::get_system_collation(), params))) {
    LOG_WARN("convert_string_collation", K(ret));
  } else {
    ObOTimestampData value;
    ObTimeConvertCtx cvrt_ctx(params.dtc_params_.tz_info_, true);
    cvrt_ctx.oracle_nls_format_ = params.dtc_params_.get_nls_format(expect_type);
    if (CAST_FAIL(ObTimeConverter::str_to_otimestamp(utf8_string, cvrt_ctx, expect_type, value, res_scale))) {
    } else {
      SET_RES_OTIMESTAMP(out);
    }
  }

  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, res_scale, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int string_raw(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  ObLength res_length = -1;

  if (OB_UNLIKELY(ObStringTC != in.get_type_class()) || OB_UNLIKELY(ObRawTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObHexUtils::hextoraw(in, params, out))) {
    LOG_WARN("fail to hextoraw", K(ret), K(in), K(expect_type));
  } else {
    res_length = static_cast<ObLength>(out.get_string_len());
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);

  return ret;
}

static int string_interval(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  ObScale res_scale = -1;
  ObLength res_length = -1;
  ObPrecision res_precision = -1;
  ObString utf8_string;

  if (OB_UNLIKELY(!in.is_string_type()) || OB_UNLIKELY(ObIntervalTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(convert_string_collation(
                 in.get_string(), in.get_collation_type(), utf8_string, ObCharset::get_system_collation(), params))) {
    LOG_WARN("convert_string_collation", K(ret));
  } else if (ObIntervalYMType == expect_type) {
    ObIntervalYMValue value;
    // don't know the scale, use the max scale and return the real scale
    res_scale = ObAccuracy::MAX_ACCURACY2[ORACLE_MODE][ObIntervalYMType].get_scale();
    if (CAST_FAIL(ObTimeConverter::str_to_interval_ym(utf8_string, value, res_scale))) {
    } else {
      SET_RES_INTERVAL_YM(out);
      out.set_scale(res_scale);
    }
  } else {
    ObIntervalDSValue value;
    // don't know the scale, use the max scale and return the real scale
    res_scale = ObAccuracy::MAX_ACCURACY2[ORACLE_MODE][ObIntervalDSType].get_scale();
    if (CAST_FAIL(ObTimeConverter::str_to_interval_ds(utf8_string, value, res_scale))) {
    } else {
      SET_RES_INTERVAL_DS(out);
      out.set_scale(res_scale);
    }
  }
  SET_RES_ACCURACY(res_precision, res_scale, res_length);
  return ret;
}

static int string_rowid(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ob_obj_type_class(expect_type) != ObRowIDTC) || OB_UNLIKELY(in.get_type_class() != ObStringTC)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected arguments", K(expect_type), K(in));
  } else if (ObURowIDType != expect_type) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("only support urowid for now", K(ret), K(expect_type));
  } else {
    ObURowIDData value;
    if (OB_FAIL(ObURowIDData::decode2urowid(in.get_string_ptr(), in.get_string_len(), *params.allocator_v2_, value))) {
      LOG_WARN("failed to decode to urowid", K(ret));
    } else {
      SET_RES_UROWID(out);
    }
  }
  return ret;
}

static int string_lob(const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out,
    const ObCastMode cast_mode, const ObLobLocator* lob_locator)
{
  int ret = OB_SUCCESS;
  ObObj tmp_out;
  if (!share::is_oracle_mode()) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("Unexpected tenant mode", K(ret));
  } else if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) ||
                         OB_UNLIKELY(!ob_is_lob_locator(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(string_string(ObLongTextType, params, in, tmp_out, cast_mode))) {
    LOG_WARN("fail to cast string to longtext", K(ret), K(in));
  } else if (tmp_out.is_null()) {
    out.set_null();
  } else {
    ObString str;
    char* buf = nullptr;
    ObLobLocator* result = nullptr;
    if (OB_FAIL(tmp_out.get_string(str))) {
      STORAGE_LOG(WARN, "Failed to get string from obj", K(ret), K(tmp_out));
    }
    const int64_t buf_len =
        sizeof(ObLobLocator) + (NULL == lob_locator ? 0 : lob_locator->payload_offset_) + str.length();
    if (OB_FAIL(ret)) {
    } else if (OB_ISNULL(buf = static_cast<char*>(params.alloc(buf_len)))) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_WARN("Failed to allocate memory for lob locator", K(ret), K(str));
    } else if (FALSE_IT(result = reinterpret_cast<ObLobLocator*>(buf))) {
    } else if (NULL == lob_locator) {
      if (OB_FAIL(result->init(str))) {
        STORAGE_LOG(WARN, "Failed to init lob locator", K(ret), K(str), KPC(result));
      }
    } else if (NULL != lob_locator) {
      ObString rowid;
      if (lob_locator->is_inline_mode()) {  // inline mode
        if (OB_FAIL(lob_locator->get_rowid(rowid))) {
          LOG_WARN("get rowid failed", K(ret));
        } else if (OB_FAIL(result->init(lob_locator->table_id_,
                       lob_locator->column_id_,
                       lob_locator->snapshot_version_,
                       lob_locator->flags_,
                       rowid,
                       str))) {
          STORAGE_LOG(WARN, "Failed to init lob locator", K(ret), K(str), KPC(result));
        }
      } else {  // compat mode
        if (OB_FAIL(result->init(str))) {
          STORAGE_LOG(WARN, "Failed to init lob locator", K(ret), K(str), KPC(result));
        }
      }
    }
    if (OB_SUCC(ret)) {
      out = tmp_out;
      out.set_lob_locator(*result);
    }
  }
  return ret;
}

////////////////////////////////////////////////////////////
// bit -> XXX
static int bit_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  int64_t value = 0;
  if (OB_UNLIKELY(ObBitTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid argument", K(in), K(expect_type), K(ret));
  } else {
    value = static_cast<int64_t>(in.get_bit());
    if (expect_type < ObIntType && CM_NEED_RANGE_CHECK(cast_mode) &&
        CAST_FAIL(int_range_check(expect_type, value, value))) {
    } else {
      SET_RES_INT(out);
      res_precision = get_precision_for_integer(out.get_int());
      SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
    }
  }
  return ret;
}

static int bit_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  uint64_t value = 0;
  if (OB_UNLIKELY(ObBitTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid argument", K(in), K(expect_type), K(ret));
  } else {
    value = static_cast<uint64_t>(in.get_bit());
    if (expect_type < ObUInt64Type && CM_NEED_RANGE_CHECK(cast_mode) &&
        CAST_FAIL(uint_upper_check(expect_type, value))) {
    } else {
      SET_RES_UINT(out);
      res_precision = get_precision_for_integer(out.get_uint64());
      SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
    }
  }
  return ret;
}

static int bit_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode);
static int bit_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj dbl;
  if (OB_UNLIKELY((ObBitTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(bit_double(ObDoubleType, params, in, dbl, cast_mode))) {
  } else if (OB_FAIL(double_float(expect_type, params, dbl, out, cast_mode))) {
  }
  // has set accuracy in prev double_float call
  return ret;
}

static int bit_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  double value = 0.0;
  if (OB_UNLIKELY((ObBitTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    value = static_cast<double>(in.get_bit());
    SET_RES_DOUBLE(out);
    SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  }
  return ret;
}

static int bit_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  number::ObNumber nmb;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObBitTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(nmb.from(in.get_bit(), params))) {
    LOG_WARN("fail to make number", K(ret), K(in));
  } else {
    out.set_number(expect_type, nmb);
    res_precision = get_precision_for_integer(in.get_bit());
    SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  }
  return ret;
}

static int bit_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  uint64_t bit_value = in.get_bit();
  int64_t value = 0;
  ObScale res_scale = -1;
  if (OB_UNLIKELY((ObBitTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (CM_IS_COLUMN_CONVERT(cast_mode)) {
    // if cast mode is column convert, using bit as int64 to do cast.
    ObTimeConvertCtx cvrt_ctx(params.dtc_params_.tz_info_, ObTimestampType == expect_type);
    if (CAST_FAIL(ObTimeConverter::int_to_datetime(bit_value, 0, cvrt_ctx, value))) {
      LOG_WARN("int_to_datetime failed", K(ret), K(bit_value));
    }
  } else {
    // using bit as char array to do cast.
    ObScale scale = in.get_scale();
    const int32_t BUF_LEN = (OB_MAX_BIT_LENGTH + 7) / 8;
    int64_t pos = 0;
    char buf[BUF_LEN];
    MEMSET(buf, 0, BUF_LEN);
    if (OB_FAIL(bit_to_char_array(bit_value, scale, buf, BUF_LEN, pos))) {
      LOG_WARN("fail to store val", KP(buf), K(BUF_LEN), K(bit_value), K(pos));
    } else {
      ObString str(pos, buf);
      ObTimeConvertCtx cvrt_ctx(params.dtc_params_.tz_info_, ObTimestampType == expect_type);
      if (CAST_FAIL(ObTimeConverter::str_to_datetime(str, cvrt_ctx, value, &res_scale))) {
        LOG_WARN("int_to_datetime failed", K(ret), K(bit_value), K(str));
      }
    }
  }
  if (OB_SUCC(ret)) {
    SET_RES_DATETIME(out);
    SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, res_scale, DEFAULT_LENGTH_FOR_TEMPORAL);
  }
  return ret;
}

static int bit_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  uint64_t bit_value = in.get_bit();
  int32_t value = 0;
  ObScale res_scale = -1;
  if (OB_UNLIKELY((ObBitTC != in.get_type_class() || ObDateTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (CM_IS_COLUMN_CONVERT(cast_mode)) {
    // if cast mode is column convert, using bit as int64 to do cast.
    if (CAST_FAIL(ObTimeConverter::int_to_date(bit_value, value))) {
      LOG_WARN("int_to_date failed", K(ret), K(bit_value));
    }
  } else {
    // using bit as char array to do cast.
    ObScale scale = in.get_scale();
    const int32_t BUF_LEN = (OB_MAX_BIT_LENGTH + 7) / 8;
    int64_t pos = 0;
    char buf[BUF_LEN];
    MEMSET(buf, 0, BUF_LEN);
    if (OB_FAIL(bit_to_char_array(bit_value, scale, buf, BUF_LEN, pos))) {
      LOG_WARN("fail to store val", KP(buf), K(BUF_LEN), K(bit_value), K(pos));
    } else {
      ObString str(pos, buf);
      if (CAST_FAIL(ObTimeConverter::str_to_date(str, value))) {
        LOG_WARN("str_to_date failed", K(ret), K(bit_value), K(str));
      }
    }
  }
  if (OB_SUCC(ret)) {
    SET_RES_DATE(out);
    SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, res_scale, DEFAULT_LENGTH_FOR_TEMPORAL);
  }
  return ret;
}

static int bit_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  uint64_t bit_value = in.get_bit();
  int64_t value = 0;
  ObScale res_scale = -1;
  if (OB_UNLIKELY((ObBitTC != in.get_type_class() || ObTimeTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (CM_IS_COLUMN_CONVERT(cast_mode)) {
    // if cast mode is column convert, using bit as int64 to do cast.
    if (CAST_FAIL(ObTimeConverter::int_to_time(bit_value, value))) {
      LOG_WARN("int_to_time failed", K(ret), K(bit_value));
    }
  } else {
    // using bit as char array to do cast.
    ObScale scale = in.get_scale();
    const int32_t BUF_LEN = (OB_MAX_BIT_LENGTH + 7) / 8;
    int64_t pos = 0;
    char buf[BUF_LEN];
    MEMSET(buf, 0, BUF_LEN);
    if (OB_FAIL(bit_to_char_array(bit_value, scale, buf, BUF_LEN, pos))) {
      LOG_WARN("fail to store val", KP(buf), K(BUF_LEN), K(bit_value), K(pos));
    } else {
      ObString str(pos, buf);
      if (CAST_FAIL(ObTimeConverter::str_to_time(str, value, &res_scale))) {
        LOG_WARN("str_to_date failed", K(ret), K(bit_value), K(str));
      }
    }
  }
  if (OB_SUCC(ret)) {
    SET_RES_TIME(out);
    SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, res_scale, DEFAULT_LENGTH_FOR_TEMPORAL);
  }
  return ret;
}

static int bit_year(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  uint64_t bit_value = in.get_bit();
  uint8_t value = 0;
  ObScale res_scale = -1;
  if (OB_UNLIKELY((ObBitTC != 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 if (CAST_FAIL(ObTimeConverter::int_to_year(bit_value, value))) {
    LOG_WARN("int_to_year faile", K(ret), K(bit_value));
  } else {
    SET_RES_YEAR(out);
    SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, res_scale, DEFAULT_LENGTH_FOR_TEMPORAL);
  }
  return ret;
}

static int bit_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  uint64_t value = in.get_bit();
  ObLength res_length = -1;
  if (OB_UNLIKELY((ObBitTC != in.get_type_class() ||
                   (ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type))))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (CM_IS_COLUMN_CONVERT(cast_mode)) {
    // if cast mode is column convert, using bit as int64 to do cast.
    ObFastFormatInt ffi(value);
    ObString tmp_str;
    if (OB_FAIL(convert_string_collation(ObString(ffi.length(), ffi.ptr()),
            ObCharset::get_system_collation(),
            tmp_str,
            params.dest_collation_,
            params))) {
      LOG_WARN("fail to convert string collation", K(ret));
    } else if (OB_FAIL(copy_string(params, expect_type, tmp_str.ptr(), tmp_str.length(), out))) {
      LOG_WARN("fail to copy string", KP(tmp_str.ptr()), K(tmp_str.length()), K(value), K(out), K(expect_type));
    }
  } else {
    // using bit as char array to do cast.
    ObScale scale = in.get_scale();
    const int32_t BUF_LEN = (OB_MAX_BIT_LENGTH + 7) / 8;
    int64_t pos = 0;
    char tmp_buf[BUF_LEN];
    MEMSET(tmp_buf, 0, BUF_LEN);
    if (OB_FAIL(bit_to_char_array(value, scale, tmp_buf, BUF_LEN, pos))) {
      LOG_WARN("fail to store val", KP(tmp_buf), K(BUF_LEN), K(value), K(pos));
    } else if (OB_FAIL(copy_string(params, expect_type, tmp_buf, pos, out))) {
      LOG_WARN("fail to copy string", KP(tmp_buf), K(pos), K(value), K(out), K(expect_type));
    }
  }
  if (OB_SUCC(ret)) {
    res_length = static_cast<ObLength>(out.get_string_len());
    SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_STRING, DEFAULT_SCALE_FOR_STRING, res_length);
  }
  return ret;
}

static int bit_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  uint64_t value = in.get_bit();
  int32_t bit_len = 0;
  if (OB_UNLIKELY(ObBitTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_bit_len(value, bit_len))) {
    LOG_WARN("fail to get bit len", K(ret), K(value), K(bit_len));
  } else {
    SET_RES_BIT(out);
    SET_RES_ACCURACY(static_cast<ObPrecision>(bit_len), DEFAULT_SCALE_FOR_BIT, DEFAULT_LENGTH_FOR_NUMERIC);
  }
  return ret;
}

static int bit_enum(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObEnumType != expect_type.get_type()) || OB_UNLIKELY(ObBitTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else {
    uint64_t value = in.get_bit();
    ObObj uint_val;
    uint_val.set_uint64(value);
    if (OB_FAIL(uint_enum(expect_type, params, uint_val, out))) {
      LOG_WARN("fail to cast int to enum", K(expect_type), K(in), K(uint_val), K(out), K(ret));
    }
  }
  return ret;
}

static int bit_set(const ObExpectType& expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObSetType != expect_type.get_type()) || OB_UNLIKELY(ObBitTC != in.get_type_class())) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid argument", K(expect_type), K(in), K(ret));
  } else {
    uint64_t value = in.get_bit();
    ObObj uint_val;
    uint_val.set_uint64(value);
    if (OB_FAIL(uint_set(expect_type, params, uint_val, out))) {
      LOG_WARN("fail to cast int to enum", K(expect_type), K(in), K(uint_val), K(out), K(ret));
    }
  }
  return ret;
}

CAST_TO_LOB_METHOD(bit, ObBitTC);

ObCastEnumOrSetFunc OB_CAST_ENUM_OR_SET[ObMaxTC][2] = {
    {
        /*null -> enum_or_set*/
        cast_identity_enum_set, /*enum*/
        cast_identity_enum_set, /*set*/
    },
    {
        /*int -> enum_or_set*/
        int_enum, /*enum*/
        int_set,  /*set*/
    },
    {
        /*uint -> enum_or_set*/
        uint_enum, /*enum*/
        uint_set,  /*set*/
    },
    {
        /*float -> enum_or_set*/
        float_enum, /*enum*/
        float_set,  /*set*/
    },
    {
        /*double -> enum_or_set*/
        double_enum, /*enum*/
        double_set,  /*set*/
    },
    {
        /*number -> enum_or_set*/
        number_enum, /*enum*/
        number_set,  /*set*/
    },
    {
        /*datetime -> enum_or_set*/
        datetime_enum, /*enum*/
        datetime_set,  /*set*/
    },
    {
        /*date -> enum_or_set*/
        date_enum, /*enum*/
        date_set,  /*set*/
    },
    {
        /*time -> enum_or_set*/
        time_enum, /*enum*/
        time_set,  /*set*/
    },
    {
        /*year -> enum_or_set*/
        year_enum, /*enum*/
        year_set,  /*set*/
    },
    {
        /*string -> enum_or_set*/
        string_enum, /*enum*/
        string_set,  /*set*/
    },
    {
        /*extend -> enum_or_set*/
        cast_not_support_enum_set, /*enum*/
        cast_not_support_enum_set, /*set*/
    },
    {
        /*unknow -> enum_or_set*/
        cast_not_support_enum_set, /*enum*/
        cast_not_support_enum_set, /*set*/
    },
    {
        /*text -> enum_or_set*/
        string_enum, /*enum*/
        string_set,  /*set*/
    },
    {
        /*bit -> enum_or_set*/
        bit_enum, /*enum*/
        bit_set,  /*set*/
    },
    {
        /*enumset tc -> enum_or_set*/
        cast_not_expected_enum_set, /*enum*/
        cast_not_expected_enum_set, /*set*/
    },
    {
        /*enumset_inner tc -> enum_or_set*/
        cast_not_expected_enum_set, /*enum*/
        cast_not_expected_enum_set, /*set*/
    },
    {
        /*text -> enum_or_set*/
        cast_not_support_enum_set, /*enum*/
        cast_not_support_enum_set, /*set*/
    },
};

////////////////////////////////////////////////////////////
// enum -> XXX

static int enumset_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint64 when int_value is needed
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    ObObj uint64_in;
    uint64_in.set_uint64(in.get_uint64());
    ret = uint_int(expect_type, params, uint64_in, out, cast_mode);
  }
  return ret;
}

static int enumset_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    uint64_t value = in.get_uint64();
    if (CAST_FAIL(uint_upper_check(expect_type, value))) {
    } else {
      out.set_uint(expect_type, value);
      res_precision = get_precision_for_integer(value);
    }
  }
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int enumset_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    out.set_float(expect_type, static_cast<float>(in.get_uint64()));
  }
  UNUSED(cast_mode);
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int enumset_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    out.set_double(expect_type, static_cast<double>(in.get_uint64()));
  }
  UNUSED(cast_mode);
  SET_RES_ACCURACY(PRECISION_UNKNOWN_YET, SCALE_UNKNOWN_YET, LENGTH_UNKNOWN_YET);
  return ret;
}

static int enumset_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  number::ObNumber nmb;
  ObPrecision res_precision = -1;
  if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(nmb.from(in.get_uint64(), params))) {
    LOG_ERROR("failed to from number", K(ret), K(in), K(expect_type));
  } else {
    out.set_number(expect_type, nmb);
    res_precision = get_precision_for_integer(in.get_uint64());
  }
  UNUSED(cast_mode);
  SET_RES_ACCURACY(res_precision, DEFAULT_SCALE_FOR_INTEGER, DEFAULT_LENGTH_FOR_NUMERIC);
  return ret;
}

static int enumset_year(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj int64;
  if (OB_UNLIKELY(ObEnumSetTC != 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 if (OB_FAIL(enumset_int(ObIntType, params, in, int64, CM_UNSET_NO_CAST_INT_UINT(cast_mode)))) {
  } else if (OB_FAIL(int_year(expect_type, params, int64, out, cast_mode))) {
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, DEFAULT_SCALE_FOR_YEAR, DEFAULT_LENGTH_FOR_TEMPORAL);
  return ret;
}

static int enumset_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  uint64_t value = in.get_uint64();
  int32_t bit_len = 0;
  if (OB_UNLIKELY(ObEnumSetTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_bit_len(value, bit_len))) {
    LOG_WARN("fail to get bit len", K(ret), K(value), K(bit_len));
  } else {
    SET_RES_BIT(out);
    SET_RES_ACCURACY(static_cast<ObPrecision>(bit_len), DEFAULT_SCALE_FOR_BIT, DEFAULT_LENGTH_FOR_NUMERIC);
  }
  return ret;
}

static int get_uint64_from_enumset_inner(const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObEnumSetInnerValue inner_value;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class())) {
    LOG_ERROR("invalid input type", K(ret), K(in));
  } else if (OB_FAIL(in.get_enumset_inner_value(inner_value))) {
    LOG_WARN("failed to get_enumset_inner_value", K(in), K(ret));
  } else {
    out.set_uint64(inner_value.numberic_value_);
  }
  return ret;
}

static int get_string_from_enumset_inner(const ObObj& in, ObObj& out)
{
  int ret = OB_SUCCESS;
  ObEnumSetInnerValue inner_value;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class())) {
    LOG_ERROR("invalid input type", K(ret), K(in));
  } else if (OB_FAIL(in.get_enumset_inner_value(inner_value))) {
    LOG_WARN("failed to get_enumset_inner_value", K(in), K(ret));
  } else {
    out.set_varchar(inner_value.string_value_);
    out.set_collation_type(in.get_collation_type());
    out.set_collation_level(in.get_collation_level());
  }
  return ret;
}
/* used for case when or in , comment temporary */

// static int enumset_inner_int(const ObObjType expect_type, ObObjCastParams &params,
//                          const ObObj &in, ObObj &out, const ObCastMode cast_mode)
//{
//  //we regard enum as uint16 when int_value is needed
//  int ret = OB_SUCCESS;
//  ObObj uint64;
//  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class()
//                  || ObIntTC != ob_obj_type_class(expect_type))) {
//    ret = OB_ERR_UNEXPECTED;
//    LOG_ERROR("invalid input type",
//        K(ret), K(in), K(expect_type));
//  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
//    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
//  } else if (OB_FAIL(uint_int(expect_type, params, uint64, out, cast_mode))) {
//    LOG_WARN("failed to cast uint to int", K(in), K(uint64), K(ret));
//  } else {/*do nothing*/}
//  return ret;
//}
//
// static int enumset_inner_uint(const ObObjType expect_type, ObObjCastParams &params,
//                           const ObObj &in, ObObj &out, const ObCastMode cast_mode)
//{
//  //we regard enum as uint16 when int_value is needed
//  int ret = OB_SUCCESS;
//  ObObj uint64;
//  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class()
//                  || ObUIntTC != ob_obj_type_class(expect_type))) {
//    ret = OB_ERR_UNEXPECTED;
//    LOG_ERROR("invalid input type",
//        K(ret), K(in), K(expect_type));
//  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
//    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
//  } else if (OB_FAIL(uint_uint(expect_type, params, uint64, out, cast_mode))) {
//    LOG_WARN("failed to cast uint to uint", K(in), K(uint64), K(ret));
//  } else {/*do nothing*/}
//  return ret;
//}
//
// static int enumset_inner_float(const ObObjType expect_type, ObObjCastParams &params,
//                            const ObObj &in, ObObj &out, const ObCastMode cast_mode)
//{
//  //we regard enum as uint16 when int_value is needed
//  int ret = OB_SUCCESS;
//  ObObj uint64;
//  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class()
//                  || ObFloatTC != ob_obj_type_class(expect_type))) {
//    ret = OB_ERR_UNEXPECTED;
//    LOG_ERROR("invalid input type",
//        K(ret), K(in), K(expect_type));
//  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
//    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
//  } else if (OB_FAIL(uint_float(expect_type, params, uint64, out, cast_mode))) {
//    LOG_WARN("failed to cast uint to float", K(in), K(uint64), K(ret));
//  } else {/*do nothing*/}
//  return ret;
//}
//
// static int enumset_inner_double(const ObObjType expect_type, ObObjCastParams &params,
//                             const ObObj &in, ObObj &out, const ObCastMode cast_mode)
//{
//  //we regard enum as uint16 when int_value is needed
//  int ret = OB_SUCCESS;
//  ObObj uint64;
//  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class()
//                  || ObDoubleTC != ob_obj_type_class(expect_type))) {
//    ret = OB_ERR_UNEXPECTED;
//    LOG_ERROR("invalid input type",
//        K(ret), K(in), K(expect_type));
//  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
//    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
//  } else if (OB_FAIL(uint_double(expect_type, params, uint64, out, cast_mode))) {
//    LOG_WARN("failed to cast uint to double", K(in), K(uint64), K(ret));
//  } else {/*do nothing*/}
//  return ret;
//}
//
// static int enumset_inner_number(const ObObjType expect_type, ObObjCastParams &params,
//                             const ObObj &in, ObObj &out, const ObCastMode cast_mode)
//{
//  //we regard enum as uint16 when int_value is needed
//  int ret = OB_SUCCESS;
//  ObObj uint64;
//  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class()
//                  || ObNumberTC != ob_obj_type_class(expect_type))) {
//    ret = OB_ERR_UNEXPECTED;
//    LOG_ERROR("invalid input type", K(in), K(expect_type), K(ret));
//  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
//    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
//  } else if (OB_FAIL(uint_number(expect_type, params, uint64, out, cast_mode))) {
//    LOG_WARN("failed to cast uint to number", K(in), K(uint64), K(ret));
//  } else {/*do nothing*/}
//  return ret;
//}

static int enumset_inner_int(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint16 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj uint64;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class() || ObIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(uint_int(expect_type, params, uint64, out, cast_mode))) {
    LOG_WARN("failed to cast uint to int", K(in), K(uint64), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

static int enumset_inner_uint(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint16 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj uint64;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class() || ObUIntTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(uint_uint(expect_type, params, uint64, out, cast_mode))) {
    LOG_WARN("failed to cast uint to uint", K(in), K(uint64), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

static int enumset_inner_float(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint16 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj uint64;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class() || ObFloatTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(uint_float(expect_type, params, uint64, out, cast_mode))) {
    LOG_WARN("failed to cast uint to float", K(in), K(uint64), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

static int enumset_inner_double(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint16 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj uint64;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class() || ObDoubleTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(uint_double(expect_type, params, uint64, out, cast_mode))) {
    LOG_WARN("failed to cast uint to double", K(in), K(uint64), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

static int enumset_inner_number(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint16 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj uint64;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class() || ObNumberTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(in), K(expect_type), K(ret));
  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(uint_number(expect_type, params, uint64, out, cast_mode))) {
    LOG_WARN("failed to cast uint to number", K(in), K(uint64), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

static int enumset_inner_year(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint64 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj uint64;
  if (OB_UNLIKELY(ObEnumSetInnerTC != 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 if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(uint_year(expect_type, params, uint64, out, cast_mode))) {
    LOG_WARN("failed to cast uint to year", K(in), K(uint64), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

static int enumset_inner_bit(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint16 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj uint64;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class() || ObBitTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_uint64_from_enumset_inner(in, uint64))) {
    LOG_WARN("failed to get_uint64_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(uint_bit(expect_type, params, uint64, out, cast_mode))) {
    LOG_WARN("failed to cast uint to year", K(in), K(uint64), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

static int enumset_inner_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint16 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj str_value;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class() || ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_string_from_enumset_inner(in, str_value))) {
    LOG_WARN("failed to get_string_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(string_datetime(expect_type, params, str_value, out, cast_mode))) {
    LOG_WARN("failed to cast string to datetime", K(in), K(str_value), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

static int enumset_inner_date(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint16 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj str_value;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class() || ObDateTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_string_from_enumset_inner(in, str_value))) {
    LOG_WARN("failed to get_string_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(string_date(expect_type, params, str_value, out, cast_mode))) {
    LOG_WARN("failed to cast string to date", K(in), K(str_value), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

static int enumset_inner_time(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint16 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj str_value;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class() || ObTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_string_from_enumset_inner(in, str_value))) {
    LOG_WARN("failed to get_string_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(string_time(expect_type, params, str_value, out, cast_mode))) {
    LOG_WARN("failed to cast string to time", K(in), K(str_value), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

static int enumset_inner_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  // we regard enum as uint16 when int_value is needed
  int ret = OB_SUCCESS;
  ObObj str_value;
  if (OB_UNLIKELY(ObEnumSetInnerTC != in.get_type_class() || ObStringTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(get_string_from_enumset_inner(in, str_value))) {
    LOG_WARN("failed to get_string_from_enumset_inner", K(in), K(ret));
  } else if (OB_FAIL(string_string(expect_type, params, str_value, out, cast_mode))) {
    LOG_WARN("failed to cast string to string", K(in), K(str_value), K(ret));
  } else { /*do nothing*/
  }
  return ret;
}

////////////////////////////////////////////////////////////
// OTimestamp -> XXX

static int otimestamp_datetime(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  int64_t usec = 0;
  if (OB_UNLIKELY(ObOTimestampTC != in.get_type_class()) ||
      OB_UNLIKELY(ObDateTimeTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObTimeConverter::otimestamp_to_odate(
                 in.get_type(), in.get_otimestamp_value(), params.dtc_params_.tz_info_, usec))) {
    LOG_WARN("fail to timestamp_tz_to_timestamp", K(ret), K(in), K(expect_type));
  } else {
    ObTimeConverter::trunc_datetime(OB_MAX_DATE_PRECISION, usec);
    out.set_datetime(expect_type, usec);
    out.set_scale(OB_MAX_DATE_PRECISION);
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, in.get_scale(), DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

static int otimestamp_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObOTimestampTC != in.get_type_class()) ||
      OB_UNLIKELY(ObStringTC != ob_obj_type_class(expect_type) && ObTextTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
    int64_t len = 0;
    if (OB_FAIL(ObTimeConverter::otimestamp_to_str(in.get_otimestamp_value(),
            params.dtc_params_,
            in.get_scale(),
            in.get_type(),
            buf,
            OB_CAST_TO_VARCHAR_MAX_LENGTH,
            len))) {
      LOG_WARN("failed to convert otimestamp to string", K(ret));
    } else {
      ObString tmp_str;
      ObObj tmp_out;
      if (OB_FAIL(convert_string_collation(
              ObString(len, buf), ObCharset::get_system_collation(), tmp_str, params.dest_collation_, params))) {
        LOG_WARN("fail to convert string collation", K(ret));
      } else if (OB_FAIL(check_convert_string(expect_type, params, tmp_str, tmp_out))) {
        LOG_WARN("fail to check_convert_string", K(ret), K(in), K(expect_type));
      } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out))) {
        LOG_WARN("failed to copy_string", K(ret), K(expect_type), K(len));
      } else {
        out.set_type(expect_type);
        res_length = static_cast<ObLength>(out.get_string_len());
      }
    }
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  UNUSED(cast_mode);
  return ret;
}

static int otimestamp_otimestamp(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObOTimestampData value;
  if (OB_UNLIKELY(ObOTimestampTC != in.get_type_class()) ||
      OB_UNLIKELY(ObOTimestampTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (ObTimestampNanoType == in.get_type()) {
    if (OB_FAIL(ObTimeConverter::odate_to_otimestamp(
            in.get_otimestamp_value().time_us_, params.dtc_params_.tz_info_, expect_type, value))) {
      LOG_WARN("fail to odate_to_otimestamp", K(ret), K(expect_type));
    } else {
      value.time_ctx_.tail_nsec_ = in.get_otimestamp_value().time_ctx_.tail_nsec_;
    }
  } else if (ObTimestampNanoType == expect_type) {
    if (OB_FAIL(ObTimeConverter::otimestamp_to_odate(
            in.get_type(), in.get_otimestamp_value(), params.dtc_params_.tz_info_, *(int64_t*)&value.time_us_))) {
      LOG_WARN("fail to otimestamp_to_odate", K(ret), K(expect_type));
    } else {
      value.time_ctx_.tail_nsec_ = in.get_otimestamp_value().time_ctx_.tail_nsec_;
    }
  } else {
    if (OB_FAIL(ObTimeConverter::otimestamp_to_otimestamp(
            in.get_type(), in.get_otimestamp_value(), params.dtc_params_.tz_info_, expect_type, value))) {
      LOG_WARN("fail to otimestamp_to_otimestamp", K(ret), K(expect_type));
    }
  }

  if (OB_SUCC(ret)) {
    SET_RES_OTIMESTAMP(out);
  }
  SET_RES_ACCURACY(DEFAULT_PRECISION_FOR_TEMPORAL, in.get_scale(), DEFAULT_LENGTH_FOR_TEMPORAL);
  UNUSED(cast_mode);
  return ret;
}

////////////////////////////////////////////////////////////
// Interval -> XXX
static int interval_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0};
  int64_t len = 0;
  ObLength res_length = -1;
  bool is_explicit_cast = CM_IS_EXPLICIT_CAST(cast_mode);
  if (OB_UNLIKELY(!ob_is_string_type(expect_type) || ObIntervalTC != in.get_type_class())) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else {
    ret = in.is_interval_ym()
              ? ObTimeConverter::interval_ym_to_str(
                    in.get_interval_ym(), in.get_scale(), buf, OB_CAST_TO_VARCHAR_MAX_LENGTH, len, is_explicit_cast)
              : ObTimeConverter::interval_ds_to_str(
                    in.get_interval_ds(), in.get_scale(), buf, OB_CAST_TO_VARCHAR_MAX_LENGTH, len, is_explicit_cast);
    if (OB_FAIL(ret)) {
      LOG_WARN("failed to convert interval to str");
    } else {
      ObString tmp_str;
      ObObj tmp_out;
      if (OB_FAIL(convert_string_collation(
              ObString(len, buf), ObCharset::get_system_collation(), tmp_str, params.dest_collation_, params))) {
        LOG_WARN("fail to convert string collation", K(ret));
      } else if (OB_FAIL(check_convert_string(expect_type, params, tmp_str, tmp_out))) {
        LOG_WARN("fail to check_convert_string", K(ret), K(in), K(expect_type));
      } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out))) {
        LOG_WARN("failed to copy_string", K(ret), K(expect_type), K(len));
      } else {
        out.set_type(expect_type);
        res_length = static_cast<ObLength>(out.get_string_len());
      }
    }
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  UNUSED(cast_mode);
  return ret;
}

static int interval_interval(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObIntervalTC != ob_obj_type_class(expect_type) || ObIntervalTC != in.get_type_class())) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_UNLIKELY(expect_type != in.get_type())) {
    ret = cast_inconsistent_types(expect_type, params, in, out, cast_mode);
  } else {
    if (&in != &out) {
      out = in;
    }
  }
  return ret;
}

////////////////////////////////////////////////////////////
// Raw -> XXX

// lob is excluded.
static int raw_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  ObLength res_length = -1;
  ObString tmp_str;
  ObObj tmp_obj;

  if (OB_UNLIKELY((ObRawTC != in.get_type_class()) || OB_UNLIKELY(ObStringTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(ObHexUtils::rawtohex(in, params, tmp_obj))) {
    LOG_WARN("fail to rawtohex", K(ret), K(in), K(expect_type));
  } else {
    if (!ObCharset::is_cs_nonascii(params.dest_collation_)) {
      out.set_string(expect_type, tmp_obj.get_string_ptr(), tmp_obj.get_string_len());
      out.set_collation_type(params.dest_collation_);
      res_length = static_cast<ObLength>(out.get_string_len());
    } else {
      if (OB_FAIL(convert_string_collation(
              tmp_obj.get_string(), ObCharset::get_system_collation(), tmp_str, params.dest_collation_, params))) {
        LOG_WARN("failed to convert string collation", K(ret));
      } else {
        out.set_string(expect_type, tmp_str.ptr(), tmp_str.length());
        out.set_collation_type(params.dest_collation_);
        res_length = static_cast<ObLength>(out.get_string_len());
      }
    }
  }

  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);

  return ret;
}

static int raw_longtext(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  ObLength res_length = -1;
  ObString tmp_str;
  ObObj tmp_obj;

  if (OB_UNLIKELY((ObRawTC != in.get_type_class()) || OB_UNLIKELY(!ob_is_text_tc(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (ob_is_clob(expect_type, params.expect_obj_collation_)) {
    // raw to clob
    if (OB_FAIL(ObHexUtils::rawtohex(in, params, tmp_obj))) {
      LOG_WARN("fail to rawtohex", K(ret), K(in), K(expect_type));
    } else {
      if (!ObCharset::is_cs_nonascii(params.expect_obj_collation_)) {
        out.set_varchar_value(tmp_obj.get_string_ptr(), tmp_obj.get_string_len());
        out.set_collation_type(params.expect_obj_collation_);
      } else {
        if (OB_FAIL(convert_string_collation(tmp_obj.get_string(),
                ObCharset::get_system_collation(),
                tmp_str,
                params.expect_obj_collation_,
                params))) {
          LOG_WARN("failed to convert string collation", K(ret));
        } else {
          out.set_varchar_value(tmp_str.ptr(), tmp_str.length());
          out.set_collation_type(params.expect_obj_collation_);
        }
      }
    }
  } else if (ob_is_blob(expect_type, params.expect_obj_collation_)) {
    // raw to blob
    if (OB_FAIL(copy_string(params, expect_type, in.get_string(), out))) {
      LOG_WARN("failed to copy string", K(ret), K(in), K(expect_type));
    }
  }
  if (OB_SUCC(ret)) {
    out.set_type(expect_type);
    out.set_lob_inrow();
    out.set_collation_type(params.expect_obj_collation_);
    out.set_collation_level(CS_LEVEL_IMPLICIT);
    res_length = static_cast<ObLength>(out.get_string_len());
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);

  return ret;
}

static int raw_lob(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj tmp_val;

  if (OB_UNLIKELY((ObRawTC != in.get_type_class()) || OB_UNLIKELY(ObLobTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(raw_longtext(ObLongTextType, params, in, tmp_val, cast_mode))) {
    LOG_WARN("fail to cast raw to longtext", K(ret), K(expect_type), K(in), K(tmp_val));
  } else if (OB_FAIL(string_lob(expect_type, params, tmp_val, out, cast_mode))) {
    LOG_WARN("fail to cast string to lob", K(ret), K(expect_type), K(in), K(tmp_val));
  }
  return ret;
}

static int raw_raw(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  ObLength res_length = -1;
  ObObj tmp_out;

  if (OB_UNLIKELY((ObRawTC != in.get_type_class()) || OB_UNLIKELY(ObRawTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(check_convert_string(expect_type, params, in, tmp_out))) {
    LOG_WARN("failed to check_and_convert_string", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out))) {
    LOG_WARN("failed to copy string", K(ret), K(in), K(expect_type));
  } else {
    out.set_type(expect_type);
    res_length = static_cast<ObLength>(out.get_string_len());
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);

  return ret;
}

////////////////////////////////////////////////////////////
// rowid -> XXX
static int rowid_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  ObLength res_length = -1;
  if (OB_UNLIKELY(ObRowIDTC != in.get_type_class()) || OB_UNLIKELY(ObStringTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid input type", K(ret), K(in), K(expect_type));
  } else if (!in.is_urowid()) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("not support rowid for now", K(ret));
  } else {
    int64_t pos = 0;
    char* base64_buf = NULL;
    int64_t base64_buf_len = in.get_urowid().needed_base64_buffer_size();
    if (OB_ISNULL(base64_buf = (char*)(params.alloc(base64_buf_len)))) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      LOG_WARN("failed to allocate memory", K(ret));
    } else if (OB_FAIL(in.get_urowid().get_base64_str(base64_buf, base64_buf_len, pos))) {
      LOG_WARN("failed to get base64 string", K(ret));
    } else {
      ObString tmp_str;
      ObObj tmp_out;
      if (OB_FAIL(convert_string_collation(ObString(base64_buf_len, base64_buf),
              ObCharset::get_system_collation(),
              tmp_str,
              params.dest_collation_,
              params))) {
        LOG_WARN("failed to convert string collation", K(ret));
      } else if (OB_FAIL(check_convert_string(expect_type, params, tmp_str, tmp_out))) {
        LOG_WARN("failed to check convert string", K(ret));
      } else if (OB_FAIL(copy_string(params, expect_type, tmp_out.get_string(), out))) {
        LOG_WARN("failed to copy_string", K(ret), K(expect_type));
      } else {
        out.set_type(expect_type);
        res_length = static_cast<ObLength>(out.get_string_len());
      }
    }
  }
  SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length);
  return ret;
}

static int rowid_rowid(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObRowIDTC != in.get_type_class()) || OB_UNLIKELY(ObRowIDTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_UNLIKELY(ObURowIDType != expect_type || ObURowIDType != in.get_type())) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("only support urowid type for now", K(ret));
  } else {
    UNUSED(params);
    UNUSED(cast_mode);
    if (&in != &out) {
      out = in;
    }
  }
  return ret;
}

////////////////////////////////////////////////////////////
// Lob -> XXX
#define CAST_LOB_TO_OTHER_TYPE(TYPE, TYPE_CLASS)                                                                     \
  static int lob_##TYPE(                                                                                             \
      const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode) \
  {                                                                                                                  \
    int ret = OB_SUCCESS;                                                                                            \
    if (OB_UNLIKELY(ObLobTC != in.get_type_class() || TYPE_CLASS != ob_obj_type_class(expect_type))) {               \
      ret = OB_ERR_UNEXPECTED;                                                                                       \
      LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));                                                \
    } else if (lib::is_oracle_mode() && in.is_blob_locator()) {                                                      \
      ret = OB_NOT_SUPPORTED;                                                                                        \
      LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));                                          \
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "Blob cast to other type");                                                   \
    } else {                                                                                                         \
      ObString str;                                                                                                  \
      if (OB_FAIL(in.get_string(str))) {                                                                             \
        STORAGE_LOG(WARN, "Failed to get payload from lob locator", K(ret), K(in));                                  \
      } else {                                                                                                       \
        ObObj tmp_obj;                                                                                               \
        tmp_obj.set_varchar(str);                                                                                    \
        tmp_obj.set_collation_type(in.get_collation_type());                                                         \
        if (OB_FAIL(string_##TYPE(expect_type, params, tmp_obj, out, cast_mode))) {                                  \
          LOG_WARN("string to " #TYPE "failed", K(ret), K(tmp_obj));                                                 \
        }                                                                                                            \
      }                                                                                                              \
    }                                                                                                                \
    return ret;                                                                                                      \
  }

CAST_LOB_TO_OTHER_TYPE(int, ObIntTC);
CAST_LOB_TO_OTHER_TYPE(uint, ObUIntTC);
CAST_LOB_TO_OTHER_TYPE(double, ObDoubleTC);
CAST_LOB_TO_OTHER_TYPE(float, ObFloatTC);
CAST_LOB_TO_OTHER_TYPE(number, ObNumberTC);
CAST_LOB_TO_OTHER_TYPE(datetime, ObDateTimeTC);
CAST_LOB_TO_OTHER_TYPE(date, ObDateTC);
CAST_LOB_TO_OTHER_TYPE(time, ObTimeTC);
CAST_LOB_TO_OTHER_TYPE(year, ObYearTC);
CAST_LOB_TO_OTHER_TYPE(bit, ObBitTC);
CAST_LOB_TO_OTHER_TYPE(otimestamp, ObOTimestampTC);
CAST_LOB_TO_OTHER_TYPE(interval, ObIntervalTC);
CAST_LOB_TO_OTHER_TYPE(rowid, ObRowIDTC);

static int lob_string(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  ObObj tmp_out;
  ObString in_str;
  if (OB_UNLIKELY(ObLobTC != in.get_type_class() || OB_UNLIKELY(ObStringTC != ob_obj_type_class(expect_type) &&
                                                                ObTextTC != ob_obj_type_class(expect_type)))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (OB_FAIL(in.get_string(in_str))) {
    LOG_WARN("get string failed", K(ret));
  } else {
    ObObj tmp_in = in;
    tmp_in.set_string(ObLongTextType, in_str);
    if (OB_FAIL(string_string(expect_type, params, tmp_in, out, cast_mode))) {
      LOG_WARN("cast string to string failed", K(ret));
    }
  }
  return ret;
}

static int lob_lob(
    const ObObjType expect_type, ObObjCastParams& params, const ObObj& in, ObObj& out, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  if (OB_UNLIKELY(ObLobTC != in.get_type_class() || ObLobTC != ob_obj_type_class(expect_type))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_ERROR("invalid input type", K(ret), K(in), K(expect_type));
  } else if (in.get_collation_type() == params.expect_obj_collation_) {
    out = in;
  } else if (lib::is_oracle_mode() && in.is_blob_locator()) {
    ret = OB_NOT_SUPPORTED;
    LOG_ERROR("invalid use of blob type", K(ret), K(in), K(expect_type));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Blob cast to other type");
  } else if (lib::is_oracle_mode() && in.is_clob_locator() && CS_TYPE_BINARY == params.expect_obj_collation_) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("Can't convert collation type of clob to binary",
        K(ret),
        K(in),
        K(expect_type),
        K(params.expect_obj_collation_));
    LOG_USER_ERROR(OB_NOT_SUPPORTED, "Convert collation type of clob to binary");
  } else {
    ObString str;
    if (OB_FAIL(in.get_string(str))) {
      STORAGE_LOG(WARN, "Failed to get payload from lob locator", K(ret), K(in));
    } else {
      ObObj tmp_obj;
      tmp_obj.set_varchar(str);
      tmp_obj.set_collation_type(in.get_collation_type());
      if (OB_FAIL(string_lob(expect_type, params, tmp_obj, out, cast_mode, in.get_lob_locator()))) {
        LOG_WARN("string to rowid failed", K(ret), K(tmp_obj));
      }
    }
  }
  return ret;
}

ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = {
    {
        /*null -> XXX*/
        cast_identity,           /*null*/
        cast_identity,           /*int*/
        cast_identity,           /*uint*/
        cast_identity,           /*float*/
        cast_identity,           /*double*/
        cast_identity,           /*number*/
        cast_identity,           /*datetime*/
        cast_identity,           /*date*/
        cast_identity,           /*time*/
        cast_identity,           /*year*/
        cast_identity,           /*string*/
        cast_identity,           /*extend*/
        cast_identity,           /*unknown*/
        cast_identity,           /*text*/
        cast_identity,           /*bit*/
        cast_identity,           /*enumset*/
        cast_identity,           /*enumsetInner*/
        cast_identity,           /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        cast_identity,           /*lob*/
    },
    {
        /*int -> XXX*/
        cast_not_support,        /*null*/
        int_int,                 /*int*/
        int_uint,                /*uint*/
        int_float,               /*float*/
        int_double,              /*double*/
        int_number,              /*number*/
        int_datetime,            /*datetime*/
        int_date,                /*date*/
        int_time,                /*time*/
        int_year,                /*year*/
        int_string,              /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        int_string,              /*text*/
        int_bit,                 /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        int_lob,                 /*lob*/
    },
    {
        /*uint -> XXX*/
        cast_not_support,        /*null*/
        uint_int,                /*int*/
        uint_uint,               /*uint*/
        uint_float,              /*float*/
        uint_double,             /*double*/
        uint_number,             /*number*/
        uint_datetime,           /*datetime*/
        uint_date,               /*date*/
        uint_time,               /*time*/
        uint_year,               /*year*/
        uint_string,             /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        uint_string,             /*text*/
        uint_bit,                /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        uint_lob,                /*lob*/
    },
    {
        /*float -> XXX*/
        cast_not_support,        /*null*/
        float_int,               /*int*/
        float_uint,              /*uint*/
        float_float,             /*float*/
        float_double,            /*double*/
        float_number,            /*number*/
        float_datetime,          /*datetime*/
        float_date,              /*date*/
        float_time,              /*time*/
        cast_not_support,        /*year*/
        float_string,            /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        float_string,            /*text*/
        float_bit,               /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        float_lob,               /*lob*/
    },
    {
        /*double -> XXX*/
        cast_not_support,        /*null*/
        double_int,              /*int*/
        double_uint,             /*uint*/
        double_float,            /*float*/
        double_double,           /*double*/
        double_number,           /*number*/
        double_datetime,         /*datetime*/
        double_date,             /*date*/
        double_time,             /*time*/
        double_year,             /*year*/
        double_string,           /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        double_string,           /*text*/
        double_bit,              /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        double_lob,              /*lob*/
    },
    {
        /*number -> XXX*/
        cast_not_support,        /*null*/
        number_int,              /*int*/
        number_uint,             /*uint*/
        number_float,            /*float*/
        number_double,           /*double*/
        number_number,           /*number*/
        number_datetime,         /*datetime*/
        number_date,             /*date*/
        number_time,             /*time*/
        number_year,             /*year*/
        number_string,           /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        number_string,           /*text*/
        number_bit,              /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        number_lob,              /*lob*/
    },
    {
        /*datetime -> XXX*/
        cast_not_support,        /*null*/
        datetime_int,            /*int*/
        datetime_uint,           /*uint*/
        datetime_float,          /*float*/
        datetime_double,         /*double*/
        datetime_number,         /*number*/
        datetime_datetime,       /*datetime*/
        datetime_date,           /*date*/
        datetime_time,           /*time*/
        datetime_year,           /*year*/
        datetime_string,         /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        datetime_string,         /*text*/
        datetime_bit,            /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        datetime_otimestamp,     /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        datetime_lob,            /*lob*/
    },
    {
        /*date -> XXX*/
        cast_not_support,        /*null*/
        date_int,                /*int*/
        date_uint,               /*uint*/
        date_float,              /*float*/
        date_double,             /*double*/
        date_number,             /*number*/
        date_datetime,           /*datetime*/
        cast_identity,           /*date*/
        date_time,               /*time*/
        date_year,               /*year*/
        date_string,             /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        date_string,             /*text*/
        date_bit,                /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        date_lob,                /*lob*/
    },
    {
        /*time -> XXX*/
        cast_not_support,        /*null*/
        time_int,                /*int*/
        time_uint,               /*uint*/
        time_float,              /*float*/
        time_double,             /*double*/
        time_number,             /*number*/
        time_datetime,           /*datetime*/
        time_date,               /*date*/
        cast_identity,           /*time*/
        cast_not_support,        /*year*/
        time_string,             /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        time_string,             /*text*/
        time_bit,                /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        time_lob,                /*lob*/
    },
    {
        /*year -> XXX*/
        cast_not_support,        /*null*/
        year_int,                /*int*/
        year_uint,               /*uint*/
        year_float,              /*float*/
        year_double,             /*double*/
        year_number,             /*number*/
        cast_not_support,        /*datetime*/
        year_date,               /*date*/
        cast_not_support,        /*time*/
        cast_identity,           /*year*/
        year_string,             /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        year_string,             /*text*/
        year_bit,                /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        year_lob,                /*lob*/
    },
    {
        /*string -> XXX*/
        cast_not_support,        /*null*/
        string_int,              /*int*/
        string_uint,             /*uint*/
        string_float,            /*float*/
        string_double,           /*double*/
        string_number,           /*number*/
        string_datetime,         /*datetime*/
        string_date,             /*date*/
        string_time,             /*time*/
        string_year,             /*year*/
        string_string,           /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        string_string,           /*text*/
        string_bit,              /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        string_otimestamp,       /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        string_lob,              /*lob*/
    },
    {
        /*extend -> XXX*/
        cast_not_support,        /*null*/
        cast_not_support,        /*int*/
        cast_not_support,        /*uint*/
        cast_not_support,        /*float*/
        cast_not_support,        /*double*/
        cast_not_support,        /*number*/
        cast_not_support,        /*datetime*/
        cast_not_support,        /*date*/
        cast_not_support,        /*time*/
        cast_not_support,        /*year*/
        cast_not_support,        /*string*/
        cast_identity,           /*extend*/
        cast_not_support,        /*unknown*/
        cast_not_support,        /*text*/
        cast_not_support,        /*bit*/
        cast_not_support,        /*enumset*/
        cast_not_support,        /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        cast_not_support,        /*lob*/
    },
    {
        /*unknown -> XXX*/
        unknown_other,           /*null*/
        unknown_other,           /*int*/
        unknown_other,           /*uint*/
        unknown_other,           /*float*/
        unknown_other,           /*double*/
        unknown_other,           /*number*/
        unknown_other,           /*datetime*/
        unknown_other,           /*date*/
        unknown_other,           /*time*/
        unknown_other,           /*year*/
        unknown_other,           /*string*/
        unknown_other,           /*extend*/
        cast_identity,           /*unknown*/
        cast_not_support,        /*text*/
        unknown_other,           /*bit*/
        unknown_other,           /*enumset*/
        unknown_other,           /*enumsetInner*/
        unknown_other,           /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        cast_not_support,        /*lob*/
    },
    {
        /*text -> XXX*/
        cast_not_support,        /*null*/
        string_int,              /*int*/
        string_uint,             /*uint*/
        string_float,            /*float*/
        string_double,           /*double*/
        string_number,           /*number*/
        string_datetime,         /*datetime*/
        string_date,             /*date*/
        string_time,             /*time*/
        string_year,             /*year*/
        string_string,           /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        string_string,           /*text*/
        string_bit,              /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        string_otimestamp,       /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        string_lob,              /*lob*/
    },
    {
        /*bit -> XXX*/
        cast_not_support,        /*null*/
        bit_int,                 /*int*/
        bit_uint,                /*uint*/
        bit_float,               /*float*/
        bit_double,              /*double*/
        bit_number,              /*number*/
        bit_datetime,            /*datetime*/
        bit_date,                /*date*/
        bit_time,                /*time*/
        bit_year,                /*year*/
        bit_string,              /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        bit_string,              /*text*/
        bit_bit,                 /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        bit_lob,                 /*lob*/
    },
    {
        /*enum -> XXX*/
        cast_not_support,        /*null*/
        enumset_int,             /*int*/
        enumset_uint,            /*uint*/
        enumset_float,           /*float*/
        enumset_double,          /*double*/
        enumset_number,          /*number*/
        cast_not_expected,       /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        enumset_year,            /*year*/
        cast_not_expected,       /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        cast_not_expected,       /*text*/
        enumset_bit,             /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        cast_not_expected,       /*lob*/
    },
    {
        /*enumset_inner -> XXX*/
        cast_not_support,        /*null*/
        enumset_inner_int,       /*int*/
        enumset_inner_uint,      /*uint*/
        enumset_inner_float,     /*float*/
        enumset_inner_double,    /*double*/
        enumset_inner_number,    /*number*/
        enumset_inner_datetime,  /*datetime*/
        enumset_inner_date,      /*date*/
        enumset_inner_time,      /*time*/
        enumset_inner_year,      /*year*/
        enumset_inner_string,    /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        cast_not_support,        /*text*/
        enumset_inner_bit,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_expected,       /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        cast_not_support,        /*lob*/
    },
    {
        /*otimestamp -> XXX*/
        cast_not_expected,       /*null*/
        cast_not_expected,       /*int*/
        cast_not_expected,       /*uint*/
        cast_not_expected,       /*float*/
        cast_not_expected,       /*double*/
        cast_not_expected,       /*number*/
        cast_not_expected,       /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        cast_not_expected,       /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_not_expected,       /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        otimestamp_otimestamp,   /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        cast_not_expected,       /*lob*/
    },
    {
        /*raw -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*interval -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*rowid -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*lob -> XXX*/
        cast_not_support,        /*null*/
        lob_int,                 /*int*/
        lob_uint,                /*uint*/
        lob_float,               /*float*/
        lob_double,              /*double*/
        lob_number,              /*number*/
        lob_datetime,            /*datetime*/
        lob_date,                /*date*/
        lob_time,                /*time*/
        lob_year,                /*year*/
        lob_string,              /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        lob_string,              /*text*/
        lob_bit,                 /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        lob_otimestamp,          /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_not_expected,       /*interval*/
        cast_not_expected,       /*rowid*/
        lob_lob,                 /*lob*/
    },
};

ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = {
    {
        /*null -> XXX*/
        cast_identity, /*null*/
        cast_identity, /*int*/
        cast_identity, /*uint*/
        cast_identity, /*float*/
        cast_identity, /*double*/
        cast_identity, /*number*/
        cast_identity, /*datetime*/
        cast_identity, /*date*/
        cast_identity, /*time*/
        cast_identity, /*year*/
        cast_identity, /*string*/
        cast_identity, /*extend*/
        cast_identity, /*unknown*/
        cast_identity, /*text*/
        cast_identity, /*bit*/
        cast_identity, /*enumset*/
        cast_identity, /*enumsetInner*/
        cast_identity, /*otimestamp*/
        cast_identity, /*raw*/
        cast_identity, /*interval*/
        cast_identity, /*rowid*/
        cast_identity, /*lob*/
    },
    {
        /*int -> XXX*/
        cast_not_support,        /*null*/
        int_int,                 /*int*/
        int_uint,                /*uint*/
        int_float,               /*float*/
        int_double,              /*double*/
        int_number,              /*number*/
        cast_not_support,        /*datetime*/
        cast_not_support,        /*date*/
        cast_not_support,        /*time*/
        cast_not_support,        /*year*/
        int_string,              /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        int_string,              /*text*/
        int_bit,                 /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_not_support,        /*raw*/
        cast_not_support,        /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*uint -> XXX*/
        cast_not_support,        /*null*/
        uint_int,                /*int*/
        uint_uint,               /*uint*/
        uint_float,              /*float*/
        uint_double,             /*double*/
        uint_number,             /*number*/
        cast_not_support,        /*datetime*/
        cast_not_support,        /*date*/
        cast_not_support,        /*time*/
        cast_not_support,        /*year*/
        uint_string,             /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        uint_string,             /*text*/
        uint_bit,                /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_not_support,        /*raw*/
        cast_not_support,        /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*float -> XXX*/
        cast_not_support,        /*null*/
        float_int,               /*int*/
        float_uint,              /*uint*/
        float_float,             /*float*/
        float_double,            /*double*/
        float_number,            /*number*/
        cast_not_support,        /*datetime*/
        cast_not_support,        /*date*/
        cast_not_support,        /*time*/
        cast_not_support,        /*year*/
        float_string,            /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        float_string,            /*text*/
        float_bit,               /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_not_support,        /*raw*/
        cast_not_support,        /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*double -> XXX*/
        cast_not_support,        /*null*/
        double_int,              /*int*/
        double_uint,             /*uint*/
        double_float,            /*float*/
        double_double,           /*double*/
        double_number,           /*number*/
        cast_not_support,        /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_support,        /*time*/
        cast_not_support,        /*year*/
        double_string,           /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        double_string,           /*text*/
        double_bit,              /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_not_support,        /*raw*/
        cast_not_support,        /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*number -> XXX*/
        cast_not_support,        /*null*/
        number_int,              /*int*/
        number_uint,             /*uint*/
        number_float,            /*float*/
        number_double,           /*double*/
        number_number,           /*number*/
        cast_not_support,        /*datetime*/
        cast_not_support,        /*date*/
        cast_not_support,        /*time*/
        cast_not_support,        /*year*/
        number_string,           /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        number_string,           /*text*/
        number_bit,              /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_not_support,        /*raw*/
        cast_not_support,        /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*datetime -> XXX*/
        cast_not_support,        /*null*/
        cast_not_support,        /*int*/
        cast_not_support,        /*uint*/
        cast_not_support,        /*float*/
        cast_not_support,        /*double*/
        cast_not_support,        /*number*/
        datetime_datetime,       /*datetime*/
        cast_not_support,        /*date*/
        cast_not_support,        /*time*/
        cast_not_support,        /*year*/
        datetime_string,         /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        datetime_string,         /*text*/
        datetime_bit,            /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        datetime_otimestamp,     /*otimestamp*/
        cast_not_support,        /*raw*/
        cast_not_support,        /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*date -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*time -> XXX*/
        cast_not_support,  /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*year -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*string -> XXX*/
        cast_not_support,        /*null*/
        string_int,              /*int*/
        string_uint,             /*uint*/
        string_float,            /*float*/
        string_double,           /*double*/
        string_number,           /*number*/
        string_datetime,         /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        string_string,           /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        string_string,           /*text*/
        string_bit,              /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        string_otimestamp,       /*otimestamp*/
        string_raw,              /*raw*/
        string_interval,         /*interval*/
        string_rowid,            /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*extend -> XXX*/
        cast_not_support, /*null*/
        cast_not_support, /*int*/
        cast_not_support, /*uint*/
        cast_not_support, /*float*/
        cast_not_support, /*double*/
        cast_not_support, /*number*/
        cast_not_support, /*datetime*/
        cast_not_support, /*date*/
        cast_not_support, /*time*/
        cast_not_support, /*year*/
        cast_not_support, /*string*/
        cast_identity,    /*extend*/
        cast_not_support, /*unknown*/
        cast_not_support, /*text*/
        cast_not_support, /*bit*/
        cast_not_support, /*enumset*/
        cast_not_support, /*enumset_inner*/
        cast_not_support, /*otimestamp*/
        cast_not_support, /*raw*/
        cast_not_support, /*interval*/
        cast_not_support, /*rowid*/
        cast_not_support, /*lob*/
    },
    {
        /*unknown -> XXX*/
        unknown_other,    /*null*/
        unknown_other,    /*int*/
        unknown_other,    /*uint*/
        unknown_other,    /*float*/
        unknown_other,    /*double*/
        unknown_other,    /*number*/
        unknown_other,    /*datetime*/
        unknown_other,    /*date*/
        unknown_other,    /*time*/
        unknown_other,    /*year*/
        unknown_other,    /*string*/
        unknown_other,    /*extend*/
        cast_identity,    /*unknown*/
        cast_not_support, /*text*/
        unknown_other,    /*bit*/
        unknown_other,    /*enumset*/
        unknown_other,    /*enumsetInner*/
        unknown_other,    /*otimestamp*/
        unknown_other,    /*raw*/
        unknown_other,    /*interval*/
        unknown_other,    /*rowid*/
        cast_not_support, /*lob*/
    },
    {
        /*text -> XXX*/
        cast_not_support,        /*null*/
        string_int,              /*int*/
        string_uint,             /*uint*/
        string_float,            /*float*/
        string_double,           /*double*/
        string_number,           /*number*/
        string_datetime,         /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        string_string,           /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        string_string,           /*text*/
        string_bit,              /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        string_otimestamp,       /*otimestamp*/
        cast_not_support,        /*raw*/
        string_interval,         /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*bit -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*enum -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*enumset_inner -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*otimestamp -> XXX*/
        cast_not_support,        /*null*/
        cast_not_support,        /*int*/
        cast_not_support,        /*uint*/
        cast_not_support,        /*float*/
        cast_not_support,        /*double*/
        cast_not_support,        /*number*/
        otimestamp_datetime,     /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        otimestamp_string,       /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        otimestamp_string,       /*text*/
        cast_not_support,        /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        otimestamp_otimestamp,   /*otimestamp*/
        cast_not_support,        /*raw*/
        cast_not_support,        /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*raw -> XXX*/
        cast_not_support,        /*null*/
        cast_not_support,        /*int*/
        cast_not_support,        /*uint*/
        cast_not_support,        /*float*/
        cast_not_support,        /*double*/
        cast_not_support,        /*number*/
        cast_not_support,        /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        raw_string,              /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        raw_longtext,            /*text*/
        cast_not_support,        /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        raw_raw,                 /*raw*/
        cast_not_support,        /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*interval -> XXX*/
        cast_not_expected,       /*null*/
        cast_not_expected,       /*int*/
        cast_not_expected,       /*uint*/
        cast_not_expected,       /*float*/
        cast_not_expected,       /*double*/
        cast_not_expected,       /*number*/
        cast_not_expected,       /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        interval_string,         /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_not_expected,       /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_expected,       /*otimestamp*/
        cast_not_expected,       /*raw*/
        interval_interval,       /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*rowid -> XXX*/
        cast_not_support,        /*null*/
        cast_not_support,        /*int*/
        cast_not_support,        /*uint*/
        cast_not_support,        /*float*/
        cast_not_support,        /*double*/
        cast_not_support,        /*number*/
        cast_not_support,        /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        rowid_string,            /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_not_expected,       /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_not_support,        /*otimestamp*/
        cast_not_support,        /*raw*/
        cast_not_support,        /*interval*/
        rowid_rowid,             /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*lob -> XXX*/
        cast_not_support,        /*null*/
        lob_int,                 /*int*/
        lob_uint,                /*uint*/
        lob_float,               /*float*/
        lob_double,              /*double*/
        lob_number,              /*number*/
        lob_datetime,            /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        lob_string,              /*string*/
        cast_not_support,        /*extend*/
        cast_not_support,        /*unknown*/
        lob_string,              /*text*/
        lob_bit,                 /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        lob_otimestamp,          /*otimestamp*/
        cast_not_support,        /*raw*/
        lob_interval,            /*interval*/
        cast_not_support,        /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
};

/*
 * 1. I think not_support() means something we will support in future, and cast_not_expected() means
 *    something wrong, so there is no not_support() appears in OBJ_CAST_ORACLE_IMPLICIT now.
 * 2. int and uint are needed in inner operation, for example, some system variable is uint,
 *    like auto_increment_increment, which will be cast to uint in load_default_sys_variable().
 *    so this matrix allows cast from or to int / uint.
 * 3. we can't use ObObjOType as index of this matrix, because int / uint too.
 */
ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = {
    {
        /*null -> XXX*/
        cast_identity,     /*null*/
        cast_identity,     /*int*/
        cast_identity,     /*uint*/
        cast_identity,     /*float*/
        cast_identity,     /*double*/
        cast_identity,     /*number*/
        cast_identity,     /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_identity,     /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_identity,     /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumsetInner*/
        cast_identity,     /*otimestamp*/
        cast_identity,     /*raw*/
        cast_identity,     /*interval*/
        cast_identity,     /*rowid*/
        cast_identity,     /*lob*/
    },
    {
        /*int -> XXX*/
        cast_not_expected,       /*null*/
        int_int,                 /*int*/
        int_uint,                /*uint*/
        int_float,               /*float*/
        int_double,              /*double*/
        int_number,              /*number*/
        cast_inconsistent_types, /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        int_string,              /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_inconsistent_types, /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_inconsistent_types, /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_inconsistent_types, /*interval*/
        cast_inconsistent_types, /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*uint -> XXX*/
        cast_not_expected,       /*null*/
        uint_int,                /*int*/
        uint_uint,               /*uint*/
        uint_float,              /*float*/
        uint_double,             /*double*/
        uint_number,             /*number*/
        cast_inconsistent_types, /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        uint_string,             /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_inconsistent_types, /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_inconsistent_types, /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_inconsistent_types, /*interval*/
        cast_inconsistent_types, /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*float -> XXX*/
        cast_not_expected,       /*null*/
        float_int,               /*int*/
        float_uint,              /*uint*/
        float_float,             /*float*/
        float_double,            /*double*/
        float_number,            /*number*/
        cast_inconsistent_types, /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        float_string,            /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_inconsistent_types, /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_inconsistent_types, /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_inconsistent_types, /*interval*/
        cast_inconsistent_types, /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*double -> XXX*/
        cast_not_expected,       /*null*/
        double_int,              /*int*/
        double_uint,             /*uint*/
        double_float,            /*float*/
        double_double,           /*double*/
        double_number,           /*number*/
        cast_inconsistent_types, /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        double_string,           /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_inconsistent_types, /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_inconsistent_types, /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_inconsistent_types, /*interval*/
        cast_inconsistent_types, /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*number -> XXX*/
        cast_not_expected,       /*null*/
        number_int,              /*int*/
        number_uint,             /*uint*/
        number_float,            /*float*/
        number_double,           /*double*/
        number_number,           /*number*/
        cast_inconsistent_types, /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        number_string,           /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        number_string,           /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_inconsistent_types, /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_inconsistent_types, /*interval*/
        cast_inconsistent_types, /*rowid*/
        number_lob,              /*lob*/
    },
    {
        /*datetime -> XXX*/
        cast_not_expected,       /*null*/
        cast_inconsistent_types, /*int*/
        cast_inconsistent_types, /*uint*/
        cast_inconsistent_types, /*float*/
        cast_inconsistent_types, /*double*/
        cast_inconsistent_types, /*number*/
        datetime_datetime,       /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        datetime_string,         /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_inconsistent_types, /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        datetime_otimestamp,     /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_inconsistent_types, /*interval*/
        cast_inconsistent_types, /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*date -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*time -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*year -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*string -> XXX*/
        cast_not_expected, /*null*/
        string_int,        /*int*/
        string_uint,       /*uint*/
        string_float,      /*float*/
        string_double,     /*double*/
        string_number,     /*number*/
        string_datetime,   /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        string_string,     /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        string_string,     /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        string_otimestamp, /*otimestamp*/
        string_raw,        /*raw*/
        string_interval,   /*interval*/
        string_rowid,      /*rowid*/
        string_lob,        /*lob*/
    },
    {
        /*extend -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_identity,     /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*unknown -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*text -> XXX*/
        cast_not_expected,       /*null*/
        string_int,              /*int*/
        string_uint,             /*uint*/
        string_float,            /*float*/
        string_double,           /*double*/
        cast_not_support,        /*number*/
        string_datetime,         /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        string_string,           /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        string_string,           /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        string_otimestamp,       /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        string_interval,         /*interval*/
        string_rowid,            /*rowid*/
        string_lob,              /*lob*/
    },
    {
        /*bit -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*enum -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*enumset_inner -> XXX*/
        cast_not_expected, /*null*/
        cast_not_expected, /*int*/
        cast_not_expected, /*uint*/
        cast_not_expected, /*float*/
        cast_not_expected, /*double*/
        cast_not_expected, /*number*/
        cast_not_expected, /*datetime*/
        cast_not_expected, /*date*/
        cast_not_expected, /*time*/
        cast_not_expected, /*year*/
        cast_not_expected, /*string*/
        cast_not_expected, /*extend*/
        cast_not_expected, /*unknown*/
        cast_not_expected, /*text*/
        cast_not_expected, /*bit*/
        cast_not_expected, /*enumset*/
        cast_not_expected, /*enumset_inner*/
        cast_not_expected, /*otimestamp*/
        cast_not_expected, /*raw*/
        cast_not_expected, /*interval*/
        cast_not_expected, /*rowid*/
        cast_not_expected, /*lob*/
    },
    {
        /*otimestamp -> XXX*/
        cast_not_expected,       /*null*/
        cast_inconsistent_types, /*int*/
        cast_inconsistent_types, /*uint*/
        cast_inconsistent_types, /*float*/
        cast_inconsistent_types, /*double*/
        cast_inconsistent_types, /*number*/
        otimestamp_datetime,     /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        otimestamp_string,       /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_inconsistent_types, /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        otimestamp_otimestamp,   /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_inconsistent_types, /*interval*/
        cast_inconsistent_types, /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*raw -> XXX*/
        cast_not_expected,       /*null*/
        cast_inconsistent_types, /*int*/
        cast_inconsistent_types, /*uint*/
        cast_inconsistent_types, /*float*/
        cast_inconsistent_types, /*double*/
        cast_inconsistent_types, /*number*/
        cast_inconsistent_types, /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        raw_string,              /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        raw_longtext,            /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_inconsistent_types, /*otimestamp*/
        raw_raw,                 /*raw*/
        cast_inconsistent_types, /*interval*/
        cast_inconsistent_types, /*rowid*/
        raw_lob,                 /*lob*/
    },
    {
        /*interval -> XXX*/
        cast_not_expected,       /*null*/
        cast_inconsistent_types, /*int*/
        cast_inconsistent_types, /*uint*/
        cast_inconsistent_types, /*float*/
        cast_inconsistent_types, /*double*/
        cast_inconsistent_types, /*number*/
        cast_inconsistent_types, /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        interval_string,         /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_inconsistent_types, /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_inconsistent_types, /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        interval_interval,       /*interval*/
        cast_inconsistent_types, /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /* rowid -> XXX */
        cast_not_expected,       /*null*/
        cast_inconsistent_types, /*int*/
        cast_inconsistent_types, /*uint*/
        cast_inconsistent_types, /*float*/
        cast_inconsistent_types, /*double*/
        cast_inconsistent_types, /*number*/
        cast_inconsistent_types, /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        rowid_string,            /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        cast_inconsistent_types, /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        cast_inconsistent_types, /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        cast_inconsistent_types, /*interval*/
        rowid_rowid,             /*rowid*/
        cast_inconsistent_types, /*lob*/
    },
    {
        /*lob -> XXX*/
        cast_not_expected,       /*null*/
        lob_int,                 /*int*/
        lob_uint,                /*uint*/
        lob_float,               /*float*/
        lob_double,              /*double*/
        cast_not_support,        /*number*/
        lob_datetime,            /*datetime*/
        cast_not_expected,       /*date*/
        cast_not_expected,       /*time*/
        cast_not_expected,       /*year*/
        lob_string,              /*string*/
        cast_not_expected,       /*extend*/
        cast_not_expected,       /*unknown*/
        lob_string,              /*text*/
        cast_not_expected,       /*bit*/
        cast_not_expected,       /*enumset*/
        cast_not_expected,       /*enumset_inner*/
        lob_otimestamp,          /*otimestamp*/
        cast_inconsistent_types, /*raw*/
        lob_interval,            /*interval*/
        lob_rowid,               /*rowid*/
        lob_lob,                 /*lob*/
    },
};

////////////////////////////////////////////////////////////////
bool cast_supported(const ObObjType orig_type, const ObCollationType orig_cs_type, const ObObjType expect_type,
    const ObCollationType expect_cs_type)
{
  bool bret = false;
  bool clob_in = ob_is_clob(orig_type, orig_cs_type) || ob_is_clob_locator(orig_type, orig_cs_type);
  bool blob_out = ob_is_blob(expect_type, expect_cs_type) || ob_is_blob_locator(expect_type, expect_cs_type);
  if (OB_UNLIKELY(ob_is_invalid_obj_type(orig_type) || ob_is_invalid_obj_type(expect_type))) {
    LOG_WARN("invalid cast type", K(orig_type), K(expect_type));
    // number can be casted to clob, but can not casted to blob,
    // OB_OBJ_CAST and OBJ_CAST_ORACLE_IMPLICIT can not support this rule.
  } else if (is_oracle_mode() && (clob_in || ob_is_number_tc(orig_type)) && blob_out) {
    bret = false;
  } else {
    ObObjTypeClass orig_tc = ob_obj_type_class(orig_type);
    ObObjTypeClass expect_tc = ob_obj_type_class(expect_type);
    if (ObIntervalTC == orig_tc && ObIntervalTC == expect_tc && orig_type != expect_type) {
      bret = false;
      LOG_WARN("cast between intervalYM and intervalDS not allowed", K(bret), K(orig_type), K(expect_type));
    } else {
      ObObjCastFunc cast_func =
          lib::is_oracle_mode() ? OBJ_CAST_ORACLE_IMPLICIT[orig_tc][expect_tc] : OB_OBJ_CAST[orig_tc][expect_tc];
      bret = (cast_func != cast_not_support && cast_func != cast_inconsistent_types);
    }
  }
  return bret;
}

int float_range_check(ObObjCastParams& params, const ObAccuracy& accuracy, const ObObj& obj, ObObj& buf_obj,
    const ObObj*& res_obj, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  float value = obj.get_float();
  res_obj = &obj;
  if (lib::is_oracle_mode() && 0.0 == value) {
    value = 0.0;
    buf_obj.set_float(obj.get_type(), value);
    res_obj = &buf_obj;
  } else {
    if (CAST_FAIL(real_range_check(accuracy, value))) {
    } else if (obj.get_float() != value) {
      buf_obj.set_float(obj.get_type(), value);
      res_obj = &buf_obj;
    }
  }
  return ret;
}

int double_check_precision(ObObjCastParams& params, const ObAccuracy& accuracy, const ObObj& obj, ObObj& buf_obj,
    const ObObj*& res_obj, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  double value = obj.get_double();
  res_obj = &obj;
  if (lib::is_oracle_mode() && 0.0 == value) {
    value = 0.0;
    buf_obj.set_double(obj.get_type(), value);
    res_obj = &buf_obj;
  } else if (CAST_FAIL(real_range_check(accuracy, value))) {
  } else if (obj.get_double() != value) {
    buf_obj.set_double(obj.get_type(), value);
    res_obj = &buf_obj;
  }
  return ret;
}

int number_range_check(ObObjCastParams& params, const ObAccuracy& accuracy, const ObObj& obj, ObObj& buf_obj,
    const ObObj*& res_obj, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  res_obj = NULL;
  static const int64_t BUFFER_SIZE = 2 * (number::ObNumber::MAX_SCALE + number::ObNumber::MAX_PRECISION);
  if (OB_ISNULL(params.allocator_v2_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid allocator", K(ret), K(params.allocator_v2_), K(obj));
  } else {
    int& cast_ret = CM_IS_ERROR_ON_FAIL(cast_mode) ? ret : params.warning_;
    ObPrecision precision = accuracy.get_precision();
    ObScale scale = accuracy.get_scale();
    ObIAllocator& allocator = *params.allocator_v2_;
    res_obj = &obj;
    if (OB_UNLIKELY(precision < scale)) {
      ret = OB_ERR_M_BIGGER_THAN_D;
    } else if (number::ObNumber::MAX_PRECISION >= precision && number::ObNumber::MAX_SCALE >= scale && precision >= 0 &&
               scale >= 0) {
      // prepare string like "99.999".
      char buf[BUFFER_SIZE] = {0};
      int pos = 0;
      buf[pos++] = '-';
      if (precision == scale) {
        buf[pos++] = '0';
      }
      MEMSET(buf + pos, '9', precision + 1);
      buf[pos + precision - scale] = '.';
      // make min and max numbers.
      number::ObNumber min_num;
      number::ObNumber max_num;
      number::ObNumber in_val = obj.get_number();
      number::ObNumber out_val;
      if (OB_FAIL(min_num.from(buf, allocator))) {
      } else if (OB_FAIL(max_num.from(buf + 1, allocator))) {
      } else if (in_val < min_num) {
        cast_ret = OB_DATA_OUT_OF_RANGE;
        buf_obj.set_number(obj.get_type(), min_num);
      } else if (in_val > max_num) {
        cast_ret = OB_DATA_OUT_OF_RANGE;
        buf_obj.set_number(obj.get_type(), max_num);
      } else if (OB_FAIL(out_val.from(in_val, allocator))) {
      } else if (OB_FAIL(out_val.round(scale))) {
      } else {
        buf_obj.set_number(obj.get_type(), out_val);
      }
      res_obj = &buf_obj;
    } else {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("invalid arguments", K(ret), K(precision), K(scale));
    }
  }
  return ret;
}

int number_range_check_for_oracle(ObObjCastParams& params, const ObAccuracy& accuracy, const ObObj& obj, ObObj& buf_obj,
    const ObObj*& res_obj, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  res_obj = NULL;
  static const int64_t BUFFER_SIZE = 2 * (number::ObNumber::MAX_SCALE + number::ObNumber::MAX_PRECISION);
  if (OB_ISNULL(params.allocator_v2_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid allocator", K(ret), K(params.allocator_v2_), K(obj));
  } else {
    int& cast_ret = CM_IS_ERROR_ON_FAIL(cast_mode) ? ret : params.warning_;
    ObPrecision precision = accuracy.get_precision();
    ObScale scale = accuracy.get_scale();
    ObIAllocator& allocator = *params.allocator_v2_;
    res_obj = &obj;
    if (number::ObNumber::MAX_PRECISION >= precision && number::ObNumber::MAX_SCALE >= scale && precision >= 1 &&
        scale >= number::ObNumber::MIN_SCALE) {
      // make min and max numbers.
      number::ObNumber min_num;
      number::ObNumber max_num;
      number::ObNumber in_val = obj.get_number();
      bool trunc_max_zero = false;
      bool trunc_min_zero = false;
      // prepare string like "99.999".
      char buf[BUFFER_SIZE] = {0};
      int pos = 0;
      buf[pos++] = '-';
      if (precision >= scale && scale >= 0) {
        /* number(3, 1) => legal range(-99.95, 99.95) */
        if (precision == scale) {
          buf[pos++] = '0';
        }
        MEMSET(buf + pos, '9', precision + 1);
        buf[pos + precision - scale] = '.';
        buf[pos + precision + 1] = '5';

        if (OB_FAIL(min_num.from(buf, allocator))) {
        } else if (OB_FAIL(max_num.from(buf + 1, allocator))) {
        }
      } else {
        if (scale < 0) {
          /* number(2, -3) => legal range: (-99500, 99500) */
          MEMSET(buf + pos, '9', precision);
          buf[pos + precision] = '5';
          MEMSET(buf + pos + precision + 1, '0', 0 - scale - 1);
          if (OB_FAIL(min_num.from(buf, allocator))) {
          } else if (OB_FAIL(max_num.from(buf + 1, allocator))) {
          }
        } else {
          // number(2, 3) => legal range:[0, 0.0995) && (-0.00995, 0]

          buf[pos++] = '0';
          buf[pos++] = '.';
          MEMSET(buf + pos, '0', scale - precision);
          MEMSET(buf + pos + scale - precision, '9', precision);
          buf[pos + scale] = '5';
          if (in_val.is_negative()) {
            trunc_max_zero = true;
            if (OB_FAIL(min_num.from(buf, allocator))) {
              LOG_DEBUG("fail to get num from ", K(buf));
            } else {
              MEMSET(buf + pos + scale - precision, '0', precision);
              if (OB_FAIL(max_num.from(buf, allocator))) {
                LOG_DEBUG("fail to get num from ", K(buf));
              }
            }
          } else {
            trunc_min_zero = true;
            if (OB_FAIL(max_num.from(buf + 1, allocator))) {
              LOG_DEBUG("fail to get num from ", K(buf + 1));
            } else {
              MEMSET(buf + pos + scale - precision, '0', precision);
              if (OB_FAIL(min_num.from(buf + 1, allocator))) {
                LOG_DEBUG("fail to get num from ", K(buf + 1));
              }
            }
          }
        }
      }
      LOG_DEBUG("BUF", KP(buf), K(precision), K(scale), K(min_num), K(max_num), K(trunc_min_zero), K(trunc_max_zero));

      number::ObNumber out_val;
      if (OB_SUCC(ret)) {
        if (in_val <= min_num) {
          if (trunc_min_zero) {
            min_num.set_zero();
            LOG_DEBUG("set min zero");
          } else {
            cast_ret = OB_DATA_OUT_OF_RANGE;
          }
          buf_obj.set_number(obj.get_type(), min_num);
        } else if (in_val >= max_num) {
          if (trunc_max_zero) {
            max_num.set_zero();
          } else {
            cast_ret = OB_DATA_OUT_OF_RANGE;
          }
          buf_obj.set_number(obj.get_type(), max_num);
        } else if (OB_FAIL(out_val.from(in_val, allocator))) {
        } else if (OB_FAIL(out_val.round(scale))) {
        } else {
          buf_obj.set_number(obj.get_type(), out_val);
        }
      }
      res_obj = &buf_obj;
    } else if (ORA_NUMBER_SCALE_UNKNOWN_YET == scale && PRECISION_UNKNOWN_YET == precision) {
      buf_obj.set_number(obj.get_type(), obj.get_number());
      res_obj = &buf_obj;
      LOG_DEBUG("unknown scale and precision", K(obj.get_scale()), K(obj), K(buf_obj));
    } else {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("invalid arguments", K(ret), K(precision), K(scale));
    }
  }
  return ret;
}

int number_range_check_v2(ObObjCastParams& params, const ObAccuracy& accuracy, const ObObj& obj, ObObj& buf_obj,
    const ObObj*& res_obj, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  res_obj = NULL;
  if (OB_ISNULL(params.allocator_v2_)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid allocator", K(ret), K(params.allocator_v2_), K(obj));
  } else {
    int& cast_ret = CM_IS_ERROR_ON_FAIL(cast_mode) ? ret : params.warning_;
    ObPrecision precision = accuracy.get_precision();
    ObScale scale = accuracy.get_scale();
    ObIAllocator& allocator = *params.allocator_v2_;
    res_obj = &obj;
    const number::ObNumber& in_val = obj.get_number();
    const number::ObNumber* min_check_num = NULL;
    const number::ObNumber* max_check_num = NULL;
    const number::ObNumber* min_num_mysql = NULL;
    const number::ObNumber* max_num_mysql = NULL;
    number::ObNumber out_val;
    bool is_finish = false;
    if (obj.is_number_float()) {
      if (OB_MIN_NUMBER_FLOAT_PRECISION <= precision && precision <= OB_MAX_NUMBER_FLOAT_PRECISION) {
        const int64_t number_precision = static_cast<int64_t>(floor(precision * OB_PRECISION_BINARY_TO_DECIMAL_FACTOR));
        if (OB_FAIL(out_val.from(in_val, allocator))) {
        } else if (OB_FAIL(out_val.round_precision(number_precision))) {
        } else {
          buf_obj.set_number(obj.get_type(), out_val);
          res_obj = &buf_obj;
          is_finish = true;
        }
        LOG_DEBUG("finish round_precision", K(in_val), K(number_precision), K(precision), K(buf_obj));
      } else if (PRECISION_UNKNOWN_YET == precision) {
        buf_obj.set_number(obj.get_type(), in_val);
        res_obj = &buf_obj;
        is_finish = true;
      } else {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("invalid arguments", K(ret), K(precision), K(scale));
      }
    } else if (lib::is_oracle_mode()) {
      if (OB_MAX_NUMBER_PRECISION >= precision && precision >= OB_MIN_NUMBER_PRECISION &&
          number::ObNumber::MAX_SCALE >= scale && scale >= number::ObNumber::MIN_SCALE) {
        min_check_num =
            &(ObNumberConstValue::ORACLE_CHECK_MIN[precision][scale + ObNumberConstValue::MAX_ORACLE_SCALE_DELTA]);
        max_check_num =
            &(ObNumberConstValue::ORACLE_CHECK_MAX[precision][scale + ObNumberConstValue::MAX_ORACLE_SCALE_DELTA]);
      } else if (ORA_NUMBER_SCALE_UNKNOWN_YET == scale && PRECISION_UNKNOWN_YET == precision) {
        buf_obj.set_number(obj.get_type(), in_val);
        res_obj = &buf_obj;
        is_finish = true;
      } else if (PRECISION_UNKNOWN_YET == precision && number::ObNumber::MAX_SCALE >= scale &&
                 scale >= number::ObNumber::MIN_SCALE) {
        number::ObNumber num;
        if (OB_FAIL(num.from(obj.get_number(), allocator))) {
        } else if (OB_FAIL(num.round(scale))) {
        } else {
          buf_obj.set_number(obj.get_type(), num);
          res_obj = &buf_obj;
          is_finish = true;
        }
      } else {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("invalid arguments", K(ret), K(precision), K(scale));
      }
    } else {
      if (OB_UNLIKELY(precision < scale)) {
        ret = OB_ERR_M_BIGGER_THAN_D;
      } else if (number::ObNumber::MAX_PRECISION >= precision && precision >= OB_MIN_DECIMAL_PRECISION &&
                 number::ObNumber::MAX_SCALE >= scale && scale >= 0) {
        min_check_num = &(ObNumberConstValue::MYSQL_CHECK_MIN[precision][scale]);
        max_check_num = &(ObNumberConstValue::MYSQL_CHECK_MAX[precision][scale]);
        min_num_mysql = &(ObNumberConstValue::MYSQL_MIN[precision][scale]);
        max_num_mysql = &(ObNumberConstValue::MYSQL_MAX[precision][scale]);
      } else {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("invalid arguments", K(ret), K(precision), K(scale));
      }
    }

    if (OB_SUCC(ret) && !is_finish) {
      if (OB_ISNULL(min_check_num) || OB_ISNULL(max_check_num) ||
          (!lib::is_oracle_mode() && (OB_ISNULL(min_num_mysql) || OB_ISNULL(max_num_mysql)))) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("min_num or max_num is null", K(ret), KPC(min_check_num), KPC(max_check_num));
      } else if (in_val <= *min_check_num) {
        if (lib::is_oracle_mode()) {
          cast_ret = OB_ERR_VALUE_LARGER_THAN_ALLOWED;
        } else {
          cast_ret = OB_DATA_OUT_OF_RANGE;
          buf_obj.set_number(obj.get_type(), *min_num_mysql);
        }
      } else if (in_val >= *max_check_num) {
        if (lib::is_oracle_mode()) {
          cast_ret = OB_ERR_VALUE_LARGER_THAN_ALLOWED;
        } else {
          cast_ret = OB_DATA_OUT_OF_RANGE;
          buf_obj.set_number(obj.get_type(), *max_num_mysql);
        }
        // need round
      } else {
        if (OB_FAIL(out_val.from(in_val, allocator))) {
        } else if (OB_FAIL(out_val.round(scale))) {
        } else {
          buf_obj.set_number(obj.get_type(), out_val);
        }
      }
    }
    LOG_DEBUG("succ to number_range_check_v2",
        K(ret),
        K(cast_ret),
        K(is_finish),
        K(precision),
        K(scale),
        KPC(min_check_num),
        KPC(max_check_num),
        KPC(min_num_mysql),
        KPC(max_num_mysql),
        K(in_val),
        K(obj),
        K(buf_obj));
    res_obj = &buf_obj;
  }
  return ret;
}

int number_range_check_only(const ObAccuracy& accuracy, const ObObj& obj)
{
  int ret = OB_SUCCESS;
  UNUSED(obj);
  ObPrecision precision = accuracy.get_precision();
  ObScale scale = accuracy.get_scale();
  if (OB_UNLIKELY(precision < scale)) {
    ret = OB_ERR_M_BIGGER_THAN_D;
  } else if (number::ObNumber::MAX_PRECISION >= precision && number::ObNumber::MAX_SCALE >= scale && precision >= 0 &&
             scale >= 0) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("number range check not supported", K(ret));
  } else {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid arguments", K(ret), K(precision), K(scale));
  }
  return ret;
}

int datetime_scale_check(ObObjCastParams& params, const ObAccuracy& accuracy, const ObObj& obj, ObObj& buf_obj,
    const ObObj*& res_obj, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  res_obj = NULL;
  ObScale scale = accuracy.get_scale();
  if (OB_UNLIKELY(scale > MAX_SCALE_FOR_TEMPORAL)) {
    ret = OB_ERR_TOO_BIG_PRECISION;
    LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, scale, "CAST", static_cast<int64_t>(MAX_SCALE_FOR_TEMPORAL));
  } else if (OB_UNLIKELY(0 <= scale && scale < MAX_SCALE_FOR_TEMPORAL)) {
    int64_t value = obj.get_datetime();
    ObTimeConverter::round_datetime(scale, value);
    if (ObTimeConverter::is_valid_datetime(value)) {
      buf_obj.set_datetime(obj.get_type(), value);
    } else {
      buf_obj.set_null();
    }
    res_obj = &buf_obj;
  } else {
    res_obj = &obj;
  }
  UNUSED(params);
  UNUSED(cast_mode);
  return ret;
}

int otimestamp_scale_check(ObObjCastParams& params, const ObAccuracy& accuracy, const ObObj& obj, ObObj& buf_obj,
    const ObObj*& res_obj, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  res_obj = NULL;
  ObScale scale = accuracy.get_scale();
  if (OB_UNLIKELY(scale > MAX_SCALE_FOR_ORACLE_TEMPORAL)) {
    ret = OB_ERR_TOO_BIG_PRECISION;
    LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, scale, "CAST", static_cast<int64_t>(MAX_SCALE_FOR_ORACLE_TEMPORAL));
  } else if (OB_UNLIKELY(0 <= scale && scale < MAX_SCALE_FOR_ORACLE_TEMPORAL)) {
    ObOTimestampData ot_data = ObTimeConverter::round_otimestamp(scale, obj.get_otimestamp_value());
    if (ObTimeConverter::is_valid_otimestamp(ot_data.time_us_, static_cast<int32_t>(ot_data.time_ctx_.tail_nsec_))) {
      buf_obj.set_otimestamp_value(obj.get_type(), ot_data);
      buf_obj.set_scale(scale);
    } else {
      OB_LOG(DEBUG, "invalid otimestamp, set it null ", K(ot_data), K(scale), "orig_date", obj.get_otimestamp_value());
      buf_obj.set_null();
    }
    res_obj = &buf_obj;
  } else {
    res_obj = &obj;
  }
  UNUSED(params);
  UNUSED(cast_mode);
  return ret;
}

int interval_scale_check(ObObjCastParams& params, const ObAccuracy& accuracy, const ObObj& obj, ObObj& buf_obj,
    const ObObj*& res_obj, const ObCastMode cast_mode)
{
  UNUSED(cast_mode);
  UNUSED(params);
  int ret = OB_SUCCESS;
  res_obj = NULL;
  ObScale expected_scale = accuracy.get_scale();
  buf_obj = obj;

  if (obj.is_interval_ym()) {
    int8_t expected_year_scale =
        ObIntervalScaleUtil::ob_scale_to_interval_ym_year_scale(static_cast<int8_t>(expected_scale));
    int8_t input_year_scale = obj.get_interval_ym().calc_leading_scale();
    if (OB_UNLIKELY(expected_year_scale < input_year_scale)) {
      ret = OB_ERR_THE_LEADING_PRECISION_OF_THE_INTERVAL_IS_TOO_SMALL;
      LOG_WARN("interval obj scale check", K(ret), K(expected_year_scale), K(input_year_scale));
    }
  } else if (obj.is_interval_ds()) {
    ObIntervalDSValue value = obj.get_interval_ds();
    int8_t expected_day_scale =
        ObIntervalScaleUtil::ob_scale_to_interval_ds_day_scale(static_cast<int8_t>(expected_scale));
    int8_t expected_fs_scale =
        ObIntervalScaleUtil::ob_scale_to_interval_ds_second_scale(static_cast<int8_t>(expected_scale));

    if (OB_FAIL(ObTimeConverter::round_interval_ds(expected_fs_scale, value))) {
      LOG_WARN("fail to round interval ds", K(ret), K(value));
    } else {
      int8_t input_day_scale = value.calc_leading_scale();
      if (OB_UNLIKELY(expected_day_scale < input_day_scale)) {
        ret = OB_ERR_THE_LEADING_PRECISION_OF_THE_INTERVAL_IS_TOO_SMALL;
        LOG_WARN("interval obj scale check", K(ret), K(expected_day_scale), K(input_day_scale));
      } else {
        buf_obj.set_interval_ds(value);
      }
    }
  } else {
    ret = OB_ERR_UNEXPECTED;
  }
  if (OB_SUCC(ret)) {
    buf_obj.set_scale(expected_scale);
    res_obj = &buf_obj;
  }
  return ret;
}

int datetime_scale_check_only(const ObAccuracy& accuracy, const ObObj& obj)
{
  int ret = OB_SUCCESS;
  ObScale scale = accuracy.get_scale();
  if (OB_UNLIKELY(scale > MAX_SCALE_FOR_TEMPORAL)) {
    ret = OB_ERR_TOO_BIG_PRECISION;
    LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, scale, "CAST", static_cast<int64_t>(MAX_SCALE_FOR_TEMPORAL));
  } else if (OB_UNLIKELY(0 <= scale && scale < MAX_SCALE_FOR_TEMPORAL)) {
    int64_t value = obj.get_datetime();
    if (!ObTimeConverter::is_valid_datetime(value)) {
      ret = OB_INVALID_DATA;
      LOG_WARN("invalid datetime value", K(ret), K(value));
    }
  }
  return ret;
}

int time_scale_check(ObObjCastParams& params, const ObAccuracy& accuracy, const ObObj& obj, ObObj& buf_obj,
    const ObObj*& res_obj, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  res_obj = NULL;
  ObScale scale = accuracy.get_scale();
  if (OB_LIKELY(0 <= scale && scale < MAX_SCALE_FOR_TEMPORAL)) {
    int64_t value = obj.get_time();
    ObTimeConverter::round_datetime(scale, value);
    buf_obj.set_time(value);
    res_obj = &buf_obj;
  } else {
    res_obj = &obj;
  }
  UNUSED(params);
  UNUSED(cast_mode);
  return ret;
}

int time_scale_check_only(const ObAccuracy& accuracy, const ObObj& obj)
{
  int ret = OB_SUCCESS;
  UNUSED(accuracy);
  UNUSED(obj);
  return ret;
}

int get_bit_len(const ObString& str, int32_t& bit_len)
{
  int ret = OB_SUCCESS;
  if (str.empty()) {
    bit_len = 1;
  } else {
    const char* ptr = str.ptr();
    uint32_t uneven_value = reinterpret_cast<const unsigned char&>(ptr[0]);
    int32_t len = str.length();
    if (0 == uneven_value) {
      if (len > 8) {
        // Compatible with MySQL, if the length of bit string greater than 8 Bytes,
        // it would be considered too long. We set bit_len to OB_MAX_BIT_LENGTH + 1.
        bit_len = OB_MAX_BIT_LENGTH + 1;
      } else {
        bit_len = 1;
      }
    } else {
      // Built-in Function: int __builtin_clz (unsigned int x).
      // Returns the number of leading 0-bits in x, starting at the most significant bit position.
      // If x is 0, the result is undefined.
      int32_t uneven_len = static_cast<int32_t>(sizeof(unsigned int) * 8 - __builtin_clz(uneven_value));
      bit_len = uneven_len + 8 * (len - 1);
    }
  }
  return ret;
}

int get_bit_len(uint64_t value, int32_t& bit_len)
{
  int ret = OB_SUCCESS;
  if (0 == value) {
    bit_len = 1;
  } else {
    bit_len = static_cast<int32_t>(sizeof(unsigned long long) * 8 - __builtin_clzll(value));
  }
  return ret;
}

int string_length_check(ObObjCastParams& params, const ObAccuracy& accuracy, const ObCollationType cs_type,
    const ObObj& obj, ObObj& buf_obj, const ObObj*& res_obj, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  const ObLength max_accuracy_len = accuracy.get_length();
  const int32_t str_len_byte = obj.get_string_len();
  bool is_oracle = is_oracle_mode();
  if (max_accuracy_len <= 0 || str_len_byte > max_accuracy_len) {
    int& cast_ret = (CM_IS_ERROR_ON_FAIL(cast_mode) && !is_oracle) ? ret : params.warning_;
    const char* str = obj.get_string_ptr();
    int32_t str_len_char = -1;
    if (max_accuracy_len == DEFAULT_STR_LENGTH) {
      res_obj = &obj;
    } else if (OB_UNLIKELY(max_accuracy_len <= 0)) {
      buf_obj.set_string(obj.get_type(), NULL, 0);
      buf_obj.set_collation_level(obj.get_collation_level());
      buf_obj.set_collation_type(obj.get_collation_type());
      res_obj = &buf_obj;
      if (OB_UNLIKELY(0 == max_accuracy_len && str_len_byte > 0)) {
        cast_ret = OB_ERR_DATA_TOO_LONG;
        str_len_char =
            obj.is_lob() ? str_len_byte : static_cast<int32_t>(ObCharset::strlen_char(cs_type, str, str_len_byte));
        OB_LOG(WARN, "char type length is too long", K(obj), K(max_accuracy_len), K(str_len_char));
      }
    } else {
      int32_t trunc_len_byte = -1;
      int32_t trunc_len_char = -1;
      if (obj.is_varbinary() || obj.is_binary() || obj.is_blob()) {
        str_len_char =
            obj.is_lob() ? str_len_byte : static_cast<int32_t>(ObCharset::strlen_char(cs_type, str, str_len_byte));
        if (OB_UNLIKELY(str_len_char > max_accuracy_len)) {
          cast_ret = OB_ERR_DATA_TOO_LONG;
          LOG_WARN("binary type length is too long", K(max_accuracy_len), K(str_len_char), K(obj));
        }
      } else if (is_oracle_byte_length(is_oracle, accuracy.get_length_semantics())) {
        const ObLength max_len_byte = accuracy.get_length();
        if (OB_UNLIKELY(str_len_byte > max_len_byte)) {
          cast_ret = OB_ERR_DATA_TOO_LONG;
          LOG_WARN("char type length is too long", K(str_len_byte), K(max_len_byte), K(obj));
        }
      } else if (is_oracle && obj.is_fixed_len_char_type()) {
        const int32_t str_len_char = static_cast<int32_t>(ObCharset::strlen_char(cs_type, str, str_len_byte));
        if (OB_UNLIKELY(str_len_byte > OB_MAX_ORACLE_CHAR_LENGTH_BYTE)) {
          cast_ret = OB_ERR_DATA_TOO_LONG;
          LOG_WARN("char byte length is too long", K(str_len_byte), K(OB_MAX_ORACLE_CHAR_LENGTH_BYTE), K(obj));
        } else if (OB_UNLIKELY(str_len_char > max_accuracy_len)) {
          cast_ret = OB_ERR_DATA_TOO_LONG;
          LOG_WARN("char char length is too long", K(str_len_char), K(max_accuracy_len), K(obj));
        }
      } else {  // mysql, oracle varchar(char)
        // trunc_len_char > max_accuracy_len means an error or warning, without tail ' ', otherwise
        // str_len_char > max_accuracy_len means only warning, even in strict mode.
        // lengthsp()  - returns the length of the given string without trailing spaces.
        trunc_len_byte = static_cast<int32_t>(ObCharset::strlen_byte_no_sp(cs_type, str, str_len_byte));
        trunc_len_char =
            obj.is_lob() ? trunc_len_byte : static_cast<int32_t>(ObCharset::strlen_char(cs_type, str, trunc_len_byte));

        if (is_oracle && OB_UNLIKELY(str_len_byte > OB_MAX_ORACLE_VARCHAR_LENGTH)) {
          cast_ret = OB_ERR_DATA_TOO_LONG;
          LOG_WARN("varchar2 byte length is too long", K(str_len_byte), K(OB_MAX_ORACLE_VARCHAR_LENGTH), K(obj));
        } else if (OB_UNLIKELY(trunc_len_char > max_accuracy_len)) {
          cast_ret = OB_ERR_DATA_TOO_LONG;
          LOG_WARN("char type length is too long", K(max_accuracy_len), K(trunc_len_char), K(obj));
        } else {
          str_len_char =
              obj.is_lob() ? str_len_byte : static_cast<int32_t>(ObCharset::strlen_char(cs_type, str, str_len_byte));
          if (OB_UNLIKELY(str_len_char > max_accuracy_len)) {
            params.warning_ = OB_ERR_DATA_TOO_LONG;
            LOG_WARN("char type length is too long", K(max_accuracy_len), K(str_len_char), K(obj));
          }
        }
      }
      if (OB_SUCC(ret)) {
        if (OB_UNLIKELY(OB_ERR_DATA_TOO_LONG == params.warning_)) {
          // when warning, always trunc to max_accuracy_len first.
          // besides, if char (not binary), trunc to trunc_len_char again, trim tail ' ' after first trunc.
          // the reason of two-trunc for char (not binary):
          // insert 'ab  ! ' to char(3), we get an 'ab' in column, not 'ab ':
          // first trunc: 'ab  ! ' to 'ab ',
          // second trunc: 'ab ' to 'ab'.
          if (obj.is_text()) {
            int64_t char_len = 0;
            trunc_len_byte = static_cast<int32_t>(
                ObCharset::max_bytes_charpos(cs_type, str, str_len_byte, max_accuracy_len, char_len));
          } else {
            trunc_len_byte = static_cast<int32_t>(ObCharset::charpos(cs_type, str, str_len_byte, max_accuracy_len));
          }
          if (is_oracle) {
            // select cast(' a' as char) from dual
            // the query above return ' ' in oracle.
          } else if (obj.is_fixed_len_char_type() && !obj.is_binary()) {
            trunc_len_byte = static_cast<int32_t>(ObCharset::strlen_byte_no_sp(cs_type, str, trunc_len_byte));
          }
          if (OB_FAIL(copy_string(params, obj.get_type(), str, trunc_len_byte, buf_obj))) {
          } else {
            buf_obj.set_collation_level(obj.get_collation_level());
            buf_obj.set_collation_type(obj.get_collation_type());
            res_obj = &buf_obj;
          }
          if (is_oracle) {
            ret = params.warning_;
          }
        } else if (OB_SUCC(params.warning_) && is_oracle) {
          ret = params.warning_;
        } else {
          res_obj = &obj;
        }
      }
    }
  } else {
    res_obj = &obj;
  }

  return ret;
}

// no truncate
int string_length_check_only(const ObAccuracy& accuracy, const ObCollationType cs_type, const ObObj& obj)
{
  int ret = OB_SUCCESS;
  const ObLength max_len_char = accuracy.get_length();
  const char* str = obj.get_string_ptr();
  const int32_t str_len_byte = obj.get_string_len();
  const int32_t str_len_char = static_cast<int32_t>(ObCharset::strlen_char(cs_type, str, str_len_byte));
  if (OB_UNLIKELY(max_len_char <= 0)) {
    if (OB_UNLIKELY(0 == max_len_char && str_len_byte > 0)) {
      ret = OB_ERR_DATA_TOO_LONG;
      OB_LOG(WARN, "char type length is too long", K(obj), K(max_len_char), K(str_len_char));
    }
  } else if (OB_UNLIKELY(str_len_char > max_len_char)) {
    ret = OB_ERR_DATA_TOO_LONG;
    LOG_WARN("string length is too long", K(max_len_char), K(str_len_char), K(obj));
  }
  return ret;
}

int raw_length_check(ObObjCastParams& params, const ObAccuracy& accuracy, const ObCollationType cs_type,
    const ObObj& obj, ObObj& buf_obj, const ObObj*& res_obj, const ObCastMode cast_mode)
{
  UNUSED(params);
  UNUSED(cs_type);
  UNUSED(buf_obj);
  UNUSED(cast_mode);
  int ret = OB_SUCCESS;
  const ObLength max_accuracy_len = accuracy.get_length();
  const int32_t str_len_byte = obj.get_string_len();

  if (OB_UNLIKELY(max_accuracy_len >= 0 && str_len_byte > max_accuracy_len)) {
    ret = OB_ERR_DATA_TOO_LONG;
    LOG_WARN("char type length is too long", K(ret), K(str_len_byte), K(max_accuracy_len), K(obj));
  } else {
    res_obj = &obj;
  }

  return ret;
}

int bit_length_check(ObObjCastParams& params, const ObAccuracy& accuracy, const ObObj& obj, ObObj& buf_obj,
    const ObObj*& res_obj, const ObCastMode cast_mode)
{
  int ret = OB_SUCCESS;
  res_obj = NULL;
  uint64_t value = obj.get_bit();
  int32_t bit_len = 0;
  int32_t dst_bit_len = accuracy.get_precision();
  if (OB_FAIL(get_bit_len(value, bit_len))) {
    LOG_WARN("fail to get_bit_length", K(ret), K(value), K(bit_len));
  } else if (OB_UNLIKELY(bit_len <= 0)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("bit length is negative", K(ret), K(value), K(bit_len), K(obj));
  } else {
    if (OB_UNLIKELY(bit_len > dst_bit_len)) {
      ret = OB_ERR_DATA_TOO_LONG;
      LOG_WARN("bit type length is too long", K(ret), K(bit_len), K(dst_bit_len), K(value));
    } else {
      buf_obj.set_bit(value);
    }
    if (OB_FAIL(ret) && CM_IS_WARN_ON_FAIL(cast_mode)) {
      params.warning_ = OB_DATA_OUT_OF_RANGE;
      ret = OB_SUCCESS;
      uint64_t max_value = (1ULL << dst_bit_len) - 1;
      buf_obj.set_bit(max_value);
    }
    if (OB_SUCC(ret)) {
      res_obj = &buf_obj;
    }
  }
  return ret;
}

int bit_length_check_only(const ObAccuracy& accuracy, const ObObj& obj)
{
  int ret = OB_SUCCESS;
  uint64_t value = obj.get_bit();
  int32_t bit_len = 0;
  int32_t dst_bit_len = accuracy.get_precision();
  if (OB_FAIL(get_bit_len(value, bit_len))) {
    LOG_WARN("fail to get_bit_length", K(ret), K(value), K(bit_len));
  } else if (OB_UNLIKELY(bit_len <= 0)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("bit length is negative", K(ret), K(value), K(bit_len), K(obj));
  } else {
    if (OB_UNLIKELY(bit_len > dst_bit_len)) {
      ret = OB_ERR_DATA_TOO_LONG;
      LOG_WARN("bit type length is too long", K(ret), K(bit_len), K(dst_bit_len), K(value));
    }
  }
  return ret;
}

int obj_collation_check(const bool is_strict_mode, const ObCollationType cs_type, ObObj& obj)
{
  int ret = OB_SUCCESS;
  if (!ob_is_string_type(obj.get_type()) && !ob_is_lob_locator(obj.get_type())) {
    // nothing to do
  } else if (cs_type == CS_TYPE_BINARY) {
    obj.set_collation_type(cs_type);
  } else {
    ObString str;
    int64_t well_formed_len = 0;
    if (ob_is_lob_locator(obj.get_type())) {
      if (OB_FAIL(obj.get_string(str))) {
        LOG_WARN("Failed to get payload from lob locator", K(ret), K(obj));
      }
    } else {
      if (OB_FAIL(obj.get_string(str))) {
        LOG_WARN("Failed to get payload from string", K(ret), K(obj));
      }
    }
    if (OB_FAIL(ret)) {

    } else if (OB_FAIL(ObCharset::well_formed_len(cs_type, str.ptr(), str.length(), well_formed_len))) {
      LOG_WARN(
          "invalid string for charset", K(ret), K(cs_type), K(str), K(well_formed_len), KPHEX(str.ptr(), str.length()));
      if (is_strict_mode) {
        ret = OB_ERR_INCORRECT_STRING_VALUE;
        // LOG_USER_ERROR(ret, str.length(), str.ptr());
      } else {
        ret = OB_SUCCESS;
        obj.set_collation_type(cs_type);
        str.assign_ptr(str.ptr(), static_cast<ObString::obstr_size_t>(well_formed_len));
        if (ob_is_lob_locator(obj.get_type())) {
          if (OB_ISNULL(obj.get_lob_locator())) {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("Unepected null lob locator", K(ret), K(obj));
          } else {
            (const_cast<ObLobLocator*>(obj.get_lob_locator()))->payload_size_ = str.length();
          }
        } else {
          obj.set_string(obj.get_type(), str.ptr(), str.length());
        }
        LOG_WARN("invalid string for charset", K(ret), K(cs_type), K(str), K(well_formed_len), K(str.length()));
      }
    } else {
      obj.set_collation_type(cs_type);
    }
  }
  return ret;
}

int urwoid_length_check_only(const ObAccuracy& accuracy, const ObObj& obj)
{
  int ret = OB_SUCCESS;
  ObURowIDData urowid_data = obj.get_urowid();

  if (OB_UNLIKELY(urowid_data.rowid_len_ <= 0)) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("invalid urowid data length", K(ret), K(urowid_data.rowid_len_));
  } else if (OB_UNLIKELY(urowid_data.rowid_len_ > accuracy.get_precision())) {
    ret = OB_ERR_DATA_TOO_LONG;
    LOG_WARN("urowid data length us too long", K(ret), K(accuracy.get_precision()), K(urowid_data.rowid_len_));
  }
  return ret;
}

int obj_accuracy_check(ObCastCtx& cast_ctx, const ObAccuracy& accuracy, const ObCollationType cs_type, const ObObj& obj,
    ObObj& buf_obj, const ObObj*& res_obj)
{
  int ret = OB_SUCCESS;
  LOG_DEBUG("obj_accuracy_check before", K(obj), K(accuracy), K(cs_type));
  switch (obj.get_type_class()) {
    case ObFloatTC: {
      ret = float_range_check(cast_ctx, accuracy, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObDoubleTC: {
      ret = double_check_precision(cast_ctx, accuracy, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObNumberTC: {
      ret = number_range_check_v2(cast_ctx, accuracy, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObDateTimeTC: {
      ret = datetime_scale_check(cast_ctx, accuracy, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObOTimestampTC: {
      ret = otimestamp_scale_check(cast_ctx, accuracy, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObTimeTC: {
      ret = time_scale_check(cast_ctx, accuracy, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObStringTC: {
      ret = string_length_check(cast_ctx, accuracy, cs_type, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObRawTC: {
      ret = raw_length_check(cast_ctx, accuracy, cs_type, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObTextTC: {
      // TODO texttc share with stringtc temporarily
      ret = string_length_check(cast_ctx, accuracy, cs_type, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObBitTC: {
      ret = bit_length_check(cast_ctx, accuracy, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObIntervalTC: {
      ret = interval_scale_check(cast_ctx, accuracy, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObRowIDTC: {
      ret = string_length_check(cast_ctx, accuracy, cs_type, obj, buf_obj, res_obj, cast_ctx.cast_mode_);
      break;
    }
    case ObLobTC: {
      // TODO:shanting lob length check
    }
    default: {
      // LOG_WARN("unexpected type class to check", K(obj));
      break;
    }
  }
  return ret;
}

int ob_obj_accuracy_check_only(const ObAccuracy& accuracy, const ObCollationType cs_type, const ObObj& obj)
{
  int ret = OB_SUCCESS;
  switch (obj.get_type_class()) {
    case ObFloatTC: {
      switch (obj.get_type()) {
        case ObFloatType:
          ret = real_range_check_only(accuracy, obj.get_float());
          break;
        case ObUFloatType: {
          double value = obj.get_ufloat();
          ret = numeric_negative_check(value);
          if (OB_SUCC(ret)) {
            ret = real_range_check_only(accuracy, obj.get_ufloat());
          }
          break;
        }
        default:
          break;
      }
      break;
    }
    case ObDoubleTC: {
      switch (obj.get_type()) {
        case ObDoubleType:
          ret = real_range_check_only(accuracy, obj.get_double());
          break;
        case ObUDoubleType: {
          double value = obj.get_udouble();
          ret = numeric_negative_check(value);
          if (OB_SUCC(ret)) {
            ret = real_range_check_only(accuracy, obj.get_udouble());
          }
          break;
        }
        default:
          break;
      }
      break;
    }
    case ObNumberTC:
      ret = number_range_check_only(accuracy, obj);
      break;
    case ObDateTimeTC:
      ret = datetime_scale_check_only(accuracy, obj);
      break;
    case ObTimeTC:
      ret = time_scale_check_only(accuracy, obj);
      break;
    case ObStringTC:
      ret = string_length_check_only(accuracy, cs_type, obj);
      break;
    case ObTextTC:
      ret = string_length_check_only(accuracy, cs_type, obj);
      break;
    case ObBitTC:
      ret = bit_length_check_only(accuracy, obj);
      break;
    case ObIntTC: {
      int64_t value = obj.get_int();
      ret = int_range_check(obj.get_type(), value, value);
    } break;
    case ObUIntTC: {
      uint64_t value = obj.get_uint64();
      ret = uint_upper_check(obj.get_type(), value);
    } break;
    default:
      break;
  }
  return ret;
}

int ob_obj_to_ob_time_with_date(
    const ObObj& obj, const ObTimeZoneInfo* tz_info, ObTime& ob_time, const int64_t cur_ts_value, bool is_dayofmonth /*false*/)
{
  int ret = OB_SUCCESS;
  switch (obj.get_type_class()) {
    case ObIntTC:
      // fallthrough.
    case ObUIntTC: {
      ret = ObTimeConverter::int_to_ob_time_with_date(obj.get_int(), ob_time, is_dayofmonth);
      break;
    }
    case ObOTimestampTC: {
      ret = ObTimeConverter::otimestamp_to_ob_time(obj.get_type(), obj.get_otimestamp_value(), tz_info, ob_time);
      break;
    }
    case ObDateTimeTC: {
      ret = ObTimeConverter::datetime_to_ob_time(
          obj.get_datetime(), (ObTimestampType == obj.get_type()) ? tz_info : NULL, ob_time);
      break;
    }
    case ObDateTC: {
      ret = ObTimeConverter::date_to_ob_time(obj.get_date(), ob_time);
      break;
    }
    case ObTimeTC: {
      int64_t datetime_val = 0;
      if (OB_FAIL(
              ObTimeConverter::time_to_datetime(obj.get_time(), cur_ts_value, NULL, datetime_val, ObDateTimeType))) {
        LOG_WARN("time_to_datetime failed", K(ret), K(obj), K(cur_ts_value));
      } else if (OB_FAIL(ObTimeConverter::datetime_to_ob_time(datetime_val, NULL, ob_time))) {
        LOG_WARN("datetime to time failed", K(ret));
      }
      break;

      ret = ObTimeConverter::time_to_ob_time(obj.get_time(), ob_time);
      break;
    }
    case ObTextTC:  // TODO texttc share with the stringtc temporarily
    case ObStringTC: {
      ret = ObTimeConverter::str_to_ob_time_with_date(obj.get_string(), ob_time, NULL, is_dayofmonth);
      break;
    }
    case ObLobTC: {
      ObString payload;
      if (OB_FAIL(obj.get_string(payload))) {
        STORAGE_LOG(WARN, "Failed to get payload from lob locator", K(ret), K(obj));
      } else {
        ret = ObTimeConverter::str_to_ob_time_with_date(payload, ob_time, NULL, is_dayofmonth);
      }
      break;
    }
    case ObNumberTC: {
      int64_t int_part = 0;
      int64_t dec_part = 0;
      const number::ObNumber num = obj.get_number();
      if (num.is_negative()) {
        ret = OB_INVALID_DATE_FORMAT;
        LOG_WARN("invalid date format", K(ret), K(num));
      } else if (!num.is_int_parts_valid_int64(int_part, dec_part)) {
        ret = OB_INVALID_DATE_FORMAT;
        LOG_WARN("invalid date format", K(ret), K(num));
      } else {
        ret = ObTimeConverter::int_to_ob_time_with_date(int_part, ob_time, is_dayofmonth);
      }
      break;
    }
    default: {
      ret = OB_NOT_SUPPORTED;
    }
  }
  return ret;
}

int ob_obj_to_ob_time_without_date(const ObObj& obj, const ObTimeZoneInfo* tz_info, ObTime& ob_time)
{
  int ret = OB_SUCCESS;
  switch (obj.get_type_class()) {
    case ObIntTC:
      // fallthrough.
    case ObUIntTC: {
      if (OB_FAIL(ObTimeConverter::int_to_ob_time_without_date(obj.get_int(), ob_time))) {
        LOG_WARN("int to ob time without date failed", K(ret));
      } else {
        const int64_t time_max_val = 3020399 * 1000000LL;  // 838:59:59 .
        int64_t value = ObTimeConverter::ob_time_to_time(ob_time);
        if (value > time_max_val) {
          ret = OB_INVALID_DATE_VALUE;
        }
      }
      break;
    }
    case ObOTimestampTC: {
      ret = ObTimeConverter::otimestamp_to_ob_time(obj.get_type(), obj.get_otimestamp_value(), tz_info, ob_time);
      break;
    }
    case ObDateTimeTC: {
      ret = ObTimeConverter::datetime_to_ob_time(
          obj.get_datetime(), (ObTimestampType == obj.get_type()) ? tz_info : NULL, ob_time);
      break;
    }
    case ObDateTC: {
      ret = ObTimeConverter::date_to_ob_time(obj.get_date(), ob_time);
      break;
    }
    case ObTimeTC: {
      ret = ObTimeConverter::time_to_ob_time(obj.get_time(), ob_time);
      break;
    }
    case ObTextTC:  // TODO texttc share with the stringtc temporarily
    case ObStringTC: {
      ret = ObTimeConverter::str_to_ob_time_without_date(obj.get_string(), ob_time);
      break;
    }
    case ObLobTC: {
      ObString payload;
      if (OB_FAIL(obj.get_string(payload))) {
        STORAGE_LOG(WARN, "Failed to get payload from lob locator", K(ret), K(obj));
      } else {
        ret = ObTimeConverter::str_to_ob_time_without_date(payload, ob_time);
      }
      break;
    }
    case ObNumberTC: {
      const char *num_format = obj.get_number().format();
      if (OB_ISNULL(num_format)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("number format value is null", K(ret));
      } else {
        ObString num_str(num_format);
        ret = ObTimeConverter::str_to_ob_time_without_date(num_str, ob_time);
      }
      break;
    }
    default: {
      ret = OB_NOT_SUPPORTED;
    }
  }
  return ret;
}

int ObObjCaster::to_type(
    const ObObjType expect_type, ObCastCtx& cast_ctx, const ObObj& in_obj, ObObj& buf_obj, const ObObj*& res_obj)
{
  int ret = OB_SUCCESS;
  res_obj = NULL;
  cast_ctx.warning_ = OB_SUCCESS;
  ObObjType in_type = in_obj.get_type();
  bool is_string = ob_is_string_type(in_type) || ob_is_lob_locator(in_type);
  if (OB_UNLIKELY((expect_type == in_type && (!is_string)) || ObNullType == in_type)) {
    buf_obj = in_obj;
    res_obj = &buf_obj;
  } else if (in_obj.get_collation_type() == cast_ctx.dest_collation_ &&
             (ObVarcharType == in_type || ObCharType == in_type || ob_is_nstring_type(in_type)) &&
             (ObVarcharType == expect_type || ObCharType == expect_type || ob_is_nstring_type(expect_type)) &&
             NULL == cast_ctx.zf_info_ && NULL == cast_ctx.res_accuracy_) {
    // fast path for char/varchar string_string cast.
    buf_obj = in_obj;
    const_cast<ObObjMeta&>(buf_obj.get_meta()).set_type_simple(expect_type);
    res_obj = &buf_obj;
  } else if (OB_FAIL(to_type(expect_type,
                 (is_string && share::is_mysql_mode()) ? in_obj.get_collation_type() : cast_ctx.dest_collation_,
                 cast_ctx,
                 in_obj,
                 buf_obj))) {
    LOG_WARN("failed to cast obj", K(ret), K(in_obj), K(expect_type), K(cast_ctx.cast_mode_));
  } else {
    res_obj = &buf_obj;
  }
  return ret;
}

int ObObjCaster::to_datetime(
    const ObObjType expect_type, ObCastCtx& cast_ctx, const ObObj& in_obj, ObObj& buf_obj, const ObObj*& res_obj)
{
  int ret = OB_SUCCESS;
  if (ObDateTimeType == in_obj.get_type()) {
    res_obj = &in_obj;
  } else {
    cast_ctx.warning_ = OB_SUCCESS;
    switch (in_obj.get_type_class()) {
      case ObIntTC: {
        ret = int_datetime_interval(expect_type, cast_ctx, in_obj, buf_obj, cast_ctx.cast_mode_);
        break;
      }
      case ObFloatTC: {
        ret = float_datetime_interval(expect_type, cast_ctx, in_obj, buf_obj, cast_ctx.cast_mode_);
        break;
      }
      case ObDoubleTC: {
        ret = double_datetime_interval(expect_type, cast_ctx, in_obj, buf_obj, cast_ctx.cast_mode_);
        break;
      }
      case ObNumberTC: {
        ret = number_datetime_interval(expect_type, cast_ctx, in_obj, buf_obj, cast_ctx.cast_mode_);
        break;
      }
      case ObOTimestampTC: {
        ret = otimestamp_datetime(expect_type, cast_ctx, in_obj, buf_obj, cast_ctx.cast_mode_);
        break;
      }
      default: {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("it should not arrive here", K(ret), K(in_obj), K(expect_type), K(in_obj.get_type_class()));
      }
    }

    if (OB_FAIL(ret)) {
      LOG_WARN("failed to cast obj", K(ret), K(in_obj), K(expect_type), K(cast_ctx.cast_mode_));
    } else {
      res_obj = &buf_obj;
    }
  }
  return ret;
}

// ObInnerEnumType and ObInnerSetType are not supported.
int ObObjCaster::to_type(
    const ObExpectType& expect_type, ObCastCtx& cast_ctx, const ObObj& in_obj, ObObj& buf_obj, const ObObj*& res_obj)
{
  int ret = OB_SUCCESS;
  res_obj = NULL;
  cast_ctx.warning_ = OB_SUCCESS;
  ObObjType dest_type = expect_type.get_type();
  cast_ctx.expect_obj_collation_ = expect_type.get_collation_type();
  if (OB_UNLIKELY((dest_type == in_obj.get_type() && cast_ctx.dest_collation_ == in_obj.get_collation_type()) ||
                  ObNullType == in_obj.get_type())) {
    res_obj = &in_obj;
  } else if (ObEnumType == dest_type || ObSetType == dest_type) {
    if (OB_FAIL(to_type(expect_type, cast_ctx, in_obj, buf_obj))) {
      LOG_WARN("fail to cast to enum or set", K(expect_type), K(in_obj), K(cast_ctx.cast_mode_), K(ret));
    } else {
      res_obj = &buf_obj;
    }
  } else if (OB_FAIL(to_type(dest_type, expect_type.get_collation_type(), cast_ctx, in_obj, buf_obj))) {
    LOG_WARN("failed to cast obj", K(in_obj), K(expect_type), K(cast_ctx.cast_mode_), K(ret));
  } else {
    res_obj = &buf_obj;
  }
  return ret;
}

int ObObjCaster::to_type(const ObObjType expect_type, ObCastCtx& cast_ctx, const ObObj& in_obj, ObObj& out_obj)
{
  int ret = OB_SUCCESS;
  ObObjType in_type = in_obj.get_type();
  bool is_string = ob_is_string_type(in_type) || ob_is_lob_locator(in_type);
  if (OB_UNLIKELY((expect_type == in_type && (!is_string)) || ObNullType == in_type)) {
    out_obj = in_obj;
  } else if (in_obj.get_collation_type() == cast_ctx.dest_collation_ &&
             (ObVarcharType == in_type || ObCharType == in_type || ob_is_nstring_type(in_type)) &&
             (ObVarcharType == expect_type || ObCharType == expect_type || ob_is_nstring_type(expect_type)) &&
             NULL == cast_ctx.zf_info_ && NULL == cast_ctx.res_accuracy_) {
    // fast path for char/varchar string_string cast.
    out_obj = in_obj;
    const_cast<ObObjMeta&>(out_obj.get_meta()).set_type_simple(expect_type);
  } else {
    if (share::is_oracle_mode() && in_obj.is_character_type()) {
      ObCollationType dest_collation = ob_is_nstring_type(expect_type) ? cast_ctx.dtc_params_.nls_collation_nation_
                                                                       : cast_ctx.dtc_params_.nls_collation_;
      if (CS_TYPE_INVALID != dest_collation) {
        cast_ctx.dest_collation_ = dest_collation;
      }
    }
    ret = to_type(
        expect_type, is_string ? in_obj.get_collation_type() : cast_ctx.dest_collation_, cast_ctx, in_obj, out_obj);
  }
  return ret;
}

int ObObjCaster::to_type(const ObObjType expect_type, ObCollationType expect_cs_type, ObCastCtx& cast_ctx,
    const ObObj& in_obj, ObObj& out_obj)
{
  int ret = OB_SUCCESS;
  const ObObjTypeClass in_tc = in_obj.get_type_class();
  const ObObjTypeClass out_tc = ob_obj_type_class(expect_type);
  cast_ctx.warning_ = OB_SUCCESS;
  if (CS_TYPE_INVALID != cast_ctx.dest_collation_) {
    expect_cs_type = cast_ctx.dest_collation_;
  } else {
    cast_ctx.dest_collation_ = expect_cs_type;
  }
  if (OB_UNLIKELY(ob_is_invalid_obj_tc(in_tc) || ob_is_invalid_obj_tc(out_tc))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected type", K(ret), K(in_obj), K(expect_type));
  } else if (lib::is_oracle_mode()) {
    /*if (CM_IS_EXPLICIT_CAST(cast_ctx.cast_mode_)) {
      if (OB_FAIL(OBJ_CAST_ORACLE_EXPLICIT[in_tc][out_tc](expect_type, cast_ctx, in_obj, out_obj, cast_ctx.cast_mode_)))
    { LOG_WARN("failed to cast obj", K(ret), K(in_obj), K(in_tc), K(out_tc), K(expect_type), K(cast_ctx.cast_mode_));
      }
    } else {*/
    if (OB_FAIL(OBJ_CAST_ORACLE_IMPLICIT[in_tc][out_tc](expect_type, cast_ctx, in_obj, out_obj, cast_ctx.cast_mode_))) {
      LOG_WARN("failed to cast obj", K(ret), K(in_obj), K(in_tc), K(out_tc), K(expect_type), K(cast_ctx.cast_mode_));
    }
    //}
  } else {
    if (OB_FAIL(OB_OBJ_CAST[in_tc][out_tc](expect_type, cast_ctx, in_obj, out_obj, cast_ctx.cast_mode_))) {
      LOG_WARN("failed to cast obj", K(ret), K(in_obj), K(in_tc), K(out_tc), K(expect_type), K(cast_ctx.cast_mode_));
    }
  }
  if (OB_SUCC(ret)) {
    if (ObStringTC == out_tc || ObTextTC == out_tc || ObLobTC == out_tc) {
      if (ObStringTC == in_tc || ObTextTC == in_tc || ObLobTC == out_tc) {
        out_obj.set_collation_level(in_obj.get_collation_level());
      } else {
        out_obj.set_collation_level(CS_LEVEL_COERCIBLE);
      }
      if (OB_LIKELY(expect_cs_type != CS_TYPE_INVALID)) {
        out_obj.set_collation_type(expect_cs_type);
      } else {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unexpected collation type", K(ret), K(in_obj), K(out_obj), K(expect_cs_type), K(common::lbt()));
      }
    }
  }
  LOG_DEBUG("succ to to_type", K(ret), "in_type", in_obj.get_type(), K(in_obj), K(expect_type), K(out_obj), K(lbt()));
  return ret;
}

// use for cast to enum or set type
int ObObjCaster::to_type(const ObExpectType& expect_type, ObCastCtx& cast_ctx, const ObObj& in_obj, ObObj& out_obj)
{
  int ret = OB_SUCCESS;
  const ObObjTypeClass in_tc = in_obj.get_type_class();
  const ObObjType out_type = expect_type.get_type();
  if (OB_UNLIKELY(!ob_is_enumset_tc(expect_type.get_type())) || OB_UNLIKELY(ob_is_invalid_obj_tc(in_tc))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected expect_type", K(ret), K(expect_type), K(in_obj));
  } else if (OB_FAIL(OB_CAST_ENUM_OR_SET[in_tc][ObSetType == out_type](expect_type, cast_ctx, in_obj, out_obj))) {
    LOG_WARN("fail to cast to enum or set", K(ret), K(in_obj), K(expect_type));
  } else {
    LOG_DEBUG("succ to to_type", K(expect_type), K(in_obj), K(out_obj));
  }
  return ret;
}

int ObObjCaster::get_zero_value(const ObObjType expect_type, ObCollationType expect_cs_type, ObObj& zero_obj)
{
  int ret = OB_SUCCESS;
  // we need a ObObjCastParams object with warning is 1 to use SET_RES_XXX macro.
  ObObjCastParams params;
  ObCastMode cast_mode = CM_WARN_ON_FAIL;
  params.warning_ = 1;
  if (ob_is_string_tc(expect_type)) {
    zero_obj.set_string(expect_type, "");
  } else if (ob_is_int_tc(expect_type)) {
    int64_t value = 0;
    SET_RES_INT(zero_obj);
  } else if (ob_is_uint_tc(expect_type)) {
    uint64_t value = 0;
    SET_RES_UINT(zero_obj);
  } else if (ob_is_float_tc(expect_type)) {
    double value = 0.0;
    SET_RES_FLOAT(zero_obj);
  } else if (ob_is_double_tc(expect_type)) {
    double value = 0.0;
    SET_RES_DOUBLE(zero_obj);
  } else if (ob_is_number_tc(expect_type)) {
    number::ObNumber value;
    value.set_zero();
    SET_RES_NUMBER(zero_obj);
  } else if (ob_is_datetime_tc(expect_type)) {
    int64_t value = 0;
    SET_RES_DATETIME(zero_obj);
  } else if (ob_is_date_tc(expect_type)) {
    int32_t value = 0;
    SET_RES_DATE(zero_obj);
  } else if (ob_is_time_tc(expect_type)) {
    int32_t value = 0;
    SET_RES_TIME(zero_obj);
  } else if (ob_is_year_tc(expect_type)) {
    int64_t value = 0;
    SET_RES_YEAR(zero_obj);
  } else if (ob_is_bit_tc(expect_type)) {
    uint64_t value = 0;
    SET_RES_BIT(zero_obj);
  } else if (ObEnumType == expect_type) {
    uint64_t value = 0;
    SET_RES_ENUM(zero_obj);
  } else if (ObSetType == expect_type) {
    uint64_t value = 0;
    SET_RES_SET(zero_obj);
  } else if (ob_is_otimestampe_tc(expect_type)) {
    ObOTimestampData value;
    SET_RES_OTIMESTAMP(zero_obj);
  } else if (ob_is_interval_ym(expect_type)) {
    ObIntervalYMValue value;
    SET_RES_INTERVAL_YM(zero_obj);
  } else if (ob_is_interval_ds(expect_type)) {
    ObIntervalDSValue value;
    SET_RES_INTERVAL_DS(zero_obj);
  } else if (ob_is_urowid(expect_type)) {
    ret = OB_NOT_SUPPORTED;
    LOG_WARN("urowid with default value not supported");
  }
  if (OB_SUCC(ret)) {
    zero_obj.set_collation_type(expect_cs_type);
  }
  return ret;
}

int ObObjCaster::enumset_to_inner(const ObObjMeta& expect_meta, const ObObj& in_obj, ObObj& out_obj,
    common::ObIAllocator& allocator, const common::ObIArray<common::ObString>& str_values)
{
  int ret = OB_SUCCESS;
  if (ObEnumType != in_obj.get_type() && ObSetType != in_obj.get_type()) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected expect_type", K(ret), K(in_obj));
  } else {
    const ObObjType expect_type = (ObEnumType == in_obj.get_type() ? ObEnumInnerType : ObSetInnerType);
    const int64_t element_num = str_values.count();
    const uint64_t element_val = in_obj.get_enum();
    if (ObEnumInnerType == expect_type) {
      int64_t element_idx = static_cast<int64_t>(element_val - 1);  // enum value start from 1
      ObString element_str;
      if (OB_UNLIKELY(element_num < 1)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("str_values_ should not be empty", K(str_values), K(ret));
      } else if (OB_UNLIKELY(0 == element_val)) {
        // do nothing just keep element_string empty
      } else {
        if (OB_UNLIKELY(element_idx > element_num - 1)) {
          ret = OB_ERR_UNEXPECTED;
          LOG_WARN("invalid enum value", K(element_idx), K(element_num), K(element_val), K(in_obj), K(ret));
        } else {
          element_str = str_values.at(element_idx);
        }
      }

      if (OB_SUCC(ret)) {
        ObEnumSetInnerValue inner_value(element_val, element_str);
        char* buf = NULL;
        const int64_t BUF_LEN = inner_value.get_serialize_size();
        int64_t pos = 0;
        if (OB_ISNULL(buf = static_cast<char*>(allocator.alloc(BUF_LEN)))) {
          ret = OB_ALLOCATE_MEMORY_FAILED;
          LOG_WARN("alloc memory failed", K(ret), KP(buf), K(BUF_LEN));
        } else if (OB_FAIL(inner_value.serialize(buf, BUF_LEN, pos))) {
          LOG_WARN("failed to serialize inner_value", K(BUF_LEN), K(ret));
        } else {
          out_obj.set_varchar(buf, static_cast<ObString::obstr_size_t>(pos));
          out_obj.set_type(expect_type);
          out_obj.set_collation(expect_meta);
        }
      }
    } else {  // to setinner
      static const int64_t EFFECTIVE_COUNT = 64;
      if (OB_UNLIKELY(element_num < 1)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("invalid element_num", K(str_values), K(element_num), K(ret));
      } else if (OB_UNLIKELY(element_num < EFFECTIVE_COUNT) && OB_UNLIKELY(element_val >= (1ULL << element_num))) {
        // check the validation of element_val
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("set value out of range", K(element_val), K(element_num));
      }

      ObSqlString sql_string;
      uint64_t index = 1ULL;
      const ObString& sep = ObCharsetUtils::get_const_str(expect_meta.get_collation_type(), ',');
      for (int64_t i = 0; OB_SUCC(ret) && i < element_num && i < EFFECTIVE_COUNT && element_val >= index;
           ++i, index = index << 1) {
        if (element_val & (index)) {
          const ObString& tmp_val = str_values.at(i);
          if (OB_FAIL(sql_string.append(tmp_val))) {
            LOG_WARN("fail to deep copy str", K(element_val), K(i), K(ret));
          } else if ((element_val >= (index << 1)) && (OB_FAIL(sql_string.append(sep)))) {
            LOG_WARN("fail to deep copy comma", K(element_val), K(tmp_val), K(i), K(ret));
          }
        }
      }

      if (OB_SUCC(ret)) {
        ObString string_value(sql_string.length(), sql_string.ptr());
        ObEnumSetInnerValue inner_value(element_val, string_value);
        char* buf = NULL;
        const int64_t BUF_LEN = inner_value.get_serialize_size();
        int64_t pos = 0;
        if (OB_ISNULL(buf = static_cast<char*>(allocator.alloc(BUF_LEN)))) {
          ret = OB_ALLOCATE_MEMORY_FAILED;
          LOG_WARN("alloc memory failed", K(ret), KP(buf), K(BUF_LEN));
        } else if (OB_FAIL(inner_value.serialize(buf, BUF_LEN, pos))) {
          LOG_WARN("failed to serialize inner_value", K(BUF_LEN), K(ret));
        } else {
          out_obj.set_varchar(buf, static_cast<ObString::obstr_size_t>(pos));
          out_obj.set_type(expect_type);
          out_obj.set_collation(expect_meta);
        }
      }
    }
  }
  return ret;
}

// given two objects with type A: a1 and a2, cast them to type B: b1 and b2,
// if in any case:
// a1 > a2 means b1 > b2, and
// a1 < a2 means b1 < b2, and
// a1 = a2 means b1 = b2,
// then type A and B is cast monotonic.
int ObObjCaster::is_cast_monotonic(ObObjType t1, ObObjType t2, bool& is_monotonic)
{
  int ret = OB_SUCCESS;
  ObObjTypeClass tc1 = ob_obj_type_class(t1);
  ObObjTypeClass tc2 = ob_obj_type_class(t2);
  if (OB_UNLIKELY(ob_is_invalid_obj_tc(tc1) || ob_is_invalid_obj_tc(tc2))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected type", K(ret), K(t1), K(t2), K(tc1), K(tc2));
  } else {
    is_monotonic = CAST_MONOTONIC[tc1][tc2];
  }
  return ret;
}

/*
 *  c1 = 'A' check if c1 can be ordering
 */
int ObObjCaster::is_const_consistent(const ObObjMeta& const_mt, const ObObjMeta& column_mt, const ObObjType calc_type,
    const ObCollationType calc_collation, bool& result)
{
  int ret = OB_SUCCESS;
  result = false;
  ObObjTypeClass tc1 = const_mt.get_type_class();
  ObObjTypeClass tc2 = column_mt.get_type_class();
  if (OB_UNLIKELY(ob_is_invalid_obj_tc(tc1) || ob_is_invalid_obj_tc(tc2))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected obj type class", K(ret), K(const_mt), K(column_mt));
  } else if (const_mt.is_string_or_lob_locator_type() && column_mt.is_string_or_lob_locator_type()) {
    if (column_mt.get_collation_type() == calc_collation) {
      result = true;
    } else {
      // false
    }
  } else {
    if (OB_FAIL(ObObjCaster::is_cast_monotonic(column_mt.get_type(), calc_type, result))) {
      LOG_WARN("check is cast monotonic failed", K(ret));
    } else if (!result) {
      // false
    } else if (OB_FAIL(ObObjCaster::is_cast_monotonic(calc_type, column_mt.get_type(), result))) {
      LOG_WARN("check is cast monotonic failed", K(ret));
    } else {
      // do nothing
    }
  }
  return ret;
}

/* make sure that you have read the doc before you call these functions !
 *
 * doc:  http://www.atatech.org/articles/56575
 */

int ObObjCaster::is_order_consistent(const ObObjMeta& from, const ObObjMeta& to, bool& result)
{
  int ret = OB_SUCCESS;
  result = false;
  ObObjTypeClass tc1 = from.get_type_class();
  ObObjTypeClass tc2 = to.get_type_class();
  if (OB_UNLIKELY(ob_is_invalid_obj_tc(tc1) || ob_is_invalid_obj_tc(tc2))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected obj type class", K(ret), K(from), K(to));
  } else if (from.is_string_or_lob_locator_type() && to.is_string_or_lob_locator_type()) {
    ObCollationType res_cs_type = CS_TYPE_INVALID;
    ObCollationLevel res_cs_level = CS_LEVEL_INVALID;
    ObCollationType from_cs_type = from.get_collation_type();
    ObCollationType to_cs_type = to.get_collation_type();
    if (OB_FAIL(ObCharset::aggregate_collation(from.get_collation_level(),
            from_cs_type,
            to.get_collation_level(),
            to_cs_type,
            res_cs_level,
            res_cs_type))) {
      LOG_WARN("fail to aggregate collation", K(ret), K(from), K(to));
    } else {
      int64_t idx_from = get_idx_of_collate(from_cs_type);
      int64_t idx_to = get_idx_of_collate(to_cs_type);
      int64_t idx_res = get_idx_of_collate(res_cs_type);
      if (OB_UNLIKELY(idx_from < 0 || idx_to < 0 || idx_res < 0 || idx_from >= ObCharset::VALID_COLLATION_TYPES ||
                      idx_to >= ObCharset::VALID_COLLATION_TYPES || idx_res >= ObCharset::VALID_COLLATION_TYPES)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unexpected collation type", K(ret), K(from), K(to));
      } else {
        result = ORDER_CONSISTENT_WITH_BOTH_STRING[idx_from][idx_to][idx_res];
      }
    }
  } else {
    result = ORDER_CONSISTENT[tc1][tc2];
  }
  return ret;
}

/* make sure that you have read the doc before you call these functions !
 *
 * doc:  http://www.atatech.org/articles/56575
 */

int ObObjCaster::is_injection(const ObObjMeta& from, const ObObjMeta& to, bool& result)
{
  int ret = OB_SUCCESS;
  result = false;
  ObObjTypeClass tc1 = from.get_type_class();
  ObObjTypeClass tc2 = to.get_type_class();
  if (OB_UNLIKELY(ob_is_invalid_obj_tc(tc1) || ob_is_invalid_obj_tc(tc2))) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("unexpected obj type class", K(ret), K(from), K(to));
  } else if (from.is_string_or_lob_locator_type() && to.is_string_or_lob_locator_type()) {
    ObCollationType res_cs_type = CS_TYPE_INVALID;
    ObCollationLevel res_cs_level = CS_LEVEL_INVALID;
    ObCollationType from_cs_type = from.get_collation_type();
    ObCollationType to_cs_type = to.get_collation_type();
    if (OB_FAIL(ObCharset::aggregate_collation(from.get_collation_level(),
            from_cs_type,
            to.get_collation_level(),
            to_cs_type,
            res_cs_level,
            res_cs_type))) {
      LOG_WARN("fail to aggregate collation", K(ret), K(from), K(to));
    } else {
      int64_t idx_from = get_idx_of_collate(from_cs_type);
      int64_t idx_to = get_idx_of_collate(to_cs_type);
      int64_t idx_res = get_idx_of_collate(res_cs_type);
      if (OB_UNLIKELY(idx_from < 0 || idx_to < 0 || idx_res < 0 || idx_from >= ObCharset::VALID_COLLATION_TYPES ||
                      idx_to >= ObCharset::VALID_COLLATION_TYPES || idx_res >= ObCharset::VALID_COLLATION_TYPES)) {
        ret = OB_ERR_UNEXPECTED;
        LOG_WARN("unexpected collation type", K(ret), K(from), K(to));
      } else {
        result = INJECTION_WITH_BOTH_STRING[idx_from][idx_to][idx_res];
      }
    }
  } else {
    result = INJECTION[tc1][tc2];
  }
  return ret;
}

// more than 40 bytes: scientific notation.
// less or equal to 40 bytes: print directly.
int ObObjCaster::oracle_number_to_char(const number::ObNumber& number_val, const bool is_from_number_type,
    const int16_t scale, const int64_t len, char* buf, int64_t& pos)
{
  int ret = OB_SUCCESS;
  const int64_t COSNT_BUF_SIZE = 256;
  char ptr[COSNT_BUF_SIZE];
  int64_t str_len = 0;
  int64_t origin = pos;
  const int64_t SCI_NUMBER_LENGTH = 40;
  if (OB_UNLIKELY(pos > len || len < 0 || pos < 0 || NULL == buf)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid value", K(ret), K(pos), K(len), KP(buf));
  } else if (is_from_number_type) {
    if (OB_FAIL(number_val.format_with_oracle_limit(ptr, COSNT_BUF_SIZE, str_len, scale))) {
      LOG_WARN("fail to format", K(ret));
    }
  } else {
    if (OB_FAIL(number_val.format(ptr, COSNT_BUF_SIZE, str_len, scale))) {
      LOG_WARN("failed to format number to string", K(ret));
    }
  }

  if (OB_FAIL(ret)) {
  } else if (str_len <= SCI_NUMBER_LENGTH) {
    if (OB_UNLIKELY(str_len + pos > len)) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("the length of buffer is not enough", K(ret));
    } else {
      MEMCPY(buf + pos, ptr, str_len);
      pos += str_len;
    }
  } else if (OB_UNLIKELY(len - pos < SCI_NUMBER_LENGTH)) {
    ret = OB_INVALID_ARGUMENT;
    LOG_WARN("invalid value", K(ret), K(pos));
  } else {
    int64_t raw_pos = 0;
    char pow_str[6];
    int64_t pow_index = 0;
    bool pre_dot = false;
    pow_str[pow_index++] = 'E';
    pow_str[pow_index++] = '+';
    if ('-' == ptr[raw_pos]) {
      raw_pos++;
      buf[pos++] = '-';
    }
    if ('.' == ptr[raw_pos]) {
      raw_pos++;
      pre_dot = true;
      pow_str[pow_index - 1] = '-';
    }
    int64_t zero_count = 0;
    while ('0' == ptr[raw_pos] && raw_pos < str_len) {
      raw_pos++;
      zero_count++;
    }
    buf[pos++] = ptr[raw_pos++];
    buf[pos++] = '.';
    if (pre_dot) {
      if (OB_FAIL(databuff_printf(pow_str, sizeof(pow_str), pow_index, "%ld", zero_count + 1))) {
        LOG_WARN("fail to generate pow str", K(ret));
      } else {
        // pad zero to 40 bytes.
        while (pos < SCI_NUMBER_LENGTH - pow_index + origin) {
          if (raw_pos >= str_len) {
            buf[pos++] = '0';
          } else {
            buf[pos++] = ptr[raw_pos++];
          }
        }
      }
    } else if (!pre_dot && 0 == zero_count) {
      int64_t count = 0;
      bool enable_count = true;
      int64_t width_count = 0;
      while (pos < SCI_NUMBER_LENGTH - pow_index - width_count + origin) {
        if (raw_pos >= str_len) {
          buf[pos++] = '0';
        } else if ('.' == ptr[raw_pos]) {
          raw_pos++;
          enable_count = false;
        } else {
          if (enable_count) {
            count++;
            if (count >= 0 && count <= 9) {
              width_count = 1;
            } else if (count >= 10 && count <= 99) {
              width_count = 2;
            } else {
              width_count = 3;
            }
          }
          buf[pos++] = ptr[raw_pos++];
        }
      }
      for (int64_t i = raw_pos; enable_count && i < str_len && ptr[i] != '.'; ++i) {
        count++;
      }
      if (OB_FAIL(databuff_printf(pow_str, sizeof(pow_str), pow_index, "%ld", count))) {
        LOG_WARN("fail to generate pow str", K(ret));
      }
    } else {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("the number raw str is unexpected", K(ret));
    }
    // round the last digit and handle the carry.
    if (OB_SUCC(ret)) {
      int64_t carry = 0;
      int64_t carry_pos = pos;
      if (raw_pos < str_len && ptr[raw_pos] >= '5' && ptr[raw_pos] <= '9') {
        carry = 1;
        carry_pos--;
        while (carry && carry_pos >= origin && OB_SUCC(ret)) {
          if (buf[carry_pos] >= '0' && buf[carry_pos] <= '8') {
            buf[carry_pos] = (char)((int)buf[carry_pos] + carry);
            carry = 0;
            carry_pos--;
          } else if ('9' == buf[carry_pos]) {
            carry = 1;
            buf[carry_pos--] = '0';
          } else if ('.' == buf[carry_pos]) {
            carry_pos--;
          } else {
            ret = OB_ERR_UNEXPECTED;
            LOG_WARN("It's unexpected to round the number sci", K(ret));
          }
        }
        // right shift if get carry here.
        if (1 == carry && origin - 1 == carry_pos && OB_SUCC(ret)) {
          for (int64_t i = pos - 1; i >= origin + 1; --i) {
            buf[i] = buf[i - 1];
          }
          buf[origin] = '1';
        }
      }
    }
    // print power
    if (OB_SUCC(ret)) {
      for (int i = 0; i < pow_index; ++i) {
        buf[pos++] = pow_str[i];
      }
    }
    // check pos
    if (OB_SUCC(ret)) {
      if (str_len > SCI_NUMBER_LENGTH && pos - origin != SCI_NUMBER_LENGTH) {
        ret = OB_INVALID_ARGUMENT;
        LOG_WARN("the value of pos is invalid after number to char in oracle mode", K(pos), K(origin), K(ret));
      }
    }
  }
  return ret;
}

int ObObjCaster::can_cast_in_oracle_mode(const ObObjTypeClass expect_type, const ObObjTypeClass obj_type)
{
  int ret = OB_SUCCESS;
  if (cast_not_expected == OBJ_CAST_ORACLE_IMPLICIT[obj_type][expect_type]) {
    ret = OB_ERR_UNEXPECTED;
    LOG_WARN("not expected obj type convert", K(obj_type), K(expect_type), K(ret));
  } else if (cast_inconsistent_types == OBJ_CAST_ORACLE_IMPLICIT[obj_type][expect_type]) {
    ret = OB_ERR_INVALID_TYPE_FOR_OP;
    LOG_WARN("inconsistent datatypes", "expected", expect_type, "got", obj_type, K(ret));
  }

  return ret;
}

const bool ObObjCaster::CAST_MONOTONIC[ObMaxTC][ObMaxTC] = {
    // null
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        false,  // bit
        false,  // enumset
        false,  // enumsetinner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // lob
    },
    // int
    {
        false,  // null
        true,   // int
        true,   // uint
        false,  // float
        false,  // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        true,   // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // lob
    },
    // uint
    {
        false,  // null
        true,   // int
        true,   // uint
        false,  // float
        false,  // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        true,   // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // lob
    },
    // float
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        false,  // enumset
        false,  // enumsetInner
        true,   // bit
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // lob
    },
    // double
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        true,   // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // lob
    },
    // number
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        true,   // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // lob
    },
    // datetime
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        false,  // time
        true,   // year
        true,   // string
        false,  // extend
        false,  // unknown
        true,   // text
        true,   // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        true,   // lob
    },
    // date
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        false,  // time
        true,   // year
        true,   // string
        false,  // extend
        false,  // unknown
        true,   // text
        true,   // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        true,   // lob
    },
    // time
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        false,  // date
        true,   // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        true,   // text
        true,   // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        true,   // lob
    },
    // year
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        false,  // time
        true,   // year
        true,   // string
        false,  // extend
        false,  // unknown
        true,   // text
        true,   // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        true,   // lob
    },
    // string
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        true,   // string
        false,  // extend
        false,  // unknown
        true,   // text
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        true,   // raw
        true,   // interval
        true,   // rowid
        true,   // lob
    },
    // extend
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // lob
    },
    // unknown
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // lob
    },
    // text
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        true,   // string
        false,  // extend
        false,  // unknown
        true,   // text
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        true,   // lob
    },
    // bit
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        true,   // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // lob
    },
    // enumset
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // lob
    },
    // enumsetinner
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        false,  // text
    },
    // OTimestamp
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        false,  // time
        true,   // year
        true,   // string
        false,  // extend
        false,  // unknown
        true,   // text
        true,   // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        true,   // lob
    },
    // raw
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        true,   // string
        false,  // extend
        false,  // unknown
        false,  // text
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        true,   // raw
        false,  // interval,
        false,  // rowid
        false,  // lob
    },
    // interval
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // text
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        true,   // interval,
        false,  // rowid
        false,  // lob
    },
    // rowid
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        true,   // string
        false,  // extend
        false,  // unknown
        false,  // text
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval,
        true,   // rowid
        false,  // lob
    },
    // lob
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        true,   // string
        false,  // extend
        false,  // unknown
        true,   // text
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
        false,  // interval
        false,  // rowid
        true,   // lob
    },
};

const bool ObObjCaster::ORDER_CONSISTENT[ObMaxTC][ObMaxTC] = {
    // null
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // int
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // uint
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // float
    {
        false,  // null
        false,  // int
        false,  // uint
        true,   // float
        true,   // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // double
    {
        false,  // null
        false,  // int
        false,  // uint
        true,   // float
        true,   // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // number
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // datetime
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // date
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // time
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // year //0000-9999
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // string
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // extend
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // unknown
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // lob
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // bit
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // enumset
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // enumsetInner
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // OTimestamp
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // raw
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
};

const bool ObObjCaster::ORDER_CONSISTENT_WITH_BOTH_STRING[ObCharset::VALID_COLLATION_TYPES]
                                                         [ObCharset::VALID_COLLATION_TYPES]
                                                         [ObCharset::VALID_COLLATION_TYPES] = {
                                                             // CS_TYPE_UTF8MB4_GENERAL_CI
                                                             {
                                                                 // ci    //utf8bin //bin
                                                                 {true, true, true},
                                                                 {false, false, false},
                                                                 {false, false, false},
                                                             },
                                                             // CS_TYPE_UTF8MB4_BIN
                                                             {
                                                                 // ci    //utf8bin //bin
                                                                 {true, true, true},
                                                                 {false, true, true},
                                                                 {false, true, true},
                                                             },
                                                             // CS_TYPE_BINARY
                                                             {
                                                                 // ci    //utf8bin //bin
                                                                 {true, true, true},
                                                                 {false, true, true},
                                                                 {false, true, true},
                                                             },
};

const bool ObObjCaster::INJECTION[ObMaxTC][ObMaxTC] = {
    // null
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // int
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // uint
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // float
    {
        false,  // null
        false,  // int
        false,  // uint
        true,   // float
        true,   // double
        false,  // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // double
    {
        false,  // null
        false,  // int
        false,  // uint
        true,   // float
        true,   // double
        false,  // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // number
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // datetime
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number //2010-01-01 12:34:56.12345 = 20100101123456.1234520  and 2010-01-01 12:34:56.12345 =
                // 20100101123456.1234530
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // date
    {
        false,  // null
        false,  // int //think about 0000-00-00
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // time
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number //think about time(5) = decimal(40,7)
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string //00:12:34 = "00:12:34" and 00:12:34 = "00:12:34.000"
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // year //0000-9999
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime //1999 = 1999-00-00 00:00:00
        true,   // date //1999 = 1999-00-00
        true,   // time
        true,   // year
        false,  // string //1999 = "99" and 1999 = "1999"
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // string
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // extend
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // unknown
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // lob
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // bit
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // setenum
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        false,  // datetime
        false,  // date
        false,  // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // setenumInner
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number
        false,  // datetime
        false,  // date
        false,  // time
        false,  // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        false,  // OTimestamp
        false,  // raw
    },
    // OTimestamp
    {
        false,  // null
        false,  // int
        false,  // uint
        false,  // float
        false,  // double
        false,  // number //2010-01-01 12:34:56.12345 = 20100101123456.1234520  and 2010-01-01 12:34:56.12345 =
                // 20100101123456.1234530
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        false,  // bit
        false,  // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
    // raw
    {
        false,  // null
        true,   // int
        true,   // uint
        true,   // float
        true,   // double
        true,   // number
        true,   // datetime
        true,   // date
        true,   // time
        true,   // year
        false,  // string
        false,  // extend
        false,  // unknown
        false,  // lob
        true,   // bit
        true,   // enumset
        false,  // enumsetInner
        true,   // OTimestamp
        false,  // raw
    },
};

const bool ObObjCaster::INJECTION_WITH_BOTH_STRING[ObCharset::VALID_COLLATION_TYPES][ObCharset::VALID_COLLATION_TYPES]
                                                  [ObCharset::VALID_COLLATION_TYPES] = {
                                                      // CS_TYPE_UTF8MB4_GENERAL_CI
                                                      {
                                                          // ci    //utf8bin //bin
                                                          {true, true, true},   // CS_TYPE_UTF8MB4_GENERAL_CI
                                                          {false, true, true},  // CS_TYPE_UTF8MB4_BIN
                                                          {false, true, true},  // CS_TYPE_BINARY
                                                      },
                                                      // CS_TYPE_UTF8MB4_BIN
                                                      {
                                                          // ci    //utf8bin //bin
                                                          {true, true, true},   // CS_TYPE_UTF8MB4_GENERAL_CI
                                                          {false, true, true},  // CS_TYPE_UTF8MB4_BIN
                                                          {false, true, true},  // CS_TYPE_BINARY
                                                      },
                                                      // CS_TYPE_BINARY
                                                      {
                                                          // ci    //utf8bin //bin
                                                          {true, true, true},   // CS_TYPE_UTF8MB4_GENERAL_CI
                                                          {false, true, true},  // CS_TYPE_UTF8MB4_BIN
                                                          {false, true, true},  // CS_TYPE_BINARY
                                                      }};

int ObObjEvaluator::is_true(const ObObj& obj, ObCastMode cast_mode, bool& result)
{
  int ret = OB_SUCCESS;
  result = false;
  if (obj.is_null()) {
    // result is unkown
    // do nothing
  } else if (obj.is_numeric_type()) {
    result = !obj.is_zero();
  } else if (lib::is_oracle_mode() && obj.is_varchar_or_char() && 0 == obj.get_string_len()) {
    result = true;
  } else {
    ObArenaAllocator allocator(ObModIds::BLOCK_ALLOC);
    ObCastCtx cast_ctx(&allocator, NULL, cast_mode, CS_TYPE_INVALID);
    ObObj buf_obj;
    const ObObj* res_obj = NULL;
    if (OB_FAIL(ObObjCaster::to_type(ObNumberType, cast_ctx, obj, buf_obj, res_obj))) {
      LOG_WARN("failed to cast object to tinyint", K(ret), K(obj));
    } else if (NULL == res_obj || (!(res_obj->is_number()))) {
      ret = OB_ERR_UNEXPECTED;
      LOG_WARN("res_obj is NULL or unexpected obj type", K(ret), K(obj), K(res_obj));
    } else {
      result = !(res_obj->is_zero_number());
    }
  }
  return ret;
}

int ObObjEvaluator::is_false(const ObObj& obj, ObCastMode cast_mode, bool& b_result)
{
  int ret = OB_SUCCESS;
  b_result = true;

  if (OB_FAIL(is_true(obj, cast_mode, b_result))) {
    LOG_WARN("fail to evaluate obj", K(ret));
  } else {
    b_result = !b_result;
  }
  if (OB_SUCC(ret)) {
    if (obj.is_null()) {
      // result is unkown, unkown != false
      b_result = false;
    }
  }

  return ret;
}

}  // end namespace common
}  // end namespace oceanbase
