Files
oceanbase/src/sql/engine/expr/ob_expr_json_query.cpp
2023-04-27 11:11:24 +00:00

842 lines
35 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_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<uint8_t> mismatch_val_tmp;
ObVector<uint8_t> 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<ObJsonNode *>(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<uint8_t>(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<ObObjType>(node.int16_values_[0]);
dst_len = node.int32_values_[OB_NODE_CAST_C_LEN_IDX];
}
return ret;
}
} // sql
} // oceanbase