/** * 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 implement of func json expr helper */ #define USING_LOG_PREFIX SQL_ENG #include "lib/ob_errno.h" #include "sql/engine/expr/ob_expr_cast.h" #include "sql/engine/ob_exec_context.h" #include "sql/engine/expr/ob_datum_cast.h" #include "ob_expr_json_func_helper.h" #include "lib/encode/ob_base64_encode.h" // for ObBase64Encoder #include "lib/utility/ob_fast_convert.h" // ObFastFormatInt::format_unsigned #include "lib/charset/ob_dtoa.h" // ob_gcvt_opt #include "rpc/obmysql/ob_mysql_global.h" // DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE using namespace oceanbase::common; using namespace oceanbase::sql; namespace oceanbase { namespace sql { static OB_INLINE int common_construct_otimestamp(const ObObjType type, const ObDatum &in_datum, ObOTimestampData &out_val) { int ret = OB_SUCCESS; if (ObTimestampTZType == type) { out_val = in_datum.get_otimestamp_tz(); } else if (ObTimestampLTZType == type || ObTimestampNanoType == type) { out_val = in_datum.get_otimestamp_tiny(); } else { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid in type", K(ret), K(type)); } return ret; } template int get_otimestamp_from_datum(const T &datum, ObOTimestampData &in_val, ObObjType type); template <> int get_otimestamp_from_datum(const ObDatum &datum, ObOTimestampData &in_val, ObObjType type) { INIT_SUCC(ret); if (ObTimestampTZType == type) { in_val = datum.get_otimestamp_tz(); } else if (ObTimestampLTZType == type || ObTimestampNanoType == type) { in_val = datum.get_otimestamp_tiny(); } else { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid in type", K(ret), K(type)); } return ret; } template <> int get_otimestamp_from_datum(const ObObj &datum, ObOTimestampData &in_val, ObObjType type) { INIT_SUCC(ret); in_val = datum.get_otimestamp_value(); return ret; } ObJsonInType ObJsonExprHelper::get_json_internal_type(ObObjType type) { return type == ObJsonType ? ObJsonInType::JSON_BIN : ObJsonInType::JSON_TREE; } int ObJsonExprHelper::ensure_collation(ObObjType type, ObCollationType cs_type) { INIT_SUCC(ret); if (ob_is_string_type(type) && (ObCharset::charset_type_by_coll(cs_type) != CHARSET_UTF8MB4)) { LOG_WARN("unsuport json string type with binary charset", K(type), K(cs_type)); ret = OB_ERR_INVALID_JSON_CHARSET; LOG_USER_ERROR(OB_ERR_INVALID_JSON_CHARSET); } return ret; } int ObJsonExprHelper::get_json_or_str_data(ObExpr *expr, ObEvalCtx &ctx, common::ObArenaAllocator &allocator, ObString& str, bool& is_null) { INIT_SUCC(ret); ObDatum *json_datum = NULL; ObObjType val_type = expr->datum_meta_.type_; if (OB_UNLIKELY(OB_FAIL(expr->eval(ctx, json_datum)))) { LOG_WARN("eval json arg failed", K(ret)); } else if (json_datum->is_null() || val_type == ObNullType) { is_null = true; } else if (!ob_is_extend(val_type) && !ob_is_json(val_type) && !ob_is_raw(val_type) && !ob_is_string_type(val_type)) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("input type error", K(val_type)); } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, *json_datum, expr->datum_meta_, expr->obj_meta_.has_lob_header(), str))) { LOG_WARN("fail to get real data.", K(ret), K(str)); } return ret; } int ObJsonExprHelper::get_json_doc(const ObExpr &expr, ObEvalCtx &ctx, common::ObArenaAllocator &allocator, uint16_t index, ObIJsonBase*& j_base, bool &is_null, bool need_to_tree, bool relax) { INIT_SUCC(ret); ObDatum *json_datum = NULL; ObExpr *json_arg = expr.args_[index]; ObObjType val_type = json_arg->datum_meta_.type_; ObCollationType cs_type = json_arg->datum_meta_.cs_type_; bool is_oracle = lib::is_oracle_mode(); if (OB_UNLIKELY(OB_FAIL(json_arg->eval(ctx, json_datum)))) { LOG_WARN("eval json arg failed", K(ret)); } else if (val_type == ObNullType || json_datum->is_null()) { is_null = true; } else if (val_type != ObJsonType && !ob_is_string_type(val_type)) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("input type error", K(val_type)); } else if (lib::is_mysql_mode() && OB_FAIL(ObJsonExprHelper::ensure_collation(val_type, cs_type))) { LOG_WARN("fail to ensure collation", K(ret), K(val_type), K(cs_type)); } else { ObString j_str; if (OB_FAIL(get_json_or_str_data(json_arg, ctx, allocator, j_str, is_null))) { LOG_WARN("fail to get real data.", K(ret), K(j_str)); } else if (is_null) { } else { ObJsonInType j_in_type = ObJsonExprHelper::get_json_internal_type(val_type); ObJsonInType expect_type = need_to_tree ? ObJsonInType::JSON_TREE : j_in_type; bool relax_json = (lib::is_oracle_mode() && relax); uint32_t parse_flag = relax_json ? ObJsonParser::JSN_RELAXED_FLAG : 0; if (is_oracle && j_str.length() == 0) { is_null = true; } else if (OB_FAIL(ObJsonBaseFactory::get_json_base(&allocator, j_str, j_in_type, expect_type, j_base, parse_flag))) { LOG_WARN("fail to get json base", K(ret), K(j_in_type)); if (is_oracle) { ret = OB_ERR_JSON_SYNTAX_ERROR; } else { ret = OB_ERR_INVALID_JSON_TEXT_IN_PARAM; LOG_USER_ERROR(OB_ERR_INVALID_JSON_TEXT_IN_PARAM); } } } } return ret; } int ObJsonExprHelper::get_json_val(const common::ObObj &data, ObExprCtx &ctx, bool is_bool, common::ObIAllocator *allocator, ObIJsonBase*& j_base, bool to_bin) { INIT_SUCC(ret); ObObjType val_type = data.get_type(); if (data.is_null()) { void *json_node_buf = allocator->alloc(sizeof(ObJsonNull)); if (OB_ISNULL(json_node_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed: alloscate jsonboolean", K(ret)); } else { ObJsonNull *null_node = static_cast(new(json_node_buf) ObJsonNull()); if (to_bin) { if (OB_FAIL(ObJsonBaseFactory::transform(allocator, null_node, ObJsonInType::JSON_BIN, j_base))) { LOG_WARN("failed: json tree to bin", K(ret)); } } else { j_base = null_node; } } } else if (is_bool) { void *json_node_buf = allocator->alloc(sizeof(ObJsonBoolean)); if (OB_ISNULL(json_node_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed: alloscate jsonboolean", K(ret)); } else { ObJsonBoolean *bool_node = (ObJsonBoolean*)new(json_node_buf)ObJsonBoolean(data.get_bool()); if (to_bin) { if (OB_FAIL(ObJsonBaseFactory::transform(allocator, bool_node, ObJsonInType::JSON_BIN, j_base))) { LOG_WARN("failed: json tree to bin", K(ret)); } } else { j_base = bool_node; } } } else if (ObJsonExprHelper::is_convertible_to_json(val_type)) { ObCollationType cs_type = data.get_collation_type(); if (OB_FAIL(ObJsonExprHelper::transform_convertible_2jsonBase(data, val_type, allocator, cs_type, j_base, to_bin, data.has_lob_header(), false))) { LOG_WARN("failed: parse value to jsonBase", K(ret), K(val_type)); } } else { ObBasicSessionInfo *session = ctx.exec_ctx_->get_my_session(); if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else if (OB_FAIL(ObJsonExprHelper::transform_scalar_2jsonBase(data, val_type, allocator, data.get_scale(), session->get_timezone_info(), session, j_base, to_bin))) { LOG_WARN("failed: parse value to jsonBase", K(ret), K(val_type)); } } return ret; } int ObJsonExprHelper::cast_to_json_tree(ObString &text, common::ObIAllocator *allocator, uint32_t parse_flag) { INIT_SUCC(ret); ObJsonNode *j_tree = NULL; if (OB_FAIL(ObJsonParser::get_tree(allocator, text, j_tree, parse_flag))) { LOG_WARN("get json tree fail", K(ret)); } else { ObJsonBuffer jbuf(allocator); if (OB_FAIL(j_tree->print(jbuf, true, false, 0))) { LOG_WARN("json binary to string failed", K(ret)); } else if (jbuf.empty()) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory for result failed", K(ret)); } else { text.assign_ptr(jbuf.ptr(), jbuf.length()); } } return ret; } int ObJsonExprHelper::get_json_val(const ObExpr &expr, ObEvalCtx &ctx, common::ObIAllocator *allocator, uint16_t index, ObIJsonBase*& j_base, bool to_bin, bool format_json, uint32_t parse_flag) { INIT_SUCC(ret); ObDatum *json_datum = NULL; ObExpr *json_arg = expr.args_[index]; ObObjType val_type = json_arg->datum_meta_.type_; if (OB_UNLIKELY(OB_FAIL(json_arg->eval(ctx, json_datum)))) { LOG_WARN("eval json arg failed", K(ret), K(val_type)); } else if (json_datum->is_null()) { void *json_node_buf = allocator->alloc(sizeof(ObJsonNull)); if (OB_ISNULL(json_node_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed: alloscate jsonboolean", K(ret)); } else { ObJsonNull *null_node = static_cast(new(json_node_buf) ObJsonNull()); if (to_bin) { if (OB_FAIL(ObJsonBaseFactory::transform(allocator, null_node, ObJsonInType::JSON_BIN, j_base))) { LOG_WARN("failed: json tree to bin", K(ret)); } } else { j_base = null_node; } } } else if (json_arg->is_boolean_ == 1) { void *json_node_buf = allocator->alloc(sizeof(ObJsonBoolean)); if (OB_ISNULL(json_node_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed: alloscate jsonboolean", K(ret)); } else { ObJsonBoolean *bool_node = (ObJsonBoolean*)new(json_node_buf)ObJsonBoolean(json_datum->get_bool()); if (to_bin) { if (OB_FAIL(ObJsonBaseFactory::transform(allocator, bool_node, ObJsonInType::JSON_BIN, j_base))) { LOG_WARN("failed: json tree to bin", K(ret)); } } else { j_base = bool_node; } } } else if (ObJsonExprHelper::is_convertible_to_json(val_type)) { ObCollationType cs_type = json_arg->datum_meta_.cs_type_; if (OB_FAIL(ObJsonExprHelper::transform_convertible_2jsonBase(*json_datum, val_type, allocator, cs_type, j_base, to_bin, json_arg->obj_meta_.has_lob_header(), false, HAS_FLAG(parse_flag, ObJsonParser::JSN_RELAXED_FLAG), format_json))) { LOG_WARN("failed: parse value to jsonBase", K(ret), K(val_type)); } } else { ObBasicSessionInfo *session = ctx.exec_ctx_.get_my_session(); ObScale scale = json_arg->datum_meta_.scale_; scale = (val_type == ObBitType) ? json_arg->datum_meta_.length_semantics_ : scale; if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else if (OB_FAIL(ObJsonExprHelper::transform_scalar_2jsonBase(*json_datum, val_type, allocator, scale, session->get_timezone_info(), session, j_base, to_bin))) { LOG_WARN("failed: parse value to jsonBase", K(ret), K(val_type)); } } return ret; } int ObJsonExprHelper::eval_oracle_json_val(ObExpr *expr, ObEvalCtx &ctx, common::ObIAllocator *allocator, ObIJsonBase*& j_base, bool is_format_json, bool is_strict, bool is_bin) { INIT_SUCC(ret); ObDatum *json_datum = nullptr; ObExpr *json_arg = expr; bool is_bool_data_type = json_arg->is_boolean_; if (OB_FAIL(json_arg->eval(ctx, json_datum))) { LOG_WARN("eval json arg failed", K(ret), K(json_arg->datum_meta_)); } else if (OB_FAIL(oracle_datum2_json_val(json_datum, json_arg->obj_meta_, allocator, ctx.exec_ctx_.get_my_session(), j_base, is_bool_data_type, is_format_json, is_strict, is_bin))) { LOG_WARN("failed to wrapper json base", K(ret), K(json_arg->datum_meta_), K(is_format_json), K(is_strict), K(is_bin)); } return ret; } int ObJsonExprHelper::oracle_datum2_json_val(const ObDatum *json_datum, ObObjMeta& data_meta, common::ObIAllocator *allocator, ObBasicSessionInfo *session, ObIJsonBase*& j_base, bool is_bool_data_type, bool is_format_json, bool is_strict, bool is_bin) { INIT_SUCC(ret); ObObjType val_type = data_meta.get_type(); ObCollationType cs_type = data_meta.get_collation_type(); bool is_nchar = (val_type == ObNCharType || val_type == ObNVarchar2Type); bool is_raw_type = (val_type == ObRawType); if (json_datum->is_null() || ob_is_null(val_type)) { ObJsonNull *null_node = nullptr; if (OB_ISNULL(null_node = OB_NEWx(ObJsonNull, allocator))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed: alloscate jsonboolean", K(ret)); } j_base = null_node; } else if (is_bool_data_type) { ObJsonBoolean *bool_node = nullptr; if (OB_ISNULL(bool_node = OB_NEWx(ObJsonBoolean, allocator, (json_datum->get_bool())))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed: alloscate jsonboolean", K(ret)); } j_base = bool_node; } else if (ObJsonExprHelper::is_convertible_to_json(val_type)) { if (val_type == ObVarcharType || val_type == ObCharType || val_type == ObTinyTextType || val_type == ObTextType || val_type == ObMediumTextType || val_type == ObLongTextType || is_raw_type || is_nchar) { uint32_t parse_flag = ObJsonParser::JSN_RELAXED_FLAG; ObString j_str = json_datum->get_string(); if (OB_FAIL(ObTextStringHelper::read_real_string_data( allocator, val_type, cs_type, data_meta.has_lob_header(), j_str))) { LOG_WARN("fail to get real data.", K(ret), K(j_str)); } else if (cs_type != CS_TYPE_INVALID && cs_type != CS_TYPE_BINARY && OB_FAIL(ObExprUtil::convert_string_collation(j_str, cs_type, j_str, CS_TYPE_UTF8MB4_BIN, *allocator))) { LOG_WARN("fail to convert charset.", K(ret), K(j_str), K(cs_type)); } else if (!is_format_json || is_raw_type) { if (is_raw_type) { ObObj tmp_result; ObObj obj; ObDatum tmp_datum = *json_datum; tmp_datum.set_string(j_str); ObCastCtx cast_ctx(allocator, nullptr, CM_NONE, CS_TYPE_INVALID); if (OB_FAIL(tmp_datum.to_obj(obj, data_meta))) { LOG_WARN("datum to obj fail", K(ret)); } else if (OB_FAIL(ObHexUtils::rawtohex(obj, cast_ctx, tmp_result))) { LOG_WARN("fail to check json syntax", K(ret), K(data_meta)); } else { j_str = tmp_result.get_string(); } } ObJsonString* string_node = nullptr; if (OB_FAIL(ret)) { } else if (OB_ISNULL(string_node = OB_NEWx(ObJsonString, allocator, j_str.ptr(), j_str.length()))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed: alloscate json string node", K(ret)); } else { j_base = string_node; } } else { if (OB_FAIL(ObJsonParser::check_json_syntax(j_str, allocator, parse_flag))) { if (!is_strict) { ret = OB_SUCCESS; ObJsonString* string_node = nullptr; if (OB_ISNULL(string_node = OB_NEWx(ObJsonString, allocator, j_str.ptr(), j_str.length()))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed: alloscate json string node", K(ret)); } j_base = string_node; } else { ret = OB_ERR_JSON_SYNTAX_ERROR; LOG_WARN("fail to check json syntax", K(ret), K(j_str)); } } else if (OB_FAIL(ObJsonBaseFactory::get_json_base( allocator, j_str, ObJsonInType::JSON_TREE, ObJsonInType::JSON_TREE, j_base, parse_flag))) { LOG_WARN("failed: parse json string node", K(ret), K(j_str)); } } } else if (val_type == ObJsonType) { ObJsonInType to_type = is_bin ? ObJsonInType::JSON_BIN : ObJsonInType::JSON_TREE; ObString j_str = json_datum->get_string(); if (OB_FAIL(ObTextStringHelper::read_real_string_data( allocator, val_type, cs_type, data_meta.has_lob_header(), j_str))) { LOG_WARN("fail to get real data.", K(ret), K(j_str)); } else if (OB_FAIL(ObJsonBaseFactory::get_json_base(allocator, j_str, ObJsonInType::JSON_BIN, to_type, j_base))) { ret = OB_ERR_INVALID_JSON_TEXT_IN_PARAM; LOG_WARN("fail to get json base", K(ret)); } } else { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(val_type)); } if (OB_SUCC(ret)) { if (OB_FAIL(ObJsonBaseFactory::transform(allocator, j_base, is_bin ? ObJsonInType::JSON_BIN : ObJsonInType::JSON_TREE , j_base))) { LOG_WARN("failed: json tree to bin", K(ret)); } else { j_base->set_allocator(allocator); } } } else { ObScale scale = data_meta.get_scale(); if (is_format_json) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("input type error", K(val_type)); } else if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else if (val_type == ObIntervalDSType || val_type == ObIntervalYMType) { // internal json type not support interval type using string type instead int64_t len = 0; char* string_buf = nullptr; ObJsonString* string_node = nullptr; if (OB_ISNULL(string_buf = static_cast(allocator->alloc(OB_CAST_TO_VARCHAR_MAX_LENGTH)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory", K(ret)); } else if (ob_is_interval_ym(val_type)) { ObIntervalYMValue in_val(json_datum->get_interval_nmonth()); if (OB_FAIL(ObTimeConverter::interval_ym_to_str( in_val, scale, string_buf, OB_CAST_TO_VARCHAR_MAX_LENGTH, len, true))) { LOG_WARN("interval_ym_to_str failed", K(ret)); } } else { ObIntervalDSValue in_val(json_datum->get_interval_ds()); if (OB_FAIL(ObTimeConverter::interval_ds_to_str( in_val, scale, string_buf, OB_CAST_TO_VARCHAR_MAX_LENGTH, len, true))) { LOG_WARN("interval_ym_to_str failed", K(ret)); } } if (OB_FAIL(ret)) { } else if (OB_ISNULL(string_node = OB_NEWx(ObJsonString, allocator, (const char*)string_buf, len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to create json string node", K(ret)); } else { j_base = string_node; } } else if (val_type == ObTimestampTZType || val_type == ObTimestampLTZType) { // internal json type not support time zone or local time zone type using string type instead char* string_buf = nullptr; int64_t len = 0; ObJsonString* string_node = nullptr; if (OB_ISNULL(string_buf = static_cast(allocator->alloc(OB_CAST_TO_VARCHAR_MAX_LENGTH)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to allocate memory", K(ret)); } else { ObOTimestampData in_val; ObScale scale = data_meta.get_scale(); const ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params(session); if (OB_FAIL(common_construct_otimestamp(val_type, *json_datum, in_val))) { LOG_WARN("common_construct_otimestamp failed", K(ret)); } else if (OB_FAIL(ObTimeConverter::otimestamp_to_str(in_val, dtc_params, scale, val_type, string_buf, OB_CAST_TO_VARCHAR_MAX_LENGTH, len))) { LOG_WARN("failed to convert otimestamp to string", K(ret)); } else if (OB_ISNULL(string_node = OB_NEWx(ObJsonString, allocator, (const char*)string_buf, len))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("failed to create json string node", K(ret)); } else { j_base = string_node; } } } else if (OB_FAIL(ObJsonExprHelper::transform_scalar_2jsonBase(*json_datum, val_type, allocator, scale, session->get_timezone_info(), session, j_base, is_bin))) { LOG_WARN("failed: parse value to jsonBase", K(ret), K(val_type)); } } return ret; } int ObJsonExprHelper::json_base_replace(ObIJsonBase *json_old, ObIJsonBase *json_new, ObIJsonBase *&json_doc) { INIT_SUCC(ret); if (json_old == json_doc) { json_doc = json_new; } else { ObIJsonBase *json_old_tree = json_old; ObIAllocator *allocator = json_doc->get_allocator(); if (!json_old->is_tree() && ObJsonBaseFactory::transform(allocator, json_old, ObJsonInType::JSON_TREE, json_old_tree)) { LOG_WARN("fail to transform to tree", K(ret), K(*json_old)); } else { ObIJsonBase *parent = static_cast(json_old_tree)->get_parent(); if(OB_NOT_NULL(parent) && parent != json_doc) { if (OB_FAIL(parent->replace(json_old_tree, json_new))) { LOG_WARN("json base replace failed", K(ret)); } } else { if (OB_FAIL(json_doc->replace(json_old_tree, json_new))) { LOG_WARN("json base replace failed", K(ret)); } } } } return ret; } // get json expr path cache context, if not exists cache context do nothing ObJsonPathCache* ObJsonExprHelper::get_path_cache_ctx(const uint64_t& id, ObExecContext *exec_ctx) { INIT_SUCC(ret); ObJsonPathCacheCtx* cache_ctx = NULL; if (ObExpr::INVALID_EXP_CTX_ID != id) { cache_ctx = static_cast(exec_ctx->get_expr_op_ctx(id)); if (OB_ISNULL(cache_ctx)) { // if pathcache not exist, create one void *cache_ctx_buf = NULL; ret = exec_ctx->create_expr_op_ctx(id, sizeof(ObJsonPathCacheCtx), cache_ctx_buf); if (OB_SUCC(ret) && OB_NOT_NULL(cache_ctx_buf)) { cache_ctx = new (cache_ctx_buf) ObJsonPathCacheCtx(&exec_ctx->get_allocator()); } } } return (cache_ctx == NULL) ? NULL : cache_ctx->get_path_cache(); } int ObJsonExprHelper::find_and_add_cache(ObJsonPathCache* path_cache, ObJsonPath*& res_path, ObString& path_str, int arg_idx, bool enable_wildcard) { INIT_SUCC(ret); if (OB_FAIL(path_cache->find_and_add_cache(res_path, path_str, arg_idx))) { ret = OB_ERR_INVALID_JSON_PATH; LOG_USER_ERROR(OB_ERR_INVALID_JSON_PATH); } else if (!enable_wildcard && res_path->can_match_many()) { ret = OB_ERR_INVALID_JSON_PATH_WILDCARD; LOG_USER_ERROR(OB_ERR_INVALID_JSON_PATH_WILDCARD); } return ret; } bool ObJsonExprHelper::is_convertible_to_json(ObObjType &type) { bool val = false; switch (type) { case ObNullType: case ObJsonType: case ObVarcharType: case ObCharType: case ObTinyTextType: case ObTextType: case ObMediumTextType: case ObLobType: case ObRawType: case ObLongTextType: { val = true; break; } default: break; } if (lib::is_oracle_mode()) { switch (type) { case ObNVarchar2Type: case ObNCharType: { val = true; break; } default: break; } } return val; } int ObJsonExprHelper::is_valid_for_json(ObExprResType* types_stack, uint32_t index, const char* func_name) { INIT_SUCC(ret); ObObjType in_type = types_stack[index].get_type(); if (!is_convertible_to_json(in_type)) { ret = OB_ERR_INVALID_TYPE_FOR_JSON; LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_JSON, index + 1, func_name); } else if (ob_is_string_type(in_type)) { if (types_stack[index].get_collation_type() == CS_TYPE_BINARY) { types_stack[index].set_calc_collation_type(CS_TYPE_BINARY); } else { if (types_stack[index].get_charset_type() != CHARSET_UTF8MB4) { types_stack[index].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN); } } } return ret; } int ObJsonExprHelper::is_valid_for_json(ObExprResType& type, uint32_t index, const char* func_name) { INIT_SUCC(ret); ObObjType in_type = type.get_type(); if (!is_convertible_to_json(in_type)) { ret = OB_ERR_INVALID_TYPE_FOR_JSON; LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_JSON, index, func_name); } else if (ob_is_string_type(in_type) && type.get_collation_type() != CS_TYPE_BINARY) { if (type.get_charset_type() != CHARSET_UTF8MB4) { type.set_calc_collation_type(CS_TYPE_UTF8MB4_BIN); } } return ret; } int ObJsonExprHelper::is_valid_for_path(ObExprResType* types_stack, uint32_t index) { INIT_SUCC(ret); ObObjType in_type = types_stack[index].get_type(); if (in_type == ObNullType || in_type == ObJsonType) { } else if (ob_is_string_type(in_type)) { if (types_stack[index].get_charset_type() != CHARSET_UTF8MB4) { types_stack[index].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN); } } else { ret = OB_ERR_INVALID_JSON_PATH; LOG_USER_ERROR(OB_ERR_INVALID_JSON_PATH); } return ret; } void ObJsonExprHelper::set_type_for_value(ObExprResType* types_stack, uint32_t index) { ObObjType in_type = types_stack[index].get_type(); if (in_type == ObNullType) { } else if (ob_is_string_type(in_type)) { if (types_stack[index].get_charset_type() != CHARSET_UTF8MB4) { types_stack[index].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN); } } else if (in_type == ObJsonType) { types_stack[index].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN); } } int ObJsonExprHelper::is_json_zero(const ObString& data, int& result) { INIT_SUCC(ret); int tmp_result = 0; ObJsonBin j_bin(data.ptr(), data.length()); if (data.length() == 0) { result = 1; } else if (OB_FAIL(j_bin.reset_iter())) { LOG_WARN("failed: reset iter", K(ret)); } else if (OB_FAIL(ObJsonBaseUtil::compare_int_json(0, &j_bin, tmp_result))) { LOG_WARN("failed: cmp json", K(ret)); } else { result = (tmp_result == 0) ? 0 : 1; } return ret; } template int ObJsonExprHelper::transform_scalar_2jsonBase(const T &datum, ObObjType type, common::ObIAllocator *allocator, ObScale scale, const ObTimeZoneInfo *tz_info, ObBasicSessionInfo *session, ObIJsonBase*& j_base, bool to_bin) { int ret = OB_SUCCESS; void* buf = NULL; ObIJsonBase* json_node = NULL; switch(type) { case ObTinyIntType: { // mysql boolean type buf = allocator->alloc(sizeof(ObJsonInt)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret), K(type)); } else { json_node = (ObJsonInt*)new(buf)ObJsonInt(datum.get_int()); } break; } case ObSmallIntType: case ObMediumIntType: case ObInt32Type: case ObIntType: { buf = allocator->alloc(sizeof(ObJsonInt)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret), K(type)); } else { json_node = (ObJsonInt*)new(buf)ObJsonInt(datum.get_int()); } break; } case ObUTinyIntType: case ObUSmallIntType: case ObUMediumIntType: case ObUInt32Type: case ObUInt64Type: case ObYearType: { buf = allocator->alloc(sizeof(ObJsonUint)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret), K(type)); } else { json_node = (ObJsonInt*)new(buf)ObJsonUint(datum.get_uint64()); } break; } case ObDateTimeType: case ObTimestampType: case ObTimestampNanoType: case ObDateType: case ObTimeType: { ObTime ob_time; int64_t value = 0; ObJsonNodeType node_type; if (type == ObDateType) { node_type = ObJsonNodeType::J_DATE; value = datum.get_date(); ob_time.mode_ = DT_TYPE_DATE; if (OB_FAIL(ObTimeConverter::date_to_ob_time(value, ob_time))) { LOG_WARN("date transform to ob time failed", K(ret), K(value)); } } else if (type == ObTimeType) { node_type = ObJsonNodeType::J_TIME; value = datum.get_time(); ob_time.mode_ = DT_TYPE_TIME; if (OB_FAIL(ObTimeConverter::time_to_ob_time(value, ob_time))) { LOG_WARN("time transform to ob time failed", K(ret), K(value)); } } else if (type == ObDateTimeType) { node_type = ObJsonNodeType::J_DATETIME; value = datum.get_datetime(); ob_time.mode_ = DT_TYPE_DATETIME; if (OB_FAIL(ObTimeConverter::datetime_to_ob_time(value, tz_info, ob_time))) { LOG_WARN("datetime transform to ob time failed", K(ret), K(value)); } } else { node_type = ObJsonNodeType::J_TIMESTAMP; if (lib::is_oracle_mode()) { ObOTimestampData in_val; char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0}; int64_t len = 0; if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else { const ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params(session); if (OB_FAIL(get_otimestamp_from_datum(datum, in_val, type))) { LOG_WARN("get otimestamp fail", K(ret)); } else if (OB_SUCC(ret) && OB_FAIL(ObTimeConverter::otimestamp_to_ob_time(type, in_val, NULL, ob_time))) { LOG_WARN("fail to convert otimestamp to ob_time", K(ret), K(in_val)); } } } else { value = datum.get_timestamp(); ob_time.mode_ = DT_TYPE_DATETIME; if (OB_FAIL(ObTimeConverter::datetime_to_ob_time(value, tz_info, ob_time))) { LOG_WARN("default transform : datetime to ob time failed", K(ret), K(value)); } } } if (OB_SUCC(ret)) { buf = allocator->alloc(sizeof(ObJsonDatetime)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret)); } else { json_node = (ObJsonDatetime *)new(buf)ObJsonDatetime(node_type, ob_time); } } break; } case ObFloatType: case ObDoubleType: case ObUFloatType: case ObUDoubleType: { double val; if (type == ObFloatType || type ==ObUFloatType ) { val = datum.get_float(); } else { val = datum.get_double(); } if (isnan(val)) { buf = allocator->alloc(sizeof(ObJsonString)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret), K(type)); } else { json_node = (ObJsonString *)new(buf)ObJsonString("Nan", 3); } } else if (isinf(val) != 0) { buf = allocator->alloc(sizeof(ObJsonString)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret), K(type)); } else { if (isinf(val) == 1) { json_node = (ObJsonString *)new(buf)ObJsonString("Inf", 3); } else { json_node = (ObJsonString *)new(buf)ObJsonString("-Inf", 4); } } } else { buf = allocator->alloc(sizeof(ObJsonDouble)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret), K(type)); } else { json_node = (ObJsonDouble *)new(buf)ObJsonDouble(val); } } break; } case ObUNumberType: case ObNumberFloatType: case ObNumberType: { // won't waster much memory, do deep copy num number::ObNumber num; buf = allocator->alloc(sizeof(ObJsonDecimal)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret), K(type)); } else if (OB_FAIL(num.deep_copy_v3(datum.get_number(), *allocator))) { LOG_WARN("num deep copy failed", K(ret), K(type)); } else { // shadow copy json_node = (ObJsonDecimal *)new(buf)ObJsonDecimal(num, -1, scale); } break; } case ObHexStringType: { buf = allocator->alloc(sizeof(ObJsonOpaque)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("buf allocate failed", K(ret), K(type)); } else { json_node = (ObJsonOpaque *)new(buf)ObJsonOpaque(datum.get_string(), type); } break; } default: { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(type)); } } if (OB_SUCC(ret)) { if (to_bin) { if (OB_FAIL(ObJsonBaseFactory::transform(allocator, json_node, ObJsonInType::JSON_BIN, j_base))) { LOG_WARN("failed: json tree to bin", K(ret)); } } else { j_base = json_node; } } return ret; } #define PRINT_OB_DATETIME(ob_time, value, j_buf) \ const int64_t tmp_buf_len = DATETIME_MAX_LENGTH + 1; \ char tmp_buf[tmp_buf_len] = {0}; \ int64_t pos = 0; \ const int16_t print_scale = 6; \ if (OB_FAIL(j_buf.append("\""))) { \ LOG_WARN("fail to append \"", K(ret)); \ } else if (OB_FAIL(ObTimeConverter::datetime_to_ob_time(value, tz_info, ob_time))) { \ } else if (OB_FAIL(ObTimeConverter::ob_time_to_str(ob_time, ob_time.mode_, print_scale, \ tmp_buf, tmp_buf_len, pos, true))) { \ LOG_WARN("fail to change time to string", K(ret), K(ob_time), K(pos)); \ } else if (OB_FAIL(j_buf.append(tmp_buf))) { \ LOG_WARN("fail to append date_buf to j_buf", K(ret), KCSTRING(tmp_buf)); \ } else if (OB_FAIL(j_buf.append("\""))) { \ LOG_WARN("fail to append \"", K(ret)); \ } #define PRINT_OB_TIME(ob_time, value, TO_OB_TIME_METHOD, j_buf) \ const int64_t tmp_buf_len = DATETIME_MAX_LENGTH + 1; \ char tmp_buf[tmp_buf_len] = {0}; \ int64_t pos = 0; \ const int16_t print_scale = 6; \ if (OB_FAIL(j_buf.append("\""))) { \ LOG_WARN("fail to append \"", K(ret)); \ } else if (OB_FAIL(ObTimeConverter::TO_OB_TIME_METHOD(value, ob_time))) { \ } else if (OB_FAIL(ObTimeConverter::ob_time_to_str(ob_time, ob_time.mode_, print_scale, \ tmp_buf, tmp_buf_len, pos, true))) { \ LOG_WARN("fail to change time to string", K(ret), K(ob_time), K(pos)); \ } else if (OB_FAIL(j_buf.append(tmp_buf))) { \ LOG_WARN("fail to append date_buf to j_buf", K(ret), KCSTRING(tmp_buf)); \ } else if (OB_FAIL(j_buf.append("\""))) { \ LOG_WARN("fail to append \"", K(ret)); \ } struct ObFindDoubleEscapeFunc { ObFindDoubleEscapeFunc() {} bool operator()(const char c) { return c == '.' || c == 'e'; } }; int ObJsonExprHelper::get_timestamp_str_in_oracle_mode(ObEvalCtx &ctx, const ObDatum &datum, ObObjType type, ObScale scale, const ObTimeZoneInfo *tz_info, ObJsonBuffer &j_buf) { INIT_SUCC(ret); ObOTimestampData in_val; char buf[OB_CAST_TO_VARCHAR_MAX_LENGTH] = {0}; int64_t len = 0; ObBasicSessionInfo *session = ctx.exec_ctx_.get_my_session(); if (OB_ISNULL(session)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else { const ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params(session); if (OB_FAIL(common_construct_otimestamp(type, datum, in_val))) { LOG_WARN("common_construct_otimestamp failed", K(ret)); } else if (OB_FAIL(ObTimeConverter::otimestamp_to_str(in_val, dtc_params, scale, type, buf, OB_CAST_TO_VARCHAR_MAX_LENGTH, len))) { LOG_WARN("failed to convert otimestamp to string", K(ret)); } else { ObString in_str(sizeof(buf), static_cast(len), buf); if (OB_FAIL(j_buf.append("\""))) { LOG_WARN("fail to append \"", K(ret)); } else if (OB_FAIL(j_buf.append(in_str))) { LOG_WARN("fail to append date_buf to j_buf", K(ret), K(in_str)); } else if (OB_FAIL(j_buf.append("\""))) { LOG_WARN("fail to append \"", K(ret)); } } } return ret; } bool ObJsonExprHelper::is_cs_type_bin(ObCollationType &cs_type) { bool res = false; switch(cs_type){ case CS_TYPE_BINARY : { res = true; break; } default : { break; } } return res; } template int ObJsonExprHelper::transform_convertible_2jsonBase(const T &datum, ObObjType type, common::ObIAllocator *allocator, ObCollationType cs_type, ObIJsonBase*& j_base, bool to_bin, bool has_lob_header, bool deep_copy, bool relax_type, bool format_json) { int ret = OB_SUCCESS; void* buf = NULL; ObIJsonBase* json_node = NULL; switch(type) { case ObNullType: { buf = allocator->alloc(sizeof(ObJsonNull)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; } else { json_node = (ObJsonNull*)new(buf)ObJsonNull(); } break; } case ObVarcharType: case ObCharType: case ObTinyTextType: case ObTextType : case ObMediumTextType: case ObLongTextType: { ObString j_str; if (is_mysql_mode() && OB_FAIL(ObJsonExprHelper::ensure_collation(type, cs_type))) { // should check collation first LOG_WARN("Invalid collation type for input string.", K(ret)); } else { j_str = datum.get_string(); if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, type, cs_type, has_lob_header, j_str))) { LOG_WARN("fail to get real data.", K(ret), K(j_str)); } else if (deep_copy) { ret = deep_copy_ob_string(*allocator, j_str, j_str); } } if (OB_SUCC(ret)) { if (format_json) { uint32_t parse_flag = relax_type ? ObJsonParser::JSN_RELAXED_FLAG : ObJsonParser::JSN_STRICT_FLAG; if(OB_FAIL(ObJsonExprHelper::cast_to_json_tree(j_str, allocator, parse_flag))) { LOG_WARN("cast to json tree fail", K(ret)); } else { ObJsonInType to_type = to_bin ? ObJsonInType::JSON_BIN : ObJsonInType::JSON_TREE; if (OB_FAIL(ObJsonBaseFactory::get_json_base(allocator, j_str, ObJsonInType::JSON_TREE, to_type, json_node, parse_flag))) { ret = OB_ERR_INVALID_JSON_TEXT_IN_PARAM; LOG_WARN("fail to get json base", K(ret), K(j_str)); } } } else { uint64_t len = j_str.length(); const char *ptr = j_str.ptr(); buf = allocator->alloc(sizeof(ObJsonString)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; } else { json_node = (ObJsonString*)new(buf)ObJsonString(ptr, len); } } } break; } case ObJsonType: { ObString j_str = datum.get_string(); if (OB_SUCC(ret)) { ObString tmp_str = j_str; if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, type, cs_type, has_lob_header, tmp_str))) { LOG_WARN("fail to get real data.", K(ret), K(j_str)); } else if (deep_copy) { if (OB_FAIL(deep_copy_ob_string(*allocator, tmp_str, j_str))) { LOG_WARN("do deep copy failed", K(ret)); } } else { j_str = tmp_str; } } if (OB_SUCC(ret)) { ObJsonInType to_type = to_bin ? ObJsonInType::JSON_BIN : ObJsonInType::JSON_TREE; uint32_t parse_flag = relax_type ? ObJsonParser::JSN_RELAXED_FLAG : ObJsonParser::JSN_STRICT_FLAG; if (OB_FAIL(ObJsonBaseFactory::get_json_base(allocator, j_str, ObJsonInType::JSON_BIN, to_type, json_node, parse_flag))) { ret = OB_ERR_INVALID_JSON_TEXT_IN_PARAM; LOG_WARN("fail to get json base", K(ret)); } } break; } default: { ret = OB_INVALID_ARGUMENT; LOG_WARN("Invalid argument", K(ret), K(type)); } } if (OB_SUCC(ret)) { if (to_bin) { if (OB_FAIL(ObJsonBaseFactory::transform(allocator, json_node, ObJsonInType::JSON_BIN, j_base))) { LOG_WARN("failed: json tree to bin", K(ret)); } } else { json_node->set_allocator(allocator); j_base = json_node; } } return ret; } int ObJsonExprHelper::get_cast_type(const ObExprResType param_type2, ObExprResType &dst_type) { 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 ¶m = param_type2.get_param(); ParseNode parse_node; ObObjType obj_type; parse_node.value_ = param.get_int(); obj_type = static_cast(parse_node.int16_values_[OB_NODE_CAST_TYPE_IDX]); ObCollationType collation_type = static_cast(parse_node.int16_values_[OB_NODE_CAST_COLL_IDX]); dst_type.set_collation_type(collation_type); 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()); // if (collation_type != CS_TYPE_UTF8MB4_BIN && obj_type == ObLongTextType) { // dst_type.set_collation_type(CS_TYPE_UTF8MB4_BIN); // } } else if (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 ObJsonExprHelper::set_dest_type(ObExprResType &type1, ObExprResType &type, ObExprResType &dst_type, ObExprTypeCtx &type_ctx) { 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 type.set_type(dst_type.get_type()); type.set_collation_type(dst_type.get_collation_type()); int16_t scale = dst_type.get_scale(); if (OB_SUCC(ret)) { 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); type.set_scale(dst_type.get_scale()); } if (OB_SUCC(ret) && ob_is_json(dst_type.get_type())) { type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObJsonType]).get_length()); } } } return ret; } int ObJsonExprHelper::get_dest_type(const ObExpr &expr, int64_t pos, ObEvalCtx& ctx, ObObjType &dest_type, int32_t &dst_len) { INIT_SUCC(ret); ParseNode node; ObDatum *dst_type_dat = NULL; if (OB_ISNULL(expr.args_) || OB_ISNULL(expr.args_[pos])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected expr", K(ret), K(expr.arg_cnt_), KP(expr.args_)); } else if (OB_FAIL(expr.args_[pos]->eval(ctx, dst_type_dat))) { LOG_WARN("eval dst type datum failed", K(ret)); } else { node.value_ = dst_type_dat->get_int(); dest_type = static_cast(node.int16_values_[0]); dst_len = node.int32_values_[OB_NODE_CAST_C_LEN_IDX]; } return ret; } int ObJsonExprHelper::get_cast_string_len(ObExprResType &type1, ObExprResType &type2, common::ObExprTypeCtx &type_ctx, int32_t &res_len, int16_t &length_semantics, common::ObCollationType conn) { 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 ObTextType: case ObLongTextType: case ObVarcharType: case ObCharType: { 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(ObCharset::strlen_byte_no_sp(cast_coll_type, val_str.ptr(), len_byte)); res_len = static_cast(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 ObJsonExprHelper::parse_res_type(ObExprResType& type1, ObExprResType& res_type, ObExprResType& result_type, ObExprTypeCtx& type_ctx) { INIT_SUCC(ret); const int32_t VARCHAR2_DEFAULT_LEN = 4000; ObExprResType dst_type; const ObObj ¶m = res_type.get_param(); if (param.get_int() == 0) { // result_type.set_type(type1.get_type()); // result_type.set_collation_type(type1.get_collation_type()); // result_type.set_accuracy(type1.get_accuracy()); // ObObjType obj_type = type1.get_type(); ObObjType obj_type = ObJsonType; result_type.set_type(ObJsonType); result_type.set_collation_type(CS_TYPE_UTF8MB4_BIN); int16_t length_semantics = (OB_NOT_NULL(type_ctx.get_session()) ? type_ctx.get_session()->get_actual_nls_length_semantics() : LS_BYTE); result_type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObJsonType]).get_length()); result_type.set_collation_level(CS_LEVEL_IMPLICIT); } else if (OB_FAIL(ObJsonExprHelper::get_cast_type(res_type, dst_type))) { LOG_WARN("get cast dest type failed", K(ret)); } else if (OB_FAIL(ObJsonExprHelper::set_dest_type(type1, result_type, dst_type, type_ctx))) { LOG_WARN("set dest type failed", K(ret)); } else { result_type.set_calc_collation_type(result_type.get_collation_type()); } return ret; } int ObJsonExprHelper::eval_and_check_res_type(int64_t value, ObObjType& type, int32_t& dst_len) { INIT_SUCC(ret); ParseNode node; node.value_ = value; ObObjType dst_type = static_cast(node.int16_values_[0]); dst_len = node.int32_values_[OB_NODE_CAST_C_LEN_IDX]; if (dst_type != ObVarcharType && dst_type != ObLongTextType && dst_type != ObJsonType) { ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_USER_ERROR(OB_ERR_INVALID_DATA_TYPE_RETURNING); } else { type = dst_type; } return ret; } // JSON_EXPR_FLAG 0 json value , 1 json query int ObJsonExprHelper::check_item_func_with_return(ObJsonPathNodeType path_type, ObObjType dst_type, common::ObCollationType dst_coll_type, int8_t JSON_EXPR_FLAG) { INIT_SUCC(ret); switch (path_type) { case JPN_ABS :{ break; } case JPN_BOOLEAN : case JPN_BOOL_ONLY :{ if (dst_type == ObVarcharType) { } else { ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_WARN("item func is double, but return type is ", K(dst_type), K(ret)); } break; } case JPN_DATE :{ if (dst_type == ObDateTimeType) { } else { ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_WARN("item func is double, but return type is ", K(dst_type), K(ret)); } break; } case JPN_DOUBLE :{ if (dst_type == ObDoubleType || dst_type == ObUDoubleType) { } else { ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_WARN("item func is double, but return type is ", K(dst_type), K(ret)); } break; } case JPN_FLOOR : case JPN_CEILING : case JPN_LENGTH : case JPN_NUMBER : case JPN_NUM_ONLY : case JPN_SIZE :{ if (JSON_EXPR_FLAG == 1 || (JSON_EXPR_FLAG == 0 && dst_type == ObNumberType)) { } else { ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_WARN("item func is lower/upper, but return type is ", K(dst_type), K(ret)); } break; } case JPN_TIMESTAMP :{ if (dst_type != ObTimestampNanoType && dst_type != ObTimestampType) { ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_WARN("item func is type, but return type is ", K(dst_type), K(ret)); } break; } case JPN_TYPE :{ if (dst_type == ObJsonType && JSON_EXPR_FLAG != 1) { ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_WARN("item func is type, but return type is ", K(dst_type), K(ret)); } } case JPN_STRING : case JPN_STR_ONLY : case JPN_LOWER : case JPN_UPPER :{ if (dst_type == ObVarcharType || (dst_type == ObLongTextType && dst_coll_type != CS_TYPE_BINARY)) { } else { ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_WARN("item func is lower/upper, but return type is ", K(dst_type), K(ret)); } break; } default :{ ret = OB_ERR_UNEXPECTED; LOG_WARN("can't find right path type", K(ret)); } } return ret; } int ObJsonExprHelper::get_expr_option_value(const ObExprResType param_type2, int64_t &dst_type) { 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 { dst_type = param_type2.get_param().get_int(); } return ret; } int ObJsonExprHelper::calc_asciistr_in_expr(const ObString &src, const ObCollationType src_cs_type, const ObCollationType dst_cs_type, char* buf, const int64_t buf_len, int32_t &pos) { int ret = OB_SUCCESS; ObStringScanner scanner(src, src_cs_type); ObString encoding; int32_t wchar = 0; while (OB_SUCC(ret) && scanner.next_character(encoding, wchar, ret)) { if (ob_isascii(wchar) && '\\' != wchar) { int32_t written_bytes = 0; if (OB_FAIL(ObCharset::wc_mb(dst_cs_type, wchar, buf + pos, buf_len - pos, written_bytes))) { LOG_WARN("fail to convert unicode to multi-byte", K(ret), K(wchar)); } else { pos += written_bytes; } } else { const int64_t temp_buf_len = 4; char temp_buf[temp_buf_len]; int32_t temp_written_bytes = 0; if (OB_FAIL(ObCharset::wc_mb(CS_TYPE_UTF16_BIN, wchar, temp_buf, temp_buf_len, temp_written_bytes))) { LOG_WARN("fail to convert unicode to multi-byte", K(ret), K(wchar)); } else { const int utf16_minmb_len = 2; if (OB_UNLIKELY(ObCharset::is_cs_nonascii(dst_cs_type))) { // not support non-ascii database charset for now ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "charset except ascii"); LOG_WARN("not support charset", K(ret), K(dst_cs_type)); } else { for (int i = 0; OB_SUCC(ret) && i < temp_written_bytes/utf16_minmb_len; ++i) { if (OB_UNLIKELY(pos >= buf_len)) { ret = OB_SIZE_OVERFLOW; LOG_WARN("size overflow", K(ret), K(pos), K(buf_len)); } else { buf[pos++] = '\\'; } if (OB_SUCC(ret)) { int64_t hex_writtern_bytes = 0; if (OB_FAIL(hex_print(temp_buf + i*utf16_minmb_len, utf16_minmb_len, buf + pos, buf_len - pos, hex_writtern_bytes))) { LOG_WARN("fail to convert to hex", K(ret), K(temp_written_bytes), K(pos), K(buf_len)); } else { pos += hex_writtern_bytes; } } } } } } } return ret; } int ObJsonExprHelper::parse_asc_option(ObExprResType& asc_type, ObExprResType& type1, ObExprResType& res_type, ObExprTypeCtx& type_ctx) { INIT_SUCC(ret); ObExprResType temp_type; ObObjType doc_type = type1.get_type(); int64_t asc_option = 0; if (asc_type.get_type() != ObIntType) { ret = OB_ERR_UNEXPECTED; LOG_WARN(" param type is unexpected", K(asc_type.get_type())); } else if (OB_FAIL(ObJsonExprHelper::get_expr_option_value(asc_type, asc_option))) { LOG_WARN("get ascii type fail", K(ret)); } else if (asc_option == 1 && ob_is_string_type(doc_type) && ((res_type.is_character_type() && (res_type.get_length_semantics() == LS_CHAR || res_type.get_length_semantics() == LS_BYTE)) || res_type.is_lob())) { type1.set_calc_length_semantics(res_type.get_length_semantics()); ObLength length = 0; ObExprResType temp_type; temp_type.set_meta(type1.get_calc_meta()); temp_type.set_length_semantics(res_type.get_length_semantics()); if (doc_type == ObNCharType) { length = type1.get_param().get_string_len() * ObCharset::MAX_MB_LEN * 2; type1.set_calc_length(length); res_type.set_length(length); } else if (!temp_type.is_blob() && OB_FAIL(ObExprResultTypeUtil::deduce_max_string_length_oracle( type_ctx.get_session()->get_dtc_params(), type1, temp_type, length))) { LOG_WARN("fail to deduce max string length.", K(ret), K(temp_type), K(type1)); } else { type1.set_calc_length(length); res_type.set_length(length * 10); if (res_type.is_lob()) { res_type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType]).get_length()); } } } return ret; } int ObJsonExprHelper::character2_ascii_string(common::ObIAllocator *allocator, const ObExpr &expr, ObEvalCtx &ctx, ObString& result, int32_t reserve_len) { INIT_SUCC(ret); char *buf = NULL; int64_t buf_len = result.length() * ObCharset::MAX_MB_LEN * 2; int32_t length = 0; if ((OB_NOT_NULL(allocator) && OB_ISNULL(buf = static_cast(allocator->alloc(buf_len + reserve_len + 1)))) || (OB_ISNULL(allocator) && OB_ISNULL(buf = static_cast(expr.get_str_res_mem(ctx, buf_len + reserve_len + 1))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate memory", K(ret), K(buf_len), K(result.length())); } else if (OB_FAIL(ObJsonExprHelper::calc_asciistr_in_expr(result, expr.datum_meta_.cs_type_, expr.datum_meta_.cs_type_, buf, buf_len, length))) { LOG_WARN("fail to calc unistr", K(ret)); } else { buf[length] = 0; result.assign_ptr(buf, length); } return ret; } int ObJsonExprHelper::pre_default_value_check(ObObjType dst_type, ObString time_str, ObObjType val_type) { INIT_SUCC(ret); size_t len; switch (dst_type) { case ObTinyTextType: case ObTextType: case ObMediumTextType: case ObLongTextType: case ObVarcharType: case ObCharType: case ObHexStringType: case ObRawType: case ObNVarchar2Type: case ObNCharType: { if (lib::is_oracle_mode() && val_type != ObVarcharType && val_type != ObCharType) { ret = OB_ERR_DEFAULT_VALUE_NOT_MATCH; LOG_WARN("default value not match",K(ret)); } break; } case ObNumberType: { if (val_type == ObNumberType) { } else { len = time_str.length(); for(size_t i = 0; i < len; i++) { if (time_str[i] == '-' || time_str[i] == '+') { } else if (time_str[i] > '9' || time_str[i] < '0') { ret = OB_ERR_INVALID_DEFAULT_VALUE_PROVIDED; LOG_WARN("number check fail"); } } } break; } case ObDateType: case ObTimestampNanoType: case ObTimestampTZType: case ObDateTimeType: case ObTimestampLTZType: { if (val_type != ObCharType) { ret = OB_ERR_INVALID_DEFAULT_VALUE_PROVIDED; } else { len = time_str.length(); if(len >= 5 && time_str[4] != '-') { ret = OB_ERR_INVALID_DEFAULT_VALUE_PROVIDED; } else if(len >= 8 && time_str[7] != '-') { ret = OB_ERR_INVALID_DEFAULT_VALUE_PROVIDED; } } break; } default: break; } return ret; } } }