2862 lines
110 KiB
C++
2862 lines
110 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#define USING_LOG_PREFIX SQL_ENG
|
|
|
|
#include "ob_number_format_models.h"
|
|
#include "lib/charset/ob_charset.h"
|
|
#include "sql/engine/ob_exec_context.h"
|
|
#include "sql/engine/expr/ob_expr_util.h"
|
|
#include "share/system_variable/ob_nls_system_variable.h"
|
|
|
|
namespace oceanbase
|
|
{
|
|
namespace sql
|
|
{
|
|
const int64_t MAX_TO_CHAR_BUFFER_SIZE_IN_FORMAT_MODELS= 256;
|
|
|
|
const ObNFMKeyWord ObNFMElem::NFM_KEYWORDS[MAX_TYPE_NUMBER] =
|
|
{
|
|
{",", NFM_COMMA, GROUPING_GROUP, 1},
|
|
{".", NFM_PERIOD, GROUPING_GROUP, 1},
|
|
{"$", NFM_DOLLAR, DOLLAR_GROUP, 1},
|
|
{"0", NFM_ZERO, NUMBER_GROUP, 1},
|
|
{"9", NFM_NINE, NUMBER_GROUP, 1},
|
|
{"B", NFM_B, BLANK_GROUP, 0},
|
|
{"C", NFM_C, CURRENCY_GROUP, 7},
|
|
{"D", NFM_D, ISO_GROUPING_GROUP, 1},
|
|
{"EEEE", NFM_EEEE, EEEE_GROUP, 5},
|
|
{"G", NFM_G, ISO_GROUPING_GROUP, 1},
|
|
{"L", NFM_L, CURRENCY_GROUP, 10},
|
|
{"MI", NFM_MI, SIGN_GROUP, 1},
|
|
{"PR", NFM_PR, SIGN_GROUP, 2},
|
|
{"RN", NFM_RN, ROMAN_GROUP, 15},
|
|
{"S", NFM_S, SIGN_GROUP, 1},
|
|
{"TME", NFM_TME, TM_GROUP, 64},
|
|
{"TM9", NFM_TM9, TM_GROUP, 64},
|
|
{"TM", NFM_TM, TM_GROUP, 64},
|
|
{"U", NFM_U, CURRENCY_GROUP, 10},
|
|
{"V", NFM_V, MULTI_GROUP, 0},
|
|
{"X", NFM_X, HEX_GROUP, 1},
|
|
{"FM", NFM_FM, FILLMODE_GROUP, 0}
|
|
};
|
|
|
|
ObString ObNFMElem::get_elem_type_name() const
|
|
{
|
|
ObString result;
|
|
if (OB_ISNULL(keyword_) || is_valid_type(keyword_->elem_type_) || offset_ < 0) {
|
|
result = ObString("INVALID ELEMENT TYPE");
|
|
} else {
|
|
result = ObNFMElem::NFM_KEYWORDS[keyword_->elem_type_].to_obstring();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_conflict_group(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(elem_item)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid elem item", K(ret));
|
|
} else {
|
|
const ObNFMElem::ElementGroup elem_group = elem_item->keyword_->elem_group_;
|
|
switch(elem_group) {
|
|
case ObNFMElem::NUMBER_GROUP:
|
|
if (ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_tm_group(fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::GROUPING_GROUP:
|
|
if (ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_iso_grouping_group(fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_tm_group(fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::ISO_GROUPING_GROUP:
|
|
if (ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_grouping_group(fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_tm_group(fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::DOLLAR_GROUP:
|
|
if (ObNFMElem::has_type(NFM_DOLLAR_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_currency_group(fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_tm_group(fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::CURRENCY_GROUP:
|
|
if (ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_DOLLAR_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_currency_group(fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_tm_group(fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::EEEE_GROUP:
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_tm_group(fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::ROMAN_GROUP:
|
|
if (ObNFMElem::has_type(~NFM_FILLMODE_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::MULTI_GROUP:
|
|
if (ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_tm_group(fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::HEX_GROUP:
|
|
if (ObNFMElem::has_type((~NFM_HEX_FLAG) & (~NFM_ZERO_FLAG) & (~NFM_NINE_FLAG)
|
|
& (~NFM_FILLMODE_FLAG) & (~NFM_COMMA_FLAG)
|
|
& (~NFM_G_FLAG), fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::SIGN_GROUP:
|
|
if (ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_sign_group(fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_tm_group(fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::BLANK_GROUP:
|
|
if (ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_tm_group(fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::TM_GROUP:
|
|
if (ObNFMElem::has_type(~NFM_FILLMODE_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(elem_group));
|
|
}
|
|
break;
|
|
case ObNFMElem::FILLMODE_GROUP:
|
|
// do nothing
|
|
break;
|
|
default :
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unknown group type", K(ret), K(elem_group));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_comma_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can only appear in the integral part of a number
|
|
// can't appear before the number
|
|
// can't appear at the same time as element 'EEEE'
|
|
// can't appear after the element 'V'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (-1 == fmt_desc.digital_start_
|
|
|| elem_item->offset_ >= fmt_desc.decimal_pos_
|
|
|| ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem comma is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_period_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can appear only once
|
|
// can't appear at the same time as element 'V'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (fmt_desc.decimal_pos_ != INT32_MAX
|
|
|| ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem period is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_dollar_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can appear only once
|
|
// can't appear after the element 'EEEE'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_DOLLAR_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem dollar is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_zero_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can't appear after element 'EEEE' or element 'X'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem zero is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_nine_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can't appear after element 'EEEE' or element 'X'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem nine is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_b_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can appear only once
|
|
// can't appear after the element 'EEEE'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_BLANK_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem blank is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_c_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can appear only once
|
|
// can't appear after the element 'EEEE'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_currency_group(fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem currency is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_d_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can't appear at the same time as element 'V'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (fmt_desc.decimal_pos_ != INT32_MAX
|
|
|| ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem d is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_eeee_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can't appear at the same time as thousands separator
|
|
// when element 'V' appears in front of all numbers, element 'EEEE' can't appear behind
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)
|
|
|| (ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_)
|
|
&& fmt_desc.multi_ == fmt_desc.pre_num_count_)
|
|
|| ObNFMElem::has_type(NFM_COMMA_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem eeee is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_g_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can only appear in the integral part of a number
|
|
// can't appear before the number
|
|
// can't appear after the element 'V'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (-1 == fmt_desc.digital_start_
|
|
|| elem_item->offset_ >= fmt_desc.decimal_pos_
|
|
|| ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem g is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_l_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can't appear after the element 'EEEE'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_C_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem l is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_mi_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can only appear at the end of the fmt string
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_MI_FLAG, fmt_desc.elem_flag_)
|
|
|| !elem_item->is_last_elem_) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem mi is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_pr_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can only appear at the end of the fmt string
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_PR_FLAG, fmt_desc.elem_flag_)
|
|
|| !elem_item->is_last_elem_) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem pr is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_rn_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem rn is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_s_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can only appear at the front or the end of the fmt string
|
|
// but 'FM' + 'S' is an exception
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_S_FLAG, fmt_desc.elem_flag_)
|
|
|| (0 !=elem_item->offset_
|
|
&& (!elem_item->is_last_elem_
|
|
&& elem_item->prefix_type_ != ObNFMElem::NFM_FM))) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem s is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_tm_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_TM_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem tm is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_u_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can't appear after the element 'EEEE'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_U_FLAG, fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem u is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_v_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can't appear at the same time as element '.' or element 'D'
|
|
// can't appear after the element 'EEEE'
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_)
|
|
|| fmt_desc.decimal_pos_ != INT32_MAX
|
|
|| ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem multi is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_x_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::NFM_NINE == elem_item->prefix_type_) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem multi is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::check_elem_fm_is_valid(const ObNFMElem *elem_item,
|
|
const OBNFMDesc &fmt_desc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
// can only appear at the front of the fmt string
|
|
if (OB_FAIL(check_conflict_group(elem_item, fmt_desc))) {
|
|
LOG_WARN("check conflict group failed", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_FILLMODE_FLAG, fmt_desc.elem_flag_)
|
|
|| elem_item->offset_ != 0) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem hex is invalid", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMDescPrepare::fmt_desc_prepare(const common::ObSEArray<ObNFMElem*, 64> &fmt_elem_list,
|
|
OBNFMDesc &fmt_desc, bool need_check/*true*/)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
for (int32_t i = 0; OB_SUCC(ret) && i < fmt_elem_list.count(); ++i) {
|
|
const ObNFMElem *elem_item = fmt_elem_list.at(i);
|
|
if (OB_ISNULL(elem_item)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid elem item", K(ret));
|
|
} else {
|
|
switch (elem_item->keyword_->elem_type_) {
|
|
case ObNFMElem::NFM_COMMA:
|
|
if (need_check && OB_FAIL(check_elem_comma_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem comma is valid", K(ret));
|
|
} else {
|
|
fmt_desc.last_separator_ = elem_item->offset_;
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_COMMA_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_PERIOD:
|
|
if (need_check && OB_FAIL(check_elem_period_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem period is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_PERIOD_FLAG;
|
|
fmt_desc.decimal_pos_ = elem_item->offset_;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_DOLLAR:
|
|
if (need_check && OB_FAIL(check_elem_dollar_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem dollar is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_DOLLAR_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_ZERO:
|
|
if (need_check && OB_FAIL(check_elem_zero_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem zero is valid", K(ret));
|
|
} else {
|
|
if (-1 == fmt_desc.digital_start_) {
|
|
fmt_desc.digital_start_ = elem_item->offset_;
|
|
fmt_desc.zero_start_ = elem_item->offset_;
|
|
} else if (-1 == fmt_desc.zero_start_) {
|
|
fmt_desc.zero_start_ = elem_item->offset_;
|
|
}
|
|
fmt_desc.zero_end_ = elem_item->offset_;
|
|
fmt_desc.digital_end_ = elem_item->offset_;
|
|
// whether the decimal point appears
|
|
if (INT32_MAX == fmt_desc.decimal_pos_) {
|
|
++fmt_desc.pre_num_count_;
|
|
} else {
|
|
++fmt_desc.post_num_count_;
|
|
}
|
|
// if element 'V' appears, count the number of digits after element 'V'
|
|
if (ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_)) {
|
|
++fmt_desc.multi_;
|
|
}
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_ZERO_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_NINE:
|
|
if (need_check && OB_FAIL(check_elem_nine_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem nine is valid", K(ret));
|
|
} else {
|
|
if (-1 == fmt_desc.digital_start_) {
|
|
fmt_desc.digital_start_ = elem_item->offset_;
|
|
}
|
|
fmt_desc.digital_end_ = elem_item->offset_;
|
|
// whether the decimal point appears
|
|
if (INT32_MAX == fmt_desc.decimal_pos_) {
|
|
++fmt_desc.pre_num_count_;
|
|
} else {
|
|
++fmt_desc.post_num_count_;
|
|
}
|
|
// if element 'V' appears, count the number of digits after element 'V'
|
|
if (ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_)) {
|
|
++fmt_desc.multi_;
|
|
}
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_NINE_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_B:
|
|
if (need_check && OB_FAIL(check_elem_b_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem blank is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_BLANK_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_C:
|
|
if (need_check && OB_FAIL(check_elem_c_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem c is valid", K(ret));
|
|
} else {
|
|
// if the iso currency ('C', 'L', 'U') does not appear in the first or last position of
|
|
// the fmt string, it will also be treated as a decimal point
|
|
// but element ('FM', 'S') + element ('C', 'L', 'U') is exception
|
|
// element ('C', 'L', 'U') + element ('MI', 'PR', 'S') is exception
|
|
if (0 == elem_item->offset_
|
|
|| (elem_item->prefix_type_ == ObNFMElem::NFM_FM
|
|
|| elem_item->prefix_type_ == ObNFMElem::NFM_S)) {
|
|
fmt_desc.currency_appear_pos_ = OBNFMDesc::FIRST_POS;
|
|
} else if (elem_item->is_last_elem_
|
|
|| (elem_item->suffix_type_ == ObNFMElem::NFM_MI
|
|
|| elem_item->suffix_type_ == ObNFMElem::NFM_PR
|
|
|| elem_item->suffix_type_ == ObNFMElem::NFM_S)) {
|
|
fmt_desc.currency_appear_pos_ = OBNFMDesc::LAST_POS;
|
|
} else {
|
|
// if decimal point has appeared, fmt is invalid
|
|
if (need_check && (fmt_desc.decimal_pos_ != INT32_MAX
|
|
|| ObNFMElem::has_grouping_group(fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_))) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem currency is invalid", K(ret));
|
|
} else {
|
|
fmt_desc.decimal_pos_ = elem_item->offset_;
|
|
fmt_desc.currency_appear_pos_ = OBNFMDesc::MIDDLE_POS;
|
|
}
|
|
}
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_C_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_D:
|
|
if (need_check && OB_FAIL(check_elem_d_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem d is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_D_FLAG;
|
|
fmt_desc.decimal_pos_ = elem_item->offset_;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_EEEE:
|
|
if (need_check && OB_FAIL(check_elem_eeee_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem eeee is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_EEEE_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_G:
|
|
if (need_check && OB_FAIL(check_elem_g_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem g is valid", K(ret));
|
|
} else {
|
|
fmt_desc.last_separator_ = elem_item->offset_;
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_G_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_L:
|
|
if (need_check && OB_FAIL(check_elem_l_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem l is valid", K(ret));
|
|
} else {
|
|
// if the iso currency ('C', 'L', 'U') does not appear in the first or last position of
|
|
// the fmt string, it will also be treated as a decimal point
|
|
// but element ('FM', 'S') + element ('C', 'L', 'U') is exception
|
|
// element ('C', 'L', 'U') + element ('MI', 'PR', 'S') is exception
|
|
if (0 == elem_item->offset_
|
|
|| (elem_item->prefix_type_ == ObNFMElem::NFM_FM
|
|
|| elem_item->prefix_type_ == ObNFMElem::NFM_S)) {
|
|
fmt_desc.currency_appear_pos_ = OBNFMDesc::FIRST_POS;
|
|
} else if (elem_item->is_last_elem_
|
|
|| (elem_item->suffix_type_ == ObNFMElem::NFM_MI
|
|
|| elem_item->suffix_type_ == ObNFMElem::NFM_PR
|
|
|| elem_item->suffix_type_ == ObNFMElem::NFM_S)) {
|
|
fmt_desc.currency_appear_pos_ = OBNFMDesc::LAST_POS;
|
|
} else {
|
|
// if decimal point has appeared, fmt is invalid
|
|
if (need_check && (fmt_desc.decimal_pos_ != INT32_MAX
|
|
|| ObNFMElem::has_grouping_group(fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_))) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem currency is invalid", K(ret));
|
|
} else {
|
|
fmt_desc.decimal_pos_ = elem_item->offset_;
|
|
fmt_desc.currency_appear_pos_ = OBNFMDesc::MIDDLE_POS;
|
|
}
|
|
}
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_L_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_MI:
|
|
if (need_check && OB_FAIL(check_elem_mi_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem mi is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_MI_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_PR:
|
|
if (need_check && OB_FAIL(check_elem_pr_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem pr is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_PR_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_RN:
|
|
if (need_check && OB_FAIL(check_elem_rn_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem rn is valid", K(ret));
|
|
} else {
|
|
if (elem_item->case_mode_ == ObNFMElem::UPPER_CASE) {
|
|
fmt_desc.upper_case_flag_ |= NFM_RN_FLAG;
|
|
}
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_RN_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_S:
|
|
if (need_check && OB_FAIL(check_elem_s_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem s is valid", K(ret));
|
|
} else {
|
|
if (elem_item->is_last_elem_) {
|
|
fmt_desc.sign_appear_pos_ = OBNFMDesc::LAST_POS;
|
|
} else {
|
|
fmt_desc.sign_appear_pos_ = OBNFMDesc::FIRST_POS;
|
|
}
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_S_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_TME:
|
|
if (need_check && OB_FAIL(check_elem_tm_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem tme is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_TME_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_TM:
|
|
case ObNFMElem::NFM_TM9:
|
|
if (need_check && OB_FAIL(check_elem_tm_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem tm9 is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_TM_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_U:
|
|
if (need_check && OB_FAIL(check_elem_u_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem u is valid", K(ret));
|
|
} else {
|
|
// if the iso currency ('C', 'L', 'U') does not appear in the first or last position of
|
|
// the fmt string, it will also be treated as a decimal point
|
|
// but element ('FM', 'S') + element ('C', 'L', 'U') is exception
|
|
// element ('C', 'L', 'U') + element ('MI', 'PR', 'S') is exception
|
|
if (0 == elem_item->offset_
|
|
|| (elem_item->prefix_type_ == ObNFMElem::NFM_FM
|
|
|| elem_item->prefix_type_ == ObNFMElem::NFM_S)) {
|
|
fmt_desc.currency_appear_pos_ = OBNFMDesc::FIRST_POS;
|
|
} else if (elem_item->is_last_elem_
|
|
|| (elem_item->suffix_type_ == ObNFMElem::NFM_MI
|
|
|| elem_item->suffix_type_ == ObNFMElem::NFM_PR
|
|
|| elem_item->suffix_type_ == ObNFMElem::NFM_S)) {
|
|
fmt_desc.currency_appear_pos_ = OBNFMDesc::LAST_POS;
|
|
} else {
|
|
// if decimal point has appeared, fmt is invalid
|
|
if (need_check && (fmt_desc.decimal_pos_ != INT32_MAX
|
|
|| ObNFMElem::has_grouping_group(fmt_desc.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc.elem_flag_))) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("check elem currency is invalid", K(ret));
|
|
} else {
|
|
fmt_desc.decimal_pos_ = elem_item->offset_;
|
|
fmt_desc.currency_appear_pos_ = OBNFMDesc::MIDDLE_POS;
|
|
}
|
|
}
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_U_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_V:
|
|
if (need_check && OB_FAIL(check_elem_v_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem v is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_MULTI_FLAG;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_X:
|
|
if (0 == fmt_desc.elem_x_count_
|
|
&& elem_item->case_mode_ == ObNFMElem::UPPER_CASE) {
|
|
fmt_desc.upper_case_flag_ |= NFM_HEX_FLAG;
|
|
}
|
|
if (need_check && OB_FAIL(check_elem_x_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem hex is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_HEX_FLAG;
|
|
fmt_desc.elem_x_count_++;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_FM:
|
|
if (need_check && OB_FAIL(check_elem_fm_is_valid(elem_item, fmt_desc))) {
|
|
LOG_WARN("check elem fm is valid", K(ret));
|
|
} else {
|
|
fmt_desc.output_len_ += elem_item->keyword_->output_len_;
|
|
fmt_desc.elem_flag_ |= NFM_FILLMODE_FLAG;
|
|
}
|
|
break;
|
|
default :
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unknown elem type", K(ret), K(elem_item->keyword_->elem_type_));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc.elem_flag_)) {
|
|
fmt_desc.output_len_ = fmt_desc.output_len_ - fmt_desc.pre_num_count_ + 1;
|
|
}
|
|
if (!ObNFMElem::has_sign_group(fmt_desc.elem_flag_)
|
|
&& !ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc.elem_flag_)) {
|
|
// if no sign or element 'RN' appears, add a sign character
|
|
fmt_desc.output_len_ += 1;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
const char *const ObNFMBase::LOWER_RM1[9] =
|
|
{"i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"};
|
|
const char *const ObNFMBase::LOWER_RM10[9] =
|
|
{"x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"};
|
|
const char *const ObNFMBase::LOWER_RM100[9] =
|
|
{"c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"};
|
|
const char *const ObNFMBase::UPPER_RM1[9] =
|
|
{"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
|
|
const char *const ObNFMBase::UPPER_RM10[9] =
|
|
{"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
|
|
const char *const ObNFMBase::UPPER_RM100[9] =
|
|
{"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
|
|
|
|
int ObNFMBase::search_keyword(const char *cur_ch, const int32_t remain_len,
|
|
const ObNFMKeyWord *&match_key,
|
|
ObNFMElem::ElemCaseMode &case_mode) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(cur_ch) || remain_len <= 0) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid fmt str", K(ret), K(cur_ch), K(remain_len));
|
|
} else {
|
|
// if the first character of an element is lowercase, it is interpreted as lowercase
|
|
// otherwise, it is interpreted as uppercase
|
|
if ((*cur_ch >= 'a') && (*cur_ch <= 'z')) {
|
|
case_mode = ObNFMElem::LOWER_CASE;
|
|
} else if ((*cur_ch >= 'A') && (*cur_ch <= 'Z')) {
|
|
case_mode = ObNFMElem::UPPER_CASE;
|
|
} else {
|
|
case_mode = ObNFMElem::IGNORE_CASE;
|
|
}
|
|
int32_t index = 0;
|
|
for (index = 0; index < ObNFMElem::MAX_TYPE_NUMBER; ++index) {
|
|
const ObNFMKeyWord &keyword = ObNFMElem::NFM_KEYWORDS[index];
|
|
if (remain_len >= keyword.len_
|
|
&& (0 == strncasecmp(cur_ch, keyword.ptr_, keyword.len_))) {
|
|
match_key = &keyword;
|
|
break;
|
|
}
|
|
}
|
|
if (ObNFMElem::MAX_TYPE_NUMBER == index) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("invalid fmt character ", K(ret), K(cur_ch), K(remain_len));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::parse_fmt(const char* fmt_str, const int32_t fmt_len, bool need_check/*true*/)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(fmt_str) || fmt_len <= 0) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("invalid fmt str", K(ret), K(fmt_str), K(fmt_len));
|
|
} else {
|
|
fmt_str_.assign_ptr(fmt_str, fmt_len);
|
|
int32_t remain_len = fmt_len;
|
|
int32_t index = 0;
|
|
const char* cur_ch = fmt_str;
|
|
const char* fmt_end = fmt_str + fmt_len;
|
|
ObNFMElem *last_elem = NULL;
|
|
ObNFMElem::ElementType prefix_type = ObNFMElem::INVALID_TYPE;
|
|
for (index = 0; OB_SUCC(ret) && remain_len > 0 && cur_ch < fmt_end; ++index) {
|
|
char *elem_buf = NULL;
|
|
const ObNFMKeyWord *match_keyword = NULL;
|
|
ObNFMElem::ElemCaseMode case_mode = ObNFMElem::IGNORE_CASE;
|
|
if (OB_FAIL(search_keyword(cur_ch, remain_len, match_keyword, case_mode))) {
|
|
LOG_WARN("fail to search match keyword", K(ret), K(cur_ch), K(remain_len));
|
|
} else if (OB_ISNULL(elem_buf = static_cast<char*>(allocator_.alloc(sizeof(ObNFMElem))))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory");
|
|
} else {
|
|
ObNFMElem *cur_elem = new(elem_buf) ObNFMElem;
|
|
cur_elem->keyword_ = match_keyword;
|
|
cur_elem->offset_ = index;
|
|
cur_elem->case_mode_ = case_mode;
|
|
cur_elem->prefix_type_ = prefix_type;
|
|
if (OB_NOT_NULL(last_elem)) {
|
|
last_elem->suffix_type_ = cur_elem->keyword_->elem_type_;
|
|
}
|
|
prefix_type = cur_elem->keyword_->elem_type_;
|
|
last_elem = cur_elem;
|
|
cur_ch += cur_elem->keyword_->len_;
|
|
remain_len -= cur_elem->keyword_->len_;
|
|
if (remain_len <= 0) {
|
|
cur_elem->is_last_elem_ = true;
|
|
}
|
|
if (OB_FAIL(fmt_elem_list_.push_back(cur_elem))) {
|
|
LOG_WARN("fail to push back elem to fmt_elem_list", K(ret));
|
|
}
|
|
}
|
|
}
|
|
// fill format desc
|
|
if (OB_SUCC(ret) && OB_FAIL(ObNFMDescPrepare::fmt_desc_prepare(fmt_elem_list_,
|
|
fmt_desc_,
|
|
need_check))) {
|
|
LOG_WARN("fail to prepare format desc", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::fill_str(char *str, const int32_t str_len, const int32_t offset,
|
|
const char fill_ch, const int32_t fill_len) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(str) || (str_len - offset < fill_len)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("fail to fill str", K(ret), K(str), K(str_len), K(offset), K(fill_len));
|
|
} else {
|
|
MEMSET(str + offset, fill_ch, fill_len);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::append_decimal_digit(BigNumber &num, const uint32_t decimal_digit) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
uint64_t carry = decimal_digit;
|
|
for (size_t i = 0; i < num.count(); ++i) {
|
|
uint64_t product = num.at(i) * (uint64_t)10 + carry;
|
|
num[i] = static_cast<uint32_t>(product);
|
|
carry = product >> 32;
|
|
}
|
|
if (carry > 0 && OB_FAIL(num.push_back(carry))) {
|
|
LOG_WARN("fail to push digit", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::decimal_to_hex(const ObString &origin_str, char *buf,
|
|
const int64_t buf_len, int64_t &pos) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
BigNumber num;
|
|
const char *ptr = origin_str.ptr();
|
|
int32_t num_pos = 0;
|
|
pos = 0;
|
|
if (origin_str.empty()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("origin_str is empty", K(ret));
|
|
} else {
|
|
// if is negative, fill it with '#'
|
|
if ('-' == ptr[num_pos] && !is_zero(origin_str)) {
|
|
if (OB_FAIL(fill_str(buf, buf_len, 0, '#', fmt_desc_.output_len_))) {
|
|
LOG_WARN("fail to fill str", K(ret));
|
|
}
|
|
pos = fmt_desc_.output_len_;
|
|
} else if (ObNFMElem::has_type((~NFM_HEX_FLAG) & (~NFM_ZERO_FLAG)
|
|
& (~NFM_NINE_FLAG) & (~NFM_FILLMODE_FLAG),
|
|
fmt_desc_.elem_flag_)) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("incompatible with other formats", K(ret));
|
|
} else {
|
|
while (OB_SUCC(ret) && num_pos < origin_str.length()) {
|
|
if (is_digit(ptr[num_pos]) && OB_FAIL(append_decimal_digit(num, ptr[num_pos] - '0'))) {
|
|
LOG_WARN("fail to append decimal digit", K(ret));
|
|
}
|
|
++num_pos;
|
|
}
|
|
if (num.empty()) {
|
|
*buf = '0';
|
|
pos = 1;
|
|
} else {
|
|
uint32_t last_digit = num.at(num.count() - 1);
|
|
if (fmt_desc_.upper_case_flag_ & NFM_HEX_FLAG) {
|
|
if (OB_FAIL(databuff_printf(buf, buf_len, pos, "%X", last_digit))) {
|
|
LOG_WARN("fail to print hex", K(ret));
|
|
}
|
|
} else {
|
|
if (OB_FAIL(databuff_printf(buf, buf_len, pos, "%x", last_digit))) {
|
|
LOG_WARN("fail to print hex", K(ret));
|
|
}
|
|
}
|
|
for (ssize_t i = num.count() - 2; OB_SUCC(ret) && i >= 0; --i) {
|
|
if (fmt_desc_.upper_case_flag_ & NFM_HEX_FLAG) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%08X", num.at(i));
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%08x", num.at(i));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
// if the length of the fmt is less than the length of the result, fill it with '#'
|
|
int32_t valid_len = fmt_desc_.elem_x_count_ + fmt_desc_.pre_num_count_;
|
|
if (pos > valid_len) {
|
|
if (OB_FAIL(fill_str(buf, buf_len, 0, '#', fmt_desc_.output_len_))) {
|
|
LOG_WARN("fail to fill str", K(ret));
|
|
}
|
|
pos = fmt_desc_.output_len_;
|
|
} else {
|
|
ObString hex_str(pos, buf);
|
|
LOG_DEBUG("decimal_to_hex", K(hex_str));
|
|
if (pos < valid_len
|
|
&& ObNFMElem::has_type(NFM_ZERO_FLAG, fmt_desc_.elem_flag_)) {
|
|
// if the length of the fmt is greater than the length of the result string
|
|
// and the fmt model contains leading zero, the return result needs to be
|
|
// supplemented with '0'
|
|
// eg: to_char(100, '00x') --> '064'
|
|
int64_t fill_zero_count = valid_len - pos;
|
|
MEMMOVE(buf + fill_zero_count, buf, pos);
|
|
if (OB_FAIL(fill_str(buf, buf_len, 0, '0', fill_zero_count))) {
|
|
LOG_WARN("fail to fill str", K(ret));
|
|
} else {
|
|
pos += fill_zero_count;
|
|
}
|
|
}
|
|
// process fill mode
|
|
if (OB_SUCC(ret) && OB_FAIL(process_fillmode(buf, buf_len, pos))) {
|
|
LOG_WARN("fail to process fillmode", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::check_hex_str_valid(const char *str,
|
|
const int32_t str_len,
|
|
const int32_t offset) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int32_t hex_str_len = 0;
|
|
int32_t fmt_len = fmt_desc_.elem_x_count_ + fmt_desc_.pre_num_count_;
|
|
for (int32_t i = offset; OB_SUCC(ret) && i < str_len; i++) {
|
|
if ((str[i] >= '0' && str[i] <= '9')
|
|
|| (str[i] >= 'a' && str[i] <= 'f')
|
|
|| (str[i] >= 'A' && str[i] <= 'F')) {
|
|
++hex_str_len;
|
|
} else {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("invalid hex character", K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && hex_str_len > fmt_len) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("overflowed digit format", K(ret), K(hex_str_len), K(fmt_len));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// we'll represent an arbitrary-precision non-negative hexadecimal string as a vector of uint64
|
|
// every 15 hexadecimal strings are converted into a uint64 number
|
|
// eg: 12345123456789abcdef --> '12345' and '123456789abcdef'
|
|
// '12345' and '123456789abcdef' --> [81985529216486900, 74565]
|
|
int ObNFMBase::build_hex_number(const char *str, const int32_t str_len,
|
|
int32_t &offset, HexNumber &nums) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int32_t digit = 0;
|
|
uint64_t num = 0;
|
|
int32_t index = 0;
|
|
const int32_t batch_size = 15;
|
|
for (int32_t i = str_len - 1; OB_SUCC(ret) && i >= offset; i--) {
|
|
++index;
|
|
if (OB_FAIL(hex_to_num(str[i], digit))) {
|
|
LOG_WARN("invalid hex character", K(ret));
|
|
} else {
|
|
uint64_t power_val = pow(16, index - 1);
|
|
num = digit * power_val + num;
|
|
if (index % batch_size == 0) {
|
|
nums.push_back(num);
|
|
index = 0;
|
|
num = 0;
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && index % batch_size != 0) {
|
|
nums.push_back(num);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::int_to_roman_str(const int64_t num, char *buf,
|
|
const int64_t buf_len, int64_t &pos) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if ((num < 1 || num > 3999)) {
|
|
if (OB_FAIL(fill_str(buf, buf_len, 0, '#', fmt_desc_.output_len_))) {
|
|
LOG_WARN("fail to fill str", K(ret));
|
|
}
|
|
pos = fmt_desc_.output_len_;
|
|
} else {
|
|
int64_t str_len = 0;
|
|
char num_str[12] = {0};
|
|
str_len = snprintf(num_str, sizeof(num_str), "%d", static_cast<int32_t>(num));
|
|
for (char *p = num_str; OB_SUCC(ret) && *p != '\0'; p++, --str_len) {
|
|
int32_t val = *p - 49;
|
|
if (val < 0) {
|
|
continue;
|
|
}
|
|
if (str_len > 3) {
|
|
while (OB_SUCC(ret) && val-- != -1) {
|
|
if (fmt_desc_.upper_case_flag_ & NFM_RN_FLAG) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%s", "M");
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%s", "m");
|
|
}
|
|
}
|
|
} else {
|
|
if (str_len == 3) {
|
|
if (fmt_desc_.upper_case_flag_ & NFM_RN_FLAG) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%s", UPPER_RM100[val]);
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%s", LOWER_RM100[val]);
|
|
}
|
|
} else if (str_len == 2) {
|
|
if (fmt_desc_.upper_case_flag_ & NFM_RN_FLAG) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%s", UPPER_RM10[val]);
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%s", LOWER_RM10[val]);
|
|
}
|
|
} else if (str_len == 1) {
|
|
if (fmt_desc_.upper_case_flag_ & NFM_RN_FLAG) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%s", UPPER_RM1[val]);
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%s", LOWER_RM1[val]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && OB_FAIL(process_fillmode(buf, buf_len, pos))) {
|
|
LOG_WARN("fail to process fillmode", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::get_integer_part_len(const common::ObString &num_str,
|
|
int32_t &integer_part_len) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const char *ptr = num_str.ptr();
|
|
integer_part_len = 0;
|
|
bool digit_appear = false;
|
|
for (int32_t i = 0; i < num_str.length(); ++i) {
|
|
if (ptr[i] >= '0' && ptr[i] <= '9') {
|
|
integer_part_len++;
|
|
digit_appear = true;
|
|
} else if ('.' == ptr[i] || 'E' == ptr[i]) {
|
|
// if it's scientific notation
|
|
// eg: to_number('1E+00', '9BEEEE') --> integer_part_len = 1
|
|
break;
|
|
} else if (digit_appear && ptr[i] != ',') {
|
|
// to_number('USD123.123', 'c999.999')
|
|
// to_number('23USD00', '99C99') --> integer_part_len = 2
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::get_decimal_part_len(const common::ObString &num_str,
|
|
int32_t &decimal_part_len) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const char *ptr = num_str.ptr();
|
|
decimal_part_len = 0;
|
|
bool dc_appear = false;
|
|
for (int32_t i = 0; i < num_str.length(); ++i) {
|
|
if ('.' == ptr[i]) {
|
|
if (dc_appear) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("decimal already appear", K(ret));
|
|
} else {
|
|
dc_appear = true;
|
|
}
|
|
} else if ('E' == ptr[i]) {
|
|
// if it's scientific notation
|
|
// eg: to_number('1.23E+03', '9.99EEEE') --> decimal_part_len = 2
|
|
break;
|
|
} else if (ptr[i] < '0' || ptr[i] > '9') {
|
|
if (dc_appear) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("decimal already appear", K(ret));
|
|
} else {
|
|
dc_appear = true;
|
|
}
|
|
} else if (dc_appear && (ptr[i] >= '0' && ptr[i] <= '9')) {
|
|
++decimal_part_len;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool ObNFMBase::is_digit(const char c) const
|
|
{
|
|
return c >= '0' && c <= '9';
|
|
}
|
|
|
|
bool ObNFMBase::is_zero(const common::ObString &num_str) const
|
|
{
|
|
const char *ptr = num_str.ptr();
|
|
for (int32_t i = 0; i < num_str.length(); i++) {
|
|
if (ptr[i] != '-' && ptr[i] != '.' && ptr[i] != '0') {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int ObNFMBase::hex_to_num(const char c, int32_t &val) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (c >= '0' && c <= '9') {
|
|
val = c - '0';
|
|
} else if (c >= 'a' && c <= 'f') {
|
|
val = c - 'a' + 10;
|
|
} else if (c >= 'A' && c <= 'F') {
|
|
val = c - 'A' + 10;
|
|
} else {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("invalid hex character", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::process_fillmode(char *buf, const int64_t buf_len, int64_t &pos) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(buf) || buf_len < 0 || fmt_desc_.output_len_ < pos) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Invalid argument", K(ret), K(buf), K(buf_len));
|
|
} else {
|
|
int32_t space_size = fmt_desc_.output_len_ - pos;
|
|
if (!ObNFMElem::has_type(NFM_TME_FLAG, fmt_desc_.elem_flag_)
|
|
&& !ObNFMElem::has_type(NFM_TM_FLAG, fmt_desc_.elem_flag_)
|
|
&& !ObNFMElem::has_type(NFM_FILLMODE_FLAG, fmt_desc_.elem_flag_)) {
|
|
// if is not fill mode. needs to be moved to the end to fill leading ' '
|
|
if (space_size) {
|
|
MEMMOVE(buf + space_size, buf, pos);
|
|
for (int32_t i = 0; i < space_size; ++i) {
|
|
buf[i] = ' ';
|
|
}
|
|
}
|
|
pos = fmt_desc_.output_len_;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::get_nls_currency(const ObSQLSessionInfo &session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (ObNFMElem::has_type(NFM_C_FLAG, fmt_desc_.elem_flag_)) {
|
|
fmt_desc_.nls_currency_ = session.get_iso_nls_currency();
|
|
} else if (ObNFMElem::has_type(NFM_L_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(session.get_sys_variable(share::SYS_VAR_NLS_CURRENCY,
|
|
fmt_desc_.nls_currency_))) {
|
|
LOG_WARN("fail to get sys variable", K(ret));
|
|
}
|
|
} else if (ObNFMElem::has_type(NFM_U_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(session.get_sys_variable(share::SYS_VAR_NLS_DUAL_CURRENCY,
|
|
fmt_desc_.nls_currency_))) {
|
|
LOG_WARN("fail to get sys variable", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::get_iso_grouping(const ObSQLSessionInfo &session)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(session.get_sys_variable(share::SYS_VAR_NLS_NUMERIC_CHARACTERS,
|
|
fmt_desc_.iso_grouping_))) {
|
|
LOG_WARN("fail to get sys variable", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::conv_num_to_nfm_obj(const common::ObObj &obj,
|
|
common::ObExprCtx &expr_ctx,
|
|
ObNFMObj &nfm_obj)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
number::ObNumber num;
|
|
if (OB_ISNULL(expr_ctx.calc_buf_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Invalid argument.", K(ret), K(expr_ctx.calc_buf_));
|
|
} else {
|
|
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
|
|
if (obj.is_float() || obj.is_ufloat() || obj.is_double() || obj.is_udouble()) {
|
|
if (obj.is_double() || obj.is_udouble()) {
|
|
nfm_obj.set_obj_type(ObDoubleType);
|
|
nfm_obj.set_double(obj.get_double());
|
|
} else {
|
|
nfm_obj.set_obj_type(ObFloatType);
|
|
nfm_obj.set_float(obj.get_float());
|
|
}
|
|
} else {
|
|
EXPR_GET_NUMBER_V2(obj, num);
|
|
if (OB_FAIL(ret)) {
|
|
LOG_WARN("failed to cast obj as number", K(ret));
|
|
} else {
|
|
nfm_obj.set_obj_type(ObNumberType);
|
|
nfm_obj.set_number(num);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::conv_num_to_nfm_obj(const common::ObObjMeta &obj_meta,
|
|
const ObDatum &obj,
|
|
ObNFMObj &nfm_obj,
|
|
common::ObIAllocator &alloc)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const bool is_float = obj_meta.is_float();
|
|
const bool is_double = obj_meta.is_double();
|
|
const bool is_ufloat = obj_meta.is_ufloat();
|
|
const bool is_udouble = obj_meta.is_udouble();
|
|
const bool is_int_tc = obj_meta.is_integer_type();
|
|
if (is_float || is_ufloat || is_double || is_udouble) {
|
|
if (is_float || is_ufloat) {
|
|
nfm_obj.set_obj_type(ObFloatType);
|
|
nfm_obj.set_float(obj.get_float());
|
|
} else {
|
|
nfm_obj.set_obj_type(ObDoubleType);
|
|
nfm_obj.set_double(obj.get_double());
|
|
}
|
|
} else {
|
|
number::ObNumber num;
|
|
if (is_int_tc) { // int tc, to support PLS_INTERGER type
|
|
if (OB_FAIL(num.from(obj.get_int(), alloc))) {
|
|
LOG_WARN("fail to int_number", K(ret));
|
|
}
|
|
} else { // number
|
|
num.assign(obj.get_number().desc_.desc_,
|
|
const_cast<uint32_t *>(&(obj.get_number().digits_[0])));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
nfm_obj.set_obj_type(ObNumberType);
|
|
nfm_obj.set_number(num);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::cast_obj_to_int(const ObNFMObj &nfm_obj, int64_t &res_val)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObObjType obj_type = nfm_obj.get_obj_type();
|
|
int32_t scale = 0;
|
|
if (ObFloatType == obj_type) {
|
|
res_val = static_cast<int64_t>(ObExprUtil::round_double(nfm_obj.get_float(), scale));
|
|
} else if (ObDoubleType == obj_type) {
|
|
res_val = static_cast<int64_t>(ObExprUtil::round_double(nfm_obj.get_double(), scale));
|
|
} else {
|
|
number::ObNumber num = nfm_obj.get_number();
|
|
number::ObNumber nmb;
|
|
ObNumStackOnceAlloc tmp_alloc;
|
|
if (OB_FAIL(nmb.from(num, tmp_alloc))) {
|
|
LOG_WARN("copy number failed.", K(ret), K(num));
|
|
} else if (OB_FAIL(nmb.round(scale))) {
|
|
LOG_WARN("round failed.", K(ret), K(num.format()), K(scale));
|
|
} else if (!nmb.is_valid_int64(res_val)) {
|
|
// if it is not a valid int64, negative number returns INT64_MIN
|
|
// positive number returns INT64_MAX
|
|
if (nmb.is_negative()) {
|
|
res_val = INT64_MIN;
|
|
} else {
|
|
res_val = INT64_MAX;
|
|
}
|
|
}
|
|
}
|
|
LOG_DEBUG("cast_obj_to_int", K(ret), K(res_val));
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::remove_leading_zero(char *buf, int64_t &offset)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(buf)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid buf");
|
|
} else {
|
|
bool is_negative = false;
|
|
int32_t pos = 0;
|
|
if (offset > 0 && '-' == buf[0]) {
|
|
is_negative = true;
|
|
pos++;
|
|
}
|
|
int32_t leading_zero = 0;
|
|
for (; pos < offset; ++pos) {
|
|
if ('0' == buf[pos]) {
|
|
++leading_zero;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (leading_zero > 0) {
|
|
if (is_negative) {
|
|
MEMMOVE(buf + 1, buf + leading_zero + 1, offset - leading_zero);
|
|
} else {
|
|
MEMMOVE(buf, buf + leading_zero, offset - leading_zero);
|
|
}
|
|
offset -= leading_zero;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::cast_obj_to_num_str(const ObNFMObj &nfm_obj,
|
|
const int64_t scale,
|
|
common::ObString &num_str)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_negative = false;
|
|
int64_t num_str_len = 0;
|
|
number::ObNumber nmb;
|
|
char *num_str_buf = NULL;
|
|
const int64_t alloc_size = MAX_TO_CHAR_BUFFER_SIZE_IN_FORMAT_MODELS;
|
|
ObObjType obj_type = nfm_obj.get_obj_type();
|
|
if (OB_ISNULL(num_str_buf = static_cast<char *>(
|
|
allocator_.alloc(alloc_size)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory", K(ret));
|
|
} else {
|
|
if (ObFloatType == obj_type || ObDoubleType == obj_type) {
|
|
if (ObFloatType == obj_type) {
|
|
num_str_len = ob_gcvt_strict(nfm_obj.get_float(), OB_GCVT_ARG_FLOAT, alloc_size,
|
|
num_str_buf, NULL, lib::is_oracle_mode(), TRUE, FALSE);
|
|
} else if (ObDoubleType == obj_type) {
|
|
num_str_len = ob_gcvt_strict(nfm_obj.get_double(), OB_GCVT_ARG_DOUBLE, alloc_size,
|
|
num_str_buf, NULL, lib::is_oracle_mode(), TRUE, FALSE);
|
|
}
|
|
if (OB_FAIL(nmb.from(num_str_buf, num_str_len, allocator_))) {
|
|
LOG_WARN("number from str failed", K(ret));
|
|
}
|
|
num_str_len = 0;
|
|
} else {
|
|
number::ObNumber num = nfm_obj.get_number();
|
|
if (OB_FAIL(nmb.from(num, allocator_))) {
|
|
LOG_WARN("copy number failed.", K(ret), K(num));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(nmb.format_v2(num_str_buf, alloc_size, num_str_len, scale, false))) {
|
|
LOG_WARN("fail to convert number to string", K(ret));
|
|
} else {
|
|
is_negative = nmb.is_negative();
|
|
num_str.assign_ptr(num_str_buf, static_cast<int32_t>(num_str_len));
|
|
// is if "-0", special treatment for compatible with oracle
|
|
// eg: to_char(-0.4000, '0000') --> -0000
|
|
if (is_zero(num_str)) {
|
|
int32_t pos = 0;
|
|
if (is_negative) {
|
|
num_str_buf[pos++] = '-';
|
|
}
|
|
if (fmt_desc_.pre_num_count_ != 0
|
|
&& 0 == fmt_desc_.post_num_count_) {
|
|
num_str_buf[pos++] = '0';
|
|
}
|
|
num_str_buf[pos++] = '.';
|
|
if (fmt_desc_.post_num_count_ != 0) {
|
|
num_str_buf[pos++] = '0';
|
|
}
|
|
num_str.assign_ptr(num_str_buf, pos);
|
|
} else if (OB_FAIL(remove_leading_zero(num_str_buf, num_str_len))) {
|
|
LOG_WARN("fail to remove leading zero", K(ret));
|
|
} else {
|
|
num_str.assign_ptr(num_str_buf, static_cast<int32_t>(num_str_len));
|
|
}
|
|
LOG_DEBUG("cast_obj_to_num_str", K(num_str));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMBase::num_str_to_sci(const common::ObString &num_str, const int32_t scale,
|
|
char *buf, const int64_t len, int64_t &pos, bool is_tm) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const char *ptr = num_str.ptr();
|
|
int64_t str_len = num_str.length();
|
|
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_zero(num_str)) {
|
|
if (OB_FAIL(databuff_printf(buf, len, pos, "%.*s", num_str.length(),
|
|
num_str.ptr()))) {
|
|
LOG_WARN("fail to fill num str", K(ret), K(len), K(num_str));
|
|
} else if (OB_FAIL(databuff_printf(buf, len, pos, "%s", "E+00"))) {
|
|
LOG_WARN("fail to fill num str", K(ret));
|
|
}
|
|
} else {
|
|
int64_t raw_pos = 0;
|
|
//the string of the exponent part
|
|
char pow_str[6];
|
|
int64_t pow_size = 0;
|
|
int64_t pow_index = 0;
|
|
bool pre_dot = false;
|
|
bool is_negative = false;
|
|
int64_t width_count = 0;
|
|
pow_str[pow_index++] = 'E';
|
|
pow_str[pow_index++] = '+';
|
|
// handle the negative sign or decimal point at the beginning of num str
|
|
if ('-' == ptr[raw_pos]) {
|
|
raw_pos++;
|
|
buf[pos++] = '-';
|
|
is_negative = true;
|
|
}
|
|
if ('.' == ptr[raw_pos]) {
|
|
raw_pos++;
|
|
pre_dot = true;
|
|
pow_str[pow_index - 1] = '-';
|
|
}
|
|
int64_t zero_count = 0;
|
|
// first non-zero number found
|
|
while ('0' == ptr[raw_pos] && raw_pos < str_len) {
|
|
raw_pos++;
|
|
zero_count++;
|
|
}
|
|
buf[pos++] = ptr[raw_pos++];
|
|
if (scale != 0) {
|
|
buf[pos++] = '.';
|
|
}
|
|
// determine the index part and the number part according to
|
|
// whether there is a decimal point in the front
|
|
if (pre_dot) {
|
|
pow_size = zero_count + 1;
|
|
if (pow_size >= 0 && pow_size <= 99) {
|
|
width_count = 2;
|
|
} else {
|
|
width_count = 3;
|
|
}
|
|
if (scale > 0) {
|
|
for (int32_t count = 0; count < scale
|
|
&& pos < SCI_NUMBER_LENGTH - width_count - pow_index + origin;
|
|
++count) {
|
|
if (raw_pos >= str_len) {
|
|
buf[pos++] = '0';
|
|
} else {
|
|
buf[pos++] = ptr[raw_pos++];
|
|
}
|
|
}
|
|
} else if (scale < 0) {
|
|
while (raw_pos < str_len
|
|
&& pos < SCI_NUMBER_LENGTH - width_count - pow_index + origin) {
|
|
buf[pos++] = ptr[raw_pos++];
|
|
}
|
|
}
|
|
} else if (!pre_dot && 0 == zero_count) {
|
|
int64_t index_count = 0;
|
|
// if numbers greater than 10, always need to traverse the number
|
|
// array to know the final exponent. when a decimal point is encountered
|
|
// it will not be traversed. the index value will affect the number of bytes
|
|
// in the index part
|
|
for (int64_t i = raw_pos; i < str_len && ptr[i] != '.'; ++i) {
|
|
index_count++;
|
|
}
|
|
if (index_count >= 0 && index_count <= 99) {
|
|
width_count = 2;
|
|
} else {
|
|
width_count = 3;
|
|
}
|
|
if (scale > 0) {
|
|
for (int32_t count = 0; count < scale
|
|
&& pos < SCI_NUMBER_LENGTH - pow_index - width_count + origin;) {
|
|
if (raw_pos >= str_len) {
|
|
buf[pos++] = '0';
|
|
++count;
|
|
} else if ('.' == ptr[raw_pos]) {
|
|
raw_pos++;
|
|
} else {
|
|
buf[pos++] = ptr[raw_pos++];
|
|
++count;
|
|
}
|
|
}
|
|
} else if (scale < 0) {
|
|
while (raw_pos < str_len && pos < SCI_NUMBER_LENGTH - pow_index - width_count + origin) {
|
|
if ('.' == ptr[raw_pos]) {
|
|
raw_pos++;
|
|
} else {
|
|
buf[pos++] = ptr[raw_pos++];
|
|
}
|
|
}
|
|
}
|
|
pow_size = index_count;
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("the number raw str is unexpected", K(ret));
|
|
}
|
|
// round the last digit and process the carry
|
|
if (!is_tm && OB_SUCC(ret)) {
|
|
int64_t carry = 0;
|
|
int64_t carry_pos = pos;
|
|
int64_t digit_start_pos = is_negative ? origin + 1 : origin;
|
|
if ('.' == ptr[raw_pos]) { ++raw_pos; }
|
|
if (raw_pos < str_len && ptr[raw_pos] >= '5' && ptr[raw_pos] <= '9') {
|
|
carry = 1;
|
|
carry_pos--;
|
|
while (carry && carry_pos >= digit_start_pos && 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));
|
|
}
|
|
}
|
|
if (1 == carry && digit_start_pos - 1 == carry_pos && OB_SUCC(ret)) {
|
|
bool decimal_appear = false;
|
|
for (int64_t i = pos - 1; i >= digit_start_pos + 1; --i) {
|
|
if (buf[i - 1] != '.') {
|
|
buf[i] = buf[i - 1];
|
|
} else {
|
|
decimal_appear = true;
|
|
}
|
|
}
|
|
buf[digit_start_pos] = '1';
|
|
if (decimal_appear) {
|
|
buf[digit_start_pos + 1] = '.';
|
|
}
|
|
++pow_size;
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && is_tm) {
|
|
int32_t offset = 0;
|
|
// 1.0000000000000000000000000000000000E+65 --> 1E+65
|
|
for (offset = pos - 1; offset > origin; offset--) {
|
|
if (buf[offset] != '0') {
|
|
break;
|
|
}
|
|
}
|
|
pos = offset + 1;
|
|
if ('.' == buf[offset]) {
|
|
--pos;
|
|
}
|
|
}
|
|
// print exponent
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(databuff_printf(pow_str, sizeof(pow_str), pow_index, "%02ld", pow_size))) {
|
|
LOG_WARN("fail to generate pow str", K(ret));
|
|
} else {
|
|
for (int i = 0; i < pow_index; ++i) {
|
|
buf[pos++] = pow_str[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::process_mul_format(const ObNFMObj &nfm_obj, common::ObString &num_str)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
number::ObNumber num_val;
|
|
number::ObNumber base_num;
|
|
number::ObNumber power_num;
|
|
number::ObNumber origin_num;
|
|
const int64_t base_val = 10;
|
|
const int64_t scale = 0;
|
|
int64_t origin_str_len = 0;
|
|
char *origin_str_buf = NULL;
|
|
int64_t exponent = fmt_desc_.multi_;
|
|
const int64_t alloc_size = MAX_TO_CHAR_BUFFER_SIZE_IN_FORMAT_MODELS;
|
|
if (OB_ISNULL(origin_str_buf = static_cast<char *>(
|
|
allocator_.alloc(alloc_size)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory", K(ret));
|
|
} else {
|
|
ObObjType obj_type = nfm_obj.get_obj_type();
|
|
int64_t power_val = pow(10, exponent);
|
|
if (ObFloatType == obj_type) {
|
|
origin_str_len = ob_fcvt(ObExprUtil::round_double(nfm_obj.get_float() * power_val, scale),
|
|
scale, alloc_size, origin_str_buf, NULL);
|
|
} else if (ObDoubleType == obj_type) {
|
|
origin_str_len = ob_fcvt(ObExprUtil::round_double(nfm_obj.get_double() * power_val, scale),
|
|
scale, alloc_size, origin_str_buf, NULL);
|
|
} else if (ObNumberType == obj_type) {
|
|
num_val = nfm_obj.get_number();
|
|
if (OB_FAIL(base_num.from(base_val, allocator_))) {
|
|
LOG_WARN("fail to cast int to number", K(ret));
|
|
} else if (OB_FAIL(base_num.power(exponent, power_num, allocator_))) {
|
|
LOG_WARN("power calc failed", K(ret));
|
|
} else if (OB_FAIL(num_val.mul_v2(power_num, origin_num, allocator_))) {
|
|
LOG_WARN("fail to mul number", K(ret));
|
|
} else if (OB_FAIL(origin_num.round(scale))) {
|
|
LOG_WARN("round failed", K(ret), K(origin_num), K(scale));
|
|
} else if (OB_FAIL(origin_num.format_v2(origin_str_buf, alloc_size,
|
|
origin_str_len, scale, false))) {
|
|
LOG_WARN("fail to convert number to string", K(ret));
|
|
}
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid obj type", K(ret), K(obj_type));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
num_str.assign_ptr(origin_str_buf, static_cast<int32_t>(origin_str_len));
|
|
LOG_DEBUG("obj_to_multi_num_str", K(num_str));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::process_roman_format(const ObNFMObj &nfm_obj, char *buf,
|
|
const int64_t buf_len, int64_t &pos)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t val;
|
|
if (OB_FAIL(cast_obj_to_int(nfm_obj, val))) {
|
|
LOG_WARN("fail to cast obj to int", K(ret));
|
|
} else if (OB_FAIL(int_to_roman_str(val, buf, buf_len, pos))) {
|
|
LOG_WARN("fail to convert int to roman str", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::process_hex_format(const ObNFMObj &nfm_obj, char *buf,
|
|
const int64_t buf_len, int64_t &pos)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t scale = 0;
|
|
ObString origin_str;
|
|
if (OB_FAIL(cast_obj_to_num_str(nfm_obj, scale, origin_str))) {
|
|
LOG_WARN("fail to cast obj to num str", K(ret));
|
|
} else if (OB_FAIL(decimal_to_hex(origin_str, buf, buf_len, pos))) {
|
|
LOG_WARN("fail to convert decimal to hex str", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::process_tm_format(const ObNFMObj &nfm_obj, char *buf,
|
|
const int64_t buf_len, int64_t &pos)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t num_str_len = 0;
|
|
char *num_str_buf = NULL;
|
|
ObString num_str;
|
|
const int32_t scale = -1;
|
|
const int64_t alloc_size = MAX_TO_CHAR_BUFFER_SIZE_IN_FORMAT_MODELS;
|
|
if (OB_ISNULL(num_str_buf = static_cast<char *>(
|
|
allocator_.alloc(alloc_size)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory", K(ret));
|
|
} else {
|
|
ObObjType obj_type = nfm_obj.get_obj_type();
|
|
if (ObFloatType == obj_type) {
|
|
num_str_len = ob_gcvt_opt(nfm_obj.get_float(), OB_GCVT_ARG_FLOAT, static_cast<int32_t>(alloc_size),
|
|
num_str_buf, NULL, lib::is_oracle_mode(), TRUE);
|
|
} else if (ObDoubleType == obj_type) {
|
|
num_str_len = ob_gcvt_opt(nfm_obj.get_double(), OB_GCVT_ARG_DOUBLE, static_cast<int32_t>(alloc_size),
|
|
num_str_buf, NULL, lib::is_oracle_mode(), TRUE);
|
|
} else if (ObNumberType == obj_type) {
|
|
number::ObNumber num = nfm_obj.get_number();
|
|
number::ObNumber nmb;
|
|
if (OB_FAIL(nmb.from(num, allocator_))) {
|
|
LOG_WARN("copy number failed.", K(ret), K(num));
|
|
} else if (OB_FAIL(nmb.format_v2(num_str_buf, alloc_size, num_str_len, scale, false))) {
|
|
LOG_WARN("fail to format", K(ret), K(nmb));
|
|
}
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid obj type", K(ret), K(obj_type));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
num_str.assign_ptr(num_str_buf, static_cast<int32_t>(num_str_len));
|
|
LOG_DEBUG("process_tme_format", K(ret), K(num_str_buf), K(num_str_len));
|
|
if (num_str_len <= 64) {
|
|
MEMCPY(buf, num_str_buf, num_str_len);
|
|
pos += num_str_len;
|
|
} else if (num_str_len > 64) {
|
|
if (OB_FAIL(num_str_to_sci(num_str, scale, buf, buf_len, pos, true))) {
|
|
LOG_WARN("failed to convert num to sci str", K(ret));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && OB_FAIL(process_fillmode(buf, buf_len, pos))) {
|
|
LOG_WARN("fail to process fillmode", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::process_tme_format(const ObNFMObj &nfm_obj, char *buf,
|
|
const int64_t buf_len, int64_t &pos)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t num_str_len = 0;
|
|
char *num_str_buf = NULL;
|
|
ObString num_str;
|
|
const int32_t scale = -1;
|
|
const int64_t alloc_size = MAX_TO_CHAR_BUFFER_SIZE_IN_FORMAT_MODELS;
|
|
if (OB_ISNULL(num_str_buf = static_cast<char *>(
|
|
allocator_.alloc(alloc_size)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory", K(ret));
|
|
} else {
|
|
ObObjType obj_type = nfm_obj.get_obj_type();
|
|
if (ObFloatType == obj_type) {
|
|
num_str_len = ob_gcvt_opt(nfm_obj.get_float(), OB_GCVT_ARG_FLOAT, static_cast<int32_t>(alloc_size),
|
|
num_str_buf, NULL, lib::is_oracle_mode(), TRUE);
|
|
} else if (ObDoubleType == obj_type) {
|
|
num_str_len = ob_gcvt_opt(nfm_obj.get_double(), OB_GCVT_ARG_DOUBLE, static_cast<int32_t>(alloc_size),
|
|
num_str_buf, NULL, lib::is_oracle_mode(), TRUE);
|
|
} else if (ObNumberType == obj_type) {
|
|
number::ObNumber num = nfm_obj.get_number();
|
|
number::ObNumber nmb;
|
|
if (OB_FAIL(nmb.from(num, allocator_))) {
|
|
LOG_WARN("copy number failed.", K(ret), K(num));
|
|
} else if (OB_FAIL(nmb.format_v2(num_str_buf, alloc_size, num_str_len, scale, false))) {
|
|
LOG_WARN("fail to format", K(ret), K(nmb));
|
|
}
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid obj type", K(ret), K(obj_type));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
num_str.assign_ptr(num_str_buf, static_cast<int32_t>(num_str_len));
|
|
LOG_DEBUG("process_tme_format", K(ret), K(num_str_buf), K(num_str_len));
|
|
if (OB_FAIL(num_str_to_sci(num_str, scale, buf, buf_len, pos, true))) {
|
|
LOG_WARN("failed to convert num to sci str", K(ret));
|
|
} else if (OB_FAIL(process_fillmode(buf, buf_len, pos))) {
|
|
LOG_WARN("fail to process fillmode", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::process_sci_format(const common::ObString &origin_str, const int32_t scale,
|
|
common::ObString &num_str)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t sci_str_len = 0;
|
|
char *sci_str_buf = NULL;
|
|
const int64_t alloc_size = MAX_TO_CHAR_BUFFER_SIZE_IN_FORMAT_MODELS;
|
|
if (fmt_desc_.pre_num_count_ < 1) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("invalid number fmt model", K_(fmt_str));
|
|
} else if (OB_ISNULL(sci_str_buf = static_cast<char *>(
|
|
allocator_.alloc(alloc_size)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory", K(ret));
|
|
} else {
|
|
if (OB_FAIL(num_str_to_sci(origin_str, scale, sci_str_buf, alloc_size, sci_str_len, false))) {
|
|
LOG_WARN("failed to convert num to sci str", K(ret));
|
|
} else {
|
|
num_str.assign_ptr(sci_str_buf, sci_str_len);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::process_output_fmt(const common::ObString &str,
|
|
const int32_t integer_part_len,
|
|
char *buf, const int64_t buf_len, int64_t &pos)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const char *num_str = str.ptr();
|
|
int32_t num_str_len = str.length();
|
|
int32_t num_str_pos = 0;
|
|
pos = 0;
|
|
bool is_negative = false;
|
|
if ('-' == num_str[num_str_pos]) {
|
|
num_str_pos++;
|
|
is_negative = true;
|
|
}
|
|
// processing leading positive or negative sign element
|
|
if (ObNFMElem::has_sign_group(fmt_desc_.elem_flag_)) {
|
|
if (ObNFMElem::has_type(NFM_S_FLAG, fmt_desc_.elem_flag_)
|
|
&& OBNFMDesc::FIRST_POS == fmt_desc_.sign_appear_pos_) {
|
|
if (is_negative) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '-');
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '+');
|
|
}
|
|
} else if (ObNFMElem::has_type(NFM_PR_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (is_negative) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '<');
|
|
}
|
|
}
|
|
} else {
|
|
// if there is no leading positive or negative sign element
|
|
// fill in '-' before negative
|
|
if (is_negative) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '-');
|
|
}
|
|
}
|
|
// processing element '$'
|
|
if (OB_SUCC(ret) && ObNFMElem::has_type(NFM_DOLLAR_FLAG, fmt_desc_.elem_flag_)) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '$');
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
int32_t need_skip_num = fmt_desc_.pre_num_count_ - integer_part_len;
|
|
bool digit_appear = false;
|
|
int32_t traversed_num_count = 0;
|
|
for (int32_t i = 0; OB_SUCC(ret) && i < fmt_elem_list_.count(); ++i) {
|
|
const ObNFMElem *elem_item = fmt_elem_list_.at(i);
|
|
if (OB_ISNULL(elem_item)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid elem item", K(ret));
|
|
} else {
|
|
switch (elem_item->keyword_->elem_type_) {
|
|
case ObNFMElem::NFM_COMMA:
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (!digit_appear ||
|
|
traversed_num_count > integer_part_len) {
|
|
// skip, do nothing
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", ',');
|
|
}
|
|
} else {
|
|
if (!digit_appear ||
|
|
(need_skip_num && (fmt_desc_.zero_start_ < 0 || fmt_desc_.zero_start_ > i))) {
|
|
// skip, do nothing
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", ',');
|
|
}
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_PERIOD:
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '.');
|
|
if ('.' == num_str[num_str_pos]) {
|
|
num_str_pos++;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_ZERO:
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (traversed_num_count >= integer_part_len) {
|
|
// skip, do nothing
|
|
} else if (num_str_pos >= num_str_len || !is_digit(num_str[num_str_pos])) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("invalid number", K(ret), K(str));
|
|
} else {
|
|
digit_appear = true;
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", num_str[num_str_pos++]);
|
|
}
|
|
} else {
|
|
if (need_skip_num) {
|
|
// need to fill leading '0'
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '0');
|
|
need_skip_num--;
|
|
digit_appear = true;
|
|
} else if (num_str_pos >= num_str_len || !is_digit(num_str[num_str_pos])) {
|
|
// need to fill '0' at last
|
|
// eg: to_char(123456789, 'FM999999999.00000') --> 123456789.00000
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '0');
|
|
digit_appear = true;
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", num_str[num_str_pos++]);
|
|
digit_appear = true;
|
|
}
|
|
}
|
|
++traversed_num_count;
|
|
break;
|
|
case ObNFMElem::NFM_NINE:
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (traversed_num_count >= integer_part_len) {
|
|
// skip, do nothing
|
|
} else if (num_str_pos >= num_str_len || !is_digit(num_str[num_str_pos])) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("invalid number", K(ret), K(str));
|
|
} else {
|
|
digit_appear = true;
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", num_str[num_str_pos++]);
|
|
}
|
|
} else {
|
|
if (need_skip_num) {
|
|
// if element '0' has appeared, the following numbers need to fill '0'
|
|
// eg: to_char(123.123, '9099999.999') --> 000123.123
|
|
if (fmt_desc_.zero_start_ >= 0 && fmt_desc_.zero_start_ < i) {
|
|
digit_appear = true;
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '0');
|
|
}
|
|
need_skip_num--;
|
|
} else if (num_str_pos >= num_str_len || !is_digit(num_str[num_str_pos])) {
|
|
// eg: to_char(10000, 'FM99,999.99') --> 10,000.
|
|
// eg: to_char(10000, '99,999.99') --> 10,000.00
|
|
if (!ObNFMElem::has_type(NFM_FILLMODE_FLAG, fmt_desc_.elem_flag_)
|
|
|| (fmt_desc_.zero_end_ >= 0 && fmt_desc_.zero_end_ > i)) {
|
|
digit_appear = true;
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '0');
|
|
}
|
|
} else {
|
|
digit_appear = true;
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", num_str[num_str_pos++]);
|
|
}
|
|
}
|
|
++traversed_num_count;
|
|
break;
|
|
case ObNFMElem::NFM_D:
|
|
if (fmt_desc_.iso_grouping_.length() < 2) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid iso grouping", K(ret), K(fmt_desc_.iso_grouping_));
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", fmt_desc_.iso_grouping_.ptr()[0]);
|
|
// eg: to_char(123, 'FM999.9999') --> 123.
|
|
if (fmt_desc_.iso_grouping_.ptr()[0] == num_str[num_str_pos]) {
|
|
num_str_pos++;
|
|
}
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_G:
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (!digit_appear ||
|
|
traversed_num_count > integer_part_len) {
|
|
// skip, do nothing
|
|
} else {
|
|
if (fmt_desc_.iso_grouping_.length() < 2) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid iso grouping", K(ret), K(fmt_desc_.iso_grouping_));
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", fmt_desc_.iso_grouping_.ptr()[1]);
|
|
}
|
|
}
|
|
} else {
|
|
if (!digit_appear ||
|
|
(need_skip_num && (fmt_desc_.zero_start_ < 0 || fmt_desc_.zero_start_ > i))) {
|
|
// skip, do nothing
|
|
} else {
|
|
if (fmt_desc_.iso_grouping_.length() < 2) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid iso grouping", K(ret), K(fmt_desc_.iso_grouping_));
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", fmt_desc_.iso_grouping_.ptr()[1]);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_C:
|
|
case ObNFMElem::NFM_L:
|
|
case ObNFMElem::NFM_U:
|
|
ret = databuff_printf(buf, buf_len, pos, "%.*s",
|
|
fmt_desc_.nls_currency_.length(), fmt_desc_.nls_currency_.ptr());
|
|
if (OBNFMDesc::MIDDLE_POS == fmt_desc_.currency_appear_pos_) {
|
|
// if the element('C', 'L', 'U') appears in the middle, it will be regarded as the
|
|
// decimal point, so the iso currency symbol is used to replace the decimal point
|
|
if (num_str_pos < num_str_len && '.' == num_str[num_str_pos]) {
|
|
num_str_pos++;
|
|
}
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_EEEE:
|
|
while (OB_SUCC(ret) && num_str_pos < num_str_len) {
|
|
buf[pos++] = num_str[num_str_pos];
|
|
num_str_pos++;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// processing the last positive or negative sign element
|
|
if (OB_SUCC(ret) && ObNFMElem::has_sign_group(fmt_desc_.elem_flag_)) {
|
|
if (ObNFMElem::has_type(NFM_S_FLAG, fmt_desc_.elem_flag_)
|
|
&& OBNFMDesc::LAST_POS == fmt_desc_.sign_appear_pos_) {
|
|
if (is_negative) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '-');
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '+');
|
|
}
|
|
} else if (ObNFMElem::has_type(NFM_PR_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (is_negative) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '>');
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", ' ');
|
|
}
|
|
} else if (ObNFMElem::has_type(NFM_MI_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (is_negative) {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", '-');
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, pos, "%c", ' ');
|
|
}
|
|
}
|
|
}
|
|
// processing result is zero and has element 'B'
|
|
if (OB_SUCC(ret) && ObNFMElem::has_type(NFM_BLANK_FLAG, fmt_desc_.elem_flag_) && is_zero(str)) {
|
|
if (ObNFMElem::has_type(NFM_FILLMODE_FLAG, fmt_desc_.elem_flag_)) {
|
|
fmt_desc_.output_len_ = 0;
|
|
} else {
|
|
if (OB_FAIL(fill_str(buf, buf_len, 0, ' ', fmt_desc_.output_len_))) {
|
|
LOG_WARN("fail to fill str", K(ret));
|
|
}
|
|
}
|
|
pos = fmt_desc_.output_len_;
|
|
}
|
|
if (pos > fmt_desc_.output_len_) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("res str is larger than output len", K(ret), K(pos), K(fmt_desc_.output_len_));
|
|
}
|
|
if (OB_SUCC(ret) && OB_FAIL(process_fillmode(buf, buf_len, pos))) {
|
|
LOG_WARN("fail to process fillmode", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::process_fmt_conv(const ObSQLSessionInfo &session,
|
|
const char *fmt_str, const int32_t fmt_len,
|
|
const ObNFMObj &nfm_obj, char *res_buf,
|
|
const int64_t res_buf_len, int64_t &offset)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObString num_str;
|
|
bool is_overflow = false;
|
|
int32_t integer_part_len = 0;
|
|
if (OB_FAIL(parse_fmt(fmt_str, fmt_len))) {
|
|
LOG_WARN("fail to parse fmt model", K(ret), K(fmt_str), K(fmt_len));
|
|
} else {
|
|
// processing calculation conversion element
|
|
if (ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(process_roman_format(nfm_obj, res_buf, res_buf_len, offset))) {
|
|
LOG_WARN("fail to process roman fmt", K(ret));
|
|
}
|
|
} else if (ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(process_hex_format(nfm_obj, res_buf, res_buf_len, offset))) {
|
|
LOG_WARN("fail to process hex fmt", K(ret));
|
|
}
|
|
} else if (ObNFMElem::has_type(NFM_TM_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(process_tm_format(nfm_obj, res_buf, res_buf_len, offset))) {
|
|
LOG_WARN("fail to process tm fmt", K(ret));
|
|
}
|
|
} else if (ObNFMElem::has_type(NFM_TME_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(process_tme_format(nfm_obj, res_buf, res_buf_len, offset))) {
|
|
LOG_WARN("fail to process tme fmt", K(ret));
|
|
}
|
|
} else {
|
|
// the number of digits after the decimal point means how many decimal places are reserved
|
|
// eg: to_char(123.123, '999.99') --> 123.12
|
|
// the value is rounded to two decimal places
|
|
const int32_t scale = fmt_desc_.post_num_count_;
|
|
if (ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(process_mul_format(nfm_obj, num_str))) {
|
|
LOG_WARN("fail to process mul format", K(ret));
|
|
}
|
|
} else {
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(cast_obj_to_num_str(nfm_obj, -1, num_str))) {
|
|
LOG_WARN("fail to cast obj to num str", K(ret));
|
|
}
|
|
} else {
|
|
if (OB_FAIL(cast_obj_to_num_str(nfm_obj, scale, num_str))) {
|
|
LOG_WARN("fail to cast obj to num str", K(ret));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(process_sci_format(num_str, scale, num_str))) {
|
|
LOG_WARN("fail to process sci fmt", K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
// if the length of the integer part exceeds the number of the integer part in fmt str
|
|
// fill with '#'
|
|
// eg: to_char(123.12, '99.99') --> ######
|
|
if (OB_FAIL(get_integer_part_len(num_str, integer_part_len))) {
|
|
LOG_WARN("fail to get num str pre num count", K(ret));
|
|
} else if (!is_zero(num_str) && integer_part_len > fmt_desc_.pre_num_count_) {
|
|
is_overflow = true;
|
|
if (OB_FAIL(fill_str(res_buf, res_buf_len, 0, '#', fmt_desc_.output_len_))) {
|
|
LOG_WARN("fail to fill str", K(ret));
|
|
} else {
|
|
offset = fmt_desc_.output_len_;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!is_overflow) {
|
|
if (OB_SUCC(ret) && ObNFMElem::has_currency_group(fmt_desc_.elem_flag_)
|
|
&& OB_FAIL(get_nls_currency(session))) {
|
|
LOG_WARN("fail to get nls currency", K(ret));
|
|
}
|
|
if (OB_SUCC(ret) && ObNFMElem::has_iso_grouping_group(fmt_desc_.elem_flag_)
|
|
&& OB_FAIL(get_iso_grouping(session))) {
|
|
LOG_WARN("fail to get iso grouping", K(ret));
|
|
}
|
|
if (OB_SUCC(ret) && OB_FAIL(process_output_fmt(num_str, integer_part_len,
|
|
res_buf, res_buf_len, offset))) {
|
|
LOG_WARN("fail to processor fmt print", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::convert_num_to_fmt_str(const ObObj &obj,
|
|
const char *fmt_str,
|
|
const int32_t fmt_len,
|
|
ObExprCtx &expr_ctx,
|
|
ObString &res_str)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t offset = 0;
|
|
char *res_buf = NULL;
|
|
ObNFMObj nfm_obj;
|
|
ObSQLSessionInfo *session = expr_ctx.my_session_;
|
|
const int64_t res_buf_len = MAX_TO_CHAR_BUFFER_SIZE_IN_FORMAT_MODELS;
|
|
if (OB_ISNULL(fmt_str) || OB_ISNULL(expr_ctx.calc_buf_) || OB_ISNULL(session)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Invalid argument", K(ret), K(fmt_str), K(expr_ctx.calc_buf_),
|
|
K(session));
|
|
} else if (fmt_len >= MAX_FMT_STR_LEN) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("invalid fmt string", K(ret));
|
|
} else if (OB_ISNULL(res_buf = static_cast<char *>(
|
|
expr_ctx.calc_buf_->alloc(res_buf_len)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory", K(ret));
|
|
} else if (OB_FAIL(conv_num_to_nfm_obj(obj, expr_ctx, nfm_obj))) {
|
|
LOG_WARN("fail to conv obj to nfm obj", K(ret));
|
|
} else if (OB_FAIL(process_fmt_conv(*session, fmt_str, fmt_len, nfm_obj,
|
|
res_buf, res_buf_len, offset))) {
|
|
LOG_WARN("fail to process fmt conversion", K(ret), K(fmt_str), K(fmt_len));
|
|
} else {
|
|
res_str.assign_ptr(res_buf, offset);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::calc_result_length(const common::ObObj &obj, int32_t &length)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool need_check = false;
|
|
ObExprCtx expr_ctx;
|
|
expr_ctx.calc_buf_ = &allocator_;
|
|
EXPR_DEFINE_CAST_CTX(expr_ctx, CM_NONE);
|
|
ObString fmt_str;
|
|
EXPR_GET_VARCHAR_V2(obj, fmt_str);
|
|
if (OB_FAIL(ret)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid input format. need varchar.", K(ret), K(obj));
|
|
} else if (OB_FAIL(parse_fmt(fmt_str.ptr(), fmt_str.length(), need_check))) {
|
|
LOG_WARN("fail to parse fmt model", K(ret), K(fmt_str));
|
|
} else {
|
|
length = fmt_desc_.output_len_;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToChar::convert_num_to_fmt_str(const common::ObObjMeta &obj_meta,
|
|
const common::ObDatum &obj,
|
|
common::ObIAllocator &alloc,
|
|
const char *fmt_str, const int32_t fmt_len,
|
|
ObEvalCtx &ctx,
|
|
common::ObString &res_str)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t offset = 0;
|
|
char *res_buf = NULL;
|
|
ObNFMObj nfm_obj;
|
|
const int64_t res_buf_len = MAX_TO_CHAR_BUFFER_SIZE_IN_FORMAT_MODELS;
|
|
ObSQLSessionInfo *session = ctx.exec_ctx_.get_my_session();
|
|
if (OB_ISNULL(fmt_str) || OB_ISNULL(session)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Invalid argument", K(ret), K(fmt_str), K(session));
|
|
} else if (fmt_len >= MAX_FMT_STR_LEN) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("invalid fmt string", K(ret));
|
|
} else if (OB_ISNULL(res_buf = static_cast<char *>(alloc.alloc(res_buf_len)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory", K(ret));
|
|
} else if (OB_FAIL(conv_num_to_nfm_obj(obj_meta, obj, nfm_obj, alloc))) {
|
|
LOG_WARN("fail to conv obj to nfm obj", K(ret));
|
|
} else if (OB_FAIL(process_fmt_conv(*session, fmt_str, fmt_len, nfm_obj,
|
|
res_buf, res_buf_len, offset))) {
|
|
LOG_WARN("fail to process fmt conversion", K(ret), K(fmt_str), K(fmt_len));
|
|
} else {
|
|
res_str.assign_ptr(res_buf, offset);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToNumber::process_hex_format(const common::ObString &in_str,
|
|
number::ObNumber &res_num,
|
|
common::ObIAllocator &allocator)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const char *str = in_str.ptr();
|
|
int32_t str_len = in_str.length();
|
|
int32_t str_pos = 0;
|
|
HexNumber nums;
|
|
// remove leading spaces
|
|
// eg: to_number(' fff', 'xxx') --> 4095
|
|
// eg: to_number('fff ', 'xxxx') --> invalid number
|
|
while (str_pos < str_len && isspace(str[str_pos])) {
|
|
++str_pos;
|
|
}
|
|
if (ObNFMElem::has_type(NFM_ZERO_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (str_len - str_pos != fmt_desc_.pre_num_count_ + fmt_desc_.elem_x_count_) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str));
|
|
}
|
|
} else {
|
|
if (str_len - str_pos > fmt_desc_.elem_x_count_) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if ('-' == str[str_pos]) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("not support negative number", K(ret), K(in_str));
|
|
} else if (ObNFMElem::has_type((~NFM_HEX_FLAG) & (~NFM_ZERO_FLAG)
|
|
& (~NFM_NINE_FLAG) & (~NFM_FILLMODE_FLAG),
|
|
fmt_desc_.elem_flag_)) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("incompatible with other formats", K(ret), K(in_str));
|
|
} else if (OB_FAIL(check_hex_str_valid(str, str_len, str_pos))) {
|
|
LOG_WARN("invalid hex character", K(ret), K(in_str));
|
|
} else if (OB_FAIL(build_hex_number(str, str_len, str_pos, nums))) {
|
|
LOG_WARN("fail to build hex number", K(ret), K(in_str));
|
|
} else {
|
|
int32_t hex_num_size = nums.count();
|
|
if (1 == hex_num_size) {
|
|
if (OB_FAIL(res_num.from(nums.at(0), allocator))) {
|
|
LOG_WARN("failed to cast obj as number", K(ret));
|
|
}
|
|
} else {
|
|
const uint64_t base = 16;
|
|
const uint64_t exponent = 15;
|
|
number::ObNumber base_num;
|
|
number::ObNumber power_num;
|
|
number::ObNumber res;
|
|
if (base_num.from(base, allocator)) {
|
|
LOG_WARN("fail to cast uint64 to number", K(ret), K(base));
|
|
} else if (base_num.power(exponent, power_num, allocator)) {
|
|
LOG_WARN("power calc failed", K(ret));
|
|
} else {
|
|
for (int32_t i = 0; OB_SUCC(ret) && i < hex_num_size; i++) {
|
|
uint64_t val = nums.at(i);
|
|
number::ObNumber num;
|
|
if (num.from(val, allocator)) {
|
|
LOG_WARN("fail to cast uint64 to number", K(ret), K(val));
|
|
} else {
|
|
for (int32_t j = i; OB_SUCC(ret) && j > 0; j--) {
|
|
if (num.mul_v2(power_num, num, allocator)) {
|
|
LOG_WARN("fail to mul number", K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && OB_FAIL(res.add(num, res, allocator))) {
|
|
LOG_WARN("fail to add number", K(ret));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
res_num = res;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToNumber::process_output_fmt(const ObString &in_str,
|
|
const int32_t integer_part_len,
|
|
common::ObString &num_str)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const char *str = in_str.ptr();
|
|
int32_t str_len = in_str.length();
|
|
int32_t str_pos = 0;
|
|
int64_t offset = 0;
|
|
bool is_negative = false;
|
|
char *buf = NULL;
|
|
const int64_t buf_len = MAX_TO_CHAR_BUFFER_SIZE_IN_FORMAT_MODELS;
|
|
// skip leading spaces
|
|
while (str_pos < str_len && ' ' == str[str_pos]) {
|
|
++str_pos;
|
|
}
|
|
// reserve the positive and negative sign position
|
|
++offset;
|
|
// eg: to_number(' ', 'B') --> 0
|
|
if (str_pos == str_len
|
|
&& (!ObNFMElem::has_type(NFM_BLANK_FLAG, fmt_desc_.elem_flag_)
|
|
|| str_len != fmt_elem_list_.count())) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("invalid number", K(ret), K(in_str));
|
|
} else if (OB_ISNULL(buf = static_cast<char *>(
|
|
allocator_.alloc(buf_len)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory", K(ret));
|
|
} else if (ObNFMElem::has_sign_group(fmt_desc_.elem_flag_)) {
|
|
// processing leading positive or negative sign element
|
|
if (ObNFMElem::has_type(NFM_S_FLAG, fmt_desc_.elem_flag_)
|
|
&& OBNFMDesc::FIRST_POS == fmt_desc_.sign_appear_pos_) {
|
|
if (str_pos >= str_len) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str));
|
|
} else if ('-' == str[str_pos]) {
|
|
is_negative = true;
|
|
++str_pos;
|
|
} else if ('+' == str[str_pos]) {
|
|
++str_pos;
|
|
} else {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str));
|
|
}
|
|
} else if (ObNFMElem::has_type(NFM_PR_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (str_pos < str_len) {
|
|
if ('<' == str[str_pos]) {
|
|
is_negative = true;
|
|
++str_pos;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (str_pos < str_len) {
|
|
if ('-' == str[str_pos]) {
|
|
is_negative = true;
|
|
++str_pos;
|
|
}
|
|
}
|
|
}
|
|
// processing element '$'
|
|
if (OB_SUCC(ret) && ObNFMElem::has_type(NFM_DOLLAR_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (str_pos >= str_len || str[str_pos++] != '$'
|
|
|| (0 == fmt_desc_.pre_num_count_ && 0 == fmt_desc_.post_num_count_)) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str));
|
|
}
|
|
}
|
|
// processing the last positive or negative sign element
|
|
if (OB_SUCC(ret) && ObNFMElem::has_sign_group(fmt_desc_.elem_flag_)) {
|
|
if (ObNFMElem::has_type(NFM_S_FLAG, fmt_desc_.elem_flag_)
|
|
&& OBNFMDesc::LAST_POS == fmt_desc_.sign_appear_pos_) {
|
|
if ('-' == str[str_len - 1]) {
|
|
is_negative = true;
|
|
--str_len;
|
|
} else if ('+' == str[str_len - 1]) {
|
|
--str_len;
|
|
} else {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str));
|
|
}
|
|
} else if (ObNFMElem::has_type(NFM_PR_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (is_negative) {
|
|
if (str[str_len - 1] != '>') {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str));
|
|
}
|
|
--str_len;
|
|
}
|
|
} else if (ObNFMElem::has_type(NFM_MI_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (is_negative) {
|
|
if ('-' == str[str_len - 1]) {
|
|
is_negative = true;
|
|
--str_len;
|
|
} else {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str));
|
|
}
|
|
} else {
|
|
if (' ' == str[str_len - 1]) {
|
|
--str_len;
|
|
} else if ('-' == str[str_len - 1]) {
|
|
is_negative = true;
|
|
--str_len;
|
|
} else if (!ObNFMElem::has_type(NFM_FILLMODE_FLAG, fmt_desc_.elem_flag_)) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
// need to skip leading and trailing redundant numbers in the fmt string
|
|
// eg: to_number('123.123', '999999999.999999999')
|
|
// pre_need_skip_num = 6;
|
|
const int32_t pre_need_skip_num = fmt_desc_.pre_num_count_ - integer_part_len;
|
|
int32_t traversed_num_count = 0;
|
|
for (int32_t i = 0; OB_SUCC(ret) && i < fmt_elem_list_.count(); ++i) {
|
|
const ObNFMElem *elem_item = fmt_elem_list_.at(i);
|
|
if (OB_ISNULL(elem_item)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid elem item", K(ret));
|
|
} else {
|
|
ObNFMElem::ElementType elem_type = elem_item->keyword_->elem_type_;
|
|
// skip thousands separator
|
|
// eg: to_number('123,12,12,', '99999999999999') --> 1231212
|
|
// eg: to_number('1,,,.235', '9GGD999') --> 1.235
|
|
if (elem_type != ObNFMElem::NFM_COMMA && elem_type != ObNFMElem::NFM_G) {
|
|
if (traversed_num_count > 0
|
|
&& traversed_num_count <= fmt_desc_.pre_num_count_
|
|
&& fmt_desc_.last_separator_ < i) {
|
|
while (str_pos < str_len && ((',' == str[str_pos])
|
|
|| (ObNFMElem::has_iso_grouping_group(fmt_desc_.elem_flag_)
|
|
&& str[str_pos] == fmt_desc_.iso_grouping_.ptr()[1]))) {
|
|
++str_pos;
|
|
}
|
|
}
|
|
}
|
|
switch (elem_type) {
|
|
case ObNFMElem::NFM_COMMA:
|
|
if (traversed_num_count <= pre_need_skip_num
|
|
&& ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else if (traversed_num_count <= pre_need_skip_num
|
|
&& (fmt_desc_.zero_start_ < 0 || fmt_desc_.zero_start_ > i)) {
|
|
// skip, do nothing
|
|
} else if (str_pos >= str_len || str[str_pos] != ',') {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),K(str_pos), K(i));
|
|
} else {
|
|
++str_pos;
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_PERIOD:
|
|
// ignore decimal point
|
|
// eg: to_number(1265, '0000.000')
|
|
if (str_pos >= str_len) {
|
|
// do nothing
|
|
} else {
|
|
if (str[str_pos] != '.') {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, offset, "%c", str[str_pos]);
|
|
++str_pos;
|
|
}
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_ZERO:
|
|
// if there is fractional part and the number of decimal parts exceeds the precision
|
|
// the following numbers need to be skipped
|
|
// eg: to_number('123.123', '999999999.999999999')
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (fmt_desc_.pre_num_count_ - traversed_num_count > 1
|
|
|| (fmt_desc_.decimal_pos_ != INT32_MAX
|
|
&& fmt_desc_.decimal_pos_ < i
|
|
&& str_pos >= str_len)) {
|
|
// do nothing
|
|
} else if (str_pos >= str_len || !is_digit(str[str_pos])) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, offset, "%c", str[str_pos++]);
|
|
}
|
|
} else {
|
|
if (fmt_desc_.decimal_pos_ != INT32_MAX
|
|
&& fmt_desc_.decimal_pos_ < i
|
|
&& str_pos >= str_len) {
|
|
// do nothing
|
|
} else if (str_pos >= str_len || !is_digit(str[str_pos])) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else {
|
|
if (traversed_num_count < pre_need_skip_num) {
|
|
str_pos++;
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, offset, "%c", str[str_pos++]);
|
|
}
|
|
}
|
|
}
|
|
++traversed_num_count;
|
|
break;
|
|
case ObNFMElem::NFM_NINE:
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (fmt_desc_.pre_num_count_ - traversed_num_count > 1
|
|
|| (fmt_desc_.decimal_pos_ != INT32_MAX
|
|
&& fmt_desc_.decimal_pos_ < i
|
|
&& str_pos >= str_len)) {
|
|
// do nothing
|
|
} else {
|
|
if (str_pos >= str_len || !is_digit(str[str_pos])) {
|
|
// do nothing
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, offset, "%c", str[str_pos++]);
|
|
}
|
|
}
|
|
} else {
|
|
// if there is fractional part and the number of decimal parts exceeds the precision
|
|
// the following numbers need to be skipped
|
|
// eg: to_number('123.123', '999999999.999999999')
|
|
if (fmt_desc_.decimal_pos_ != INT32_MAX
|
|
&& fmt_desc_.decimal_pos_ < i
|
|
&& str_pos >= str_len) {
|
|
// do nothing
|
|
} else if (traversed_num_count < pre_need_skip_num) {
|
|
// if element '0' has appeared, the following numbers need to fill '0'
|
|
// eg: to_char(123.123, '9099999.999') --> 000123.123
|
|
// eg: to_number('000123.123', '9099999.999') --> 123.123
|
|
if ((fmt_desc_.zero_start_ >= 0 && fmt_desc_.zero_start_ < i)) {
|
|
if (str_pos >= str_len || !is_digit(str[str_pos])) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else {
|
|
++str_pos;
|
|
}
|
|
}
|
|
} else {
|
|
if (str_pos >= str_len || !is_digit(str[str_pos])) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, offset, "%c", str[str_pos++]);
|
|
}
|
|
}
|
|
}
|
|
++traversed_num_count;
|
|
break;
|
|
case ObNFMElem::NFM_D:
|
|
// ignore decimal point
|
|
// eg: to_number(1265, '0000.000')
|
|
if (str_pos >= str_len) {
|
|
// do nothing
|
|
} else {
|
|
if (str[str_pos] != fmt_desc_.iso_grouping_.ptr()[0]) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else {
|
|
ret = databuff_printf(buf, buf_len, offset, "%c", str[str_pos]);
|
|
++str_pos;
|
|
}
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_G:
|
|
if (traversed_num_count <= pre_need_skip_num
|
|
&& ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else if (traversed_num_count <= pre_need_skip_num
|
|
&& (fmt_desc_.zero_start_ < 0 || fmt_desc_.zero_start_ > i)) {
|
|
// skip, do nothing
|
|
} else {
|
|
if (str_pos >= str_len || str[str_pos] != fmt_desc_.iso_grouping_.ptr()[1]) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else {
|
|
++str_pos;
|
|
}
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_C:
|
|
case ObNFMElem::NFM_L:
|
|
case ObNFMElem::NFM_U:
|
|
if (OBNFMDesc::MIDDLE_POS == fmt_desc_.currency_appear_pos_) {
|
|
if (str_pos >= str_len) {
|
|
// do nothing
|
|
} else {
|
|
if ((str[str_pos] != '.'
|
|
&& (str_len - str_pos < fmt_desc_.nls_currency_.length()
|
|
|| (0 != strncasecmp(str + str_pos, fmt_desc_.nls_currency_.ptr(),
|
|
fmt_desc_.nls_currency_.length()))))
|
|
|| (ObNFMElem::has_type(NFM_S_FLAG, fmt_desc_.elem_flag_)
|
|
&& OBNFMDesc::LAST_POS == fmt_desc_.sign_appear_pos_)) {
|
|
// eg: to_number('23$00+', '99L99S') --> error 1722
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else {
|
|
if (str[str_pos] == '.') {
|
|
++str_pos;
|
|
} else {
|
|
str_pos += fmt_desc_.nls_currency_.length();
|
|
}
|
|
// if the element('C', 'L', 'U') appears in the middle, it will be regarded as the
|
|
// decimal point, so use decimal point to replace the iso currency
|
|
ret = databuff_printf(buf, buf_len, offset, "%c", '.');
|
|
}
|
|
}
|
|
} else {
|
|
if (str_pos >= str_len || str_len - str_pos < fmt_desc_.nls_currency_.length()
|
|
|| (0 != strncasecmp(str + str_pos, fmt_desc_.nls_currency_.ptr(),
|
|
fmt_desc_.nls_currency_.length()))) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
} else {
|
|
str_pos += fmt_desc_.nls_currency_.length();
|
|
}
|
|
}
|
|
break;
|
|
case ObNFMElem::NFM_EEEE:
|
|
if (str_pos < str_len && str[str_pos] != 'e' && str[str_pos] != 'E') {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K_(fmt_str),
|
|
K(str_pos), K(i));
|
|
}
|
|
// eg: to_number('1.2E+03 ', '9.9EEEEMI')
|
|
while (str_pos < str_len && str[str_pos] != ' ') {
|
|
buf[offset++] = str[str_pos++];
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// eg: to_number('123.', '999') --> 123
|
|
// eg: to_number('123,', '999') --> 123
|
|
for (; OB_SUCC(ret) && str_pos < str_len; ++str_pos) {
|
|
if (str[str_pos] != ',' && str[str_pos] != '.') {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("fmt does not match", K(ret), K(str_pos), K(str_len), K(in_str), K_(fmt_str));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (is_negative) {
|
|
buf[0] = '-';
|
|
} else {
|
|
buf[0] = '+';
|
|
}
|
|
// if string is empty, set num_str to '+0' or '-0' as a valid number.
|
|
if (offset == 1) {
|
|
buf[offset++] = '0';
|
|
}
|
|
num_str.assign(buf, offset);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToNumber::process_fmt_conv(const ObSQLSessionInfo &session,
|
|
const common::ObString &in_str,
|
|
const common::ObString &in_fmt_str,
|
|
common::ObIAllocator &alloc,
|
|
common::number::ObNumber &res_num)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int32_t integer_part_len = 0;
|
|
ObPrecision res_precision = -1;
|
|
ObScale res_scale = -1;
|
|
ObString num_str;
|
|
if (OB_FAIL(parse_fmt(in_fmt_str.ptr(), in_fmt_str.length()))) {
|
|
LOG_WARN("fail to parse format model", K(ret), K(in_fmt_str));
|
|
} else if (ObNFMElem::has_type(NFM_RN_FLAG, fmt_desc_.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_TM_FLAG, fmt_desc_.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_TME_FLAG, fmt_desc_.elem_flag_)
|
|
|| ObNFMElem::has_type(NFM_MULTI_FLAG, fmt_desc_.elem_flag_)) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("not support elem type", K(ret));
|
|
} else if (OB_FAIL(get_integer_part_len(in_str, integer_part_len))) {
|
|
LOG_WARN("fail to get integer part len", K(ret));
|
|
} else if (ObNFMElem::has_type(NFM_HEX_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(process_hex_format(in_str, res_num, alloc))) {
|
|
LOG_WARN("fail to process hex format", K(ret));
|
|
}
|
|
} else {
|
|
// here are two cases, return invalid number
|
|
// eg: to_number('1.23E+03', '9.9EEEE') invalid number
|
|
// eg: to_number('123.12', '99.99') invalid number
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (fmt_desc_.pre_num_count_ <= 0) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("fmt does not match", K(ret), K(in_str), K(in_fmt_str));
|
|
}
|
|
} else {
|
|
if (integer_part_len > fmt_desc_.pre_num_count_) {
|
|
ret = OB_ERR_CAST_VARCHAR_TO_NUMBER;
|
|
LOG_WARN("overflowed digit format", K(ret), K(integer_part_len),
|
|
K(fmt_desc_.pre_num_count_), K(fmt_desc_.post_num_count_));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
} else if (ObNFMElem::has_currency_group(fmt_desc_.elem_flag_)
|
|
&& OB_FAIL(get_nls_currency(session))) {
|
|
LOG_WARN("fail to get nls currency", K(ret));
|
|
} else if (ObNFMElem::has_iso_grouping_group(fmt_desc_.elem_flag_)
|
|
&& OB_FAIL(get_iso_grouping(session))) {
|
|
LOG_WARN("fail to get iso grouping", K(ret));
|
|
} else if (OB_FAIL(process_output_fmt(in_str, integer_part_len, num_str))) {
|
|
LOG_WARN("fail to process output fmt", K(ret));
|
|
} else {
|
|
if (ObNFMElem::has_type(NFM_EEEE_FLAG, fmt_desc_.elem_flag_)) {
|
|
if (OB_FAIL(res_num.from_sci_opt(num_str.ptr(), num_str.length(), alloc,
|
|
&res_precision, &res_scale))) {
|
|
LOG_WARN("fail to calc function to_number with", K(ret), K(num_str));
|
|
}
|
|
} else {
|
|
if (OB_FAIL(res_num.from(num_str.ptr(), num_str.length(), alloc, NULL,
|
|
&res_precision, &res_scale))) {
|
|
LOG_WARN("fail to calc function to_number with", K(ret), K(num_str));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToNumber::convert_char_to_num(const common::ObString &in_str,
|
|
const common::ObString &in_fmt_str,
|
|
common::ObExprCtx &expr_ctx,
|
|
common::number::ObNumber &res_num)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo *session = expr_ctx.my_session_;
|
|
if (OB_ISNULL(expr_ctx.calc_buf_) || OB_ISNULL(session)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret), K(expr_ctx.calc_buf_), K(session));
|
|
} else if (in_fmt_str.length() >= MAX_FMT_STR_LEN) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("invalid format string", K(ret));
|
|
} else if (OB_FAIL(process_fmt_conv(*session, in_str, in_fmt_str,
|
|
*(expr_ctx.calc_buf_), res_num))) {
|
|
LOG_WARN("fail to parse format model", K(ret), K(in_fmt_str));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObNFMToNumber::convert_char_to_num(const common::ObString &in_str,
|
|
const common::ObString &in_fmt_str,
|
|
common::ObIAllocator &alloc,
|
|
ObEvalCtx &ctx,
|
|
common::number::ObNumber &res_num)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo *session = ctx.exec_ctx_.get_my_session();
|
|
if (OB_ISNULL(session)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Invalid argument", K(ret), K(session));
|
|
} else if (in_fmt_str.length() >= MAX_FMT_STR_LEN) {
|
|
ret = OB_ERR_INVALID_NUMBER_FORMAT_MODEL;
|
|
LOG_WARN("invalid format string", K(ret));
|
|
} else if (OB_FAIL(process_fmt_conv(*session, in_str, in_fmt_str,
|
|
alloc, res_num))) {
|
|
LOG_WARN("fail to parse format model", K(ret), K(in_fmt_str));
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
}
|