Files
oceanbase/src/sql/engine/expr/ob_expr_json_value.cpp

1918 lines
68 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.
*/
// This file is for func json_value.
#define USING_LOG_PREFIX SQL_ENG
#include "ob_expr_json_value.h"
#include "sql/engine/expr/ob_expr_util.h"
#include "share/object/ob_obj_cast.h"
#include "sql/session/ob_sql_session_info.h"
#include "share/object/ob_obj_cast_util.h"
#include "share/object/ob_obj_cast.h"
#include "sql/engine/expr/ob_expr_cast.h"
#include "sql/engine/expr/ob_datum_cast.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
#include "lib/oblog/ob_log_module.h"
#include "ob_expr_json_func_helper.h"
#include "sql/engine/ob_exec_context.h"
// from sql_parser_base.h
#define DEFAULT_STR_LENGTH -1
using namespace oceanbase::common;
using namespace oceanbase::sql;
namespace oceanbase
{
namespace sql
{
#define CAST_FAIL(stmt) \
(OB_UNLIKELY((OB_SUCCESS != (ret = get_cast_ret((stmt))))))
#define GET_SESSION() \
ObBasicSessionInfo *session = ctx.exec_ctx_.get_my_session(); \
if (OB_ISNULL(session)) { \
ret = OB_ERR_UNEXPECTED; \
LOG_WARN("session is NULL", K(ret)); \
} else
ObExprJsonValue::ObExprJsonValue(ObIAllocator &alloc)
: ObFuncExprOperator(alloc, T_FUN_SYS_JSON_VALUE, N_JSON_VALUE, MORE_THAN_TWO, NOT_ROW_DIMENSION)
{
}
ObExprJsonValue::~ObExprJsonValue()
{
}
int ObExprJsonValue::calc_result_typeN(ObExprResType& type,
ObExprResType* types_stack,
int64_t param_num,
ObExprTypeCtx& type_ctx) const
{
INIT_SUCC(ret);
if (OB_UNLIKELY(param_num != 7)) {
ret = OB_ERR_PARAM_SIZE;
LOG_WARN("invalid param number", K(ret), K(param_num));
} else {
//type.set_json();
// json doc : 0
ObObjType doc_type = types_stack[0].get_type();
if (types_stack[0].get_type() == ObNullType) {
} else if (!ObJsonExprHelper::is_convertible_to_json(doc_type)) {
ret = OB_ERR_INVALID_TYPE_FOR_JSON;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_JSON, 1, "json_value");
LOG_WARN("Invalid type for json doc", K(doc_type));
} else if (ob_is_string_type(doc_type)) {
if (types_stack[0].get_collation_type() == CS_TYPE_BINARY) {
// unsuport string type with binary charset
ret = OB_ERR_INVALID_JSON_CHARSET;
LOG_WARN("Unsupport for string type with binary charset input.", K(ret), K(doc_type));
} else if (types_stack[0].get_charset_type() != CHARSET_UTF8MB4) {
types_stack[0].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN);
}
} else if (doc_type == ObJsonType) {
// do nothing
} else {
types_stack[0].set_calc_type(ObLongTextType);
types_stack[0].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN);
}
// json path : 1
if (OB_SUCC(ret)) {
if (types_stack[1].get_type() == ObNullType) {
// do nothing
} else if (ob_is_string_type(types_stack[1].get_type())) {
if (types_stack[1].get_charset_type() != CHARSET_UTF8MB4) {
types_stack[1].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN);
}
} else {
types_stack[1].set_calc_type(ObLongTextType);
types_stack[1].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN);
}
}
// returning type : 2
ObExprResType dst_type;
if (OB_SUCC(ret)) {
if (OB_FAIL(get_cast_type(types_stack[2], dst_type))) {
LOG_WARN("get cast dest type failed", K(ret));
} else if (OB_FAIL(set_dest_type(types_stack[0], type, dst_type, type_ctx))) {
LOG_WARN("set dest type failed", K(ret));
} else {
type.set_calc_collation_type(type.get_collation_type());
}
}
// empty : 3, 4
if (OB_SUCC(ret)) {
ObExprResType temp_type;
if (types_stack[3].get_type() == ObNullType) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("<empty type> param type is unexpected", K(types_stack[3].get_type()));
} else if (types_stack[3].get_type() != ObIntType) {
types_stack[3].set_calc_type(ObIntType);
} else if (types_stack[4].get_type() == ObNullType) {
// do nothing
} else if (OB_FAIL(set_dest_type(types_stack[4], temp_type, dst_type, type_ctx))) {
LOG_WARN("set dest type failed", K(ret));
} else {
types_stack[4].set_calc_type(temp_type.get_type());
types_stack[4].set_calc_collation_type(temp_type.get_collation_type());
types_stack[4].set_calc_collation_level(temp_type.get_collation_level());
types_stack[4].set_calc_accuracy(temp_type.get_accuracy());
}
}
// error : 5, 6
if (OB_SUCC(ret)) {
ObExprResType temp_type;
if (types_stack[5].get_type() == ObNullType) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("<error type> param type is unexpected", K(types_stack[5].get_type()));
} else if (types_stack[5].get_type() != ObIntType) {
types_stack[5].set_calc_type(ObIntType);
} else if (types_stack[6].get_type() == ObNullType) {
// do nothing
} else if (OB_FAIL(set_dest_type(types_stack[6], temp_type, dst_type, type_ctx))) {
LOG_WARN("set dest type failed", K(ret));
} else {
types_stack[6].set_calc_type(temp_type.get_type());
types_stack[6].set_calc_collation_type(temp_type.get_collation_type());
types_stack[6].set_calc_collation_level(temp_type.get_collation_level());
types_stack[6].set_calc_accuracy(temp_type.get_accuracy());
}
}
}
return ret;
}
int ObExprJsonValue::calc_resultN(ObObj& result,
const ObObj *params,
int64_t params_count,
ObExprCtx& expr_ctx) const
{
INIT_SUCC(ret);
ObIAllocator *allocator = expr_ctx.calc_buf_;
bool is_cover_by_error = true;
bool is_null_result = false;
ObIJsonBase *j_base = NULL;
if (OB_ISNULL(params) || OB_UNLIKELY(params_count != 7)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid arguments", K(ret), K(params), K(params_count));
} else if (OB_ISNULL(allocator)) { // check allocator
ret = OB_NOT_INIT;
LOG_WARN("varchar buffer not init", K(ret));
} else if (OB_FAIL(param_eval(expr_ctx, params[0], 0))) {
LOG_WARN("failed: eval json doc", K(ret));
} else {
ObObjType type = params[0].get_type();
if (type == ObNullType || params[0].is_null()) {
is_null_result = true;
} else if (type != ObJsonType && !ob_is_string_type(type)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("input type error", K(type));
} else {
ObString j_str = params[0].get_string();
ObJsonInType j_in_type = ObJsonExprHelper::get_json_internal_type(type);
if (j_str.length() == 0) { // maybe input json doc is null type
is_null_result = true;
} else if (OB_FAIL(ObJsonBaseFactory::get_json_base(allocator, j_str, j_in_type,
j_in_type, j_base))) {
LOG_WARN("fail to get json base.", K(ret), K(type), K(j_str), K(j_in_type));
if (ret == OB_ERR_JSON_OUT_OF_DEPTH) {
is_cover_by_error = false;
}
}
}
}
// parse return node acc
ObAccuracy accuracy;
ObObjType dst_type;
if (is_cover_by_error) { // adapt mysql, Parse return node even if parse json doc wrong.
int32_t temp_ret = param_eval(expr_ctx, params[2], 2);
if (temp_ret != OB_SUCCESS) {
ret = (ret == OB_SUCCESS) ? temp_ret : ret;
is_cover_by_error = false;
LOG_WARN("eval json arg failed", K(temp_ret));
} else {
temp_ret = get_accuracy_internal(accuracy, dst_type, params[2].get_int(),
result_type_.get_length_semantics());
if (temp_ret != OB_SUCCESS) {
ret = (ret == OB_SUCCESS) ? temp_ret : ret;
is_cover_by_error = false;
LOG_WARN("get accuracy failed", K(temp_ret));
}
}
}
// parse empty option
ObObj empty_val;
uint8_t empty_type = OB_JSON_ON_RESPONSE_IMPLICIT;
if (OB_SUCC(ret) && !is_null_result) {
ret = get_on_empty_or_error_old(params, expr_ctx, dst_type, 3, is_cover_by_error,
accuracy, empty_type, &empty_val);
}
// parse error option
ObObj error_val;
uint8_t error_type = OB_JSON_ON_RESPONSE_IMPLICIT;
if (OB_SUCC(ret) && !is_null_result) {
ret = get_on_empty_or_error_old(params, expr_ctx, dst_type, 5, is_cover_by_error,
accuracy, error_type, &error_val);
} else if (is_cover_by_error) { // always get error option for return default value on error
int temp_ret = get_on_empty_or_error_old(params, expr_ctx, dst_type, 5, is_cover_by_error,
accuracy, error_type, &error_val);
if (temp_ret != OB_SUCCESS) {
LOG_WARN("failed to get on empty or error.", K(ret), K(dst_type));
}
}
// parse json path and do seek
ObObj *return_val = NULL;
ObJsonBaseVector hits;
if (OB_SUCC(ret) && !is_null_result) {
if (OB_FAIL(param_eval(expr_ctx, params[1], 1))) {
is_cover_by_error = false;
LOG_WARN("eval json arg failed", K(ret));
} else {
ObObjType type = params[1].get_type();
if (type == ObNullType || params[1].is_null()) {
is_null_result = true;
} else if (!ob_is_string_type(type)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("input type error", K(type));
} else {
// Old engine not support op_ctx. use local cache.
ObJsonPathCache ctx_cache(allocator);
ObJsonPathCache *path_cache = &ctx_cache;
ObString j_path_text = params[1].get_string();
ObJsonPath *j_path;
if (j_path_text.length() == 0) {
is_null_result = true;
} else if (OB_FAIL(ObJsonExprHelper::find_and_add_cache(path_cache, j_path,
j_path_text, 1, true))) {
is_cover_by_error = false;
LOG_WARN("parse text to path failed", K(j_path_text), K(ret));
} else if (OB_FAIL(j_base->seek(*j_path, j_path->path_node_cnt(), true, false, hits))) {
LOG_WARN("json seek failed", K(j_path_text), K(ret));
} else if (hits.size() == 0) {
switch (empty_type) {
case OB_JSON_ON_RESPONSE_ERROR: {
is_cover_by_error = false;
ret = OB_ERR_MISSING_JSON_VALUE;
LOG_USER_ERROR(OB_ERR_MISSING_JSON_VALUE, "json_value");
LOG_WARN("json value seek result empty.", K(hits.size()));
break;
}
case OB_JSON_ON_RESPONSE_DEFAULT: {
return_val = &empty_val;
break;
}
case OB_JSON_ON_RESPONSE_NULL:
case OB_JSON_ON_RESPONSE_IMPLICIT: {
is_null_result = true;
break;
}
default:
break;
}
} else if (hits.size() > 1) {
// return val decide by error option
switch (error_type) {
case OB_JSON_ON_RESPONSE_ERROR: {
ret = OB_ERR_MULTIPLE_JSON_VALUES;
LOG_USER_ERROR(OB_ERR_MULTIPLE_JSON_VALUES, "json_value");
LOG_WARN("json value seek result more than one.", K(hits.size()));
break;
}
case OB_JSON_ON_RESPONSE_DEFAULT: {
return_val = &error_val;
break;
}
case OB_JSON_ON_RESPONSE_NULL:
case OB_JSON_ON_RESPONSE_IMPLICIT: {
is_null_result = true;
break;
}
default:
break;
}
} else if (hits[0]->json_type() == ObJsonNodeType::J_NULL) {
is_null_result = true;
}
}
}
}
// fill output
if (OB_UNLIKELY(OB_FAIL(ret))) {
if (is_cover_by_error) {
try_set_error_val<ObObj>(result, ret, error_type, &error_val);
}
LOG_WARN("json_values failed", K(ret));
} else if (is_null_result){
result.set_null();
} else {
if (return_val != NULL) {
set_val(result, return_val);
} else {
ObCollationType in_coll_type = params[0].get_collation_type();
ObCollationType dst_coll_type = result_type_.get_collation_type();
ObCollationLevel dst_coll_level = result_type_.get_collation_level();
ret = cast_to_res(allocator, expr_ctx, hits[0], error_type, &error_val,
accuracy, dst_type, in_coll_type, dst_coll_type, dst_coll_level, result);
}
}
return ret;
}
int ObExprJsonValue::eval_json_value(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res)
{
INIT_SUCC(ret);
ObDatum *json_datum = NULL;
ObExpr *json_arg = expr.args_[0];
ObObjType type = json_arg->datum_meta_.type_;
bool is_cover_by_error = true;
bool is_null_result = false;
ObDatum *return_val = NULL;
common::ObArenaAllocator &temp_allocator = ctx.get_reset_tmp_alloc();
ObIJsonBase *j_base = NULL;
// parse json doc
if (OB_FAIL(json_arg->eval(ctx, json_datum))) {
LOG_WARN("eval json arg failed", K(ret));
is_cover_by_error = false;
} else if (type == ObNullType || json_datum->is_null()) {
is_null_result = true;
} else if (type != ObJsonType && !ob_is_string_type(type)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("input type error", K(type));
} else {
ObString j_str = json_datum->get_string();
ObJsonInType j_in_type = ObJsonExprHelper::get_json_internal_type(type);
if (j_str.length() == 0) { // maybe input json doc is null type
is_null_result = true;
} else if (OB_FAIL(ObJsonBaseFactory::get_json_base(&temp_allocator, j_str, j_in_type,
j_in_type, j_base))) {
LOG_WARN("fail to get json base.", K(ret), K(type), K(j_str), K(j_in_type));
if (ret == OB_ERR_JSON_OUT_OF_DEPTH) {
is_cover_by_error = false;
}
}
}
// parse return node acc
ObAccuracy accuracy;
ObObjType dst_type;
if (OB_SUCC(ret) && !is_null_result) {
ret = get_accuracy(expr, ctx, accuracy, dst_type, is_cover_by_error);
} else if (is_cover_by_error) { // when need error option, should do get accuracy
get_accuracy(expr, ctx, accuracy, dst_type, is_cover_by_error);
}
// parse empty option
ObDatum *empty_datum = NULL;
uint8_t empty_type = OB_JSON_ON_RESPONSE_IMPLICIT;
if (OB_SUCC(ret) && !is_null_result) {
ret = get_on_empty_or_error(expr, ctx, 3, is_cover_by_error, accuracy, empty_type, &empty_datum);
}
// parse error option
ObDatum *error_val = NULL;
uint8_t error_type = OB_JSON_ON_RESPONSE_IMPLICIT;
if (OB_SUCC(ret) && !is_null_result) {
ret = get_on_empty_or_error(expr, ctx, 5, is_cover_by_error, accuracy, error_type, &error_val);
} else if (is_cover_by_error) { // always get error option for return default value on error
int temp_ret = get_on_empty_or_error(expr, ctx, 5, is_cover_by_error, accuracy,
error_type, &error_val);
if (temp_ret != OB_SUCCESS) {
LOG_WARN("failed to get error option.", K(temp_ret));
}
}
// parse json path and do seek
ObJsonBaseVector hits;
if (OB_SUCC(ret) && !is_null_result) {
json_arg = expr.args_[1];
type = json_arg->datum_meta_.type_;
if (OB_FAIL(json_arg->eval(ctx, json_datum))) {
is_cover_by_error = false;
LOG_WARN("eval json arg failed", K(ret));
} else if (type == ObNullType || json_datum->is_null()) {
is_null_result = true;
} else if (!ob_is_string_type(type)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("input type error", K(type));
} else {
ObString j_path_text = json_datum->get_string();
ObJsonPath *j_path;
if (j_path_text.length() == 0) {
is_null_result = true;
}
ObJsonPathCache ctx_cache(&temp_allocator);
ObJsonPathCache* path_cache = ObJsonExprHelper::get_path_cache_ctx(expr.expr_ctx_id_, &ctx.exec_ctx_);
path_cache = ((path_cache != NULL) ? path_cache : &ctx_cache);
if (OB_FAIL(ObJsonExprHelper::find_and_add_cache(path_cache, j_path, j_path_text, 1, true))) {
is_cover_by_error = false;
LOG_WARN("parse text to path failed", K(json_datum->get_string()), K(ret));
} else if (OB_FAIL(j_base->seek(*j_path, j_path->path_node_cnt(), true, false, hits))) {
LOG_WARN("json seek failed", K(json_datum->get_string()), K(ret));
} else if (hits.size() == 0) {
switch (empty_type) {
case OB_JSON_ON_RESPONSE_ERROR: {
is_cover_by_error = false;
ret = OB_ERR_MISSING_JSON_VALUE;
LOG_USER_ERROR(OB_ERR_MISSING_JSON_VALUE, "json_value");
LOG_WARN("json value seek result empty.", K(hits.size()));
break;
}
case OB_JSON_ON_RESPONSE_DEFAULT: {
return_val = empty_datum;
break;
}
case OB_JSON_ON_RESPONSE_NULL:
case OB_JSON_ON_RESPONSE_IMPLICIT: {
is_null_result = true;
break;
}
default: // empty_type from get_on_empty_or_error has done range check, do nothing for default
break;
}
} else if (hits.size() > 1) {
// return val decide by error option
switch (error_type) {
case OB_JSON_ON_RESPONSE_ERROR: {
ret = OB_ERR_MULTIPLE_JSON_VALUES;
LOG_USER_ERROR(OB_ERR_MULTIPLE_JSON_VALUES, "json_value");
LOG_WARN("json value seek result more than one.", K(hits.size()));
break;
}
case OB_JSON_ON_RESPONSE_DEFAULT: {
return_val = error_val;
break;
}
case OB_JSON_ON_RESPONSE_NULL:
case OB_JSON_ON_RESPONSE_IMPLICIT: {
is_null_result = true;
break;
}
default: // error_type from get_on_empty_or_error has done range check, do nothing for default
break;
}
} else if (hits[0]->json_type() == ObJsonNodeType::J_NULL) {
is_null_result = true;
}
}
}
// fill output
if (OB_UNLIKELY(OB_FAIL(ret))) {
if (is_cover_by_error) {
try_set_error_val<ObDatum>(res, ret, error_type, error_val);
}
LOG_WARN("json_values failed", K(ret));
} else if (is_null_result){
res.set_null();
} else {
if (return_val != NULL) {
res.set_datum(*return_val);
} else {
ObCollationType in_coll_type = expr.args_[0]->datum_meta_.cs_type_;
ObCollationType dst_coll_type = expr.datum_meta_.cs_type_;
ret = cast_to_res(&temp_allocator, expr, ctx, hits[0], error_type, error_val,
accuracy, dst_type, in_coll_type, dst_coll_type, res);
}
}
return ret;
}
int ObExprJsonValue::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const
{
UNUSED(expr_cg_ctx);
UNUSED(raw_expr);
rt_expr.eval_func_ = eval_json_value;
return OB_SUCCESS;
}
template<typename Obj>
int ObExprJsonValue::check_default_val_accuracy(const ObAccuracy &accuracy,
const ObObjType &type,
const Obj *obj)
{
INIT_SUCC(ret);
ObObjTypeClass tc = ob_obj_type_class(type);
switch (tc) {
case ObNumberTC: {
number::ObNumber temp(obj->get_number());
ret = number_range_check(accuracy, NULL, temp, true);
break;
}
case ObDateTC: {
int32_t val = obj->get_date();
if (val == ObTimeConverter::ZERO_DATE) {
// check zero date for scale over mode
ret = OB_INVALID_DATE_VALUE;
LOG_WARN("Zero date is invalid for json_value", K(ret));
}
break;
}
case ObDateTimeTC: {
int64_t val = obj->get_datetime();
ret = datetime_scale_check(accuracy, val, true);
break;
}
case ObTimeTC: {
int64_t val = obj->get_time();
ret = time_scale_check(accuracy, val, true);
break;
}
default:
break;
}
return ret;
}
int ObExprJsonValue::get_accuracy_internal(ObAccuracy &accuracy,
ObObjType &dest_type,
const int64_t value,
const ObLengthSemantics &length_semantics)
{
INIT_SUCC(ret);
ParseNode node;
node.value_ = value;
dest_type = static_cast<ObObjType>(node.int16_values_[0]);
if (ObFloatType == dest_type) {
// boundaries already checked in calc result type
if (node.int16_values_[OB_NODE_CAST_N_PREC_IDX] > OB_MAX_FLOAT_PRECISION) {
dest_type = ObDoubleType;
}
}
ObObjTypeClass dest_tc = ob_obj_type_class(dest_type);
if (ObStringTC == dest_tc) {
// parser will abort all negative number
// if length < 0 means DEFAULT_STR_LENGTH or OUT_OF_STR_LEN.
accuracy.set_full_length(node.int32_values_[1], length_semantics,
lib::is_oracle_mode());
} else if (ObRawTC == dest_tc) {
accuracy.set_length(node.int32_values_[1]);
} else if(ObTextTC == dest_tc || ObJsonTC == dest_tc) {
accuracy.set_length(node.int32_values_[1] < 0 ?
ObAccuracy::DDL_DEFAULT_ACCURACY[dest_type].get_length() : node.int32_values_[1]);
} else if (ObIntervalTC == dest_tc) {
if (OB_UNLIKELY(!ObIntervalScaleUtil::scale_check(node.int16_values_[3]) ||
!ObIntervalScaleUtil::scale_check(node.int16_values_[2]))) {
ret = OB_ERR_DATETIME_INTERVAL_PRECISION_OUT_OF_RANGE;
LOG_WARN("Invalid scale.", K(ret), K(node.int16_values_[3]), K(node.int16_values_[2]));
} else {
ObScale scale = (dest_type == ObIntervalYMType) ?
ObIntervalScaleUtil::interval_ym_scale_to_ob_scale(
static_cast<int8_t>(node.int16_values_[3]))
: ObIntervalScaleUtil::interval_ds_scale_to_ob_scale(
static_cast<int8_t>(node.int16_values_[2]),
static_cast<int8_t>(node.int16_values_[3]));
accuracy.set_scale(scale);
}
} else {
const ObAccuracy &def_acc =
ObAccuracy::DDL_DEFAULT_ACCURACY2[lib::is_oracle_mode()][dest_type];
if (ObNumberType == dest_type && 0 == node.int16_values_[2]) {
accuracy.set_precision(def_acc.get_precision());
} else {
accuracy.set_precision(node.int16_values_[2]);
}
accuracy.set_scale(node.int16_values_[3]);
if (lib::is_oracle_mode() && ObDoubleType == dest_type) {
accuracy.set_accuracy(def_acc.get_precision());
}
}
return ret;
}
int ObExprJsonValue::get_accuracy(const ObExpr &expr,
ObEvalCtx &ctx,
ObAccuracy &accuracy,
ObObjType &dest_type,
bool &is_cover_by_error)
{
INIT_SUCC(ret);
ObDatum *dst_type_dat = NULL;
if (OB_ISNULL(expr.args_) || OB_ISNULL(expr.args_[2])) {
ret = OB_ERR_UNEXPECTED;
is_cover_by_error = false;
LOG_WARN("unexpected expr", K(ret), K(expr.arg_cnt_), KP(expr.args_));
} else if (OB_FAIL(expr.args_[2]->eval(ctx, dst_type_dat))) {
is_cover_by_error = false;
LOG_WARN("eval dst type datum failed", K(ret));
} else {
ret = get_accuracy_internal(accuracy,
dest_type,
dst_type_dat->get_int(),
expr.datum_meta_.length_semantics_);
}
return ret;
}
int ObExprJsonValue::number_range_check(const ObAccuracy &accuracy,
ObIAllocator *allocator,
number::ObNumber &val,
bool strict)
{
INIT_SUCC(ret);
ObPrecision precision = accuracy.get_precision();
ObScale scale = accuracy.get_scale();
const number::ObNumber *min_check_num = NULL;
const number::ObNumber *max_check_num = NULL;
const number::ObNumber *min_num_mysql = NULL;
const number::ObNumber *max_num_mysql = NULL;
bool is_finish = false;
if (OB_UNLIKELY(precision < scale)) {
ret = OB_ERR_M_BIGGER_THAN_D;
LOG_WARN("Invalid accuracy.", K(ret), K(scale), K(precision));
} else if (number::ObNumber::MAX_PRECISION >= precision
&& precision >= OB_MIN_DECIMAL_PRECISION
&& number::ObNumber::MAX_SCALE >= scale
&& scale >= 0) {
min_check_num = &(ObNumberConstValue::MYSQL_CHECK_MIN[precision][scale]);
max_check_num = &(ObNumberConstValue::MYSQL_CHECK_MAX[precision][scale]);
min_num_mysql = &(ObNumberConstValue::MYSQL_MIN[precision][scale]);
max_num_mysql = &(ObNumberConstValue::MYSQL_MAX[precision][scale]);
} else {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid arguments", K(ret), K(precision), K(scale));
}
if (OB_SUCC(ret)) {
if (OB_ISNULL(min_check_num) || OB_ISNULL(max_check_num)
|| (!lib::is_oracle_mode()
&& (OB_ISNULL(min_num_mysql) || OB_ISNULL(max_num_mysql)))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("min_num or max_num is null", K(ret), KPC(min_check_num), KPC(max_check_num));
} else if (val <= *min_check_num) {
if (lib::is_oracle_mode()) {
ret = OB_ERR_VALUE_LARGER_THAN_ALLOWED;
} else {
ret = OB_DATA_OUT_OF_RANGE;
}
LOG_WARN("val is out of min range check.", K(val), K(*min_check_num));
is_finish = true;
} else if (val >= *max_check_num) {
if (lib::is_oracle_mode()) {
ret = OB_ERR_VALUE_LARGER_THAN_ALLOWED;
} else {
ret = OB_DATA_OUT_OF_RANGE;
}
LOG_WARN("val is out of max range check.", K(val), K(*max_check_num));
is_finish = true;
} else {
ObNumStackOnceAlloc tmp_alloc;
number::ObNumber num;
if (OB_FAIL(num.from(val, tmp_alloc))) {
} else if (OB_FAIL(num.round(scale))) {
LOG_WARN("num.round failed", K(ret), K(scale));
} else {
if (strict) {
if (num.compare(val) != 0) {
ret = OB_OPERATE_OVERFLOW;
LOG_WARN("input value is out of range.", K(scale), K(val));
} else {
is_finish = true;
}
} else {
if (OB_ISNULL(allocator)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("allocator is null", K(ret));
} else if (OB_FAIL(val.deep_copy_v3(num, *allocator))) {
LOG_WARN("val.deep_copy_v3 failed", K(ret), K(num));
} else {
is_finish = true;
}
}
}
}
}
if (OB_SUCC(ret) && !is_finish) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected situation, res is not set", K(ret));
}
LOG_DEBUG("number_range_check_v2 done", K(ret), K(is_finish), K(accuracy), K(val),
KPC(min_check_num), KPC(max_check_num));
return ret;
}
int ObExprJsonValue::datetime_scale_check(const ObAccuracy &accuracy,
int64_t &value,
bool strict)
{
INIT_SUCC(ret);
ObScale scale = accuracy.get_scale();
if (OB_UNLIKELY(scale > MAX_SCALE_FOR_TEMPORAL)) {
ret = OB_ERR_TOO_BIG_PRECISION;
LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, scale, "CAST",
static_cast<int64_t>(MAX_SCALE_FOR_TEMPORAL));
} else if (OB_UNLIKELY(0 <= scale && scale < MAX_SCALE_FOR_TEMPORAL)) {
// first check zero
if (strict &&
(value == ObTimeConverter::ZERO_DATE ||
value == ObTimeConverter::ZERO_DATETIME)) {
ret = OB_INVALID_DATE_VALUE;
LOG_WARN("Zero datetime is invalid in json_value.", K(value));
} else {
int64_t temp_value = value;
ObTimeConverter::round_datetime(scale, temp_value);
if (strict && temp_value != value) {
ret = OB_OPERATE_OVERFLOW;
LOG_WARN("Invalid input value.", K(value), K(scale));
} else if (ObTimeConverter::is_valid_datetime(temp_value)) {
value = temp_value;
} else {
ret = OB_ERR_NULL_VALUE; // set null for res
LOG_DEBUG("Invalid datetime val, return set_null", K(temp_value));
}
}
}
return ret;
}
int ObExprJsonValue::time_scale_check(const ObAccuracy &accuracy, int64_t &value, bool strict)
{
INIT_SUCC(ret);
ObScale scale = accuracy.get_scale();
if (OB_LIKELY(0 <= scale && scale < MAX_SCALE_FOR_TEMPORAL)) {
int64_t temp_value = value;
ObTimeConverter::round_datetime(scale, temp_value);
if (strict && temp_value != value) { // round success
ret = OB_OPERATE_OVERFLOW;
LOG_WARN("Invalid input value.", K(value), K(scale));
} else {
value = temp_value;
}
}
return ret;
}
int ObExprJsonValue::get_cast_ret(int ret)
{
// compatibility for old ob
if (OB_UNLIKELY(OB_ERR_UNEXPECTED_TZ_TRANSITION == ret) ||
OB_UNLIKELY(OB_ERR_UNKNOWN_TIME_ZONE == ret)) {
ret = OB_INVALID_DATE_VALUE;
}
return ret;
}
int ObExprJsonValue::cast_to_int(ObIJsonBase *j_base, ObObjType dst_type, int64_t &val)
{
INIT_SUCC(ret);
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_int(val, true))) {
ret = OB_OPERATE_OVERFLOW;
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "SIGNED", "json_value");
LOG_WARN("cast to int failed", K(ret), K(*j_base));
} else if (dst_type < ObIntType &&
CAST_FAIL(int_range_check(dst_type, val, val))) {
ret = OB_OPERATE_OVERFLOW;
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "SIGNED", "json_value");
}
return ret;
}
int ObExprJsonValue::cast_to_uint(ObIJsonBase *j_base, ObObjType dst_type, uint64_t &val)
{
INIT_SUCC(ret);
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_uint(val, true, true))) {
LOG_WARN("cast to uint failed", K(ret), K(*j_base));
if (ret == OB_OPERATE_OVERFLOW) {
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "UNSIGNED", "json_value");
}
} else if (dst_type < ObUInt64Type &&
CAST_FAIL(uint_upper_check(dst_type, val))) {
LOG_WARN("uint_upper_check failed", K(ret));
}
return ret;
}
int ObExprJsonValue::cast_to_datetime(ObIJsonBase *j_base,
common::ObAccuracy &accuracy,
int64_t &val)
{
INIT_SUCC(ret);
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_datetime(val))) {
LOG_WARN("wrapper to datetime failed.", K(ret), K(*j_base));
} else if (CAST_FAIL(datetime_scale_check(accuracy, val))) {
LOG_WARN("datetime_scale_check failed.", K(ret));
}
return ret;
}
int ObExprJsonValue::cast_to_otimstamp(ObIJsonBase *j_base,
const ObBasicSessionInfo *session,
common::ObAccuracy &accuracy,
ObObjType dst_type,
ObOTimestampData &out_val)
{
INIT_SUCC(ret);
int64_t val;
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_datetime(val))) {
LOG_WARN("wrapper to datetime failed.", K(ret), K(*j_base));
} else {
if (session != NULL) {
const ObTimeZoneInfo *tz_info = session->get_timezone_info();
ObScale scale = accuracy.get_scale();
if (OB_FAIL(ObTimeConverter::odate_to_otimestamp(val, tz_info, dst_type, out_val))) {
LOG_WARN("fail to timestamp_to_timestamp_tz", K(ret), K(val), K(dst_type));
} else if (OB_UNLIKELY(0 <= scale && scale < MAX_SCALE_FOR_ORACLE_TEMPORAL)) {
ObOTimestampData ot_data = ObTimeConverter::round_otimestamp(scale, out_val);
if (ObTimeConverter::is_valid_otimestamp(ot_data.time_us_,
static_cast<int32_t>(ot_data.time_ctx_.tail_nsec_))) {
out_val = ot_data;
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid otimestamp, set it null ", K(ot_data), K(scale), "orig_date", out_val);
}
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("session is NULL", K(ret));
}
}
return ret;
}
int ObExprJsonValue::cast_to_date(ObIJsonBase *j_base, int32_t &val)
{
INIT_SUCC(ret);
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_date(val))) {
LOG_WARN("wrapper to date failed.", K(ret), K(*j_base));
ret = OB_OPERATE_OVERFLOW;
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "DATE", "json_value");
}
return ret;
}
int ObExprJsonValue::cast_to_time(ObIJsonBase *j_base,
common::ObAccuracy &accuracy,
int64_t &val)
{
INIT_SUCC(ret);
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_time(val))) {
LOG_WARN("wrapper to time failed.", K(ret), K(*j_base));
ret = OB_OPERATE_OVERFLOW;
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "TIME", "json_value");
} else if (CAST_FAIL(time_scale_check(accuracy, val))) {
LOG_WARN("time_scale_check failed.", K(ret));
}
return ret;
}
int ObExprJsonValue::cast_to_year(ObIJsonBase *j_base, uint8_t &val)
{
INIT_SUCC(ret);
// Compatible with mysql.
// There is no year type in json binary, it is store as a full int.
// For example, 1901 is stored as 1901, not 01.
// in mysql 8.0, json is converted to int first, then converted to year.
// However, json value returning as different behavior to cast expr.
int64_t int_val;
const uint16 min_year = 1901;
const uint16 max_year = 2155;
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_int(int_val))) {
LOG_WARN("wrapper to year failed.", K(ret), K(*j_base));
} else if (0 != int_val && (int_val < min_year || int_val > max_year)) {
// different with cast, if 0 < int val < 100, do not add base year
LOG_DEBUG("int out of year range", K(int_val));
ret = OB_DATA_OUT_OF_RANGE;
} else if(CAST_FAIL(ObTimeConverter::int_to_year(int_val, val))) {
LOG_WARN("int to year failed.", K(ret), K(int_val));
}
return ret;
}
int ObExprJsonValue::cast_to_float(ObIJsonBase *j_base, ObObjType dst_type, float &val)
{
INIT_SUCC(ret);
double tmp_val = 0;
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_double(tmp_val))) {
LOG_WARN("wrapper to date failed.", K(ret), K(*j_base));
} else {
val = static_cast<float>(tmp_val);
if (CAST_FAIL(real_range_check(dst_type, tmp_val, val))) {
LOG_WARN("real_range_check failed", K(ret), K(tmp_val));
}
}
return ret;
}
int ObExprJsonValue::cast_to_double(ObIJsonBase *j_base, ObObjType dst_type, double &val)
{
INIT_SUCC(ret);
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_double(val))) {
LOG_WARN("wrapper to date failed.", K(ret), K(*j_base));
} else if (ObUDoubleType == dst_type && CAST_FAIL(numeric_negative_check(val))) {
LOG_WARN("numeric_negative_check failed", K(ret), K(val));
}
return ret;
}
int ObExprJsonValue::cast_to_number(common::ObIAllocator *allocator,
ObIJsonBase *j_base,
common::ObAccuracy &accuracy,
ObObjType dst_type,
number::ObNumber &val)
{
INIT_SUCC(ret);
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_number(allocator, val))) {
LOG_WARN("fail to cast json as decimal", K(ret));
} else if (ObUNumberType == dst_type && CAST_FAIL(numeric_negative_check(val))) {
LOG_WARN("numeric_negative_check failed", K(ret), K(val));
} else if (CAST_FAIL(number_range_check(accuracy, allocator, val))) {
LOG_WARN("number_range_check failed", K(ret), K(val));
}
return ret;
}
int ObExprJsonValue::cast_to_string(common::ObIAllocator *allocator,
ObIJsonBase *j_base,
ObCollationType in_cs_type,
ObCollationType dst_cs_type,
common::ObAccuracy &accuracy,
ObObjType dst_type,
ObString &val)
{
INIT_SUCC(ret);
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (OB_ISNULL(allocator)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("allocator is null", K(ret));
} else {
ObJsonBuffer j_buf(allocator);
if (CAST_FAIL(j_base->print(j_buf, false))) {
LOG_WARN("fail to_string as json", K(ret));
} else {
ObObjType in_type = ObLongTextType;
ObString temp_str_val(j_buf.length(), j_buf.ptr());
bool is_need_string_string_convert = ((CS_TYPE_BINARY == dst_cs_type) ||
(ObCharset::charset_type_by_coll(in_cs_type) !=
ObCharset::charset_type_by_coll(dst_cs_type)));
if (is_need_string_string_convert) {
if (CS_TYPE_BINARY != in_cs_type
&& CS_TYPE_BINARY != dst_cs_type
&& (ObCharset::charset_type_by_coll(in_cs_type) !=
ObCharset::charset_type_by_coll(dst_cs_type))) {
char *buf = NULL;
const int64_t factor = 2;
int64_t buf_len = temp_str_val.length() * factor;
uint32_t result_len = 0;
buf = reinterpret_cast<char*>(allocator->alloc(buf_len));
if (OB_ISNULL(buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("alloc memory failed", K(ret));
} else if (OB_FAIL(ObCharset::charset_convert(in_cs_type, temp_str_val.ptr(),
temp_str_val.length(), dst_cs_type, buf,
buf_len, result_len))) {
LOG_WARN("charset convert failed", K(ret));
} else {
val.assign_ptr(buf, result_len);
}
} else {
if (CS_TYPE_BINARY == in_cs_type || CS_TYPE_BINARY == dst_cs_type) {
// just copy string when in_cs_type or out_cs_type is binary
const ObCharsetInfo *cs = NULL;
int64_t align_offset = 0;
if (CS_TYPE_BINARY == in_cs_type && lib::is_mysql_mode()
&& (NULL != (cs = ObCharset::get_charset(dst_cs_type)))) {
if (cs->mbminlen > 0 && temp_str_val.length() % cs->mbminlen != 0) {
align_offset = cs->mbminlen - temp_str_val.length() % cs->mbminlen;
}
}
int64_t len = align_offset + temp_str_val.length();
char *buf = reinterpret_cast<char*>(allocator->alloc(len));
if (OB_ISNULL(buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("allocate memory failed", K(ret));
} else {
MEMMOVE(buf + align_offset, temp_str_val.ptr(), len - align_offset);
MEMSET(buf, 0, align_offset);
val.assign_ptr(buf, len);
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("same charset should not be here, just use cast_eval_arg", K(ret),
K(in_type), K(dst_type), K(in_cs_type), K(dst_cs_type));
}
}
} else {
val.assign_ptr(temp_str_val.ptr(), temp_str_val.length());
}
// do str length check
const int32_t str_len_char = static_cast<int32_t>(ObCharset::strlen_char(dst_cs_type,
val.ptr(), val.length()));
const ObLength max_accuracy_len = accuracy.get_length();
if (OB_SUCC(ret)) {
if (max_accuracy_len == DEFAULT_STR_LENGTH) { // default string len
} else if (max_accuracy_len <= 0 || str_len_char > max_accuracy_len) {
ret = OB_OPERATE_OVERFLOW;
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "STRING", "json_value");
}
}
}
}
return ret;
}
int ObExprJsonValue::cast_to_bit(ObIJsonBase *j_base, uint64_t &val)
{
INIT_SUCC(ret);
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->to_bit(val))) {
LOG_WARN("fail get bit from json", K(ret));
}
return ret;
}
int ObExprJsonValue::cast_to_json(common::ObIAllocator *allocator,
ObIJsonBase *j_base, ObString &val)
{
INIT_SUCC(ret);
if (OB_ISNULL(j_base)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("json base is null", K(ret));
} else if (CAST_FAIL(j_base->get_raw_binary(val, allocator))) {
LOG_WARN("failed to get raw binary", K(ret));
}
return ret;
}
int ObExprJsonValue::cast_to_res(common::ObIAllocator *allocator,
ObExprCtx& expr_ctx,
ObIJsonBase *j_base,
uint8_t error_type,
ObObj *error_val,
common::ObAccuracy &accuracy,
ObObjType dst_type,
common::ObCollationType in_coll_type,
common::ObCollationType dst_coll_type,
common::ObCollationLevel dst_coll_level,
ObObj &res)
{
INIT_SUCC(ret);
switch (dst_type) {
case ObNullType : {
res.set_null();
break;
}
case ObTinyIntType:
case ObSmallIntType:
case ObMediumIntType:
case ObInt32Type:
case ObIntType: {
int64_t val = 0;
ret = cast_to_int(j_base, dst_type, val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_int(dst_type, val);
}
break;
}
case ObUTinyIntType:
case ObUSmallIntType:
case ObUMediumIntType:
case ObUInt32Type:
case ObUInt64Type: {
uint64_t val = 0;
ret = cast_to_uint(j_base, dst_type, val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_uint(dst_type, val);
}
break;
}
case ObDateTimeType: {
int64_t val = 0;
ret = cast_to_datetime(j_base, accuracy, val);
if (ret == OB_ERR_NULL_VALUE) {
res.set_null();
} else if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_datetime(dst_type, val);
}
break;
}
case ObTimestampType: {
const ObBasicSessionInfo *session = expr_ctx.my_session_;
ObOTimestampData val;
ret = cast_to_otimstamp(j_base, session, accuracy, dst_type, val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_otimestamp_value(dst_type, val);
}
break;
}
case ObDateType: {
int32_t val = 0;
ret = cast_to_date(j_base, val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_date(val);
}
break;
}
case ObTimeType: {
int64_t val = 0;
ret = cast_to_time(j_base, accuracy, val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_time(val);
}
break;
}
case ObYearType: {
uint8_t val = 0;
ret = cast_to_year(j_base, val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_year(val);
}
break;
}
case ObFloatType:
case ObUFloatType: {
float out_val = 0;
ret = cast_to_float(j_base, dst_type, out_val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_float(dst_type, out_val);
}
break;
}
case ObDoubleType:
case ObUDoubleType: {
double out_val = 0;
ret = cast_to_double(j_base, dst_type, out_val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_double(dst_type, out_val);
}
break;
}
case ObUNumberType:
case ObNumberType: {
number::ObNumber out_val;
ret = cast_to_number(allocator, j_base, accuracy, dst_type, out_val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_number(dst_type, out_val);
}
break;
}
case ObVarcharType:
case ObCharType:
case ObTinyTextType:
case ObTextType :
case ObMediumTextType:
case ObHexStringType:
case ObLongTextType: {
ObString val;
ret = cast_to_string(allocator, j_base, in_coll_type, dst_coll_type, accuracy, dst_type, val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
// old engine set same alloctor for wrapper, so we can use val without copy
res.set_string(dst_type, val);
res.set_collation_type(dst_coll_type);
res.set_collation_level(dst_coll_level);
}
break;
}
case ObBitType: {
uint64_t out_val = 0;
ret = cast_to_bit(j_base, out_val);
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_bit(out_val);
}
break;
}
case ObJsonType: {
ObString out_val;
ret = cast_to_json(allocator, j_base, out_val);
if (OB_SUCC(ret)) {
char *buf = reinterpret_cast<char *>(expr_ctx.calc_buf_->alloc(out_val.length()));
if (OB_UNLIKELY(buf == NULL)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to alloc memory for json array result", K(ret), K(out_val.length()));
} else {
MEMCPY(buf, out_val.ptr(), out_val.length());
out_val.assign_ptr(buf, out_val.length());
}
}
if (!try_set_error_val<ObObj>(res, ret, error_type, error_val)) {
res.set_string(dst_type, out_val);
res.set_collation_type(dst_coll_type);
res.set_collation_level(dst_coll_level);
}
break;
}
default: {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected dst_type", K(dst_type));
try_set_error_val<ObObj>(res, ret, error_type, error_val);
break;
}
}
LOG_DEBUG("finish cast_to_res.", K(ret), K(dst_type), K(error_type));
return ret;
}
int ObExprJsonValue::cast_to_res(common::ObIAllocator *allocator,
const ObExpr &expr,
ObEvalCtx &ctx,
ObIJsonBase *j_base,
uint8_t error_type,
ObDatum *error_val,
ObAccuracy &accuracy,
ObObjType dst_type,
ObCollationType in_coll_type,
ObCollationType dst_coll_type,
ObDatum &res)
{
INIT_SUCC(ret);
switch (dst_type) {
case ObNullType : {
res.set_null();
break;
}
case ObTinyIntType:
case ObSmallIntType:
case ObMediumIntType:
case ObInt32Type:
case ObIntType: {
int64_t val = 0;
ret = cast_to_int(j_base, dst_type, val);
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_int(val);
}
break;
}
case ObUTinyIntType:
case ObUSmallIntType:
case ObUMediumIntType:
case ObUInt32Type:
case ObUInt64Type: {
uint64_t val = 0;
ret = cast_to_uint(j_base, dst_type, val);
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_uint(val);
}
break;
}
case ObDateTimeType: {
int64_t val = 0;
ret = cast_to_datetime(j_base, accuracy, val);
if (ret == OB_ERR_NULL_VALUE) {
res.set_null();
} else if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_datetime(val);
}
break;
}
case ObTimestampType: {
ObOTimestampData val;
GET_SESSION()
{
ret = cast_to_otimstamp(j_base, session, accuracy, dst_type, val);
}
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_otimestamp_tiny(val);
}
break;
}
case ObDateType: {
int32_t val = 0;
ret = cast_to_date(j_base, val);
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_date(val);
}
break;
}
case ObTimeType: {
int64_t val = 0;
ret = cast_to_time(j_base, accuracy, val);
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_time(val);
}
break;
}
case ObYearType: {
uint8_t val = 0;
ret = cast_to_year(j_base, val);
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_year(val);
}
break;
}
case ObFloatType:
case ObUFloatType: {
float out_val = 0;
ret = cast_to_float(j_base, dst_type, out_val);
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_float(out_val);
}
break;
}
case ObDoubleType:
case ObUDoubleType: {
double out_val = 0;
ret = cast_to_double(j_base, dst_type, out_val);
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_double(out_val);
}
break;
}
case ObUNumberType:
case ObNumberType: {
number::ObNumber out_val;
ret = cast_to_number(allocator, j_base, accuracy, dst_type, out_val);
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_number(out_val);
}
break;
}
case ObVarcharType:
case ObCharType:
case ObTinyTextType:
case ObTextType :
case ObMediumTextType:
case ObHexStringType:
case ObLongTextType: {
ObString val;
ret = cast_to_string(allocator, j_base, in_coll_type, dst_coll_type, accuracy, dst_type, val);
if (OB_SUCC(ret)) {
char *buf = expr.get_str_res_mem(ctx, val.length());
if (OB_ISNULL(buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("allocate memory failed", K(ret));
} else {
MEMCPY(buf, val.ptr(), val.length());
val.assign_ptr(buf, val.length());
}
}
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
// old engine set same alloctor for wrapper, so we can use val without copy
res.set_string(val);
}
break;
}
case ObBitType: {
uint64_t out_val = 0;
ret = cast_to_bit(j_base, out_val);
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_bit(out_val);
}
break;
}
case ObJsonType: {
ObString out_val;
ret = cast_to_json(allocator, j_base, out_val);
if (OB_SUCC(ret)) {
char *buf = expr.get_str_res_mem(ctx, out_val.length());
if (OB_ISNULL(buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("allocate memory failed", K(ret));
} else {
MEMCPY(buf, out_val.ptr(), out_val.length());
out_val.assign_ptr(buf, out_val.length());
}
}
if (!try_set_error_val<ObDatum>(res, ret, error_type, error_val)) {
res.set_string(out_val);
}
break;
}
default: {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected dst_type", K(dst_type));
try_set_error_val<ObDatum>(res, ret, error_type, error_val);
break;
}
}
LOG_DEBUG("finish cast_to_res.", K(ret), K(dst_type), K(error_type));
return ret;
}
template<typename Obj>
bool ObExprJsonValue::try_set_error_val(Obj &res, int &ret, uint8_t error_type, Obj *error_val)
{
bool has_set_res = true;
if (OB_FAIL(ret)) {
if (error_type == OB_JSON_ON_RESPONSE_DEFAULT) {
set_val(res, error_val);
ret = OB_SUCCESS;
} else if (error_type == OB_JSON_ON_RESPONSE_NULL ||
error_type == OB_JSON_ON_RESPONSE_IMPLICIT) {
res.set_null();
ret = OB_SUCCESS;
}
} else {
has_set_res = false;
}
return has_set_res;
}
int ObExprJsonValue::get_on_empty_or_error_old(const ObObj *params,
ObExprCtx& expr_ctx,
const ObObjType dst_type,
uint8_t index,
bool &is_cover_by_error,
const ObAccuracy &accuracy,
uint8_t &type,
ObObj *default_value) const
{
INIT_SUCC(ret);
if (OB_FAIL(param_eval(expr_ctx, params[index], index))) {
is_cover_by_error = false;
LOG_WARN("eval json arg failed", K(ret));
} else {
ObObjType val_type = params[index].get_type();
if (val_type != ObIntType) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("input type error", K(val_type));
} else {
int64_t option_type = params[index].get_int();
if (option_type < OB_JSON_ON_RESPONSE_ERROR ||
option_type > OB_JSON_ON_RESPONSE_IMPLICIT) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("input option type error", K(option_type));
} else {
type = static_cast<uint8_t>(option_type);
}
}
}
if (OB_SUCC(ret)) {
common::ObCastMode cast_mode = expr_ctx.cast_mode_;
expr_ctx.cast_mode_ &= ~CM_WARN_ON_FAIL; // make cast return error when fail
expr_ctx.cast_mode_ &= ~CM_NO_RANGE_CHECK; // make cast check range
expr_ctx.cast_mode_ &= ~CM_STRING_INTEGER_TRUNC; // make cast check range when string to uint
expr_ctx.cast_mode_ |= CM_ERROR_ON_SCALE_OVER; // make cast check presion and scale
expr_ctx.cast_mode_ |= CM_EXPLICIT_CAST; // make cast json fail return error
if (OB_FAIL(param_eval(expr_ctx, params[index + 1], index + 1))) {
is_cover_by_error = false;
LOG_WARN("eval json arg failed", K(ret));
} else if (params[index + 1].get_type() == ObNullType || params[index + 1].is_null()) {
} else if (OB_FAIL(check_default_val_accuracy<ObObj>(accuracy, dst_type, &(params[index + 1])))) {
is_cover_by_error = false;
} else {
*default_value = params[index + 1];
}
if (ret == OB_OPERATE_OVERFLOW) {
if (dst_type >= ObDateTimeType && dst_type <= ObYearType) {
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "TIME DEFAULT", "json_value");
} else if (dst_type == ObNumberType || dst_type == ObUNumberType) {
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "DECIMAL DEFAULT", "json_value");
}
}
expr_ctx.cast_mode_ = cast_mode; // recover cast mode in old engine for cast mode used in global at expr
}
return ret;
}
int ObExprJsonValue::get_on_empty_or_error(const ObExpr &expr,
ObEvalCtx &ctx,
uint8_t index,
bool &is_cover_by_error,
const ObAccuracy &accuracy,
uint8_t &type,
ObDatum **default_value)
{
INIT_SUCC(ret);
ObExpr *json_arg = expr.args_[index];
ObObjType val_type = json_arg->datum_meta_.type_;
ObDatum *json_datum = NULL;
if (OB_FAIL(json_arg->eval(ctx, json_datum))) {
is_cover_by_error = false;
LOG_WARN("eval json arg failed", K(ret));
} else if (val_type != ObIntType) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("input type error", K(val_type));
} else {
int64_t option_type = json_datum->get_int();
if (option_type < OB_JSON_ON_RESPONSE_ERROR ||
option_type > OB_JSON_ON_RESPONSE_IMPLICIT) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("input option type error", K(option_type));
} else {
type = static_cast<uint8_t>(option_type);
}
}
if (OB_SUCC(ret)) {
json_arg = expr.args_[index + 1];
val_type = json_arg->datum_meta_.type_;
json_arg->extra_ &= ~CM_WARN_ON_FAIL; // make cast return error when fail
json_arg->extra_ &= ~CM_NO_RANGE_CHECK; // make cast check range
json_arg->extra_ &= ~CM_STRING_INTEGER_TRUNC; // make cast check range when string to uint
json_arg->extra_ |= CM_ERROR_ON_SCALE_OVER; // make cast check presion and scale
json_arg->extra_ |= CM_EXPLICIT_CAST; // make cast json fail return error
if (OB_FAIL(json_arg->eval(ctx, json_datum))) {
is_cover_by_error = false;
LOG_WARN("eval json arg failed", K(ret));
} else if (val_type == ObNullType || json_datum->is_null()) {
} else if (OB_FAIL(check_default_val_accuracy<ObDatum>(accuracy, val_type, json_datum))) {
is_cover_by_error = false;
} else {
*default_value = json_datum;
}
if (ret == OB_OPERATE_OVERFLOW) {
if (val_type >= ObDateTimeType && val_type <= ObYearType) {
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "TIME DEFAULT", "json_value");
} else if (val_type == ObNumberType || val_type == ObUNumberType) {
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "DECIMAL DEFAULT", "json_value");
}
}
}
return ret;
}
int ObExprJsonValue::get_cast_type(const ObExprResType param_type2, ObExprResType &dst_type) const
{
INIT_SUCC(ret);
if (!param_type2.is_int() && !param_type2.get_param().is_int()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cast param type is unexpected", K(param_type2));
} else {
const ObObj &param = param_type2.get_param();
ParseNode parse_node;
parse_node.value_ = param.get_int();
ObObjType obj_type = static_cast<ObObjType>(parse_node.int16_values_[OB_NODE_CAST_TYPE_IDX]);
dst_type.set_collation_type(static_cast<ObCollationType>(parse_node.int16_values_[OB_NODE_CAST_COLL_IDX]));
dst_type.set_type(obj_type);
if (ob_is_string_type(obj_type) || ob_is_lob_locator(obj_type)) {
// cast(x as char(10)) or cast(x as binary(10))
dst_type.set_full_length(parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX],
param_type2.get_accuracy().get_length_semantics());
} else if (ob_is_raw(obj_type)) {
dst_type.set_length(parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX]);
} else if (ObFloatType == dst_type.get_type()) {
// Compatible with mysql. If the precision p is not specified, produces a result of type FLOAT.
// If p is provided and 0 <= < p <= 24, the result is of type FLOAT. If 25 <= p <= 53,
// the result is of type DOUBLE. If p < 0 or p > 53, an error is returned
// however, ob use -1 as default precision, so it is a valid value
ObPrecision float_precision = parse_node.int16_values_[OB_NODE_CAST_N_PREC_IDX];
if (float_precision < -1 || float_precision > OB_MAX_DOUBLE_FLOAT_PRECISION) {
ret = OB_ERR_TOO_BIG_PRECISION;
LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, float_precision, "CAST", OB_MAX_DOUBLE_FLOAT_PRECISION);
} else if (float_precision <= OB_MAX_FLOAT_PRECISION) {
dst_type.set_type(ObFloatType);
} else {
dst_type.set_type(ObDoubleType);
}
dst_type.set_precision(-1);
dst_type.set_scale(parse_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX]);
} else if (lib::is_mysql_mode() && ObJsonType == dst_type.get_type()) {
dst_type.set_collation_type(CS_TYPE_UTF8MB4_BIN);
} else {
dst_type.set_precision(parse_node.int16_values_[OB_NODE_CAST_N_PREC_IDX]);
dst_type.set_scale(parse_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX]);
}
LOG_DEBUG("get_cast_type", K(dst_type), K(param_type2));
}
return ret;
}
int ObExprJsonValue::set_dest_type(ObExprResType &type1,
ObExprResType &type,
ObExprResType &dst_type,
ObExprTypeCtx &type_ctx) const
{
INIT_SUCC(ret);
const sql::ObSQLSessionInfo *session = type_ctx.get_session();
if (OB_ISNULL(session)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("ptr is NULL", K(ret), KP(session));
} else {
// always cast to user requested type
if (!lib::is_oracle_mode() &&
ObCharType == dst_type.get_type()) {
// cast(x as binary(10)), in parser,binary->T_CHAR+bianry, but, result type should be varchar, so set it.
type.set_type(ObVarcharType);
} else {
type.set_type(dst_type.get_type());
type.set_collation_type(dst_type.get_collation_type());
}
int16_t scale = dst_type.get_scale();
if (!lib::is_oracle_mode()
&& (ObTimeType == dst_type.get_type() || ObDateTimeType == dst_type.get_type())
&& scale > MAX_SCALE_FOR_TEMPORAL) {
ret = OB_ERR_TOO_BIG_PRECISION;
LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, scale, "CAST", OB_MAX_DATETIME_PRECISION);
}
if (OB_SUCC(ret)) {
ObCompatibilityMode compatibility_mode = get_compatibility_mode();
ObCollationType collation_connection = type_ctx.get_coll_type();
ObCollationType collation_nation = session->get_nls_collation_nation();
int32_t length = 0;
if (ob_is_string_type(dst_type.get_type()) || ob_is_json(dst_type.get_type())) {
type.set_collation_level(CS_LEVEL_IMPLICIT);
int32_t len = dst_type.get_length();
int16_t length_semantics = ((dst_type.is_string_type())
? dst_type.get_length_semantics()
: (OB_NOT_NULL(type_ctx.get_session())
? type_ctx.get_session()->get_actual_nls_length_semantics()
: LS_BYTE));
if (len > 0) { // cast(1 as char(10))
type.set_full_length(len, length_semantics);
} else if (OB_FAIL(get_cast_string_len(type1, dst_type, type_ctx, len, length_semantics,
collation_connection))) { // cast (1 as char)
LOG_WARN("fail to get cast string length", K(ret));
} else {
type.set_full_length(len, length_semantics);
}
if (CS_TYPE_INVALID != dst_type.get_collation_type()) {
// cast as binary
type.set_collation_type(dst_type.get_collation_type());
} else {
// use collation of current session
type.set_collation_type(ob_is_nstring_type(dst_type.get_type()) ?
collation_nation : collation_connection);
}
} else {
type.set_length(length);
if (ObNumberTC == dst_type.get_type_class() && 0 == dst_type.get_precision()) {
// MySql:cast (1 as decimal(0)) = cast(1 as decimal)
// Oracle: cast(1.4 as number) = cast(1.4 as number(-1, -1))
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY2[compatibility_mode][ObNumberType].get_precision());
} else if (ObIntTC == dst_type.get_type_class() || ObUIntTC == dst_type.get_type_class()) {
// for int or uint , the precision = len
int32_t len = 0;
int16_t length_semantics = LS_BYTE;//unused
if (OB_FAIL(get_cast_inttc_len(type1, dst_type, type_ctx, len, length_semantics, collation_connection))) {
LOG_WARN("fail to get cast inttc length", K(ret));
} else {
len = len > OB_LITERAL_MAX_INT_LEN ? OB_LITERAL_MAX_INT_LEN : len;
type.set_precision(static_cast<int16_t>(len));
}
} else if (ORACLE_MODE == compatibility_mode && ObDoubleType == dst_type.get_type()) {
ObAccuracy acc = ObAccuracy::DDL_DEFAULT_ACCURACY2[compatibility_mode][dst_type.get_type()];
type.set_accuracy(acc);
} else {
type.set_precision(dst_type.get_precision());
}
type.set_scale(dst_type.get_scale());
}
}
}
return ret;
}
int ObExprJsonValue::get_cast_string_len(ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx,
int32_t &res_len,
int16_t &length_semantics,
ObCollationType conn) const
{
INIT_SUCC(ret);
const ObObj &val = type1.get_param();
if (!type1.is_literal()) { // column
res_len = CAST_STRING_DEFUALT_LENGTH[type1.get_type()];
int16_t prec = type1.get_accuracy().get_precision();
int16_t scale = type1.get_accuracy().get_scale();
switch(type1.get_type()) {
case ObTinyIntType:
case ObSmallIntType:
case ObMediumIntType:
case ObInt32Type:
case ObIntType:
case ObUTinyIntType:
case ObUSmallIntType:
case ObUMediumIntType:
case ObUInt32Type:
case ObUInt64Type: {
int32_t prec = static_cast<int32_t>(type1.get_accuracy().get_precision());
res_len = prec > res_len ? prec : res_len;
break;
}
case ObNumberType:
case ObUNumberType: {
if (lib::is_oracle_mode()) {
if (0 < prec) {
if (0 < scale) {
res_len = prec + 2;
} else if (0 == scale){
res_len = prec + 1;
} else {
res_len = prec - scale;
}
}
} else {
if (0 < prec) {
if (0 < scale) {
res_len = prec + 2;
} else {
res_len = prec + 1;
}
}
}
break;
}
case ObTimestampTZType:
case ObTimestampLTZType:
case ObTimestampNanoType:
case ObDateTimeType:
case ObTimestampType: {
if (scale > 0) {
res_len += scale + 1;
}
break;
}
case ObTimeType: {
if (scale > 0) {
res_len += scale + 1;
}
break;
}
case ObTinyTextType:
case ObTextType:
case ObMediumTextType:
case ObLongTextType:
case ObVarcharType:
case ObCharType:
case ObHexStringType:
case ObRawType:
case ObNVarchar2Type:
case ObNCharType: {
res_len = type1.get_length();
length_semantics = type1.get_length_semantics();
break;
}
default: {
break;
}
}
} else if (type1.is_null()) {
res_len = 0;//compatible with mysql;
} else if (OB_ISNULL(type_ctx.get_session())) {
// calc type don't set ret, just print the log. by design.
LOG_WARN("my_session is null");
} else { // literal
ObArenaAllocator oballocator(ObModIds::BLOCK_ALLOC);
ObCastMode cast_mode = CM_NONE;
ObCollationType cast_coll_type = (CS_TYPE_INVALID != type2.get_collation_type())
? type2.get_collation_type()
: conn;
const ObDataTypeCastParams dtc_params =
ObBasicSessionInfo::create_dtc_params(type_ctx.get_session());
ObCastCtx cast_ctx(&oballocator,
&dtc_params,
0,
cast_mode,
cast_coll_type);
ObString val_str;
EXPR_GET_VARCHAR_V2(val, val_str);
if (OB_SUCC(ret) && NULL != val_str.ptr()) {
int32_t len_byte = val_str.length();
res_len = len_byte;
length_semantics = LS_CHAR;
if (NULL != val_str.ptr()) {
int32_t trunc_len_byte = static_cast<int32_t>(ObCharset::strlen_byte_no_sp(cast_coll_type,
val_str.ptr(), len_byte));
res_len = static_cast<int32_t>(ObCharset::strlen_char(cast_coll_type,
val_str.ptr(), trunc_len_byte));
}
if (type1.is_numeric_type() && !type1.is_integer_type()) {
res_len += 1;
}
}
}
return ret;
}
int ObExprJsonValue::get_cast_inttc_len(ObExprResType &type1,
ObExprResType &type2,
ObExprTypeCtx &type_ctx,
int32_t &res_len,
int16_t &length_semantics,
ObCollationType conn) const
{
INIT_SUCC(ret);
if (type1.is_literal()) { // literal
if (ObStringTC == type1.get_type_class()) {
res_len = type1.get_accuracy().get_length();
length_semantics = type1.get_length_semantics();
} else if (OB_FAIL(ObField::get_field_mb_length(type1.get_type(),
type1.get_accuracy(), type1.get_collation_type(), res_len))) {
LOG_WARN("failed to get filed mb length");
}
} else {
res_len = CAST_STRING_DEFUALT_LENGTH[type1.get_type()];
ObObjTypeClass tc1 = type1.get_type_class();
int16_t scale = type1.get_accuracy().get_scale();
if (ObDoubleTC == tc1) {
res_len -= 1;
} else if (ObDateTimeTC == tc1 && scale > 0) {
res_len += scale - 1;
} else if (OB_FAIL(get_cast_string_len(type1, type2, type_ctx, res_len, length_semantics, conn))) {
LOG_WARN("fail to get cast string length", K(ret));
} else {
// do nothing
}
}
return ret;
}
}
}