/** * 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_query. */ #define USING_LOG_PREFIX SQL_ENG #include "ob_expr_json_query.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 "ob_expr_json_value.h" // from sql_parser_base.h #define DEFAULT_STR_LENGTH -1 using namespace oceanbase::common; using namespace oceanbase::sql; namespace oceanbase { namespace sql { #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 ObExprJsonQuery::ObExprJsonQuery(ObIAllocator &alloc) : ObFuncExprOperator(alloc, T_FUN_SYS_JSON_QUERY, N_JSON_QUERY, MORE_THAN_TWO, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) { } ObExprJsonQuery::~ObExprJsonQuery() { } int ObExprJsonQuery::calc_result_typeN(ObExprResType& type, ObExprResType* types_stack, int64_t param_num, ObExprTypeCtx& type_ctx) const { UNUSED(type_ctx); INIT_SUCC(ret); common::ObArenaAllocator allocator; if (OB_UNLIKELY(param_num != 10)) { ret = OB_ERR_PARAM_SIZE; LOG_WARN("invalid param number", K(ret), K(param_num)); } else { bool input_judge_json_type = false; 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_OP; LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(types_stack[0].get_type()), "JSON"); } else if (ob_is_string_type(doc_type)) { if (types_stack[0].get_collation_type() == CS_TYPE_BINARY) { // suport string type with binary charset types_stack[0].set_calc_collation_type(CS_TYPE_BINARY); } 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) { input_judge_json_type = true; // do nothing // types_stack[0].set_calc_type(ObJsonType); // types_stack[0].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN); } 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) { ret = OB_ERR_PATH_EXPRESSION_NOT_LITERAL; LOG_USER_ERROR(OB_ERR_PATH_EXPRESSION_NOT_LITERAL); } 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 判断default ObExprResType dst_type; if (OB_SUCC(ret)) { if (types_stack[2].get_type() == ObNullType) { ObString j_path_text(types_stack[1].get_param().get_string().length(), types_stack[1].get_param().get_string().ptr()); ObJsonPath j_path(j_path_text, &allocator); if (j_path_text.length() == 0) { } else if (OB_FAIL(j_path.parse_path())) { ret = OB_ERR_JSON_PATH_EXPRESSION_SYNTAX_ERROR; LOG_USER_ERROR(OB_ERR_JSON_PATH_EXPRESSION_SYNTAX_ERROR, j_path_text.length(), j_path_text.ptr()); } if (OB_FAIL(ret)) { } else if (input_judge_json_type && !j_path.is_last_func()) { dst_type.set_type(ObObjType::ObJsonType); dst_type.set_collation_type(CS_TYPE_UTF8MB4_BIN); } else { dst_type.set_type(ObObjType::ObVarcharType); dst_type.set_collation_type(CS_TYPE_INVALID); dst_type.set_full_length(4000, 1); } } else if (OB_FAIL(ObJsonExprHelper::get_cast_type(types_stack[2], dst_type))) { LOG_WARN("get cast dest type failed", K(ret)); } if (OB_SUCC(ret)) { if (OB_FAIL(ObJsonExprHelper::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()); } } } // scalars 3, pretty 4, ascii 5, wrapper 6, error 7, empty 8, mismatch 9 for (int64_t i = 3; i < param_num && OB_SUCC(ret); ++i) { if (types_stack[i].get_type() == ObNullType) { ret = OB_ERR_UNEXPECTED; LOG_WARN("param type is unexpected", K(types_stack[i].get_type()), K(i)); } else if (types_stack[i].get_type() != ObIntType) { types_stack[i].set_calc_type(ObIntType); } } // ASCII clause if (OB_SUCC(ret)) { if (OB_FAIL(ObJsonExprHelper::parse_asc_option(types_stack[5], types_stack[0], type, type_ctx))) { LOG_WARN("fail to parse asc option.", K(ret)); } } } return ret; } int ObExprJsonQuery::eval_json_query(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) { INIT_SUCC(ret); ObDatum *json_datum = NULL; ObExpr *json_arg = expr.args_[1]; ObObjType type = json_arg->datum_meta_.type_; bool is_cover_by_error = true; bool is_null_result = false; bool is_null_json_obj = false; bool is_null_json_array = false; uint8_t is_type_cast = 0; int8_t JSON_QUERY_EXPR = 1; ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); ObIJsonBase *j_base = NULL; // parse json path ObJsonPath *j_path = NULL; if (OB_FAIL(get_ora_json_path(expr, ctx, temp_allocator, j_path, 1, is_null_result, is_cover_by_error, json_datum))) { LOG_WARN("get_json_path failed", K(ret)); } // parse pretty ascii scalars uint8_t pretty_type = OB_JSON_PRE_ASC_EMPTY; uint8_t ascii_type = OB_JSON_PRE_ASC_EMPTY; uint8_t scalars_type = OB_JSON_SCALARS_IMPLICIT; if (OB_SUCC(ret) && !is_null_result) { ret = get_clause_pre_asc_sca_opt(expr, ctx, is_cover_by_error, pretty_type, ascii_type, scalars_type); } // parse return node acc ObAccuracy accuracy; ObObjType dst_type; json_arg = expr.args_[0]; type = json_arg->datum_meta_.type_; ObExpr *json_arg_ret = expr.args_[2]; ObObjType val_type = json_arg_ret->datum_meta_.type_; int32_t dst_len = OB_MAX_TEXT_LENGTH; if (OB_SUCC(ret) && val_type == ObNullType) { if (expr.args_[0]->datum_meta_.type_ != ObJsonType && j_path->is_last_func() && OB_FAIL(ObJsonExprHelper::check_item_func_with_return(j_path->get_last_node_type(), ObVarcharType, expr.datum_meta_.cs_type_, JSON_QUERY_EXPR))) { is_cover_by_error = false; LOG_WARN("check item func with return type fail", K(ret)); } } else if (OB_SUCC(ret) && !is_null_result) { ret = get_dest_type(expr, dst_len, ctx, dst_type, is_cover_by_error); } else if (is_cover_by_error) { // when need error option, should do get accuracy get_dest_type(expr, dst_len, ctx, dst_type, is_cover_by_error); } if (OB_SUCC(ret) && val_type != ObNullType && j_path->is_last_func() && OB_FAIL( ObJsonExprHelper::check_item_func_with_return(j_path->get_last_node_type(), dst_type, expr.datum_meta_.cs_type_, JSON_QUERY_EXPR))) { is_cover_by_error = false; LOG_WARN("check item func with return type fail", K(ret)); } if (OB_SUCC(ret) && val_type == ObNullType) { if (ob_is_string_type(type) || j_path->is_last_func()) { dst_type = ObVarcharType; accuracy.set_full_length(4000, 1, lib::is_oracle_mode()); } else { dst_type = ObJsonType; accuracy.set_length(0); } } if (OB_SUCC(ret) && dst_type != ObVarcharType && dst_type != ObLongTextType && dst_type != ObJsonType) { is_cover_by_error = false; ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_USER_ERROR(OB_ERR_INVALID_DATA_TYPE_RETURNING); } if ((expr.datum_meta_.cs_type_ == CS_TYPE_BINARY || dst_type == ObJsonType) && (pretty_type > 0 || ascii_type > 0)) { is_cover_by_error = false; ret = OB_ERR_NON_TEXT_RET_NOTSUPPORT; LOG_WARN("ASCII or PRETTY not supported for non-textual return data type", K(ret)); } // parse json doc if ((OB_SUCC(ret) || is_cover_by_error) && OB_FAIL(get_ora_json_doc(expr, ctx, temp_allocator, 0, j_base, dst_type, is_null_result, is_cover_by_error))) { LOG_WARN("get_json_doc failed", K(ret)); } // parse error option uint8_t error_type = OB_JSON_ON_RESPONSE_IMPLICIT; ObDatum *error_val = NULL; if (OB_SUCC(ret) && !is_null_result) { ret = get_clause_opt(expr, ctx, 7, is_cover_by_error, error_type, OB_JSON_ON_RESPONSE_COUNT); } else if (is_cover_by_error) { // always get error option on error int temp_ret = get_clause_opt(expr, ctx, 7, is_cover_by_error, error_type, OB_JSON_ON_RESPONSE_COUNT); if (temp_ret != OB_SUCCESS) { ret = temp_ret; LOG_WARN("failed to get error option.", K(temp_ret)); } } // parse wrapper uint8_t wrapper_type = OB_WRAPPER_IMPLICIT; if (OB_SUCC(ret)) { ret = get_clause_opt(expr, ctx, 6, is_cover_by_error, wrapper_type, OB_WRAPPER_COUNT); } if (OB_SUCC(ret) && j_path->get_last_node_type() > JPN_BEGIN_FUNC_FLAG && j_path->get_last_node_type() < JPN_END_FUNC_FLAG && (j_path->get_last_node_type() == JPN_NUMBER || j_path->get_last_node_type() == JPN_NUM_ONLY || j_path->get_last_node_type() == JPN_LENGTH || j_path->get_last_node_type() == JPN_TYPE || j_path->get_last_node_type() == JPN_SIZE ) && (wrapper_type == OB_WITHOUT_WRAPPER || wrapper_type == OB_WITHOUT_ARRAY_WRAPPER || wrapper_type == OB_WRAPPER_IMPLICIT)) { is_cover_by_error = false; ret = OB_ERR_WITHOUT_ARR_WRAPPER; // result cannot be returned without array wrapper LOG_WARN("result cannot be returned without array wrapper.", K(ret), K(j_path->get_last_node_type()), K(wrapper_type)); } // mismatch // if mismatch_type == 3 from dot notation uint8_t mismatch_type = OB_JSON_ON_MISMATCH_IMPLICIT; uint8_t mismatch_val = 7; if (OB_SUCC(ret) && !is_null_result) { if (OB_FAIL(get_clause_opt(expr, ctx, 9, is_cover_by_error, mismatch_type, OB_JSON_ON_MISMATCH_COUNT))) { LOG_WARN("failed to get mismatch option.", K(ret), K(mismatch_type)); } } // do seek // chose wrapper int use_wrapper = 0; ObJsonBaseVector hits; if (json_datum == nullptr) { ret = ret = OB_ERR_UNEXPECTED;; LOG_WARN("json path parse fail", K(ret)); } else if (OB_SUCC(ret) && !is_null_result) { if (OB_FAIL(j_base->seek(*j_path, j_path->path_node_cnt(), true, false, hits))) { if (ret == OB_ERR_JSON_PATH_EXPRESSION_SYNTAX_ERROR) { is_cover_by_error = false; } else if (ret == OB_ERR_DOUBLE_TRUNCATED) { ret = OB_ERR_CONVERSION_FAIL; } LOG_WARN("json seek failed", K(json_datum->get_string()), K(ret)); } else if (hits.size() == 1) { if (mismatch_type == OB_JSON_ON_MISMATCH_DOT) { if (hits[0]->json_type() == ObJsonNodeType::J_NULL && hits[0]->is_real_json_null(hits[0]) && dst_type != ObJsonType) { is_null_result = true; } } else { if (OB_FAIL(get_single_obj_wrapper(wrapper_type, use_wrapper, hits[0]->json_type(), scalars_type))) { is_cover_by_error = true; LOG_WARN("error occur in wrapper type"); } else if (use_wrapper == 0 && hits[0]->json_type() == ObJsonNodeType::J_NULL && !hits[0]->is_real_json_null(hits[0])) { is_null_result = true; } else if (use_wrapper == 0 && j_path->is_last_func() && j_path->path_node_cnt() == 1) { // do nothing } else if (use_wrapper == 0 && j_path->get_last_node_type() == JPN_BOOLEAN && (hits[0]->is_json_number(hits[0]->json_type()) || hits[0]->json_type() == ObJsonNodeType::J_NULL)) { is_null_result = true; } else if (use_wrapper == 0 && (j_path->get_last_node_type() == JPN_DATE || j_path->get_last_node_type() == JPN_TIMESTAMP) && !hits[0]->is_json_date(hits[0]->json_type())) { is_null_result = true; } else if (use_wrapper == 0 && j_path->get_last_node_type() == JPN_DOUBLE && !hits[0]->is_json_number(hits[0]->json_type()) && hits[0]->json_type() != ObJsonNodeType::J_NULL) { is_null_result = true; } else if (use_wrapper == 0 && (j_path->get_last_node_type() == JPN_STRING || j_path->get_last_node_type() == JPN_STR_ONLY) && (hits[0]->json_type() == ObJsonNodeType::J_OBJECT || hits[0]->json_type() == ObJsonNodeType::J_ARRAY)) { is_null_result = true; } else if (use_wrapper == 0 && (j_path->get_last_node_type() == JPN_UPPER || j_path->get_last_node_type() == JPN_LOWER) && (hits[0]->json_type() == ObJsonNodeType::J_OBJECT || hits[0]->json_type() == ObJsonNodeType::J_ARRAY)) { is_null_result = true; } else if (use_wrapper == 0 && (j_path->get_last_node_type() == JPN_NUMBER || j_path->get_last_node_type() == JPN_NUM_ONLY || j_path->get_last_node_type() == JPN_DOUBLE) && (!hits[0]->is_json_number(hits[0]->json_type()) && hits[0]->json_type() != ObJsonNodeType::J_NULL)) { is_null_result = true; } else if (use_wrapper == 0 && j_path->get_last_node_type() == JPN_LENGTH && !(hits[0]->json_type() == ObJsonNodeType::J_UINT && ((ObJsonUint *)hits[0])->get_is_string_length())) { is_null_result = true; } else if (use_wrapper == 0 && (j_path->get_last_node_type() == JPN_DATE || j_path->get_last_node_type() == JPN_TIMESTAMP) && !hits[0]->is_json_date(hits[0]->json_type())) { is_null_result = true; } } } else if (hits.size() == 0) { // parse empty option uint8_t empty_type = OB_JSON_ON_RESPONSE_IMPLICIT; if (OB_SUCC(ret) && !is_null_result) { ret = get_clause_opt(expr, ctx, 8, is_cover_by_error, empty_type, OB_JSON_ON_RESPONSE_COUNT); } if (OB_SUCC(ret) && OB_FAIL(get_empty_option(hits, is_cover_by_error, empty_type, is_null_result, is_null_json_obj, is_null_json_array))) { LOG_WARN("get empty type", K(ret)); } } else if (hits.size() > 1) { // return val decide by wrapper option if (OB_FAIL(get_multi_scalars_wrapper_type(wrapper_type, use_wrapper, hits, scalars_type))) { is_cover_by_error = true; LOG_WARN("error occur in wrapper type"); } } } // fill output if (OB_UNLIKELY(OB_FAIL(ret))) { if (is_cover_by_error) { if (!try_set_error_val(&temp_allocator, ctx, expr, res, ret, error_type, mismatch_type, dst_type)) { LOG_WARN("set error val fail", K(ret)); } } LOG_WARN("json_query failed", K(ret)); } else if (is_null_result) { res.set_null(); } else if (mismatch_type == OB_JSON_ON_MISMATCH_DOT && hits.size() == 1 && dst_type != ObJsonType) { ObVector mismatch_val_tmp; ObVector mismatch_type_tmp; //OB_JSON_TYPE_IMPLICIT ObCollationType in_coll_type = expr.args_[0]->datum_meta_.cs_type_; ObCollationType dst_coll_type = expr.datum_meta_.cs_type_; ret = ObExprJsonValue::cast_to_res(&temp_allocator, expr, ctx, hits[0], OB_JSON_ON_RESPONSE_NULL, error_val, accuracy, dst_type, in_coll_type, dst_coll_type, res, mismatch_val_tmp, mismatch_type_tmp, is_type_cast, ascii_type); } else { if (is_null_json_obj) { ObJsonObject j_node_null(&temp_allocator); ObIJsonBase *jb_res = NULL; jb_res = &j_node_null; if (OB_FAIL(set_result(dst_type, dst_len, jb_res, &temp_allocator, ctx, expr, res, error_type, ascii_type, pretty_type))) { LOG_WARN("result set fail", K(ret)); } } else if (use_wrapper == 1 || is_null_json_array) { int32_t hit_size = hits.size(); ObJsonArray j_arr_res(&temp_allocator); ObIJsonBase *jb_res = NULL; ObJsonNode *j_node = NULL; ObIJsonBase *jb_node = NULL; jb_res = &j_arr_res; if (is_null_json_array) { } else { for (int32_t i = 0; OB_SUCC(ret) && i < hit_size; i++) { bool is_null_res = false; if (hits[i]->json_type() == ObJsonNodeType::J_NULL && !(hits[i]->is_real_json_null(hits[i]))) { is_null_res = true; } else if (j_path->get_last_node_type() == JPN_BOOLEAN && (hits[i]->is_json_number(hits[i]->json_type()) || hits[i]->json_type() == ObJsonNodeType::J_NULL)) { is_null_res = true; } else if (j_path->get_last_node_type() == JPN_LENGTH && !(hits[i]->json_type() == ObJsonNodeType::J_UINT && ((ObJsonUint *)hits[i])->get_is_string_length())) { is_null_res = true; } else if ((j_path->get_last_node_type() == JPN_STRING || j_path->get_last_node_type() == JPN_STR_ONLY) && (hits[i]->json_type() == ObJsonNodeType::J_OBJECT || hits[i]->json_type() == ObJsonNodeType::J_ARRAY)) { is_null_res = true; } else if ((j_path->get_last_node_type() == JPN_UPPER || j_path->get_last_node_type() == JPN_LOWER) && (hits[i]->json_type() == ObJsonNodeType::J_OBJECT || hits[i]->json_type() == ObJsonNodeType::J_ARRAY)) { is_null_res = true; } else if ((j_path->get_last_node_type() == JPN_DATE || j_path->get_last_node_type() == JPN_TIMESTAMP) && !hits[i]->is_json_date(hits[i]->json_type())) { is_null_res = true; } else if ((j_path->get_last_node_type() == JPN_NUMBER || j_path->get_last_node_type() == JPN_NUM_ONLY || j_path->get_last_node_type() == JPN_DOUBLE ) && !hits[i]->is_json_number(hits[i]->json_type()) && hits[i]->json_type() != ObJsonNodeType::J_NULL) { is_null_res = true; } else if ((hits[i]->json_type() == ObJsonNodeType::J_OBJECT || hits[i]->json_type() == ObJsonNodeType::J_ARRAY) && j_path->is_last_func() && j_path->path_node_cnt() == 1) { // do nothing } if (is_null_res) { void* buf = NULL; buf = temp_allocator.alloc(sizeof(ObJsonNull)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; } else { jb_node = (ObJsonNull*)new(buf)ObJsonNull(true); } } else if (OB_FAIL(ObJsonBaseFactory::transform(&temp_allocator, hits[i], ObJsonInType::JSON_TREE, jb_node))) { // to tree LOG_WARN("fail to transform to tree", K(ret), K(i), K(*(hits[i]))); } if (OB_SUCC(ret)) { j_node = static_cast(jb_node); if (OB_ISNULL(j_node)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("json node input is null", K(ret), K(i), K(is_null_res), K(hits[i])); } else if (OB_FAIL(jb_res->array_append(j_node->clone(&temp_allocator)))) { LOG_WARN("result array append failed", K(ret), K(i), K(*j_node)); } } } } if (!is_null_json_array && try_set_error_val(&temp_allocator, ctx, expr, res, ret, error_type, mismatch_type, dst_type)) { } else if (OB_FAIL(set_result(dst_type,dst_len, jb_res, &temp_allocator, ctx, expr, res, error_type, ascii_type, pretty_type))) { LOG_WARN("result set fail", K(ret)); } } else { ret = set_result(dst_type, dst_len, hits[0], &temp_allocator, ctx, expr, res, error_type, ascii_type, pretty_type); } } return ret; } int ObExprJsonQuery::set_result(ObObjType dst_type, int32_t dst_len, ObIJsonBase *jb_res, common::ObIAllocator *allocator, ObEvalCtx &ctx, const ObExpr &expr, ObDatum &res, uint8_t error_type, uint8_t ascii_type, uint8_t pretty_type) { INIT_SUCC(ret); if (dst_type == ObVarcharType || dst_type == ObLongTextType) { ObJsonBuffer jbuf(allocator); ObString res_string; if (OB_FAIL(jb_res->print(jbuf, true, pretty_type > 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 { res_string.assign_ptr(jbuf.ptr(), jbuf.length()); } if (OB_SUCC(ret)) { uint64_t length = res_string.length(); if (dst_type == ObVarcharType && length > dst_len) { char res_ptr[OB_MAX_DECIMAL_PRECISION] = {0}; if (OB_ISNULL(ObCharset::lltostr(dst_len, res_ptr, 10, 1))) { LOG_WARN("dst_len fail to string.", K(ret)); } ret = OB_OPERATE_OVERFLOW; LOG_USER_ERROR(OB_OPERATE_OVERFLOW, res_ptr, "json_query"); if (!try_set_error_val(allocator, ctx, expr, res, ret, error_type, OB_JSON_ON_MISMATCH_IMPLICIT, dst_type)) { LOG_WARN("set error val fail", K(ret)); } } else { ObTextStringDatumResult text_result(expr.datum_meta_.type_, &expr, &ctx, &res); if (ascii_type == 0) { if (OB_FAIL(text_result.init(res_string.length()))) { LOG_WARN("init lob result failed"); } else if (OB_FAIL(text_result.append(res_string))) { LOG_WARN("failed to append realdata", K(ret), K(res_string), K(text_result)); } } else { char *buf = NULL; int64_t buf_len = res_string.length() * ObCharset::MAX_MB_LEN * 2; int32_t length = 0; int64_t reserve_len = 0; if (OB_FAIL(text_result.init(buf_len))) { LOG_WARN("init lob result failed"); } else if (OB_FAIL(text_result.get_reserved_buffer(buf, reserve_len))) { LOG_WARN("fail to get reserved buffer", K(ret)); } else if (reserve_len != buf_len) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get reserve len is invalid", K(ret), K(reserve_len), K(buf_len)); } else if (OB_FAIL(ObJsonExprHelper::calc_asciistr_in_expr(res_string, expr.args_[0]->datum_meta_.cs_type_, expr.datum_meta_.cs_type_, buf, buf_len, length))) { LOG_WARN("fail to calc unistr", K(ret)); } else if (OB_FAIL(text_result.lseek(length, 0))) { LOG_WARN("text_result lseek failed", K(ret), K(text_result), K(length)); } } if (OB_SUCC(ret)) { text_result.set_result(); } } } } else if (ob_is_json(dst_type)) { ObString raw_str; ObIJsonBase *jb_res_bin = NULL; if (OB_FAIL(ret)) { LOG_WARN("json extarct get results failed", K(ret)); } else if (ObJsonBaseFactory::transform(allocator, jb_res, ObJsonInType::JSON_BIN, jb_res_bin)) { // to BIN LOG_WARN("fail to transform to tree", K(ret)); } else if (OB_FAIL(jb_res_bin->get_raw_binary(raw_str, allocator))) { LOG_WARN("json extarct get result binary failed", K(ret)); } else if (OB_FAIL(ObJsonExprHelper::pack_json_str_res(expr, ctx, res, raw_str))) { LOG_WARN("fail to pack json result", K(ret)); } } else { ret = OB_ERR_INVALID_DATA_TYPE_RETURNING; LOG_USER_ERROR(OB_ERR_INVALID_DATA_TYPE_RETURNING); } return ret; } int ObExprJsonQuery::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_query; return OB_SUCCESS; } int ObExprJsonQuery::get_clause_pre_asc_sca_opt(const ObExpr &expr, ObEvalCtx &ctx, bool &is_cover_by_error, uint8_t &pretty_type, uint8_t &ascii_type, uint8_t &scalars_type) { INIT_SUCC(ret); // parse pretty if (OB_SUCC(ret)) { ret = get_clause_opt(expr, ctx, 4, is_cover_by_error, pretty_type, OB_JSON_PRE_ASC_COUNT); } // parse ascii if (OB_SUCC(ret)) { ret = get_clause_opt(expr, ctx, 5, is_cover_by_error, ascii_type, OB_JSON_PRE_ASC_COUNT); } // parse scalars if (OB_SUCC(ret)) { ret = get_clause_opt(expr, ctx, 3, is_cover_by_error, scalars_type, OB_JSON_SCALARS_COUNT); } return ret; } int ObExprJsonQuery::get_ora_json_path(const ObExpr &expr, ObEvalCtx &ctx, common::ObArenaAllocator &allocator, ObJsonPath*& j_path, uint16_t index, bool &is_null, bool &is_cover_by_error, ObDatum*& json_datum) { INIT_SUCC(ret); ObExpr *json_arg = expr.args_[index]; ObObjType type = json_arg->datum_meta_.type_; if (OB_SUCC(ret) && !is_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 (type == ObNullType || json_datum->is_null()) { is_null = true; } else if (!ob_is_string_type(type)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("input type error", K(type)); } ObString j_path_text = json_datum->get_string(); if (OB_FAIL(ObJsonExprHelper::get_json_or_str_data(json_arg, ctx, allocator, j_path_text, is_null))) { LOG_WARN("fail to get real data.", K(ret), K(j_path_text)); } else if (j_path_text.length() == 0) { is_null = true; } ObJsonPathCache ctx_cache(&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; ret = OB_ERR_JSON_PATH_EXPRESSION_SYNTAX_ERROR; LOG_USER_ERROR(OB_ERR_JSON_PATH_EXPRESSION_SYNTAX_ERROR, j_path_text.length(), j_path_text.ptr()); } } return ret; } int ObExprJsonQuery::get_ora_json_doc(const ObExpr &expr, ObEvalCtx &ctx, common::ObArenaAllocator &allocator, uint16_t index, ObIJsonBase*& j_base, ObObjType dst_type, bool &is_null, bool &is_cover_by_error) { INIT_SUCC(ret); ObDatum *json_datum = NULL; ObExpr *json_arg = expr.args_[index]; ObObjType type = json_arg->datum_meta_.type_; ObCollationType cs_type = json_arg->datum_meta_.cs_type_; ObJsonInType j_in_type; if (OB_SUCC(ret) && 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 = true; } else if (type != ObJsonType && !ob_is_string_type(type)) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(dst_type), ob_obj_type_str(type)); } else { ObString j_str = json_datum->get_string(); j_in_type = ObJsonExprHelper::get_json_internal_type(type); uint32_t parse_flag = ObJsonParser::JSN_RELAXED_FLAG; if (OB_FAIL(ObJsonExprHelper::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 (j_str.length() == 0) { // maybe input json doc is null type is_null = true; } else if (OB_FAIL(ObJsonBaseFactory::get_json_base(&allocator, j_str, j_in_type, j_in_type, j_base, parse_flag))) { 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; } ret = OB_ERR_JSON_SYNTAX_ERROR; } } return ret; } int ObExprJsonQuery::get_empty_option(ObJsonBaseVector &hits, bool &is_cover_by_error, int8_t empty_type, bool &is_null_result, bool &is_null_json_obj, bool &is_null_json_array) { INIT_SUCC(ret); switch (empty_type) { case OB_JSON_ON_RESPONSE_IMPLICIT: { ret = OB_ERR_JSON_VALUE_NO_VALUE; LOG_USER_ERROR(OB_ERR_JSON_VALUE_NO_VALUE); LOG_WARN("json value seek result empty.", K(hits.size())); break; } case OB_JSON_ON_RESPONSE_ERROR: { is_cover_by_error = false; ret = OB_ERR_JSON_VALUE_NO_VALUE; LOG_USER_ERROR(OB_ERR_JSON_VALUE_NO_VALUE); LOG_WARN("json value seek result empty.", K(hits.size())); break; } case OB_JSON_ON_RESPONSE_EMPTY_OBJECT: { is_null_json_obj = true; break; } case OB_JSON_ON_RESPONSE_NULL: { is_null_result = true; break; } case OB_JSON_ON_RESPONSE_EMPTY: case OB_JSON_ON_RESPONSE_EMPTY_ARRAY: { is_null_json_array = true; // set_json_array break; } default: // empty_type from get_on_empty_or_error has done range check, do nothing for default break; } return ret; } int ObExprJsonQuery::get_single_obj_wrapper(uint8_t wrapper_type, int &use_wrapper, ObJsonNodeType in_type, uint8_t scalars_type) { INIT_SUCC(ret); switch (wrapper_type) { case OB_WITHOUT_WRAPPER: case OB_WITHOUT_ARRAY_WRAPPER: case OB_WRAPPER_IMPLICIT: { if ((in_type != ObJsonNodeType::J_OBJECT && in_type != ObJsonNodeType::J_ARRAY && scalars_type == OB_JSON_SCALARS_DISALLOW)) { ret = OB_ERR_WITHOUT_ARR_WRAPPER; // result cannot be returned without array wrapper LOG_USER_ERROR(OB_ERR_WITHOUT_ARR_WRAPPER); LOG_WARN("result cannot be returned without array wrapper.", K(ret)); } break; } case OB_WITH_WRAPPER: case OB_WITH_ARRAY_WRAPPER: case OB_WITH_UNCONDITIONAL_WRAPPER: case OB_WITH_UNCONDITIONAL_ARRAY_WRAPPER: { use_wrapper = 1; break; } case OB_WITH_CONDITIONAL_WRAPPER: case OB_WITH_CONDITIONAL_ARRAY_WRAPPER: { if (in_type != ObJsonNodeType::J_OBJECT && in_type != ObJsonNodeType::J_ARRAY && scalars_type == OB_JSON_SCALARS_DISALLOW ) { use_wrapper = 1; } break; } default: // error_type from get_on_empty_or_error has done range check, do nothing for default break; } return ret; } int ObExprJsonQuery::get_multi_scalars_wrapper_type(uint8_t wrapper_type, int &use_wrapper, ObJsonBaseVector &hits, uint8_t scalars_type) { INIT_SUCC(ret); switch (wrapper_type) { case OB_WITHOUT_WRAPPER: case OB_WITHOUT_ARRAY_WRAPPER: case OB_WRAPPER_IMPLICIT: { ret = OB_ERR_WITHOUT_ARR_WRAPPER; // result cannot be returned without array wrapper LOG_USER_ERROR(OB_ERR_WITHOUT_ARR_WRAPPER); LOG_WARN("result cannot be returned without array wrapper.", K(ret), K(hits.size())); break; } case OB_WITH_WRAPPER: case OB_WITH_ARRAY_WRAPPER: case OB_WITH_UNCONDITIONAL_WRAPPER: case OB_WITH_UNCONDITIONAL_ARRAY_WRAPPER: { use_wrapper = 1; break; } case OB_WITH_CONDITIONAL_WRAPPER: case OB_WITH_CONDITIONAL_ARRAY_WRAPPER: { use_wrapper = 1; break; } default: // error_type from get_on_empty_or_error has done range check, do nothing for default break; } return ret; } bool ObExprJsonQuery::try_set_error_val(common::ObIAllocator *allocator, ObEvalCtx &ctx, const ObExpr &expr, ObDatum &res, int &ret, uint8_t error_type, uint8_t mismatch_type, ObObjType dst_type) { bool has_set_res = true; bool mismatch_error = true; if (OB_FAIL(ret)) { if (error_type == OB_JSON_ON_RESPONSE_EMPTY_ARRAY || error_type == OB_JSON_ON_RESPONSE_EMPTY) { ret = OB_SUCCESS; ObJsonArray j_arr_res(allocator); ObIJsonBase *jb_res = NULL; jb_res = &j_arr_res; if (OB_FAIL(set_result(dst_type, OB_MAX_TEXT_LENGTH, jb_res, allocator, ctx, expr, res, error_type, 0))) { LOG_WARN("result set fail", K(ret)); } } else if (error_type == OB_JSON_ON_RESPONSE_EMPTY_OBJECT) { ret = OB_SUCCESS; ObJsonObject j_node_null(allocator); ObIJsonBase *jb_res = NULL; jb_res = &j_node_null; if (OB_FAIL(set_result(dst_type, OB_MAX_TEXT_LENGTH, jb_res, allocator, ctx, expr, res, error_type, 0))) { LOG_WARN("result set fail", K(ret)); } } 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 ObExprJsonQuery::get_clause_opt(const ObExpr &expr, ObEvalCtx &ctx, uint8_t index, bool &is_cover_by_error, uint8_t &type, uint8_t size_para) { 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 < 0 || option_type >= size_para) { ret = OB_ERR_UNEXPECTED; LOG_WARN("input option type error", K(option_type)); } else { type = static_cast(option_type); } } return ret; } int ObExprJsonQuery::get_dest_type(const ObExpr &expr, int32_t &dst_len, ObEvalCtx& ctx, ObObjType &dest_type, bool &is_cover_by_error) { INIT_SUCC(ret); ParseNode node; 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 { 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; } } // sql } // oceanbase