oracle json construct function refaction && oracle json expr option clause syntax support

This commit is contained in:
obdev
2023-08-02 06:54:16 +00:00
committed by ob-robot
parent 755b53ef5e
commit 90def6ad4a
16 changed files with 478 additions and 367 deletions

View File

@ -100,7 +100,14 @@ int ObExprJsonArray::calc_result_typeN(ObExprResType& type,
// returning type : 2
if (OB_SUCC(ret)) {
ObExprResType dst_type;
if (OB_FAIL(ObJsonExprHelper::get_cast_type(types_stack[param_num - 2], dst_type))) {
dst_type.set_type(ObJsonType);
dst_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);
dst_type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObJsonType]).get_length());
dst_type.set_collation_level(CS_LEVEL_IMPLICIT);
if (ele_idx > 0 && OB_FAIL(ObJsonExprHelper::parse_res_type(types_stack[0], types_stack[param_num - 2], dst_type, type_ctx))) {
LOG_WARN("get cast dest type failed", K(ret));
} else if (OB_FAIL(ObJsonExprHelper::set_dest_type(types_stack[0], type, dst_type, type_ctx))) {
LOG_WARN("set dest type failed", K(ret));
@ -157,15 +164,17 @@ int ObExprJsonArray::eval_ora_json_array(const ObExpr &expr, ObEvalCtx &ctx, ObD
ObObjType dst_type;
int32_t dst_len = OB_MAX_TEXT_LENGTH;
int64_t& opt_res_type = opt_array[OPT_TYPE_ID];
if (OB_SUCC(ret) && OB_FAIL(ObJsonExprHelper::eval_and_check_res_type(opt_res_type, dst_type, dst_len))) {
if (OB_FAIL(ret)) {
} else if (opt_res_type == 0) {
dst_type = ObJsonType;
} else if (OB_FAIL(ObJsonExprHelper::eval_and_check_res_type(opt_res_type, dst_type, dst_len))) {
LOG_WARN("fail to check returning type", K(ret));
}
int64_t& opt_null = opt_array[OPT_NULL_ID];
ObJsonBuffer jsn_buf(&temp_allocator);
if (OB_SUCC(ret) && OB_FAIL(jsn_buf.append("["))) {
LOG_WARN("fail to append curly brace", K(ret));
}
bool is_strict = (opt_strict > 0 || (dst_type == ObJsonType && opt_res_type > 0));
bool is_null_absent = opt_null > 0 ;
ObJsonArray j_arr(&temp_allocator);
for (uint32_t i = 0; OB_SUCC(ret) && i < max_val_idx; i += 2) {
// [expr][format-json]: i -> expr, i + i -> format json
@ -173,6 +182,7 @@ int ObExprJsonArray::eval_ora_json_array(const ObExpr &expr, ObEvalCtx &ctx, ObD
ObExpr *opt_expr = expr.args_[i + 1];
ObObjType val_type = opt_expr->datum_meta_.type_;
bool is_format_json = false;
ObIJsonBase* j_val = nullptr;
if (OB_UNLIKELY(OB_FAIL(opt_expr->eval(ctx, opt_format)))) {
LOG_WARN("eval json arg failed", K(ret));
} else if (val_type == ObNullType || opt_format->is_null()) {
@ -183,89 +193,33 @@ int ObExprJsonArray::eval_ora_json_array(const ObExpr &expr, ObEvalCtx &ctx, ObD
is_format_json = (opt_format->get_int() > 0);
}
ObExpr *val_expr = expr.args_[i];
val_type = val_expr->datum_meta_.type_;
ObCollationType cs_type = val_expr->datum_meta_.cs_type_;
ObScale scale = val_expr->datum_meta_.scale_;
ObDatum* j_datum = nullptr;
bool can_only_be_null = false;
if (OB_SUCC(ret) && is_format_json
&& (!ObJsonExprHelper::is_convertible_to_json(val_type) || val_type == ObJsonType)) {
if (val_type == ObObjType::ObNumberType) {
can_only_be_null = true;
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "CHAR", ob_obj_type_str(val_type));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(val_expr->eval(ctx, j_datum))) {
LOG_WARN("eval json arg failed", K(ret), K(val_type));
} else if (can_only_be_null && !j_datum->is_null()) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "CHAR", ob_obj_type_str(val_type));
} else if (j_datum->is_null()) {
if (opt_null == 0) {
if (OB_FAIL(jsn_buf.append("null"))) {
LOG_WARN("failed to append null", K(ret));
}
} else {
continue;
}
} else if (ObJsonExprHelper::is_convertible_to_json(val_type) || ob_is_raw(val_type)) {
if (OB_FAIL(ObJsonExprHelper::transform_convertible_2String(*val_expr, ctx, *j_datum,
val_type,
cs_type,
jsn_buf,
val_expr->obj_meta_.has_lob_header(),
is_format_json,
opt_strict == 1, i))) {
LOG_WARN("failed to transform to string", K(ret), K(val_type));
}
} else if (OB_FAIL(ObJsonExprHelper::transform_scalar_2String(ctx, *j_datum,
val_type,
scale,
ctx.exec_ctx_.get_my_session()->get_timezone_info(),
jsn_buf))) {
LOG_WARN("fail to parse value to json base.", K(ret), K(val_type));
} else if (OB_FAIL(ObJsonExprHelper::eval_oracle_json_val(
expr.args_[i], ctx, &temp_allocator, j_val, is_format_json, is_strict, false))) {
LOG_WARN("failed to get json value node.", K(ret), K(val_type));
} else if (is_null_absent && j_val->json_type() == ObJsonNodeType::J_NULL) {
} else if (OB_FAIL(j_arr.append(static_cast<ObJsonNode*>(j_val)))) {
LOG_WARN("failed to append in array.", K(ret), K(i));
}
if (OB_SUCC(ret) && i + 2 < max_val_idx && OB_FAIL(jsn_buf.append(","))) {
LOG_WARN("failed to append comma", K(ret));
}
}
// 添加右括号前删除多余的','
if (OB_SUCC(ret) && jsn_buf.back() == ',') {
jsn_buf.set_length(jsn_buf.length() - 1);
}
if (OB_SUCC(ret) && jsn_buf.append("]")) {
LOG_WARN("failed to append brace", K(ret), K(jsn_buf.length()));
}
if (OB_SUCC(ret)) {
ObString j_string;
j_string.assign_ptr(jsn_buf.ptr(), jsn_buf.length());
ObJsonBuffer string_buffer(&temp_allocator);
ObString res_string;
ObJsonNode* j_base = nullptr;
uint32_t parse_flag = ObJsonParser::JSN_STRICT_FLAG;
ADD_FLAG_IF_NEED(opt_strict != 1, parse_flag, ObJsonParser::JSN_RELAXED_FLAG);
if (dst_type == ObJsonType &&
OB_FAIL(ObJsonParser::get_tree(&temp_allocator,
j_string,
j_base,
parse_flag))) {
LOG_WARN("fail to get json tree.", K(ret));
} else if (dst_type == ObJsonType) {
if (OB_FAIL(j_base->get_raw_binary(res_string, &temp_allocator))) {
if (dst_type == ObJsonType) {
if (OB_FAIL(j_arr.get_raw_binary(res_string, &temp_allocator))) {
LOG_WARN("failed: get json raw binary", K(ret));
}
} else {
res_string.assign_ptr(j_string.ptr(), j_string.length());
if (OB_FAIL(string_buffer.reserve(j_arr.get_serialize_size()))) {
LOG_WARN("fail to reserve string.", K(ret), K(j_arr.get_serialize_size()));
} else if (OB_FAIL(j_arr.print(string_buffer, true, false))) {
LOG_WARN("failed: get json string text", K(ret));
} else {
res_string.assign_ptr(string_buffer.ptr(), string_buffer.length());
}
}
if (OB_SUCC(ret)) {
@ -276,7 +230,7 @@ int ObExprJsonArray::eval_ora_json_array(const ObExpr &expr, ObEvalCtx &ctx, ObD
LOG_WARN("dst_len fail to string.", K(ret));
}
ret = OB_OPERATE_OVERFLOW;
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, res_ptr, "json_array");
LOG_USER_ERROR(OB_OPERATE_OVERFLOW, res_ptr, N_JSON_ARRAY);
} else if (OB_FAIL(ObJsonExprHelper::pack_json_str_res(expr, ctx, res, res_string))) {
LOG_WARN("fail to pack ressult.", K(ret));
}

View File

@ -29,6 +29,46 @@ 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 <typename T>
int get_otimestamp_from_datum(const T &datum, ObOTimestampData &in_val, ObObjType type);
template <>
int get_otimestamp_from_datum<ObDatum>(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<ObObj>(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;
@ -118,6 +158,7 @@ int ObJsonExprHelper::get_json_doc(const ObExpr &expr, ObEvalCtx &ctx,
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)
@ -268,6 +309,195 @@ int ObJsonExprHelper::get_json_val(const ObExpr &expr, ObEvalCtx &ctx,
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;
ObObjType val_type = json_arg->datum_meta_.type_;
ObCollationType cs_type = json_arg->datum_meta_.cs_type_;
bool is_nchar = (val_type == ObNCharType || val_type == ObNVarchar2Type);
bool is_raw_type = val_type == ObRawType;
if (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() || 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 (json_arg->is_boolean_ == 1) {
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 = is_strict ? ObJsonParser::JSN_STRICT_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, json_arg->obj_meta_.has_lob_header(), j_str))) {
LOG_WARN("fail to get real data.", K(ret), K(j_str));
} else if (!is_format_json || is_nchar || is_raw_type) {
if (is_raw_type) {
ObObj tmp_result;
ObObj obj;
ObCastCtx cast_ctx(allocator, NULL, CM_NONE, CS_TYPE_INVALID);
if (OB_FAIL(json_datum->to_obj(obj, expr->obj_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(expr->obj_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, json_arg->obj_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 {
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 (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<char*>(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<char*>(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 = json_arg->datum_meta_.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)
{
@ -451,46 +681,6 @@ int ObJsonExprHelper::is_json_zero(const ObString& data, int& result)
return ret;
}
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 <typename T>
int get_otimestamp_from_datum(const T &datum, ObOTimestampData &in_val, ObObjType type);
template <>
int get_otimestamp_from_datum<ObDatum>(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<ObObj>(const ObObj &datum, ObOTimestampData &in_val, ObObjType type)
{
INIT_SUCC(ret);
in_val = datum.get_otimestamp_value();
return ret;
}
template <typename T>
int ObJsonExprHelper::transform_scalar_2jsonBase(const T &datum,
ObObjType type,
@ -1511,17 +1701,6 @@ int ObJsonExprHelper::parse_res_type(ObExprResType& type1,
result_type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObJsonType]).get_length());
result_type.set_collation_level(CS_LEVEL_IMPLICIT);
if (obj_type == ObVarcharType) {
result_type.set_full_length(VARCHAR2_DEFAULT_LEN, length_semantics);
} else if (obj_type == ObJsonType) {
result_type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObJsonType]).get_length());
} else if (obj_type == ObLongTextType && type1.get_collation_type() == CS_TYPE_BINARY) {
result_type.set_collation_type(CS_TYPE_UTF8MB4_BIN);
}
if (ob_is_string_type(type1.get_type()) || ob_is_json(type1.get_type())) {
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))) {

View File

@ -93,6 +93,9 @@ public:
static int get_json_val(const common::ObObj &data, ObExprCtx &ctx,
bool is_bool, common::ObIAllocator *allocator,
ObIJsonBase*& j_base, bool to_bin = false);
static int eval_oracle_json_val(ObExpr *expr, ObEvalCtx &ctx, common::ObIAllocator *allocator,
ObIJsonBase*& j_base, bool format_json = false, bool is_strict = false, bool is_bin = false);
/*
replace json_old with json_new in json_doc

View File

@ -248,9 +248,10 @@ int ObExprJsonMergePatch::eval_ora_json_merge_patch(const ObExpr &expr, ObEvalCt
if ((!is_cover_error && OB_FAIL(ret)) || has_null) {
// do nothing
} else if ((tmp_ret = ObJsonExprHelper::get_json_doc(expr, ctx, temp_allocator, 1, j_patch_node, has_null, true, false)) != OB_SUCCESS) {
ret = tmp_ret;
is_cover_error = false;
if (tmp_ret == OB_ERR_JSON_SYNTAX_ERROR) {
ret = OB_ERR_JSON_PATCH_INVALID;
is_cover_error = false;
}
LOG_WARN("get_json_doc failed", K(ret));
} else if (has_null) {

View File

@ -248,184 +248,107 @@ int ObExprJsonObject::eval_ora_json_object(const ObExpr &expr, ObEvalCtx &ctx, O
INIT_SUCC(ret);
ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx);
common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator();
ObJsonBuffer res_str(&temp_allocator);
ObJsonBuffer string_buffer(&temp_allocator);
ObObjType val_type;
ObCollationType value_cs_type;
uint8_t format_type = OB_JSON_ON_STRICT_IMPLICIT;
bool is_column = false;
common::hash::ObHashSet<ObString> view_key_names;
ObJsonObject j_obj(&temp_allocator);
ObIJsonBase *j_base = &j_obj;
ObJsonBuffer jbuf(&temp_allocator);
// parse null type
uint8_t null_type = OB_JSON_ON_NULL_IMPLICIT;
if (OB_SUCC(ret)) {
ret = get_clause(expr, ctx, expr.arg_cnt_ - 4, null_type, OB_JSON_ON_NULL_NUM);
if (OB_SUCC(ret)
&& OB_FAIL(eval_option_clause_value(expr.args_[expr.arg_cnt_ - 4], ctx, null_type, OB_JSON_ON_NULL_NUM))) {
LOG_WARN("fail to eval option", K(ret), K(expr.arg_cnt_));
}
// parse returning type
ObObjType dst_type;
int32_t dst_len = OB_MAX_TEXT_LENGTH;
if (OB_SUCC(ret)) {
ret = ObJsonExprHelper::get_dest_type(expr, expr.arg_cnt_ - 3, ctx, dst_type, dst_len);
int64_t opt_res_type = 0;
ObDatum *datum_res_type = nullptr;
if (OB_FAIL(ret)) {
} else if (OB_UNLIKELY(OB_FAIL(expr.args_[expr.arg_cnt_ - 3]->eval(ctx, datum_res_type)))) {
LOG_WARN("eval json arg failed", K(ret));
} else {
opt_res_type = datum_res_type->get_int();
if (opt_res_type == 0) {
dst_type = ObJsonType;
} else if (OB_FAIL(ObJsonExprHelper::eval_and_check_res_type(opt_res_type, dst_type, dst_len))) {
LOG_WARN("fail to check returning type", K(ret));
}
}
// parse strict type
// parse strict type
uint8_t strict_type = OB_JSON_ON_STRICT_IMPLICIT;
if (OB_SUCC(ret)) {
ret = get_clause(expr, ctx, expr.arg_cnt_ - 2, strict_type, OB_JSON_ON_STRICT_NUM);
if (OB_SUCC(ret)
&& OB_FAIL(eval_option_clause_value(expr.args_[expr.arg_cnt_ - 2], ctx, strict_type, OB_JSON_ON_STRICT_NUM))) {
LOG_WARN("fail to eval option", K(ret), K(expr.arg_cnt_));
}
// parse unique type
uint8_t unique_type = OB_JSON_ON_UNIQUE_IMPLICIT;
if (OB_SUCC(ret)) {
ret = get_clause(expr, ctx, expr.arg_cnt_ - 1, unique_type, OB_JSON_ON_UNIQUE_NUM);
if (OB_SUCC(ret)
&& OB_FAIL(eval_option_clause_value(expr.args_[expr.arg_cnt_ - 1], ctx, unique_type, OB_JSON_ON_UNIQUE_NUM))) {
LOG_WARN("fail to eval option", K(ret), K(expr.arg_cnt_));
}
if (OB_FAIL(res_str.append("{"))) {
LOG_WARN("symbol write fail");
}
int64_t size_set= (expr.arg_cnt_ - 4) / 3;
int64_t bucket_num = (size_set / 2) + 1;
if (size_set > 0 && OB_FAIL(view_key_names.create(bucket_num))) {
LOG_WARN("init hash failed", K(ret), K(bucket_num));
}
bool is_strict = (strict_type == OB_JSON_ON_STRICT_USE);
bool is_null_absent = (null_type == OB_JSON_ON_NULL_ABSENT);
bool is_key_unique = (unique_type == OB_JSON_ON_UNIQUE_USE || (dst_type == ObJsonType && opt_res_type > 0));
for (int32 i = 0; OB_SUCC(ret) && i < expr.arg_cnt_ - 4; i += 3) {
ObExpr *arg = expr.args_[i];
ObDatum *json_datum = NULL;
ObObjType key_type = expr.args_[i]->datum_meta_.type_;
if (OB_FAIL(arg->eval(ctx, json_datum))) {
uint8_t format_type = OB_JSON_ON_STRICT_IMPLICIT;
ObExpr *arg_key = expr.args_[i];
ObExpr *arg_value = expr.args_[i + 1];
ObExpr *arg_opt = expr.args_[i + 2];
ObObjType key_data_type = arg_key->datum_meta_.type_;
ObObjType value_data_type = arg_value->datum_meta_.type_;
ObDatum *datum_key = nullptr;
if (OB_FAIL(arg_key->eval(ctx, datum_key))) {
LOG_WARN("failed: eval json args datum failed", K(ret));
} else if (json_datum->is_null()) {
} else if (datum_key->is_null() || key_data_type == ObNullType) {
ret = OB_ERR_JSON_DOCUMENT_NULL_KEY;
LOG_USER_ERROR(OB_ERR_JSON_DOCUMENT_NULL_KEY);
LOG_WARN("failed:json key is null", K(ret));
} else if (!ob_is_string_type(key_type) && key_type != ObJsonType) {
} else if (!(ob_is_extend(key_data_type)
|| ob_is_json(key_data_type)
|| ob_is_raw(key_data_type)
|| ob_is_string_type(key_data_type))) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
}
if (OB_SUCC(ret)) {
ret = get_clause(expr, ctx, i + 2, format_type, OB_JSON_ON_STRICT_NUM);
}
ObExpr *val_expr = expr.args_[i + 1];
val_type = val_expr->datum_meta_.type_;
bool can_only_be_null = false;
if (OB_SUCC(ret) && format_type
&& (!ObJsonExprHelper::is_convertible_to_json(val_type) || val_type == ObJsonType)) {
if (val_type == ObObjType::ObNumberType) {
can_only_be_null = true;
LOG_WARN("data type not legal for key type", K(ret), K(i), K(key_data_type));
} else if ((!ob_is_string_type(key_data_type) && key_data_type != ObJsonType)) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_WARN("data type not legal for key type", K(ret), K(i), K(key_data_type));
} else if (OB_FAIL(eval_option_clause_value(arg_opt, ctx, format_type, OB_JSON_ON_STRICT_NUM))) {
LOG_WARN("fail to eval option", K(ret), K(i));
} else {
ObIJsonBase *j_val = nullptr;
ObString key = datum_key->get_string();
bool is_format_json = format_type > 0;
if (OB_FAIL(ObJsonExprHelper::eval_oracle_json_val(
arg_value, ctx, &temp_allocator, j_val, is_format_json, is_strict, false))) {
LOG_WARN("failed to get json value node.", K(ret), K(value_data_type), K(i));
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "CHAR", ob_obj_type_str(val_type));
}
}
if (OB_SUCC(ret)) {
ObString key = json_datum->get_string();
bool is_null = false;
if (OB_FAIL(ObJsonExprHelper::get_json_or_str_data(arg, ctx, temp_allocator, key, is_null))) {
LOG_WARN("fail to get real data.", K(ret), K(key));
} else if (dst_type == ObJsonType) {
ObIJsonBase *j_val = NULL;
uint32_t parse_flag = (strict_type == OB_JSON_ON_STRICT_IMPLICIT) ?
ObJsonParser::JSN_STRICT_FLAG : ObJsonParser::JSN_RELAXED_FLAG;
if (OB_FAIL(ObJsonExprHelper::get_json_val(expr, ctx, &temp_allocator, i+1, j_val, false, format_type, parse_flag))) {
ret = OB_ERR_INVALID_JSON_TEXT_IN_PARAM;
LOG_USER_ERROR(OB_ERR_INVALID_JSON_TEXT_IN_PARAM);
} else if (can_only_be_null && j_val->json_type() != ObJsonNodeType::J_NULL) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "CHAR", ob_obj_type_str(val_type));
} else if (j_val->json_type() == ObJsonNodeType::J_NULL && null_type == OB_JSON_ON_NULL_ABSENT) {
ObString key = json_datum->get_string();
if (unique_type == OB_JSON_ON_UNIQUE_USE && OB_FAIL(check_key_valid(view_key_names, key))) {
LOG_WARN("duplicate key fail");
}
// do nothing
} else if (OB_FAIL(check_key_valid(view_key_names, key))) {
LOG_WARN("duplicate key fail");
} else if (OB_FAIL(j_base->object_add(key, j_val))) {
if (ret == OB_ERR_JSON_DOCUMENT_NULL_KEY) {
LOG_USER_ERROR(OB_ERR_JSON_DOCUMENT_NULL_KEY);
}
LOG_WARN("failed: append json object kv", K(ret));
}
} else {
ObJsonString ob_str(key.ptr(), key.length());
ObDatum *j_datum = NULL;
bool t_is_null = false;
if (OB_FAIL(get_ora_json_doc(expr, ctx, i+1, j_datum, t_is_null))) {
LOG_WARN("get value json doc fail", K(ret), K(j_datum));
} else if (can_only_be_null && !t_is_null) {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "CHAR", ob_obj_type_str(val_type));
} else if (t_is_null && null_type == OB_JSON_ON_NULL_ABSENT) {
ObString key = json_datum->get_string();
if (unique_type == OB_JSON_ON_UNIQUE_USE && OB_FAIL(check_key_valid(view_key_names, key))) {
LOG_WARN("duplicate key fail");
}
// do nothing only check
} else if (t_is_null && null_type <= 1) {
if (OB_SUCC(ret) && i > 0 && res_str.length() > 1) {
if (OB_FAIL(res_str.append(","))) {
LOG_WARN("comma write fail");
}
}
if (OB_SUCC(ret)) {
if (unique_type == OB_JSON_ON_UNIQUE_USE && OB_FAIL(check_key_valid(view_key_names, key))) {
LOG_WARN("duplicate key fail");
} else if (OB_FAIL(ob_str.print(res_str, true))) {
LOG_WARN("fail to print json node", K(ret));
} else if (OB_FAIL(res_str.append(":"))) {
LOG_WARN("colon write fail");
} else if (OB_FAIL(res_str.append("null"))) {
LOG_WARN("null write fail");
}
}
} else {
if (OB_SUCC(ret) && i > 0 && res_str.length() > 1) {
if (res_str.append(",")) {
LOG_WARN("comma write fail");
}
}
if (OB_SUCC(ret)) {
if (unique_type == OB_JSON_ON_UNIQUE_USE && OB_FAIL(check_key_valid(view_key_names, key))) {
LOG_WARN("duplicate key fail");
} else if (OB_FAIL(ob_str.print(res_str, true))) {
LOG_WARN("fail to print json node", K(ret));
} else if (OB_FAIL(res_str.append(":"))) {
LOG_WARN("colon write fail");
}
}
if (OB_SUCC(ret)) {
value_cs_type = expr.args_[i + 1]->datum_meta_.cs_type_;
if (ObJsonExprHelper::is_convertible_to_json(val_type) || ob_is_raw(val_type)) {
if (OB_FAIL(ObJsonExprHelper::transform_convertible_2String(*expr.args_[i + 1], ctx, *j_datum,
val_type, value_cs_type, res_str,
expr.args_[i + 1]->obj_meta_.has_lob_header(), format_type,
strict_type == OB_JSON_ON_STRICT_USE, i + 1))) {
LOG_WARN("fail to transfrom to string");
}
} else {
ObScale scale = expr.args_[i + 1]->datum_meta_.scale_;
const ObTimeZoneInfo *tz_info = get_timezone_info(ctx.exec_ctx_.get_my_session());
if (OB_FAIL(ObJsonExprHelper::transform_scalar_2String(ctx, *j_datum, val_type, scale, tz_info, res_str))) {
LOG_WARN("Fail to transformer string");
}
}
}
if (OB_SUCC(ret) && res_str.length() > OB_MAX_PACKET_LENGTH) {
ret = OB_ERR_TOO_LONG_STRING_IN_CONCAT;
LOG_WARN("result of json_objectagg is too long", K(ret), K(res_str.length()),
K(OB_MAX_PACKET_LENGTH));
}
bool is_key_already_exist = (j_obj.get_value(key) != nullptr);
bool is_overwrite = (is_key_unique || dst_type == ObJsonType);
if (is_key_already_exist && is_key_unique) {
ret = OB_ERR_DUPLICATE_KEY;
LOG_WARN("Found duplicate key inserted before!", K(key), K(ret));
} else if (is_null_absent && j_val->json_type() == ObJsonNodeType::J_NULL) {
} else if (OB_FAIL(j_obj.add(key, static_cast<ObJsonNode*>(j_val), false, false, is_overwrite))) {
LOG_WARN("failed to get json value node.", K(ret), K(val_type));
}
}
}
}
if (OB_FAIL(ret)) {
LOG_WARN("return value fail", K(ret));
} else if (OB_FAIL(res_str.append("}"))) {
LOG_WARN("symbol write fail");
} else {
if (OB_SUCC(ret)) {
if (dst_type == ObJsonType) {
ObString raw_bin;
if (OB_FAIL(j_base->get_raw_binary(raw_bin, &temp_allocator))) {
@ -434,18 +357,23 @@ int ObExprJsonObject::eval_ora_json_object(const ObExpr &expr, ObEvalCtx &ctx, O
LOG_WARN("fail to pack json result", K(ret), K(raw_bin));
}
} else {
if (dst_type == ObVarcharType && res_str.string().length() > dst_len) {
if (OB_FAIL(string_buffer.reserve(j_obj.get_serialize_size()))) {
LOG_WARN("fail to reserve string.", K(ret), K(j_obj.get_serialize_size()));
} else if (OB_FAIL(j_base->print(string_buffer, false, false))) {
LOG_WARN("fail to transform to string.", K(ret), K(string_buffer.length()));
} else if (dst_type == ObVarcharType && string_buffer.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_object");
} else {
ret = set_result(dst_type, res_str.string(), &temp_allocator, ctx, expr, res, strict_type, unique_type);
} else if (OB_FAIL(ObJsonExprHelper::pack_json_str_res(expr, ctx, res, string_buffer.string()))) {
LOG_WARN("fail to pack json result", K(ret));
}
}
}
return ret;
}
@ -506,14 +434,13 @@ int ObExprJsonObject::get_ora_json_doc(const ObExpr &expr, ObEvalCtx &ctx,
return ret;
}
int ObExprJsonObject::get_clause(const ObExpr &expr,
ObEvalCtx &ctx,
uint8_t index,
uint8_t &type,
int64_t size_para)
int ObExprJsonObject::eval_option_clause_value(ObExpr *expr,
ObEvalCtx &ctx,
uint8_t &type,
int64_t size_para)
{
INIT_SUCC(ret);
ObExpr *json_arg = expr.args_[index];
ObExpr *json_arg = expr;
ObObjType val_type = json_arg->datum_meta_.type_;
ObDatum *json_datum = NULL;
if (OB_FAIL(json_arg->eval(ctx, json_datum))) {

View File

@ -55,11 +55,10 @@ private:
const static uint8_t OB_JSON_ON_UNIQUE_USE = 1;
const static uint8_t OB_JSON_ON_UNIQUE_IMPLICIT = 0;
static int get_clause(const ObExpr &expr,
ObEvalCtx &ctx,
uint8_t index,
uint8_t &type,
int64_t size_para);
static int eval_option_clause_value(ObExpr *expr,
ObEvalCtx &ctx,
uint8_t &type,
int64_t size_para);
static int get_ora_json_doc(const ObExpr &expr, ObEvalCtx &ctx,
uint16_t index, ObDatum*& j_datum,

View File

@ -61,7 +61,7 @@ int ObExprJsonQuery::calc_result_typeN(ObExprResType& type,
UNUSED(type_ctx);
INIT_SUCC(ret);
common::ObArenaAllocator allocator;
if (OB_UNLIKELY(param_num != 10)) {
if (OB_UNLIKELY(param_num != 11)) {
ret = OB_ERR_PARAM_SIZE;
LOG_WARN("invalid param number", K(ret), K(param_num));
} else {
@ -133,7 +133,7 @@ int ObExprJsonQuery::calc_result_typeN(ObExprResType& type,
}
}
}
// scalars 3, pretty 4, ascii 5, wrapper 6, error 7, empty 8, mismatch 9
// truncate 3 , scalars 4, pretty 5, ascii 6, wrapper 7, error 8, empty 9, mismatch 10
for (int64_t i = 3; i < param_num && OB_SUCC(ret); ++i) {
if (types_stack[i].get_type() == ObNullType) {
ret = OB_ERR_UNEXPECTED;
@ -145,7 +145,7 @@ int ObExprJsonQuery::calc_result_typeN(ObExprResType& type,
// ASCII clause
if (OB_SUCC(ret)) {
if (OB_FAIL(ObJsonExprHelper::parse_asc_option(types_stack[5], types_stack[0], type, type_ctx))) {
if (OB_FAIL(ObJsonExprHelper::parse_asc_option(types_stack[6], types_stack[0], type, type_ctx))) {
LOG_WARN("fail to parse asc option.", K(ret));
}
}
@ -242,9 +242,9 @@ int ObExprJsonQuery::eval_json_query(const ObExpr &expr, ObEvalCtx &ctx, ObDatum
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);
ret = get_clause_opt(expr, ctx, 8, 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);
int temp_ret = get_clause_opt(expr, ctx, 8, 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));
@ -254,7 +254,7 @@ int ObExprJsonQuery::eval_json_query(const ObExpr &expr, ObEvalCtx &ctx, ObDatum
// 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);
ret = get_clause_opt(expr, ctx, 7, is_cover_by_error, wrapper_type, OB_WRAPPER_COUNT);
}
if (OB_SUCC(ret) && j_path->get_last_node_type() > JPN_BEGIN_FUNC_FLAG
@ -275,7 +275,7 @@ int ObExprJsonQuery::eval_json_query(const ObExpr &expr, ObEvalCtx &ctx, ObDatum
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))) {
if (OB_FAIL(get_clause_opt(expr, ctx, 10, is_cover_by_error, mismatch_type, OB_JSON_ON_MISMATCH_COUNT))) {
LOG_WARN("failed to get mismatch option.", K(ret), K(mismatch_type));
}
}
@ -341,7 +341,7 @@ int ObExprJsonQuery::eval_json_query(const ObExpr &expr, ObEvalCtx &ctx, ObDatum
// 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);
ret = get_clause_opt(expr, ctx, 9, 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));
@ -550,15 +550,15 @@ int ObExprJsonQuery::get_clause_pre_asc_sca_opt(const ObExpr &expr, ObEvalCtx &c
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);
ret = get_clause_opt(expr, ctx, 5, 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);
ret = get_clause_opt(expr, ctx, 6, 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);
ret = get_clause_opt(expr, ctx, 4, is_cover_by_error, scalars_type, OB_JSON_SCALARS_COUNT);
}
return ret;
}