/** * 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. */ #define USING_LOG_PREFIX SHARE #include #define private public #include "lib/lob/ob_lob_base.h" #include "lib/json_type/ob_json_tree.h" #include "lib/json_type/ob_json_bin.h" #include "lib/json_type/ob_json_parse.h" #include "lib/json_type/ob_json_diff.h" #include "lib/timezone/ob_timezone_info.h" #undef private #include namespace oceanbase { namespace common { class TestJsonBin : public ::testing::Test { public: TestJsonBin() {} ~TestJsonBin() {} virtual void SetUp() {} virtual void TearDown() {} static void SetUpTestCase() {} static void TearDownTestCase() {} private: // disallow copy DISALLOW_COPY_AND_ASSIGN(TestJsonBin); }; static std::string buf_to_hex(const char* ptr, int len) { std::stringstream ss; ss << std::hex; for (int i = 0; i < len; ++i) ss << static_cast(ptr[i]) << " "; return ss.str(); } static int init_update_ctx(ObIAllocator &allocator, ObJsonBin *bin) { INIT_SUCC(ret); ObJsonBinUpdateCtx *update_ctx = nullptr; ObLobInRowUpdateCursor *cursor = nullptr; if (OB_ISNULL(update_ctx = OB_NEWx(ObJsonBinUpdateCtx, &allocator, &allocator))) { LOG_WARN("alloc update_ctx fail", K(ret)); } else if (OB_ISNULL(cursor = OB_NEWx(ObLobInRowUpdateCursor, &allocator, &allocator))) { LOG_WARN("alloc cursor fail", K(ret)); } else if (OB_FAIL(cursor->init(bin->get_cursor()))) { LOG_WARN("init cursor fail", K(ret)); } else { update_ctx->set_lob_cursor(cursor); bin->get_cursor()->reset(); bin->set_cursor(cursor); bin->get_ctx()->update_ctx_ = update_ctx; bin->get_ctx()->is_update_ctx_alloc_ = true; } return ret; } static void check_diff_valid(ObIAllocator &allocator, const ObString& old_str, ObJsonBinUpdateCtx &update_ctx) { ObJsonBuffer old_buf(&allocator); ASSERT_EQ(OB_SUCCESS, old_buf.append(old_str)); ASSERT_EQ(old_buf.length(), old_str.length()); ObString new_buf; update_ctx.current_data(new_buf); for (int i = 0; i < update_ctx.binary_diffs_.count(); ++i) { ObJsonBinaryDiff &diff = update_ctx.binary_diffs_[i]; if (diff.dst_offset_ >= old_buf.length()) { ASSERT_EQ(OB_SUCCESS, old_buf.append(new_buf.ptr() + diff.dst_offset_, diff.dst_len_)); } else { MEMCPY(old_buf.ptr() + diff.dst_offset_, new_buf.ptr() + diff.dst_offset_, diff.dst_len_); } } ASSERT_EQ(old_buf.length(), new_buf.length()); for (int i = 0; i < old_buf.length(); ++i) { uint8_t old_c = old_buf.ptr()[i]; uint8_t new_c = new_buf.ptr()[i]; ASSERT_EQ(new_c, old_c) << " pos " << i << " old buf " << buf_to_hex(old_buf.ptr(), old_buf.length()) << " new buf "<< buf_to_hex(new_buf.ptr(), new_buf.length()); } ASSERT_EQ(0, MEMCMP(old_buf.ptr(), new_buf.ptr(), new_buf.length())); } static void check_json_diff_valid(ObIAllocator &allocator, const ObString& j_text, ObJsonBinUpdateCtx &target_update_ctx, int json_diff_count) { int ret = OB_SUCCESS; ObIJsonBase *j_base = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_TREE, j_base)); ObJsonDiffArray &json_diffs = target_update_ctx.json_diffs_; ObString update_buffer; target_update_ctx.current_data(update_buffer); ASSERT_EQ(json_diff_count, json_diffs.count()); ObJsonPathCache path_cache(&allocator); for (int i = 0; i < json_diffs.count(); ++i) { ObJsonPath* json_path = nullptr; ObString path_str = json_diffs[i].path_; int path_idx = path_cache.size(); ASSERT_EQ(OB_SUCCESS, path_cache.find_and_add_cache(json_path, path_str, path_idx)); ASSERT_EQ(path_cache.path_stat_at(path_idx), ObPathParseStat::OK_NOT_NULL); ObJsonSeekResult hit; if (json_diffs[i].op_ == ObJsonDiffOp::REPLACE || json_diffs[i].op_ == ObJsonDiffOp::REMOVE) { ASSERT_EQ(OB_SUCCESS, j_base->seek(*json_path, json_path->path_node_cnt(), true, false, hit)); ASSERT_EQ(1, hit.size()); ObIJsonBase *parent = nullptr; ObIJsonBase *json_old = hit[0]; ObJsonBin j_new_bin(&allocator); j_new_bin.set_seek_flag(false); if (json_diffs[i].op_ == ObJsonDiffOp::REPLACE) { ASSERT_EQ(OB_SUCCESS, j_new_bin.reset( json_diffs[i].value_type_, json_diffs[i].value_, 0, json_diffs[i].entry_var_type_, nullptr)); ASSERT_EQ(OB_SUCCESS, json_old->get_parent(parent)); ObJsonNode *json_new = nullptr; ASSERT_EQ(OB_SUCCESS, j_new_bin.to_tree(json_new)); if(OB_NOT_NULL(parent)) { ASSERT_EQ(OB_SUCCESS, parent->replace(json_old, json_new)); } else { ASSERT_EQ(OB_SUCCESS, j_base->replace(json_old, json_new)); } } else { if(OB_NOT_NULL(parent)) { parent = j_base; } // if (j_base->json_type() == ObJsonNodeType::J_OBJECT) { // ASSERT_EQ(OB_SUCCESS, parent->object_remove()) // } else { // ASSERT_EQ(OB_SUCCESS, parent->array_remove()) // } } } else if (json_diffs[i].op_ == ObJsonDiffOp::INSERT) { ASSERT_EQ(OB_SUCCESS, j_base->seek(*json_path, json_path->path_node_cnt(), true, false, hit)); ASSERT_EQ(0, hit.size()); } else { ASSERT_FALSE(true) << "invalid op" << (int)json_diffs[i].op_; } } ObJsonBuffer j_src_buffer(&allocator); ASSERT_EQ(OB_SUCCESS, j_base->print(j_src_buffer, false)); ObJsonBin j_target_bin; j_target_bin.set_seek_flag(false); ObJsonBinCtx j_target_bin_ctx; ASSERT_EQ(OB_SUCCESS, j_target_bin.reset(update_buffer, 0, &j_target_bin_ctx)); ObJsonBuffer j_target_buffer(&allocator); ASSERT_EQ(OB_SUCCESS, j_target_bin.print(j_target_buffer, false)); ASSERT_EQ(std::string(j_src_buffer.ptr(), j_src_buffer.length()), std::string(j_target_buffer.ptr(), j_target_buffer.length())); ASSERT_NE(std::string(j_src_buffer.ptr(), j_src_buffer.length()), std::string(j_text.ptr(), j_text.length())); ASSERT_NE(std::string(j_target_buffer.ptr(), j_target_buffer.length()), std::string(j_text.ptr(), j_text.length())); std::cout << "-------- origin" << std::endl; std::cout << std::string(j_text.ptr(), j_text.length()) << std::endl; std::cout << "-------- src" << std::endl; std::cout << std::string(j_src_buffer.ptr(), j_src_buffer.length()) << std::endl; std::cout << "-------- target" << std::endl; std::cout << std::string(j_target_buffer.ptr(), j_target_buffer.length()) << std::endl; } // rapidjson 解析仅包含字符串的json text测试 // 输入: json text // 预期: 解析完整json tree TEST_F(TestJsonBin, test_tree_to_bin) { common::ObString j_text("{ \"greeting\" : 1, \"farewell\" : 2, \"json_text\" : 3 }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; common::ObString result; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // check result uint64_t doc_header_len = sizeof(ObJsonBinDocHeader); char *ptr = result.ptr() + doc_header_len; int64_t offset = 0; ObJsonBinHeader *header = reinterpret_cast(ptr); ASSERT_EQ(header->is_continuous_, 1); ASSERT_EQ(header->type_, ObJBVerType::J_OBJECT_V0); offset += OB_JSON_BIN_HEADER_LEN; int64_t count; ObJsonVar::read_var(ptr + offset, header->count_size_, &count); ASSERT_EQ(count, 3); offset += ObJsonVar::get_var_size(header->count_size_); uint64_t obj_size; ObJsonVar::read_var(ptr + offset, header->obj_size_size_, &obj_size); ASSERT_EQ(doc_header_len + obj_size, result.length()); fprintf(stdout, "[test] used_size is %lu\n", obj_size); offset += ObJsonVar::get_var_size(header->obj_size_size_); char *key_entry = ptr + offset; uint64_t key_entry_size = ObJsonVar::get_var_size(header->entry_size_); common::ObString expext_key_array[] = { "farewell","greeting", "json_text" }; for (int64_t i = 0; i < count; i++) { uint64_t key_offset, key_len; ObJsonVar::read_var(key_entry, header->entry_size_, &key_offset); ObJsonVar::read_var(key_entry + key_entry_size, header->entry_size_, &key_len); key_entry += key_entry_size * 2; char *key_ptr = reinterpret_cast(ptr) + key_offset; ASSERT_EQ(expext_key_array[i].length(), key_len); ASSERT_TRUE(STRNCMP(expext_key_array[i].ptr(), key_ptr, key_len) == 0); } char *value_entry = ptr + offset + key_entry_size * 2 * count; int64_t expect_value_array[] = { 2, 1, 3 }; for (int64_t i = 0; i < count; i++) { int64_t value_offset; ObJsonVar::read_var(value_entry, header->entry_size_, &value_offset); uint64_t value_entry_size = ObJsonVar::get_var_size(header->entry_size_); uint8_t value_type = *reinterpret_cast(value_entry + value_entry_size); value_entry += sizeof(uint8_t) + value_entry_size; int64_t val = value_offset; // int64_t pos = value_offset; // ASSERT_EQ(OB_SUCCESS, serialization::decode_vi64(reinterpret_cast(root), result.length(), pos, &val)); ASSERT_EQ((expect_value_array[i]), val); uint8_t expect_type = static_cast(ObJsonNodeType::J_INT); ASSERT_EQ((value_type & 0x7F), expect_type); ASSERT_EQ(0x80, (value_type & 0x80)); } } TEST_F(TestJsonBin, t2b_array) { common::ObString j_text("[\"greeting\", 1.1, 2, -10, true, null]"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); ASSERT_TRUE(j_bin->is_bin()); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // check result uint64_t doc_header_len = sizeof(ObJsonBinDocHeader); char *ptr = result.ptr() + doc_header_len; uint64_t offset = 0; ObJsonBinHeader *header = reinterpret_cast(ptr); offset += OB_JSON_BIN_HEADER_LEN; ASSERT_EQ(header->is_continuous_, 1); ASSERT_EQ(header->type_, ObJBVerType::J_ARRAY_V0); uint64_t count, array_size; ObJsonVar::read_var(ptr + offset, header->count_size_, &count); offset += ObJsonVar::get_var_size(header->count_size_); ObJsonVar::read_var(ptr + offset, header->obj_size_size_, &array_size); offset += ObJsonVar::get_var_size(header->obj_size_size_); ASSERT_EQ(count, 6); ASSERT_EQ(doc_header_len + array_size, result.length()); fprintf(stdout, "[test] array_size is %lu\n", array_size); uint64_t value_entry_size = ObJsonVar::get_var_size(header->entry_size_); // "greeting" { common::ObString expect_str("greeting"); uint64_t value_offset; ObJsonVar::read_var(ptr + offset, header->entry_size_, &value_offset); offset += value_entry_size; uint8_t value_type = *reinterpret_cast(ptr + offset); offset += sizeof(uint8_t); uint8_t expect_type = static_cast(ObJBVerType::J_STRING_V0); ASSERT_EQ(value_type, expect_type); int64_t num = 0; int64_t pos = value_offset; uint8_t redant_type = *reinterpret_cast(ptr + pos); pos += sizeof(uint8_t); ASSERT_EQ(OB_SUCCESS, serialization::decode_vi64(ptr, result.length(), pos, &num)); uint64_t length = static_cast(num); ASSERT_EQ(length, expect_str.length()); char* val = ptr + pos; ASSERT_TRUE(STRNCMP(expect_str.ptr(), val, length) == 0); } // 1.1 { uint64_t value_offset; ObJsonVar::read_var(ptr + offset, header->entry_size_, &value_offset); offset += value_entry_size; uint8_t value_type = *reinterpret_cast(ptr + offset); offset += sizeof(uint8_t); uint8_t expect_type = static_cast(ObJsonNodeType::J_DOUBLE); ASSERT_EQ(value_type, expect_type); double val = *reinterpret_cast(ptr + value_offset); ASSERT_FLOAT_EQ(val, 1.1); } // 2 inlined { uint64_t value_offset; ObJsonVar::read_var(ptr + offset, header->entry_size_, &value_offset); offset += value_entry_size; uint8_t value_type = *reinterpret_cast(ptr + offset); offset += sizeof(uint8_t); uint8_t expect_type = static_cast(ObJBVerType::J_INT_V0); ASSERT_EQ((value_type & 0x7F), expect_type); ASSERT_EQ((value_type & 0x80), 0x80); // int64_t val = 0; // int64_t pos = common_header_len + value_offset; // ASSERT_EQ(OB_SUCCESS, serialization::decode_vi64(ptr, result.length(), pos, &val)); uint64_t tval = static_cast(value_offset); ASSERT_EQ(tval, 2); } // -10 { uint64_t value_offset; ObJsonVar::read_var(ptr + offset, header->entry_size_, &value_offset); offset += value_entry_size; uint8_t value_type = *reinterpret_cast(ptr + offset); offset += sizeof(uint8_t); uint8_t expect_type = static_cast(ObJBVerType::J_INT_V0); ASSERT_EQ((value_type & 0x7F), expect_type); ASSERT_EQ((value_type & 0x80), 0x80); // int64_t val = 0; // int64_t pos = common_header_len + value_offset; // ASSERT_EQ(OB_SUCCESS, serialization::decode_vi64(ptr, result.length(), pos, &val)); int64_t val = static_cast(static_cast(static_cast(value_offset))); ASSERT_EQ(val, -10); } // true { uint64_t value_offset; ObJsonVar::read_var(ptr + offset, header->entry_size_, &value_offset); offset += value_entry_size; uint8_t value_type = *reinterpret_cast(ptr + offset); offset += sizeof(uint8_t); uint8_t expect_type = static_cast(ObJBVerType::J_BOOLEAN_V0); ASSERT_EQ((value_type & 0x7F), expect_type); ASSERT_EQ((value_type & 0x80), 0x80); char val = static_cast(value_offset); ASSERT_EQ(val, 1); } // null { uint64_t value_offset; ObJsonVar::read_var(ptr + offset, header->entry_size_, &value_offset); offset += value_entry_size; uint8_t value_type = *reinterpret_cast(ptr + offset); offset += sizeof(uint8_t); uint8_t expect_type = static_cast(ObJsonNodeType::J_NULL); ASSERT_EQ((value_type & 0x7F), expect_type); ASSERT_EQ((value_type & 0x80), 0x80); char val = static_cast(value_offset); ASSERT_EQ(val, '\0'); } } TEST_F(TestJsonBin, deserialize_bin_to_tree) { common::ObString j_text("[\"greeting\", 1.1, 2, -10, true, null]"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ObJsonBin *bin = static_cast(j_bin); ObJsonNode *new_json_tree = nullptr; ASSERT_EQ(OB_SUCCESS, bin->to_tree(new_json_tree)); ObJsonArray *json_array = static_cast(new_json_tree); // check string "greeting" ObJsonString *json_string = static_cast((*json_array)[0]); ASSERT_TRUE(json_string->json_type() == ObJsonNodeType::J_STRING); ASSERT_TRUE(json_string->value().case_compare("greeting") == 0); // check double 1.1 ObJsonDouble *json_double = static_cast((*json_array)[1]); ASSERT_TRUE(json_double->json_type() == ObJsonNodeType::J_DOUBLE); ASSERT_TRUE(json_double->value() == 1.1); // check uint 2 ObJsonUint *json_uint = static_cast((*json_array)[2]); ASSERT_TRUE(json_uint->json_type() == ObJsonNodeType::J_INT); ASSERT_TRUE(json_uint->value() == 2); // check int -10 ObJsonInt *json_int = static_cast((*json_array)[3]); ASSERT_TRUE(json_int->json_type() == ObJsonNodeType::J_INT); ASSERT_TRUE(json_int->value() == -10); // check boolean true ObJsonBoolean *json_boolean = static_cast((*json_array)[4]); ASSERT_TRUE(json_boolean->json_type() == ObJsonNodeType::J_BOOLEAN); ASSERT_TRUE(json_boolean->value() == true); // check null NULL ObJsonNull *json_null = static_cast((*json_array)[5]); ASSERT_TRUE(json_null->json_type() == ObJsonNodeType::J_NULL); } TEST_F(TestJsonBin, test_bin_lookup) { common::ObString j_text("{ \"greeting\" : [\"test\", 1.1, 2, -10, true, null], \"farewell\" : 2, \"json_text\" : 3 }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); uint64_t root_member_count = bin->element_count(); ASSERT_EQ(3, root_member_count); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ObString lkey("greeting"); ObIJsonBase* j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, bin->get_object_value(lkey, j_bin1)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_bin1->json_type()); uint64_t sub_member_count = j_bin1->element_count(); ASSERT_EQ(6, sub_member_count); // "test" { ObIJsonBase* j_bin_sub = NULL; ASSERT_EQ(OB_SUCCESS, j_bin1->get_array_element(0, j_bin_sub)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin_sub->json_type()); ObString ele0("test"); uint64_t data_len = j_bin_sub->get_data_length(); const char *data = j_bin_sub->get_data(); ObString actual(data_len, data); ASSERT_EQ(0, ele0.compare(actual)); } // 1.1 { ObIJsonBase* j_bin_sub = NULL; ASSERT_EQ(OB_SUCCESS, j_bin1->get_array_element(1, j_bin_sub)); ASSERT_EQ(ObJsonNodeType::J_DOUBLE, j_bin_sub->json_type()); ASSERT_FLOAT_EQ(1.1, j_bin_sub->get_double()); } // 2 { ObIJsonBase* j_bin_sub = NULL; ASSERT_EQ(OB_SUCCESS, j_bin1->get_array_element(2, j_bin_sub)); ASSERT_EQ(ObJsonNodeType::J_INT, j_bin_sub->json_type()); ASSERT_EQ(2, j_bin_sub->get_uint()); } // -10 { ObIJsonBase* j_bin_sub = NULL; ASSERT_EQ(OB_SUCCESS, j_bin1->get_array_element(3, j_bin_sub)); ASSERT_EQ(ObJsonNodeType::J_INT, j_bin_sub->json_type()); ASSERT_EQ(-10, j_bin_sub->get_int()); } // true { ObIJsonBase* j_bin_sub = NULL; ASSERT_EQ(OB_SUCCESS, j_bin1->get_array_element(4, j_bin_sub)); ASSERT_EQ(ObJsonNodeType::J_BOOLEAN, j_bin_sub->json_type()); ASSERT_EQ(true, j_bin_sub->get_boolean()); } // null { ObIJsonBase* j_bin_sub = NULL; ASSERT_EQ(OB_SUCCESS, j_bin1->get_array_element(5, j_bin_sub)); ASSERT_EQ(ObJsonNodeType::J_NULL, j_bin_sub->json_type()); } } TEST_F(TestJsonBin, test_wrapper_to_string_object) { set_compat_mode(lib::Worker::CompatMode::MYSQL); // json text 转 json tree common::ObString json_text("{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"json_text\" : \"test!\" }"); common::ObArenaAllocator allocator(ObModIds::TEST); const char *syntaxerr = NULL; ObJsonNode *json_tree = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonParser::parse_json_text(&allocator, json_text.ptr(), json_text.length(), syntaxerr, NULL, json_tree)); // wrapper to string ObJsonBin bin(&allocator); bin.parse_tree(json_tree); ObIJsonBase *j_base = &bin; ObJsonBuffer buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_base->print(buf, true)); std::cout << buf.ptr() << std::endl; // 由于构建树的过程,进行了排序,顺序已经打乱,所以输出的顺序和用户的输入顺序不一样 EXPECT_STREQ(buf.ptr(), "{\"farewell\": \"bye-bye!\", \"greeting\": \"Hello!\", \"json_text\": \"test!\"}"); } TEST_F(TestJsonBin, test_json_bin_load_without_common_header) { common::ObString j_text("[\"greeting\", 1.1, 2, -10, true, null]"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // check result uint64_t doc_header_len = sizeof(ObJsonBinDocHeader); char *ptr = result.ptr() + doc_header_len; uint64_t offset = 0; ObJsonBinHeader *header = reinterpret_cast(ptr); ASSERT_EQ(header->type_, ObJBVerType::J_ARRAY_V0); offset += OB_JSON_BIN_HEADER_LEN; uint64_t obj_size; ObJsonVar::read_var(ptr + offset + ObJsonVar::get_var_size(header->count_size_), header->obj_size_size_, &obj_size); ASSERT_EQ(doc_header_len + obj_size, result.length()); fprintf(stdout, "[test] obj_size is %lu\n", obj_size); ObJsonBin test_bin(result.ptr(), result.length(), &allocator); test_bin.set_seek_flag(false); test_bin.reset_iter(); ASSERT_EQ(ObJsonNodeType::J_ARRAY, test_bin.json_type()); uint64_t sub_member_count = test_bin.element_count(); ASSERT_EQ(6, sub_member_count); // "greeting" { test_bin.element(0); uint8_t actual_type = (static_cast(test_bin.json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString ele0("greeting"); ObString data(test_bin.get_data_length(), test_bin.get_data()); ASSERT_EQ(0, ele0.compare(data)); } // 1.1 { ASSERT_EQ(OB_SUCCESS, test_bin.move_parent_iter()); test_bin.element(1); uint8_t actual_type = (static_cast(test_bin.json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_DOUBLE), actual_type); ASSERT_FLOAT_EQ(1.1, test_bin.get_double()); } // 2 { ASSERT_EQ(OB_SUCCESS, test_bin.move_parent_iter()); test_bin.element(2); uint8_t actual_type = (static_cast(test_bin.json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_INT), actual_type); ASSERT_EQ(2, test_bin.get_uint()); } // -10 { ASSERT_EQ(OB_SUCCESS, test_bin.move_parent_iter()); test_bin.element(3); uint8_t actual_type = (static_cast(test_bin.json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_INT), actual_type); ASSERT_EQ(-10, test_bin.get_int()); } // true { ASSERT_EQ(OB_SUCCESS, test_bin.move_parent_iter()); test_bin.element(4); uint8_t actual_type = (static_cast(test_bin.json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_BOOLEAN), actual_type); ASSERT_EQ(true, test_bin.get_boolean()); } // null { test_bin.reset_iter(); // test reset iter test_bin.element(5); uint8_t actual_type = (static_cast(test_bin.json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_NULL), actual_type); } } TEST_F(TestJsonBin, test_bin_update) { common::ObString j_text("{ \"greeting\" : [\"test\", 1.1, 2, -10, true, null], \"farewell\" : 2, \"json_text\" : 3 }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); uint64_t root_member_count = bin->element_count(); ASSERT_EQ(3, root_member_count); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); ObString lkey("greeting"); bin->lookup(lkey); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); uint64_t sub_member_count = bin->element_count(); ASSERT_EQ(6, sub_member_count); // "test" --> "hahahahahah" { bin->element(0); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString ele0("test"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ObJsonString new_val("hahahahahah", strlen("hahahahahah")); ObIJsonBase *j_base_new = &new_val; ObIJsonBase *j_bin_val = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_base_new, ObJsonInType::JSON_BIN, j_bin_val)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->update(0, static_cast(j_bin_val))); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); ASSERT_EQ(update_ctx.is_rebuild_all_, false); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 1); bin->element(0); actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString new_ele("hahahahahah"); ObString data1(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, new_ele.compare(data1)); } // 1.1 --> 3.1415 { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); bin->element(1); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_DOUBLE), actual_type); ASSERT_FLOAT_EQ(1.1, bin->get_double()); ObJsonDouble new_val(3.1415); ObIJsonBase *j_base_new = &new_val; ObIJsonBase *j_bin_val = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_base_new, ObJsonInType::JSON_BIN, j_bin_val)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->update(1, static_cast(j_bin_val))); ASSERT_EQ(3, update_ctx.binary_diffs_.count()); ASSERT_EQ(update_ctx.is_rebuild_all_, false); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 2); bin->element(1); actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_DOUBLE), actual_type); ASSERT_FLOAT_EQ(3.1415, bin->get_double()); } // 2 ---> -655666 { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); bin->element(2); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_INT), actual_type); ASSERT_EQ(2, bin->get_uint()); ObJsonInt new_val(-655666); ObIJsonBase *j_base_new = &new_val; ObIJsonBase *j_bin_val = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_base_new, ObJsonInType::JSON_BIN, j_bin_val)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->update(2, static_cast(j_bin_val))); ASSERT_EQ(5, update_ctx.binary_diffs_.count()); ASSERT_EQ(update_ctx.is_rebuild_all_, false); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 3); bin->element(2); actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_INT), actual_type); ASSERT_EQ(-655666, bin->get_int()); } // -10 ---> 655666 { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); bin->element(3); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_INT), actual_type); ASSERT_EQ(-10, bin->get_int()); ObJsonUint new_val(655666); ObIJsonBase *j_base_new = &new_val; ObIJsonBase *j_bin_val = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_base_new, ObJsonInType::JSON_BIN, j_bin_val)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->update(3, static_cast(j_bin_val))); ASSERT_EQ(7, update_ctx.binary_diffs_.count()); ASSERT_EQ(update_ctx.is_rebuild_all_, false); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 4); bin->element(3); actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_UINT), actual_type); ASSERT_EQ(655666, bin->get_uint()); } // true { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); bin->element(4); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_BOOLEAN), actual_type); ASSERT_EQ(true, bin->get_boolean()); } // null { bin->reset_iter(); // test reset iter bin->lookup(lkey); bin->element(5); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_NULL), actual_type); } } TEST_F(TestJsonBin, test_bin_remove) { common::ObString j_text("{ \"greeting\" : [\"test\", 1.1, 2, -10, true, null], \"farewell\" : 2, \"json_text\" : 3 }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); uint64_t root_member_count = bin->element_count(); ASSERT_EQ(3, root_member_count); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ObString lkey("greeting"); bin->lookup(lkey); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); uint64_t sub_member_count = bin->element_count(); ASSERT_EQ(6, sub_member_count); // "test" { bin->element(0); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString ele0("test"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); } // 1.1 { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->remove(0)); ASSERT_EQ(1, update_ctx.binary_diffs_.count()); ASSERT_EQ(update_ctx.is_rebuild_all_, false); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 1); bin->element(0); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_DOUBLE), actual_type); ASSERT_FLOAT_EQ(1.1, bin->get_double()); } // 2 { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->remove(0)); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); ASSERT_EQ(update_ctx.is_rebuild_all_, false); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 2); bin->element(0); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_INT), actual_type); ASSERT_EQ(2, bin->get_uint()); } // -10 { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->remove(0)); ASSERT_EQ(3, update_ctx.binary_diffs_.count()); ASSERT_EQ(update_ctx.is_rebuild_all_, false); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 3); bin->element(0); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_INT), actual_type); ASSERT_EQ(-10, bin->get_int()); } // true { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->remove(0)); ASSERT_EQ(4, update_ctx.binary_diffs_.count()); ASSERT_EQ(update_ctx.is_rebuild_all_, false); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 4); bin->element(0); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_BOOLEAN), actual_type); ASSERT_EQ(true, bin->get_boolean()); } // null { bin->reset_iter(); // test reset iter bin->lookup(lkey); ASSERT_EQ(OB_SUCCESS, bin->remove(0)); ASSERT_EQ(5, update_ctx.binary_diffs_.count()); ASSERT_EQ(update_ctx.is_rebuild_all_, false); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 5); bin->element(0); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_NULL), actual_type); } ASSERT_EQ(OB_SUCCESS, bin->reset_iter()); size_t free_space; ASSERT_EQ(OB_SUCCESS, bin->get_free_space(free_space)); ASSERT_GT(free_space, 0); fprintf(stdout, "[test] after remove free_space is %zu\n", free_space); ASSERT_EQ(OB_SUCCESS, bin->rebuild()); ASSERT_EQ(OB_SUCCESS, bin->get_free_space(free_space)); fprintf(stdout, "[test] after rebuild free_space is %zu\n", free_space); ASSERT_EQ(0, free_space); } TEST_F(TestJsonBin, test_bin_update_with_obj) { common::ObString j_text("{ \"a\" : [1,2.2,-3,null,\"hahah\"], \"b\" : { \"b1\" : 321, \"b2\" : { \"b21\" : \"testing\" } }, \"c\" : \"ccccc\" }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin1)); common::ObString j_text2("{ \"a\" : [1,2.2,-3,null,\"hahah\"], \"b\" : { \"b1\" : 321, \"b2\" : { \"b21\" : \"killing!!!\", \"b22\" : \"newwuwuwu\" } }, \"c\" : \"ccccc\" }"); ObIJsonBase *j_bin2 = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text2, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin2)); common::ObString result2; ASSERT_EQ(OB_SUCCESS, j_bin2->get_raw_binary(result2, &allocator)); ObJsonBin *bin = static_cast(j_bin2); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); // 1. update j_bin2.b.b1 from 321 ---> "updated" { common::ObJsonBuffer buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_bin1->print(buf, true)); std::cout << buf.ptr() << std::endl; ObJsonBin *bin2 = static_cast(j_bin2); bin2->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, bin2->lookup("b")); size_t idx; ASSERT_EQ(OB_SUCCESS, bin2->lookup_index("b1", &idx)); ObJsonString j_str("updated", strlen("updated")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(OB_SUCCESS, bin2->update(idx, static_cast(j_bin_str))); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); ASSERT_EQ(update_ctx.is_rebuild_all_, false); check_diff_valid(allocator, result2, update_ctx); check_json_diff_valid(allocator, j_text2, update_ctx, 1); ASSERT_EQ(OB_SUCCESS, bin2->element(idx)); uint8_t actual_type = (static_cast(bin2->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString new_ele("updated"); ObString data(bin2->get_data_length(), bin2->get_data()); ASSERT_EQ(0, new_ele.compare(data)); ASSERT_EQ(OB_SUCCESS, bin2->reset_iter()); size_t free_space; ASSERT_EQ(OB_SUCCESS, bin2->get_free_space(free_space)); ASSERT_EQ(free_space, 2); // from 321 in storage not inlined, use 2 bytes fprintf(stdout, "[test] after update bin2 free_space is %zu\n", free_space); ASSERT_EQ(OB_SUCCESS, bin2->reset_iter()); } // 2. update j_bin1.b with j_bin2.b common::ObString result1; ASSERT_EQ(OB_SUCCESS, j_bin1->get_raw_binary(result1, &allocator)); ObJsonBin *bin1 = static_cast(j_bin1); bin1->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin1)); ObJsonBinUpdateCtx &update_ctx1 = *bin1->get_update_ctx(); { size_t free_space; ObJsonBin *bin2 = static_cast(j_bin2); bin2->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, bin2->get_free_space(free_space)); ObJsonBin *bin = static_cast(j_bin1); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, bin->get_free_space(free_space)); size_t idx; ASSERT_EQ(OB_SUCCESS, bin->lookup_index("b", &idx)); ASSERT_EQ(OB_SUCCESS, bin2->lookup("b")); ObJsonBuffer rbuf(&allocator); ASSERT_EQ(OB_SUCCESS, bin2->rebuild_at_iter(rbuf)); // ASSERT_EQ(OB_SUCCESS, bin2->get_free_space(free_space)); ObJsonBin testbin(rbuf.ptr(), rbuf.length(), &allocator); testbin.set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, testbin.reset_iter()); ASSERT_EQ(OB_SUCCESS, testbin.get_free_space(free_space)); ObIJsonBase *j_bin_test = &testbin; common::ObJsonBuffer buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_bin_test->print(buf, true)); std::cout << buf.ptr() << std::endl; ASSERT_EQ(OB_SUCCESS, bin->update(idx, bin2)); ASSERT_EQ(2, update_ctx1.binary_diffs_.count()); ASSERT_EQ(update_ctx1.is_rebuild_all_, false); check_diff_valid(allocator, result1, update_ctx1); check_json_diff_valid(allocator, j_text, update_ctx1, 1); // print free space ASSERT_EQ(OB_SUCCESS, testbin.reset_iter()); ASSERT_EQ(OB_SUCCESS, bin->get_free_space(free_space)); ASSERT_GT(free_space, 0); fprintf(stdout, "[test] after update bin free_space is %zu\n", free_space); buf.reuse(); ASSERT_EQ(OB_SUCCESS, bin->print(buf, true)); std::cout << buf.ptr() << std::endl; ASSERT_EQ(OB_SUCCESS, bin->rebuild()); ASSERT_EQ(OB_SUCCESS, bin->get_free_space(free_space)); ASSERT_EQ(free_space, 0); fprintf(stdout, "[test] after rebuild bin free_space is %zu\n", free_space); buf.reuse(); ASSERT_EQ(OB_SUCCESS, bin->print(buf, true)); std::cout << buf.ptr() << std::endl; // check value EXPECT_STREQ(buf.ptr(), "{\"a\": [1, 2.2, -3, null, \"hahah\"], \"b\": {\"b1\": \"updated\", \"b2\": {\"b21\": \"killing!!!\", \"b22\": \"newwuwuwu\"}}, \"c\": \"ccccc\"}"); buf.reuse(); ASSERT_EQ(OB_SUCCESS, bin->print(buf, true)); std::cout << buf.ptr() << std::endl; // check value EXPECT_STREQ(buf.ptr(), "{\"a\": [1, 2.2, -3, null, \"hahah\"], \"b\": {\"b1\": \"updated\", \"b2\": {\"b21\": \"killing!!!\", \"b22\": \"newwuwuwu\"}}, \"c\": \"ccccc\"}"); } } TEST_F(TestJsonBin, issue_37549565) { int ret = OB_SUCCESS; common::ObString path_str("$**.Width"); std::cout<<"path_expression:"<seek(test_path, cnt, false, false, hit); ASSERT_EQ(OB_SUCCESS, ret); } TEST_F(TestJsonBin, test_bin_to_tree_after_seek) { int ret = OB_SUCCESS; common::ObString path_str("$.x"); std::cout<<"path_expression:"<seek(test_path, cnt, false, false, hit); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_EQ(hit.size(), 1); ObJsonBuffer rbuf(&allocator); ASSERT_EQ(OB_SUCCESS, hit[0]->print(rbuf, true)); std::cout << rbuf.ptr() << std::endl; // check value EXPECT_STREQ(rbuf.ptr(), "[1, 2, 3]"); rbuf.reuse(); ASSERT_EQ(OB_SUCCESS, hit[0]->print(rbuf, true)); std::cout << rbuf.ptr() << std::endl; // check value EXPECT_STREQ(rbuf.ptr(), "[1, 2, 3]"); std::cout<<"end test"<get_raw_binary(res_str, &allocator)); // json_cell_str ObIJsonBase *j_bin2 = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, res_str, ObJsonInType::JSON_BIN, ObJsonInType::JSON_BIN, j_bin2)); common::ObJsonBuffer buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_bin2->print(buf, false)); std::cout << buf.ptr() << std::endl; EXPECT_STREQ(buf.ptr(), "2000-01-01 00:00:00.000000"); } void createTime(ObTime &ob_time) { ob_time.mode_ = DT_TYPE_TIME; common::ObString str("19:18:17.654321"); ASSERT_EQ(OB_SUCCESS, ObTimeConverter::str_to_ob_time_without_date(str, ob_time)); } // void createDate(ObTime &ob_time) // { // ob_time.mode_ = DT_TYPE_DATE; // common::ObString str("20210906"); // ASSERT_EQ(OB_SUCCESS, ObTimeConverter::str_to_ob_time_with_date(str, ob_time)); // } // // void createDateTime(ObTime &ob_time) // { // ob_time.mode_ = DT_TYPE_DATETIME; // common::ObString str("2021-09-06 11:12:13.456789"); // ASSERT_EQ(OB_SUCCESS, ObTimeConverter::str_to_ob_time_with_date(str, ob_time)); // ASSERT_EQ(OB_SUCCESS, ObTimeConverter::validate_datetime(ob_time)); // } // // TEST_F(TestJsonBin, dateAndTimeTest) // { // common::ObArenaAllocator allocator(ObModIds::TEST); // ObJsonArray array(&allocator); // ObTime obtime, obdate, obdatetime; // createTime(obtime); // createDate(obdate); // createDateTime(obdatetime); // ObJsonDatetime jt(ObJsonNodeType::J_TIME, obtime); // ObJsonDatetime jd(ObJsonNodeType::J_DATE, obdate); // ObJsonDatetime jtd(ObJsonNodeType::J_DATETIME, obdatetime); // // add to array // ASSERT_EQ(OB_SUCCESS, array.append(&jt)); // ASSERT_EQ(OB_SUCCESS, array.append(&jd)); // ASSERT_EQ(OB_SUCCESS, array.append(&jtd)); // // ObIJsonBase *j_tree_array = &array; // ObIJsonBase *j_bin_array = NULL; // ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_array, // ObJsonInType::JSON_BIN, j_bin_array)); // ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_bin_array->json_type()); // ASSERT_EQ(3, j_bin_array->element_count()); // // // check time 19:18:17.654321 // ObIJsonBase *j_bin1 = NULL; // ASSERT_EQ(OB_SUCCESS, j_bin_array->get_array_element(0, j_bin1)); // ASSERT_EQ(ObJsonNodeType::J_TIME, j_bin1->json_type()); // ObTime jt1; // j_bin1->get_obtime(jt1); // ASSERT_EQ(19, jt1.parts_[DT_HOUR]); // ASSERT_EQ(18, jt1.parts_[DT_MIN]); // ASSERT_EQ(17, jt1.parts_[DT_SEC]); // ASSERT_EQ(654321, jt1.parts_[DT_USEC]); // // // check date 20210906 // j_bin1 = NULL; // ASSERT_EQ(OB_SUCCESS, j_bin_array->get_array_element(1, j_bin1)); // ASSERT_EQ(ObJsonNodeType::J_DATE, j_bin1->json_type()); // j_bin1->get_obtime(jt1); // ASSERT_EQ(2021, jt1.parts_[DT_YEAR]); // ASSERT_EQ(9, jt1.parts_[DT_MON]); // ASSERT_EQ(6, jt1.parts_[DT_MDAY]); // // // check datetime 2021-09-06 11:12:13.456789 // j_bin1 = NULL; // ASSERT_EQ(OB_SUCCESS, j_bin_array->get_array_element(2, j_bin1)); // ASSERT_EQ(ObJsonNodeType::J_DATETIME, j_bin1->json_type()); // j_bin1->get_obtime(jt1); // ASSERT_EQ(11, jt1.parts_[DT_HOUR]); // ASSERT_EQ(12, jt1.parts_[DT_MIN]); // ASSERT_EQ(13, jt1.parts_[DT_SEC]); // ASSERT_EQ(456789, jt1.parts_[DT_USEC]); // ASSERT_EQ(2021, jt1.parts_[DT_YEAR]); // ASSERT_EQ(9, jt1.parts_[DT_MON]); // ASSERT_EQ(6, jt1.parts_[DT_MDAY]); // } long getCurrentTime() { struct timeval tv; gettimeofday(&tv,NULL); return tv.tv_sec * 1000 + tv.tv_usec / 1000; } TEST_F(TestJsonBin, test_seek_member) { int ret = OB_SUCCESS; common::ObString path_str("$.\"resolution\".x"); std::cout<<"path_expression:"<seek(test_path, cnt, false, false, hit); std::cout<<"time of seek:"<is_tree()); uint64_t data_len = hit[0]->get_data_length(); const char *data = hit[0]->get_data(); ObString actual(data_len, data); std::cout.write(actual.ptr(), actual.length()); std::cout<seek(test_path, cnt, false, false, hit)); ASSERT_EQ(hit.size(), 3); common::ObString expect_val[] = { "Mac", "Safari", "{\"x\": \"1920\", \"y\": \"1080\"}" }; for (int i=0; iis_tree()); hit[i]->print(jbuf, false); std::cout<seek(test_path, cnt, true, false, hit)); ASSERT_EQ(hit.size(), 1); ASSERT_EQ(false, hit[0]->is_tree()); ASSERT_EQ(1, hit[0]->get_uint()); } TEST_F(TestJsonBin, test_seek_array_range) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonPath test_path("$[last-4 to last -3]", &allocator); ASSERT_EQ(OB_SUCCESS, test_path.parse_path()); common::ObString j_text("[1, 2, 3, 4, 5]"); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); ObJsonSeekResult hit; int cnt = test_path.path_node_cnt(); ASSERT_EQ(OB_SUCCESS, j_bin->seek(test_path, cnt, false, false, hit)); ASSERT_EQ(hit.size(), 2); for(int i=0; iis_tree()); ASSERT_EQ(i+1, hit[i]->get_uint()); } } TEST_F(TestJsonBin, test_seek_ellipsis) { common::ObString path_str("$**[0]"); std::cout<<"path_expression:"<seek(test_path, cnt, false, false, hit)); ASSERT_EQ(hit.size(), 2); uint64_t expect_value[] = { 1, 4 }; for (int i=0; iis_tree()); hit[i]->print(jbuf, false); std::cout<get_uint()); } std::cout<<"end test"<(j_bin); bin->set_seek_flag(false); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); ObIJsonBase *j_bin1 = nullptr; ObString lkey("greeting"); ASSERT_EQ(OB_SUCCESS, j_bin->get_object_value(lkey, j_bin1)); ObJsonString j_str("hahahahahah", strlen("hahahahahah")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(OB_SUCCESS, j_bin->object_add("greeting", j_bin_str)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 1); // after j_bin has been update, j_bin1 is unavailable ASSERT_EQ(false, j_bin->is_tree()); size_t free_space; ASSERT_EQ(OB_SUCCESS, j_bin->get_free_space(free_space)); ASSERT_GT(free_space, 0); fprintf(stdout, "[test] after update bin free_space is %zu\n", free_space); // append new key, will make j_bin to tree ASSERT_EQ(OB_SUCCESS, j_bin->object_add("test_new_key", j_bin_str)); ASSERT_EQ(false, j_bin->is_tree()); ASSERT_TRUE(update_ctx.is_rebuild_all_); ObJsonBuffer buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_bin->print(buf, true)); std::cout << buf.ptr() << std::endl; EXPECT_STREQ(buf.ptr(), "{\"farewell\": 2, \"greeting\": \"hahahahahah\", \"json_text\": 3, \"test_new_key\": \"hahahahahah\"}"); } TEST_F(TestJsonBin, test_bin_object_add2) { common::ObString j_text("{ \"greeting\" : [\"test\", 1.1, 2, -10, true, null], \"farewell\" : 2, \"json_text\" : 3 }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); ObIJsonBase *j_bin1 = nullptr; ObString lkey("greeting"); ASSERT_EQ(OB_SUCCESS, j_bin->get_object_value(lkey, j_bin1)); ObJsonString j_str("hahahahahah", strlen("hahahahahah")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(OB_SUCCESS, j_bin->object_add("greeting", j_bin_str)); // after j_bin has been update, j_bin1 is unavailable ASSERT_EQ(false, j_bin->is_tree()); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 1); size_t free_space; ASSERT_EQ(OB_SUCCESS, j_bin->get_free_space(free_space)); //ASSERT_GT(free_space, 0); fprintf(stdout, "[test] after update bin free_space is %zu\n", free_space); // append new key, will make j_bin to tree ASSERT_EQ(OB_SUCCESS, j_bin->object_add("json_texa", j_bin_str)); ASSERT_EQ(false, j_bin->is_tree()); ASSERT_TRUE(update_ctx.is_rebuild_all_); ObJsonBuffer buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_bin->print(buf, true)); std::cout << buf.ptr() << std::endl; EXPECT_STREQ(buf.ptr(), "{\"farewell\": 2, \"greeting\": \"hahahahahah\", \"json_texa\": \"hahahahahah\", \"json_text\": 3}"); } TEST_F(TestJsonBin, test_bin_append) { common::ObString j_text("{}"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); common::ObString key_str1("greeting"); common::ObString j_text1("[\"greeting\", 1.1, 2, -10, true, null]"); ObIJsonBase *j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text1, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin1)); ObJsonBin *bin1 = static_cast(j_bin1); bin1->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, bin->add(key_str1, bin1)); ASSERT_TRUE(update_ctx.is_rebuild_all_); ASSERT_EQ(OB_SUCCESS, bin->lookup(key_str1)); common::ObString str2("json_string-json_string-json_string-json_string-json_string-json_string-json_string-" "json_string-json_string-json_string-json_string-json_string-json_string-json_string-" "json_string-json_string-json_string-json_string-json_string-json_string-json_string"); ObJsonString j_str(str2.ptr(), str2.length()); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ObJsonBin *bin2 = static_cast(j_bin_str); bin2->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, bin->append(bin2)); ASSERT_TRUE(update_ctx.is_rebuild_all_); ObJsonBuffer buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_bin->print(buf, true)); std::cout << buf.ptr() << std::endl; } TEST_F(TestJsonBin, test_bin_array_insert) { common::ObString j_text("[\"greeting\", 1.1, 2, -10, true, null]"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); ObJsonBin *bin = static_cast(j_bin); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); common::ObString str1("json_string-json_string-json_string-json_string-json_string-json_string-json_string-" "json_string-json_string-json_string-json_string-json_string-json_string-json_string-" "json_string-json_string-json_string-json_string-json_string-json_string-json_string"); ObJsonString json_str1(str1.ptr(), str1.length()); ObIJsonBase *j_base_str = &json_str1; ObIJsonBase *j_bin_str = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_base_str, ObJsonInType::JSON_BIN, j_bin_str)); ObJsonBin *bin1 = static_cast(j_bin_str); ASSERT_EQ(OB_SUCCESS, bin->insert(bin1, 10)); ASSERT_EQ(7, bin->element_count()); ASSERT_TRUE(update_ctx.is_rebuild_all_); ObJsonBuffer buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_bin_str->print(buf, true)); std::cout << buf.ptr() << std::endl; } void validate_large_array(const ObIJsonBase *j_base, uint64_t size) { ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_base->json_type()); ASSERT_EQ(size, j_base->element_count()); for (int i = 0; i < size/4; i++) { // check boolean true ObIJsonBase *j_bin1 = NULL; bool value; ASSERT_EQ(OB_SUCCESS, j_base->get_array_element(i * 4, j_bin1)); ASSERT_EQ(ObJsonNodeType::J_BOOLEAN, j_bin1->json_type()); ASSERT_EQ(true, j_bin1->get_boolean()); // check boolean true j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, j_base->get_array_element(i * 4 + 1, j_bin1)); ASSERT_EQ(ObJsonNodeType::J_BOOLEAN, j_bin1->json_type()); ASSERT_EQ(false, j_bin1->get_boolean()); // check null j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, j_base->get_array_element(i * 4 + 2, j_bin1)); ASSERT_EQ(ObJsonNodeType::J_NULL, j_bin1->json_type()); // check string j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, j_base->get_array_element(i * 4 + 3, j_bin1)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin1->json_type()); ObArenaAllocator allocator(ObModIds::TEST); ObJsonBuffer buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_bin1->print(buf, false)); // std::cout << buf.ptr() << std::endl; EXPECT_STREQ(buf.ptr(), "a"); } } void large_test_make_array(ObIAllocator &allocator, ObJsonArray &array) { for (int i = 0; i < 20000; i++) { // add boolean true void *buf = allocator.alloc(sizeof(ObJsonBoolean)); ObJsonBoolean *item1 = new(buf)ObJsonBoolean(true); ASSERT_EQ(OB_SUCCESS, array.append(item1)); // add boolean false buf = allocator.alloc(sizeof(ObJsonBoolean)); ObJsonBoolean *item2 = new(buf)ObJsonBoolean(false); ASSERT_EQ(OB_SUCCESS, array.append(item2)); // add json null buf = allocator.alloc(sizeof(ObJsonNull)); ObJsonNull *item3 = new(buf)ObJsonNull(); ASSERT_EQ(OB_SUCCESS, array.append(item3)); // add json string buf = allocator.alloc(sizeof(ObJsonString)); ObJsonString *item4 = new(buf)ObJsonString("a", 1); ASSERT_EQ(OB_SUCCESS, array.append(item4)); } } TEST_F(TestJsonBin, large_array) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonArray array(&allocator); large_test_make_array(allocator, array); ObIJsonBase *j_base_array = &array; ObIJsonBase *j_bin_array = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_base_array, ObJsonInType::JSON_BIN, j_bin_array)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_bin_array->json_type()); // check val validate_large_array(j_bin_array, 80000); // create new json bin load and validate { ObString raw_bin; j_bin_array->get_raw_binary(raw_bin, &allocator); ObJsonBin new_json_bin(raw_bin.ptr(), raw_bin.length(), &allocator); ASSERT_EQ(OB_SUCCESS, new_json_bin.reset_iter()); ObIJsonBase *j_base_new = &new_json_bin; validate_large_array(j_base_new, 80000); } //allocator.reset(); } TEST_F(TestJsonBin, large_two_depth_array) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonArray array(&allocator); large_test_make_array(allocator, array); ObIJsonBase *wr = &array; ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, wr, ObJsonInType::JSON_BIN, j_bin)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_bin->json_type()); // check val validate_large_array(j_bin, 80000); // make array2 { ObJsonArray array2(&allocator); large_test_make_array(allocator, array2); ObJsonArray array3(&allocator); ASSERT_EQ(OB_SUCCESS, array3.append(&array)); ASSERT_EQ(OB_SUCCESS, array3.append(&array2)); ObIJsonBase *j_base_new = &array3; ObIJsonBase *j_bin_val = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_base_new, ObJsonInType::JSON_BIN, j_bin_val)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_bin_val->json_type()); ObIJsonBase *j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, j_bin_val->get_array_element(0, j_bin1)); validate_large_array(j_bin1, 80000); j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, j_bin_val->get_array_element(1, j_bin1)); validate_large_array(j_bin1, 80000); } //allocator.reset(); } TEST_F(TestJsonBin, large_object_array) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonArray array(&allocator); large_test_make_array(allocator, array); ObIJsonBase *wr = &array; ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, wr, ObJsonInType::JSON_BIN, j_bin)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_bin->json_type()); // check val validate_large_array(j_bin, 80000); // make obj { "a" : array, "b" : "c" } { ObJsonObject obj(&allocator); ASSERT_EQ(OB_SUCCESS, obj.add("a", &array)); ObJsonString temp("c", 1); ASSERT_EQ(OB_SUCCESS, obj.add("b", &temp)); ObIJsonBase *j_base_new = &obj; ObIJsonBase *j_bin_val = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_base_new, ObJsonInType::JSON_BIN, j_bin_val)); ASSERT_EQ(ObJsonNodeType::J_OBJECT, j_bin_val->json_type()); ObIJsonBase *j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, j_bin_val->get_object_value("a", j_bin1)); validate_large_array(j_bin1, 80000); j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, j_bin_val->get_object_value("b", j_bin1)); ObJsonBuffer buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_bin1->print(buf, false)); EXPECT_STREQ(buf.ptr(), "c"); // large obj to raw binary and read raw binary again ObString raw_bin; j_bin_val->get_raw_binary(raw_bin, &allocator); ObJsonBin new_json_bin(raw_bin.ptr(), raw_bin.length(), &allocator); ASSERT_EQ(OB_SUCCESS, new_json_bin.reset_iter()); ObIJsonBase *nnwr = &new_json_bin; j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, nnwr->get_object_value("a", j_bin1)); validate_large_array(j_bin1, 80000); j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, nnwr->get_object_value("b", j_bin1)); buf.reuse(); ASSERT_EQ(OB_SUCCESS, j_bin1->print(buf, false)); EXPECT_STREQ(buf.ptr(), "c"); } //allocator.reset(); } TEST_F(TestJsonBin, large_50_depth_array) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonArray array(&allocator); large_test_make_array(allocator, array); // make 50 depth array constexpr size_t depth = 50; ObJsonArray deeply_nested_array(&allocator); ObJsonArray *curr = &deeply_nested_array; for (int i = 1; i < depth; i++) { void *buf = allocator.alloc(sizeof(ObJsonArray)); ObJsonArray *arr = new(buf)ObJsonArray(&allocator); ASSERT_EQ(OB_SUCCESS, curr->append(arr)); curr = arr; } ASSERT_EQ(OB_SUCCESS, curr->append(&array)); ObIJsonBase *wr = &deeply_nested_array; ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, wr, ObJsonInType::JSON_BIN, j_bin)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_bin->json_type()); const ObIJsonBase *curr_wraper = j_bin; for (int i = 0; i < depth; i++) { ASSERT_EQ(1, curr_wraper->element_count()); ASSERT_EQ(ObJsonNodeType::J_ARRAY, curr_wraper->json_type()); ObIJsonBase *j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, curr_wraper->get_array_element(0, j_bin1)); curr_wraper = j_bin1; } validate_large_array(curr_wraper, 80000); //allocator.reset(); } TEST_F(TestJsonBin, large_50_depth_object) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonArray array(&allocator); large_test_make_array(allocator, array); // make 50 depth array constexpr size_t depth = 50; ObJsonObject deeply_nested_obj(&allocator); ObJsonObject *curr = &deeply_nested_obj; for (int i = 1; i < depth; i++) { void *buf = allocator.alloc(sizeof(ObJsonObject)); ObJsonObject *obj = new(buf)ObJsonObject(&allocator); ASSERT_EQ(OB_SUCCESS, curr->add("ob", obj)); curr = obj; } ASSERT_EQ(OB_SUCCESS, curr->add("ob", &array)); ObIJsonBase *wr = &deeply_nested_obj; ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, wr, ObJsonInType::JSON_BIN, j_bin)); ASSERT_EQ(ObJsonNodeType::J_OBJECT, j_bin->json_type()); const ObIJsonBase *curr_wraper = j_bin; for (int i = 0; i < depth; i++) { ASSERT_EQ(1, curr_wraper->element_count()); ASSERT_EQ(ObJsonNodeType::J_OBJECT, curr_wraper->json_type()); ObIJsonBase *j_bin1 = NULL; ASSERT_EQ(OB_SUCCESS, curr_wraper->get_object_value("ob", j_bin1)); curr_wraper = j_bin1; } validate_large_array(curr_wraper, 80000); //allocator.reset(); } TEST_F(TestJsonBin, large_array_update) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonArray j_arr(&allocator); large_test_make_array(allocator, j_arr); ObIJsonBase *j_tree_arr = &j_arr; ObIJsonBase *j_bin_arr = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_arr, ObJsonInType::JSON_BIN, j_bin_arr)); common::ObString j_text("{ \"greeting\" : [\"test\", 1.1, 2, -10, true, null], \"farewell\" : 2, \"json_text\" : 3 }"); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); ObString lkey("greeting"); bin->lookup(lkey); // use large array update { bin->element(0); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString ele0("test"); ObString data(bin->get_data_length(), bin->get_data()); std::cout << "data:" << data << std::endl; ASSERT_EQ(0, ele0.compare(data)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->update(0, static_cast(j_bin_arr))); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->element(0)); ASSERT_EQ(80000, bin->element_count()); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->update(1, static_cast(j_bin_arr))); ASSERT_TRUE(update_ctx.is_rebuild_all_); ASSERT_EQ(OB_SUCCESS, bin->element(1)); ASSERT_EQ(80000, bin->element_count()); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_ARRAY), actual_type); bin->element(0); ASSERT_EQ(bin->element_count(), 80000); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); bin->element(1); ASSERT_EQ(bin->element_count(), 80000); } //allocator.reset(); } TEST_F(TestJsonBin, large_array_insert) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonArray j_arr(&allocator); large_test_make_array(allocator, j_arr); ObIJsonBase *j_tree_arr = &j_arr; ObIJsonBase *j_bin_arr = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_arr, ObJsonInType::JSON_BIN, j_bin_arr)); common::ObString j_text("{ \"greeting\" : [\"test\", 1.1, 2, -10, true, null], \"farewell\" : 2, \"json_text\" : 3 }"); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); ObString lkey("greeting"); bin->lookup(lkey); // use large array update { bin->element(0); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString ele0("test"); ObString data(bin->get_data_length(), bin->get_data()); std::cout << "data:" << data << std::endl; ASSERT_EQ(0, ele0.compare(data)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->array_insert(0, static_cast(j_bin_arr))); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); ASSERT_EQ(OB_SUCCESS, bin->element(0)); ASSERT_EQ(80000, bin->element_count()); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->array_insert(1, static_cast(j_bin_arr))); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); ASSERT_TRUE(update_ctx.is_rebuild_all_); ASSERT_EQ(OB_SUCCESS, bin->element(1)); ASSERT_EQ(80000, bin->element_count()); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); bin->element(0); ASSERT_EQ(bin->element_count(), 80000); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); bin->element(1); ASSERT_EQ(bin->element_count(), 80000); } //allocator.reset(); } void parse_string_with_length(ObIAllocator *allocator, uint64_t size) { char *str = reinterpret_cast(allocator->alloc(size + 1)); MEMSET(str, 'o', size); str[size] = '\0'; ObJsonString jstr(str, size); ObIJsonBase *j_base = &jstr; ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(allocator, j_base, ObJsonInType::JSON_BIN, j_bin)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin->json_type()); uint64_t data_len = j_bin->get_data_length(); const char *data = j_bin->get_data(); ObString actual(data_len, data); ASSERT_EQ(size, data_len); ASSERT_EQ(0, MEMCMP(str, data, size)); allocator->free(str); } TEST_F(TestJsonBin, test_string_len) { ObArenaAllocator allocator(ObModIds::TEST); parse_string_with_length(&allocator, 0); parse_string_with_length(&allocator, serialization::OB_MAX_V1B); parse_string_with_length(&allocator, serialization::OB_MAX_V2B); parse_string_with_length(&allocator, serialization::OB_MAX_V3B); parse_string_with_length(&allocator, serialization::OB_MAX_V4B); parse_string_with_length(&allocator, serialization::OB_MAX_V4B + 1); // ob_malloc only support 4G here // parse_string_with_length(&allocator, serialization::OB_MAX_V5B); // parse_string_with_length(&allocator, serialization::OB_MAX_V6B); // parse_string_with_length(&allocator, serialization::OB_MAX_V7B); // parse_string_with_length(&allocator, serialization::OB_MAX_V8B); // parse_string_with_length(&allocator, serialization::OB_MAX_V9B); // parse_string_with_length(&allocator, serialization::OB_MAX_V9B + 1); } TEST_F(TestJsonBin, test_binary_replace) { common::ObString j_text("{ \"greeting\" : [\"test\", 1.1, 2, -10, true, null], \"farewell\" : 2, \"json_text\" : 3 }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); uint64_t root_member_count = bin->element_count(); ASSERT_EQ(3, root_member_count); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ObString lkey("greeting"); bin->lookup(lkey); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); uint64_t sub_member_count = bin->element_count(); ASSERT_EQ(6, sub_member_count); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); // "test" --> "hahahahahah" { ASSERT_EQ(OB_SUCCESS, bin->element(0)); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString ele0("test"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ObJsonString j_str("hahahahahah", strlen("hahahahahah")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString objstr; ASSERT_EQ(OB_SUCCESS, bin->raw_binary_at_iter(objstr)); ObJsonBin tmp_bin(objstr.ptr(), objstr.length(), &allocator); ASSERT_EQ(OB_SUCCESS, tmp_bin.reset_iter()); ObIJsonBase *j_tmp_bin = &tmp_bin; ObIJsonBase *j_bin_replace = NULL; ASSERT_EQ(OB_SUCCESS, bin->get_array_element(0, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_str)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 1); bin->element(0); actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString new_ele("hahahahahah"); ObString data1(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, new_ele.compare(data1)); } // "test" --> "hahahahahah" { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->element(0)); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString ele0("hahahahahah"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ObJsonString j_str("hahahahahahaaaa", strlen("hahahahahahaaaa")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString objstr; ASSERT_EQ(OB_SUCCESS, bin->raw_binary_at_iter(objstr)); ObJsonBin tmp_bin(objstr.ptr(), objstr.length(), &allocator); ASSERT_EQ(OB_SUCCESS, tmp_bin.reset_iter()); ObIJsonBase *j_tmp_bin = &tmp_bin; ObIJsonBase *j_bin_replace = NULL; ASSERT_EQ(OB_SUCCESS, bin->get_array_element(0, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_str)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(4, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); bin->element(0); actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_STRING), actual_type); ObString new_ele("hahahahahahaaaa"); ObString data1(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, new_ele.compare(data1)); } // 1.1 --> 3.1415 { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); bin->element(1); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_DOUBLE), actual_type); ASSERT_FLOAT_EQ(1.1, bin->get_double()); ObJsonDouble j_double(3.1415); ObIJsonBase *j_tree_double = &j_double; ObIJsonBase *j_bin_double = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_double, ObJsonInType::JSON_BIN, j_bin_double)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString objstr; ASSERT_EQ(0, bin->raw_binary_at_iter(objstr)); ObJsonBin tmp_bin(objstr.ptr(), objstr.length(), &allocator); ASSERT_EQ(OB_SUCCESS, tmp_bin.reset_iter()); ObIJsonBase *j_tmp_bin = &tmp_bin; ObIJsonBase *j_bin_replace = NULL; ASSERT_EQ(OB_SUCCESS, bin->get_array_element(1, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_double)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(5, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); bin->element(1); actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_DOUBLE), actual_type); ASSERT_FLOAT_EQ(3.1415, bin->get_double()); } // 2 ---> -655666 { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); bin->element(2); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_INT), actual_type); ASSERT_EQ(2, bin->get_uint()); ObJsonInt j_int(-655666); ObIJsonBase *j_tree_int = &j_int; ObIJsonBase *j_bin_int = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_int, ObJsonInType::JSON_BIN, j_bin_int)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString objstr; ASSERT_EQ(0, bin->raw_binary_at_iter(objstr)); ObJsonBin tmp_bin(objstr.ptr(), objstr.length(), &allocator); ASSERT_EQ(OB_SUCCESS, tmp_bin.reset_iter()); ObIJsonBase *j_tmp_bin = &tmp_bin; ObIJsonBase *j_bin_replace = NULL; ASSERT_EQ(OB_SUCCESS, bin->get_array_element(2, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_int)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(7, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); bin->element(2); actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_INT), actual_type); ASSERT_EQ(-655666, bin->get_int()); } // -10 ---> 655666 { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); bin->element(3); uint8_t actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_INT), actual_type); ASSERT_EQ(-10, bin->get_int()); ObJsonUint j_uint(655666); ObIJsonBase *j_tree_uint = &j_uint; ObIJsonBase *j_bin_uint = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_uint, ObJsonInType::JSON_BIN, j_bin_uint)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString objstr; ASSERT_EQ(0, bin->raw_binary_at_iter(objstr)); ObJsonBin tmp_bin(objstr.ptr(), objstr.length(), &allocator); ASSERT_EQ(OB_SUCCESS, tmp_bin.reset_iter()); ObIJsonBase *j_tmp_bin = &tmp_bin; ObIJsonBase *j_bin_replace = NULL; ASSERT_EQ(OB_SUCCESS, bin->get_array_element(3, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_uint)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(9, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); bin->element(3); actual_type = (static_cast(bin->json_type()) & 0x7F); ASSERT_EQ(static_cast(ObJsonNodeType::J_UINT), actual_type); ASSERT_EQ(655666, bin->get_uint()); } } TEST_F(TestJsonBin, test_double_nan) { ObArenaAllocator allocator(ObModIds::TEST); double value = sqrt(-100); std::cout << "origin value: "<< value << std::endl; ObJsonDouble left_val(value); ObIJsonBase *left_base = &left_val; ObIJsonBase *new_bin = NULL; ASSERT_EQ(OB_INVALID_NUMERIC, ObJsonBaseFactory::transform(&allocator, left_base, ObJsonInType::JSON_BIN, new_bin)); } TEST_F(TestJsonBin, test_bin_construct_from_tree) { ObArenaAllocator allocator(ObModIds::TEST); { ObString new_value_str("abcd"); ObJsonString new_value_node(new_value_str.ptr(), new_value_str.length()); ObIJsonBase *j_bin_str = nullptr; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform( &allocator, &new_value_node, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin_str->json_type()); ASSERT_TRUE(j_bin_str->is_bin()); } { ObJsonNull j_null(true); ObIJsonBase *j_tree_null = &j_null; ObIJsonBase *j_bin_null = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_null, ObJsonInType::JSON_BIN, j_bin_null)); ASSERT_EQ(ObJsonNodeType::J_NULL, j_bin_null->json_type()); ASSERT_TRUE(j_bin_null->is_bin()); //ASSERT_EQ(1, j_bin_null); } { ObJsonInt j_int(-655666); ObIJsonBase *j_tree_int = &j_int; ObIJsonBase *j_bin_int = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_int, ObJsonInType::JSON_BIN, j_bin_int)); ASSERT_EQ(ObJsonNodeType::J_INT, j_bin_int->json_type()); ASSERT_TRUE(j_bin_int->is_bin()); } { ObString data("my opaque"); ObJsonOpaque j_opaque(data, ObObjType::ObVarcharType); ObIJsonBase *j_tree_opaque = &j_opaque; ObIJsonBase *j_bin_opaque = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_opaque, ObJsonInType::JSON_BIN, j_bin_opaque)); ASSERT_EQ(ObJsonNodeType::J_OPAQUE, j_bin_opaque->json_type()); ASSERT_TRUE(j_bin_opaque->is_bin()); ASSERT_EQ(ObObjType::ObVarcharType, j_bin_opaque->field_type()); ASSERT_EQ("my opaque", std::string(j_bin_opaque->get_data(), j_bin_opaque->get_data_length())); ObIJsonBase *j_tree_opaque_2 = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_bin_opaque, ObJsonInType::JSON_TREE, j_tree_opaque_2)); ASSERT_EQ(ObJsonNodeType::J_OPAQUE, j_tree_opaque_2->json_type()); ASSERT_TRUE(j_tree_opaque_2->is_tree()); ASSERT_EQ("my opaque", std::string(j_tree_opaque_2->get_data(), j_tree_opaque_2->get_data_length())); } } TEST_F(TestJsonBin, test_bin_construct_from_bin) { ObArenaAllocator allocator(ObModIds::TEST); { common::ObString j_text("{ \"my_str\" : \"hello my_str\", \"my_inline_number\" : 2, \"my_null\" : null, \"my_number\" : 655450}"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ASSERT_EQ(ObJsonNodeType::J_OBJECT, j_bin->json_type()); ASSERT_TRUE(j_bin->is_bin()); ObIJsonBase *child_bin = nullptr; ASSERT_EQ(OB_SUCCESS, j_bin->get_object_value(ObString("my_inline_number"), child_bin)); ASSERT_EQ(2, child_bin->get_int()); ObString raw_bin; ASSERT_EQ(OB_SUCCESS, child_bin->get_raw_binary(raw_bin, &allocator)); } { common::ObString j_text("[\"hello my_str\", 2, null, 655450]"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_bin->json_type()); ASSERT_TRUE(j_bin->is_bin()); } } TEST_F(TestJsonBin, test_bin_construct_from_nested_bin) { ObArenaAllocator allocator(ObModIds::TEST); { common::ObString j_text("{\"my_obj\" : { \"my_str\" : \"hello my_str\", \"my_inline_number\" : 2, \"my_null\" : null, \"my_number\" : 655450}}"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ASSERT_EQ(ObJsonNodeType::J_OBJECT, j_bin->json_type()); ASSERT_TRUE(j_bin->is_bin()); } { common::ObString j_text("{\"my_array\" : [\"hello my_str\", 2, null, 655450]}"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ASSERT_EQ(ObJsonNodeType::J_OBJECT, j_bin->json_type()); ASSERT_TRUE(j_bin->is_bin()); } } TEST_F(TestJsonBin, test_empty_object_seek) { ObArenaAllocator allocator(ObModIds::TEST); { ObString path_str("$.\"data\".\"a\""); ObJsonPath test_path(path_str, &allocator); ASSERT_EQ(OB_SUCCESS, test_path.parse_path()); common::ObString j_text("{\"data\" : {}}"); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ASSERT_EQ(ObJsonNodeType::J_OBJECT, j_bin->json_type()); ASSERT_TRUE(j_bin->is_bin()); ObJsonSeekResult hit; int cnt = test_path.path_node_cnt(); ASSERT_EQ(OB_SUCCESS, j_bin->seek(test_path, cnt, false, false, hit)); ASSERT_EQ(0, hit.size()); } } TEST_F(TestJsonBin, test_empty_array_seek) { ObArenaAllocator allocator(ObModIds::TEST); { ObString path_str("$.\"data[0]\""); ObJsonPath test_path(path_str, &allocator); ASSERT_EQ(OB_SUCCESS, test_path.parse_path()); common::ObString j_text("{\"data\" : []}"); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ASSERT_EQ(ObJsonNodeType::J_OBJECT, j_bin->json_type()); ASSERT_TRUE(j_bin->is_bin()); ObJsonSeekResult hit; int cnt = test_path.path_node_cnt(); ASSERT_EQ(OB_SUCCESS, j_bin->seek(test_path, cnt, false, false, hit)); ASSERT_EQ(0, hit.size()); } } TEST_F(TestJsonBin, test_array_array) { ObArenaAllocator allocator(ObModIds::TEST); { const char *str = "[[\"sfsdfasdfasdfasdfasdfasdfasdfasdf\", \"sdfsdfsdfsdfsdfsdsdfsfsdfsdfsdfsd\"], [\"sfsdfasdfasdfasdfasdfasdfasdfasdf\", \"sdfsdfsdfsdfsdfsdsdfsfsdfsdfsdfsd\"], 217]"; common::ObString j_text(str); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_bin->json_type()); ASSERT_TRUE(j_bin->is_bin()); ObJsonBuffer print_buf(&allocator); ASSERT_EQ(OB_SUCCESS, j_bin->print(print_buf, false)); ASSERT_EQ(std::string(j_text.ptr(), j_text.length()), std::string(print_buf.string().ptr(), print_buf.string().length())); ObString raw_bin; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(raw_bin, &allocator)); ObJsonBin new_bin(raw_bin.ptr(), raw_bin.length(), &allocator); ASSERT_EQ(OB_SUCCESS, new_bin.reset_iter()); print_buf.reset(); ASSERT_EQ(OB_SUCCESS, new_bin.print(print_buf, false)); ASSERT_EQ(std::string(j_text.ptr(), j_text.length()), std::string(print_buf.string().ptr(), print_buf.string().length())); } } TEST_F(TestJsonBin, test_bin_insert) { common::ObString j_text("{ \"greeting\" : [\"test\", 1.1, 2, -10, true, null], \"farewell\" : 2, \"json_text\" : 3 }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin& bin = *static_cast(j_bin); //(result.ptr(), result.length(), &allocator); bin.set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, bin.reset_iter()); ASSERT_EQ(3, bin.element_count()); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin.json_type()); ObString lkey("greeting"); bin.lookup(lkey); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin.json_type()); ASSERT_EQ(6, bin.element_count()); ObString new_value_str("abcd"); ObJsonString new_value_node(new_value_str.ptr(), new_value_str.length()); ObIJsonBase *j_bin_str = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform( &allocator, &new_value_node, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin_str->json_type()); ASSERT_TRUE(j_bin_str->is_bin()); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, &bin)); ObJsonBinUpdateCtx &update_ctx = *bin.get_update_ctx(); ASSERT_EQ(OB_SUCCESS, bin.array_insert(3, j_bin_str)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin.json_type()); ASSERT_EQ(7, bin.element_count()); ASSERT_EQ(OB_SUCCESS, bin.element(3)); ASSERT_EQ(ObJsonNodeType::J_STRING, bin.json_type()); ASSERT_EQ(std::string(new_value_str.ptr(), new_value_str.length()), std::string(bin.get_data(), bin.get_data_length())); } TEST_F(TestJsonBin, test_inline_replace) { common::ObString j_text("{ \"name\" : \"Mike\", \"age\" : 30, \"ids\" : [1, 200, 3 , 400, true, 100.1, null, 20000, false] }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); uint64_t root_member_count = bin->element_count(); ASSERT_EQ(3, root_member_count); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); { ObString name_key("name"); ASSERT_EQ(OB_SUCCESS, bin->lookup(name_key)); ASSERT_EQ(ObJsonNodeType::J_STRING, bin->json_type()); ObString ele0("Mike"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ObJsonNull j_null(true); ObIJsonBase *j_tree_null = &j_null; ObIJsonBase *j_bin_null = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_null, ObJsonInType::JSON_BIN, j_bin_null)); ASSERT_EQ(ObJsonNodeType::J_NULL, j_bin_null->json_type()); ASSERT_TRUE(j_bin_null->is_bin()); ObIJsonBase *j_bin_replace = nullptr; ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->get_object_value(name_key, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_null)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(1, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->lookup(name_key)); ASSERT_EQ(ObJsonNodeType::J_NULL, bin->json_type()); } { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString age_key("age"); ASSERT_EQ(OB_SUCCESS, bin->lookup(age_key)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_EQ(30, bin->get_int()); ObJsonInt j_int(35); ObIJsonBase *j_tree_int = &j_int; ObIJsonBase *j_bin_int = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_int, ObJsonInType::JSON_BIN, j_bin_int)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObIJsonBase *j_bin_replace = nullptr; ASSERT_EQ(OB_SUCCESS, bin->get_object_value(age_key, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_int)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->lookup(age_key)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_EQ(j_int.get_int(), bin->get_int()); } { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString ids_key("ids"); ASSERT_EQ(OB_SUCCESS, bin->lookup(ids_key)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); ASSERT_EQ(9, bin->element_count()); { ASSERT_EQ(OB_SUCCESS, bin->element(0)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_EQ(1, bin->get_int()); ObJsonInt j_int(15); ObIJsonBase *j_tree_int = &j_int; ObIJsonBase *j_bin_int = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_int, ObJsonInType::JSON_BIN, j_bin_int)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObIJsonBase *j_bin_replace = nullptr; ASSERT_EQ(OB_SUCCESS, bin->get_array_element(0, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_int)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(3, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->element(0)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_EQ(j_int.get_int(), bin->get_int()); } } } TEST_F(TestJsonBin, test_inplace_replace) { common::ObString j_text("{ \"name\" : \"Mike\", \"money\" : 3000.5, \"ids\" : [1, 200, 3 , 400, true, 100.1, null, 20000, false] }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); uint64_t root_member_count = bin->element_count(); ASSERT_EQ(3, root_member_count); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); { ObString name_key("name"); ASSERT_EQ(OB_SUCCESS, bin->lookup(name_key)); ASSERT_EQ(ObJsonNodeType::J_STRING, bin->json_type()); ObString ele0("Mike"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ObJsonString j_str("John", strlen("John")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin_str->json_type()); ASSERT_TRUE(j_bin_str->is_bin()); ObIJsonBase *j_bin_replace = nullptr; ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->get_object_value(name_key, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_str)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(1, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->lookup(name_key)); ASSERT_EQ(ObJsonNodeType::J_STRING, bin->json_type()); ObString ele1("John"); ObString data1(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele1.compare(data1)); } { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString money_key("money"); ASSERT_EQ(OB_SUCCESS, bin->lookup(money_key)); ASSERT_EQ(ObJsonNodeType::J_DOUBLE, bin->json_type()); ASSERT_FLOAT_EQ(3000.5, bin->get_double()); ObJsonDouble j_double(41234.5); ObIJsonBase *j_tree_double = &j_double; ObIJsonBase *j_bin_double = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_double, ObJsonInType::JSON_BIN, j_bin_double)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObIJsonBase *j_bin_replace = nullptr; ASSERT_EQ(OB_SUCCESS, bin->get_object_value(money_key, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_double)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->lookup(money_key)); ASSERT_EQ(ObJsonNodeType::J_DOUBLE, bin->json_type()); ASSERT_FLOAT_EQ(j_double.get_double(), bin->get_double()); } { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString ids_key("ids"); ASSERT_EQ(OB_SUCCESS, bin->lookup(ids_key)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); ASSERT_EQ(9, bin->element_count()); { ASSERT_EQ(OB_SUCCESS, bin->element(7)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_EQ(20000, bin->get_int()); ObJsonInt j_int(300); ObIJsonBase *j_tree_int = &j_int; ObIJsonBase *j_bin_int = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_int, ObJsonInType::JSON_BIN, j_bin_int)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObIJsonBase *j_bin_replace = nullptr; ASSERT_EQ(OB_SUCCESS, bin->get_array_element(7, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_int)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(3, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->element(7)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_EQ(j_int.get_int(), bin->get_int()); } } } TEST_F(TestJsonBin, test_append_replace) { common::ObString j_text("{ \"name\" : \"Mike\", \"age\" : 30, \"ids\" : [1, 200, 3 , 400, true, 100.1, null, 20000, false] }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); uint64_t root_member_count = bin->element_count(); ASSERT_EQ(3, root_member_count); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); { ObString name_key("name"); ASSERT_EQ(OB_SUCCESS, bin->lookup(name_key)); ASSERT_EQ(ObJsonNodeType::J_STRING, bin->json_type()); ObString ele0("Mike"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ObJsonString j_str("JohnSnow", strlen("JohnSnow")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin_str->json_type()); ASSERT_TRUE(j_bin_str->is_bin()); ObIJsonBase *j_bin_replace = nullptr; ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->get_object_value(name_key, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_str)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->lookup(name_key)); ASSERT_EQ(ObJsonNodeType::J_STRING, bin->json_type()); ObString ele1("JohnSnow"); ObString data1(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele1.compare(data1)); } { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString age_key("age"); ASSERT_EQ(OB_SUCCESS, bin->lookup(age_key)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_FLOAT_EQ(30, bin->get_int()); ObJsonInt j_int(3000); ObIJsonBase *j_tree_int = &j_int; ObIJsonBase *j_bin_int = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_int, ObJsonInType::JSON_BIN, j_bin_int)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObIJsonBase *j_bin_replace = nullptr; ASSERT_EQ(OB_SUCCESS, bin->get_object_value(age_key, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_int)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(4, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->lookup(age_key)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_FLOAT_EQ(j_int.get_int(), bin->get_int()); } { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObString ids_key("ids"); ASSERT_EQ(OB_SUCCESS, bin->lookup(ids_key)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); ASSERT_EQ(9, bin->element_count()); { ASSERT_EQ(OB_SUCCESS, bin->element(4)); ASSERT_EQ(ObJsonNodeType::J_BOOLEAN, bin->json_type()); ASSERT_TRUE(bin->get_boolean()); ObJsonInt j_int(300); ObIJsonBase *j_tree_int = &j_int; ObIJsonBase *j_bin_int = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_int, ObJsonInType::JSON_BIN, j_bin_int)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ObIJsonBase *j_bin_replace = nullptr; ASSERT_EQ(OB_SUCCESS, bin->get_array_element(4, j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_int)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(6, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->element(4)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_EQ(j_int.get_int(), bin->get_int()); } } } TEST_F(TestJsonBin, test_remove_diff) { common::ObString j_text("{ \"name\" : \"Mike\", \"age\" : 30, \"ids\" : [1, 200, 3 , 400, true, 100.1, null, 20000, false] }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); uint64_t root_member_count = bin->element_count(); ASSERT_EQ(3, root_member_count); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); { ObString name_key("name"); ASSERT_EQ(OB_SUCCESS, bin->lookup(name_key)); ASSERT_EQ(ObJsonNodeType::J_STRING, bin->json_type()); ObString ele0("Mike"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->remove(name_key)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(1, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SEARCH_NOT_FOUND, bin->lookup(name_key)); } { ObString age_key("age"); ASSERT_EQ(OB_SUCCESS, bin->lookup(age_key)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_FLOAT_EQ(30, bin->get_int()); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->remove(age_key)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SEARCH_NOT_FOUND, bin->lookup(age_key)); } { ObString ids_key("ids"); ASSERT_EQ(OB_SUCCESS, bin->lookup(ids_key)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); ASSERT_EQ(9, bin->element_count()); { ASSERT_EQ(OB_SUCCESS, bin->element(4)); ASSERT_EQ(ObJsonNodeType::J_BOOLEAN, bin->json_type()); ASSERT_TRUE(bin->get_boolean()); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->remove(4)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(3, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->element(4)); ASSERT_EQ(ObJsonNodeType::J_DOUBLE, bin->json_type()); ASSERT_EQ(100.1, bin->get_double()); } { ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->element(4)); ASSERT_EQ(ObJsonNodeType::J_DOUBLE, bin->json_type()); ASSERT_EQ(100.1, bin->get_double()); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->remove(4)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(4, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->element(4)); ASSERT_EQ(ObJsonNodeType::J_NULL, bin->json_type()); } } } TEST_F(TestJsonBin, test_insert_diff) { common::ObString j_text("{ \"name\" : \"Mike\", \"age\" : 30, \"ids\" : [1, 200, 3 , 400, true, 100.1, null, 20000, false] }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); uint64_t root_member_count = bin->element_count(); ASSERT_EQ(3, root_member_count); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); { ObString sex_key("sex"); ObJsonString j_str("male", strlen("male")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin_str->json_type()); ASSERT_TRUE(j_bin_str->is_bin()); ASSERT_EQ(OB_SUCCESS, bin->object_add(sex_key, j_bin_str)); ASSERT_EQ(OB_SUCCESS, bin->lookup(sex_key)); ASSERT_EQ(ObJsonNodeType::J_STRING, bin->json_type()); ObString ele0("male"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); //LOG_INFO("diff", K(update_ctx.cur_node_diff_)); ASSERT_TRUE(update_ctx.is_rebuild_all_); update_ctx.is_rebuild_all_ = false; ObString curr_data; ASSERT_EQ(OB_SUCCESS, update_ctx.current_data(curr_data)); ASSERT_EQ(OB_SUCCESS, ob_write_string(allocator, curr_data, result)); } { ObString ids_key("ids"); ASSERT_EQ(OB_SUCCESS, bin->lookup(ids_key)); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); ASSERT_EQ(9, bin->element_count()); { ASSERT_EQ(OB_SUCCESS, bin->element(0)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_EQ(1, bin->get_int()); ObJsonInt j_int(300); ObIJsonBase *j_tree_int = &j_int; ObIJsonBase *j_bin_int = NULL; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_int, ObJsonInType::JSON_BIN, j_bin_int)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->array_insert(0, j_bin_int)); ASSERT_EQ(OB_SUCCESS, bin->element(0)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_EQ(j_int.get_int(), bin->get_int()); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); //LOG_INFO("diff", K(update_ctx.cur_node_diff_)); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); ASSERT_FALSE(update_ctx.is_rebuild_all_); check_diff_valid(allocator, result, update_ctx); } ASSERT_EQ(10, bin->element_count()); { ASSERT_EQ(OB_SUCCESS, bin->element(3)); ASSERT_EQ(ObJsonNodeType::J_INT, bin->json_type()); ASSERT_EQ(3, bin->get_int()); ObJsonString j_str("weight", strlen("weight")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin_str->json_type()); ASSERT_TRUE(j_bin_str->is_bin()); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->array_insert(3, j_bin_str)); ASSERT_EQ(OB_SUCCESS, bin->element(3)); ASSERT_EQ(ObJsonNodeType::J_STRING, bin->json_type()); ObString ele0("weight"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); //LOG_INFO("diff", K(update_ctx.cur_node_diff_)); ASSERT_EQ(4, update_ctx.binary_diffs_.count()); ASSERT_FALSE(update_ctx.is_rebuild_all_); check_diff_valid(allocator, result, update_ctx); } ASSERT_EQ(11, bin->element_count()); { ASSERT_EQ(OB_SUCCESS, bin->element(10)); ASSERT_EQ(ObJsonNodeType::J_BOOLEAN, bin->json_type()); ASSERT_FALSE(bin->get_boolean()); ObJsonString j_str("weight2", strlen("weight2")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin_str->json_type()); ASSERT_TRUE(j_bin_str->is_bin()); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); ASSERT_EQ(OB_SUCCESS, bin->array_insert(10, j_bin_str)); ASSERT_EQ(OB_SUCCESS, bin->element(10)); ASSERT_EQ(ObJsonNodeType::J_STRING, bin->json_type()); ObString ele0("weight2"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); //LOG_INFO("diff", K(update_ctx.cur_node_diff_)); ASSERT_EQ(6, update_ctx.binary_diffs_.count()); ASSERT_FALSE(update_ctx.is_rebuild_all_); check_diff_valid(allocator, result, update_ctx); } ASSERT_EQ(12, bin->element_count()); { ASSERT_EQ(OB_SUCCESS, bin->element(11)); ASSERT_EQ(ObJsonNodeType::J_BOOLEAN, bin->json_type()); ASSERT_FALSE(bin->get_boolean()); } } } TEST_F(TestJsonBin, test_replace_parent_and_child) { common::ObString j_text("{ \"name\" : \"Mike\", \"age\" : 30, \"order\" : {\"stcok\" : 1000, \"name\": \"myxxxx\"} }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); // root ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); uint64_t root_member_count = bin->element_count(); ASSERT_EQ(3, root_member_count); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); { ObString order_key("order"); ASSERT_EQ(OB_SUCCESS, bin->lookup(order_key)); ASSERT_EQ(ObJsonNodeType::J_OBJECT, bin->json_type()); ASSERT_EQ(2, bin->element_count()); { ObJsonString j_str("weightxxxxx", strlen("weightxxxxx")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin_str->json_type()); ASSERT_TRUE(j_bin_str->is_bin()); ObIJsonBase *j_bin_replace = nullptr; ASSERT_EQ(OB_SUCCESS, bin->get_object_value(ObString("name"), j_bin_replace)); ASSERT_EQ(OB_SUCCESS, bin->replace(j_bin_replace, j_bin_str)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(2, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->lookup(ObString("name"))); ASSERT_EQ(ObJsonNodeType::J_STRING, bin->json_type()); ObString ele0("weightxxxxx"); ObString data(bin->get_data_length(), bin->get_data()); ASSERT_EQ(0, ele0.compare(data)); ASSERT_EQ(OB_SUCCESS, bin->move_parent_iter()); } } } TEST_F(TestJsonBin, test_decimal) { ObArenaAllocator allocator(ObModIds::TEST); number::ObNumber res_nmb; ObString nmb_str("3.14"); ObPrecision res_precision = -1; ObScale res_scale = -1; ASSERT_EQ(OB_SUCCESS, res_nmb.from_sci_opt(nmb_str.ptr(), nmb_str.length(), allocator, &res_precision, &res_scale)); ObJsonDecimal j_dec(res_nmb, res_precision, res_scale); ObIJsonBase *j_tree_dec = &j_dec; ObIJsonBase *j_bin_dec = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_dec, ObJsonInType::JSON_BIN, j_bin_dec)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin_dec->get_raw_binary(result, &allocator)); ObJsonBin bin(result.ptr(), result.length(), &allocator); ASSERT_EQ(OB_SUCCESS, bin.reset_iter()); } TEST_F(TestJsonBin, test_double) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonDouble j_double(3.1415); ObIJsonBase *j_tree_double = &j_double; ObIJsonBase *j_bin_double = NULL; // TREE -> BIN ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_double, ObJsonInType::JSON_BIN, j_bin_double)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin_double->get_raw_binary(result, &allocator)); ObJsonBin bin(result.ptr(), result.length(), &allocator); ASSERT_EQ(OB_SUCCESS, bin.reset_iter()); } TEST_F(TestJsonBin, test_get_parent) { ObArenaAllocator allocator(ObModIds::TEST); { common::ObString j_text("{ \"name\" : \"Mike\", \"age\" : 30, \"order\" : {\"stcok\" : 100, \"name\": \"myxxxx\"} }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); common::ObString path_str("$.order.stcok"); ObJsonPath test_path(path_str, &allocator); ASSERT_EQ(OB_SUCCESS, test_path.parse_path()); ObJsonSeekResult hit; int cnt = test_path.path_node_cnt(); ASSERT_EQ(OB_SUCCESS, j_bin->seek(test_path, cnt, false, false, hit)); ASSERT_EQ(1, hit.size()); ObIJsonBase *j_child_bin = hit[0]; ObIJsonBase *j_parent_bin = nullptr; ASSERT_EQ(OB_SUCCESS, j_child_bin->get_parent(j_parent_bin)); ASSERT_NE(nullptr, j_parent_bin); ASSERT_TRUE(j_parent_bin->is_bin()); ObJsonString j_str("weightxxxxx", strlen("weightxxxxx")); ObIJsonBase *j_tree_str = &j_str; ObIJsonBase *j_bin_str = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_str, ObJsonInType::JSON_BIN, j_bin_str)); ASSERT_EQ(ObJsonNodeType::J_STRING, j_bin_str->json_type()); ASSERT_TRUE(j_bin_str->is_bin()); ASSERT_EQ(OB_SUCCESS, j_parent_bin->replace(j_child_bin, j_bin_str)); ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); } { common::ObString j_text("{ \"name\" : \"Mike\", \"age\" : 30, \"order\" : {\"stcok\" : 100, \"name\": \"myxxxx\"} }"); ObArenaAllocator allocator(ObModIds::TEST); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); common::ObString path_str("$.age"); ObJsonPath test_path(path_str, &allocator); ASSERT_EQ(OB_SUCCESS, test_path.parse_path()); ObJsonSeekResult hit; int cnt = test_path.path_node_cnt(); ASSERT_EQ(OB_SUCCESS, j_bin->seek(test_path, cnt, false, false, hit)); ASSERT_EQ(1, hit.size()); ObIJsonBase *j_child_bin = hit[0]; ObIJsonBase *j_parent_bin = nullptr; ASSERT_EQ(OB_SUCCESS, j_child_bin->get_parent(j_parent_bin)); ASSERT_NE(nullptr, j_parent_bin); ASSERT_TRUE(j_parent_bin->is_bin()); ObJsonInt j_int(200); ObIJsonBase *j_tree_int = &j_int; ObIJsonBase *j_bin_int = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::transform(&allocator, j_tree_int, ObJsonInType::JSON_BIN, j_bin_int)); ASSERT_TRUE(j_bin_int->is_bin()); ASSERT_EQ(OB_SUCCESS, j_parent_bin->replace(j_child_bin, j_bin_int)); ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); } } TEST_F(TestJsonBin, test_type) { ObArenaAllocator allocator(ObModIds::TEST); ObJsonObject tree(&allocator); ObJsonBin bin(&allocator); // ObJsonNull j_null_true(true); ObJsonNull j_null_false(false); // ASSERT_EQ(OB_SUCCESS, tree.add("j_null_true", &j_null_true)); ASSERT_EQ(OB_SUCCESS, tree.add("j_null_false", &j_null_false)); ObJsonBoolean j_bool_false(false); ASSERT_EQ(OB_SUCCESS, tree.add("j_bool_false", &j_bool_false)); ObJsonBoolean j_bool_true(false); ASSERT_EQ(OB_SUCCESS, tree.add("j_bool_true", &j_bool_true)); ObJsonInt j_int_0(0); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_0", &j_int_0)); ObJsonInt j_int_1(1); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_1", &j_int_1)); ObJsonInt j_int_2(3); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_2", &j_int_2)); ObJsonInt j_int_3(100); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_3", &j_int_3)); ObJsonInt j_int_4(256); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_4", &j_int_4)); ObJsonInt j_int_5(6000); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_5", &j_int_5)); ObJsonInt j_int_6(4234234); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_6", &j_int_6)); ObJsonInt j_int_7(4234234123214321421L); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_7", &j_int_7)); ObJsonInt j_int_8(-1); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_8", &j_int_8)); ObJsonInt j_int_9(-3); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_9", &j_int_9)); ObJsonInt j_int_10(-100); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_10", &j_int_10)); ObJsonInt j_int_11(-256); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_11", &j_int_11)); ObJsonInt j_int_12(-6000); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_12", &j_int_12)); ObJsonInt j_int_13(-4234234); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_13", &j_int_13)); ObJsonInt j_int_14(-4234234123214321421L); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_14", &j_int_14)); ObJsonOInt j_int_15(INT_MIN); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_15", &j_int_15)); ObJsonOInt j_int_16(INT_MAX); ASSERT_EQ(OB_SUCCESS, tree.add("j_int_16", &j_int_16)); ObJsonOInt j_oint_0(0); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_0", &j_oint_0)); ObJsonOInt j_oint_1(1); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_1", &j_oint_1)); ObJsonOInt j_oint_2(3); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_2", &j_oint_2)); ObJsonOInt j_oint_3(100); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_3", &j_oint_3)); ObJsonOInt j_oint_4(256); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_4", &j_oint_4)); ObJsonOInt j_oint_5(6000); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_6", &j_oint_5)); ObJsonOInt j_oint_6(4234234); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_6", &j_oint_6)); ObJsonOInt j_oint_7(4234234123214321421L); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_7", &j_oint_7)); ObJsonOInt j_oint_8(-1); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_8", &j_oint_8)); ObJsonOInt j_oint_9(-3); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_9", &j_oint_9)); ObJsonOInt j_oint_10(-100); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_10", &j_oint_10)); ObJsonOInt j_oint_11(-256); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_11", &j_oint_11)); ObJsonOInt j_oint_12(-6000); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_12", &j_oint_12)); ObJsonOInt j_oint_13(-4234234); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_13", &j_oint_13)); ObJsonOInt j_oint_14(-4234234123214321421L); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_14", &j_oint_14)); ObJsonOInt j_oint_15(INT_MIN); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_15", &j_oint_15)); ObJsonOInt j_oint_16(INT_MAX); ASSERT_EQ(OB_SUCCESS, tree.add("j_oint_16", &j_oint_16)); ObJsonUint j_uint_0(0); ASSERT_EQ(OB_SUCCESS, tree.add("j_uint_0", &j_uint_0)); ObJsonUint j_uint_1(1); ASSERT_EQ(OB_SUCCESS, tree.add("j_uint_1", &j_uint_1)); ObJsonUint j_uint_2(3); ASSERT_EQ(OB_SUCCESS, tree.add("j_uint_2", &j_uint_2)); ObJsonUint j_uint_3(100); ASSERT_EQ(OB_SUCCESS, tree.add("j_uint_3", &j_uint_3)); ObJsonUint j_uint_4(256); ASSERT_EQ(OB_SUCCESS, tree.add("j_uint_4", &j_uint_4)); ObJsonUint j_uint_5(6000); ASSERT_EQ(OB_SUCCESS, tree.add("j_uint_5", &j_uint_5)); ObJsonUint j_uint_6(4234234); ASSERT_EQ(OB_SUCCESS, tree.add("j_uint_6", &j_uint_6)); ObJsonUint j_uint_7(4234234123214321421L); ASSERT_EQ(OB_SUCCESS, tree.add("j_uint_7", &j_uint_7)); ObJsonUint j_uint_8(UINT_MAX); ASSERT_EQ(OB_SUCCESS, tree.add("j_uint_8", &j_uint_8)); ObJsonUint j_uint_9(ULLONG_MAX); ASSERT_EQ(OB_SUCCESS, tree.add("j_uint_9", &j_uint_9)); ObJsonOLong j_olong_0(0); ASSERT_EQ(OB_SUCCESS, tree.add("j_olong_0", &j_olong_0)); ObJsonOLong j_olong_1(1); ASSERT_EQ(OB_SUCCESS, tree.add("j_olong_1", &j_olong_1)); ObJsonOLong j_olong_2(3); ASSERT_EQ(OB_SUCCESS, tree.add("j_olong_2", &j_olong_2)); ObJsonOLong j_olong_3(100); ASSERT_EQ(OB_SUCCESS, tree.add("j_olong_3", &j_olong_3)); ObJsonOLong j_olong_4(256); ASSERT_EQ(OB_SUCCESS, tree.add("j_olong_4", &j_olong_4)); ObJsonOLong j_olong_5(6000); ASSERT_EQ(OB_SUCCESS, tree.add("j_olong_5", &j_olong_5)); ObJsonOLong j_olong_6(4234234); ASSERT_EQ(OB_SUCCESS, tree.add("j_olong_6", &j_olong_6)); ObJsonOLong j_olong_7(4234234123214321421L); ASSERT_EQ(OB_SUCCESS, tree.add("j_olong_7", &j_olong_7)); ObJsonOLong j_olong_8(UINT_MAX); ASSERT_EQ(OB_SUCCESS, tree.add("j_olong_8", &j_olong_8)); ObJsonOLong j_olong_9(ULLONG_MAX); ASSERT_EQ(OB_SUCCESS, tree.add("j_olong_9", &j_olong_9)); number::ObNumber res_nmb; ObString nmb_str("3.14"); ObPrecision res_precision = -1; ObScale res_scale = -1; ASSERT_EQ(OB_SUCCESS, res_nmb.from_sci_opt(nmb_str.ptr(), nmb_str.length(), allocator, &res_precision, &res_scale)); ObJsonDecimal j_dec_1(res_nmb, res_precision, res_scale); ASSERT_EQ(OB_SUCCESS, tree.add("j_dec_1", &j_dec_1)); nmb_str.assign_ptr("-1.1234e9", STRLEN("-1.1234e9")); res_precision = 10; res_scale = 4; ASSERT_EQ(OB_SUCCESS, res_nmb.from_sci_opt(nmb_str.ptr(), nmb_str.length(), allocator, &res_precision, &res_scale)); ObJsonDecimal j_dec_2(res_nmb, res_precision, res_scale); ASSERT_EQ(OB_SUCCESS, tree.add("j_dec_2", &j_dec_2)); ObJsonDouble j_double_0(0); ASSERT_EQ(OB_SUCCESS, tree.add("j_double_0", &j_double_0)); ObJsonDouble j_double_1(1.12222222222222); ASSERT_EQ(OB_SUCCESS, tree.add("j_double_1", &j_double_1)); ObJsonDouble j_double_2(112132132131223.32132132132131232122); ASSERT_EQ(OB_SUCCESS, tree.add("j_double_2", &j_double_2)); ObJsonDouble j_double_3(1.121321321321321e9); ASSERT_EQ(OB_SUCCESS, tree.add("j_double_3", &j_double_3)); ObJsonDouble j_double_4(0.1212e-9); ASSERT_EQ(OB_SUCCESS, tree.add("j_double_4", &j_double_4)); ObJsonDouble j_double_5(-0.12213222e-9); ASSERT_EQ(OB_SUCCESS, tree.add("j_double_5", &j_double_5)); ObJsonDouble j_double_6(-1.21321321321321); ASSERT_EQ(OB_SUCCESS, tree.add("j_double_6", &j_double_6)); ObJsonDouble j_double_7(-21321321321.32132132132131232122); ASSERT_EQ(OB_SUCCESS, tree.add("j_double_7", &j_double_7)); ObJsonDouble j_double_8(2.12213212222); ASSERT_EQ(OB_SUCCESS, tree.add("j_double_8", &j_double_8)); ObJsonOFloat j_ofloat_0(0); ASSERT_EQ(OB_SUCCESS, tree.add("j_ofloat_0", &j_ofloat_0)); ObJsonOFloat j_ofloat_1(1.12222222222222); ASSERT_EQ(OB_SUCCESS, tree.add("j_ofloat_1", &j_ofloat_1)); ObJsonOFloat j_ofloat_2(112132132131223.32132132132131232122); ASSERT_EQ(OB_SUCCESS, tree.add("j_ofloat_2", &j_ofloat_2)); ObJsonOFloat j_ofloat_3(1.121321321321321e9); ASSERT_EQ(OB_SUCCESS, tree.add("j_ofloat_3", &j_ofloat_3)); ObJsonOFloat j_ofloat_4(0.1212e-9); ASSERT_EQ(OB_SUCCESS, tree.add("j_ofloat_4", &j_ofloat_4)); ObJsonOFloat j_ofloat_5(-0.12213222e-9); ASSERT_EQ(OB_SUCCESS, tree.add("j_ofloat_5", &j_ofloat_5)); ObJsonOFloat j_ofloat_6(-1.21321321321321); ASSERT_EQ(OB_SUCCESS, tree.add("j_ofloat_6", &j_ofloat_6)); ObJsonOFloat j_ofloat_7(-21321321321.32132132132131232122); ASSERT_EQ(OB_SUCCESS, tree.add("j_ofloat_7", &j_ofloat_7)); ObJsonOFloat j_ofloat_8(2.12213212222); ASSERT_EQ(OB_SUCCESS, tree.add("j_ofloat_8", &j_ofloat_8)); ObJsonOpaque j_opaque_0(ObString("my opaque"), ObObjType::ObVarcharType); ASSERT_EQ(OB_SUCCESS, tree.add("j_opaque_0", &j_opaque_0)); ObTime ob_time_0(DT_TYPE_DATETIME); ASSERT_EQ(OB_SUCCESS, ObTimeConverter::datetime_to_ob_time(946684800000000, NULL, ob_time_0)); ObJsonDatetime j_datetime_0(ObJsonNodeType::J_DATETIME, ob_time_0); ASSERT_EQ(OB_SUCCESS, tree.add("j_datetime_0", &j_datetime_0)); ObIJsonBase *j_tree = &tree; ObIJsonBase *j_bin = &bin; ASSERT_EQ(OB_SUCCESS, bin.parse_tree(&tree)); ObJsonBuffer j_tree_buffer(&allocator); ObJsonBuffer j_bin_buffer(&allocator); ASSERT_EQ(OB_SUCCESS, j_tree->print(j_tree_buffer, false)); ASSERT_EQ(OB_SUCCESS, j_bin->print(j_bin_buffer, false)); ObString j_tree_str = j_tree_buffer.string(); ObString j_bin_str = j_bin_buffer.string(); ASSERT_EQ(std::string(j_tree_str.ptr(), j_tree_str.length()), std::string(j_bin_str.ptr(), j_bin_str.length())); ObJsonBuffer j_tree_buffer_2(&allocator); ObJsonNode *tree_2 = nullptr; ASSERT_EQ(OB_SUCCESS, bin.to_tree(tree_2)); ASSERT_EQ(OB_SUCCESS, tree_2->print(j_tree_buffer_2, false)); ObString j_tree_str_2 = j_tree_buffer_2.string(); ASSERT_EQ(std::string(j_tree_str.ptr(), j_tree_str.length()), std::string(j_tree_str_2.ptr(), j_tree_str_2.length())); ObJsonBuffer j_bin_buffer_2(&allocator); ASSERT_EQ(OB_SUCCESS, bin.rebuild(j_bin_buffer_2)); ObJsonBin bin2; ObJsonBinCtx bin_ctx_2; ASSERT_EQ(OB_SUCCESS, bin2.reset(j_bin_buffer_2.string(), 0, &bin_ctx_2)); ObJsonBuffer j_bin_buffer_2_1(&allocator); ASSERT_EQ(OB_SUCCESS, bin2.print(j_bin_buffer_2_1, false)); ObString j_bin_str_2 = j_bin_buffer_2_1.string(); ASSERT_EQ(std::string(j_tree_str.ptr(), j_tree_str.length()), std::string(j_bin_str_2.ptr(), j_bin_str_2.length())); } static void json_set(ObIAllocator& allocator, ObString& j_text, std::vector> &updates) { ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ObJsonPathCache path_cache(&allocator); for (int i = 0 ; i < updates.size(); ++i) { ObString& path = updates[i].first; ObString& value = updates[i].second; ObJsonPath* json_path = nullptr; ObIJsonBase *j_new_node = nullptr; int path_idx = path_cache.size(); ASSERT_EQ(OB_SUCCESS, path_cache.find_and_add_cache(json_path, path, path_idx)); ASSERT_EQ(path_cache.path_stat_at(path_idx), ObPathParseStat::OK_NOT_NULL); ObJsonSeekResult hit; ASSERT_EQ(OB_SUCCESS, j_bin->seek(*json_path, json_path->path_node_cnt(), true, false, hit)); ASSERT_EQ(1, hit.size()); ObIJsonBase *j_parent = nullptr; ObIJsonBase *j_old_node = hit[0]; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, value, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_new_node)); ASSERT_EQ(OB_SUCCESS, j_old_node->get_parent(j_parent)); if(OB_NOT_NULL(j_parent)) { ASSERT_EQ(OB_SUCCESS, j_parent->replace(j_old_node, j_new_node)); } else { ASSERT_EQ(OB_SUCCESS, j_bin->replace(j_old_node, j_new_node)); } } check_diff_valid(allocator, result, update_ctx); check_json_diff_valid(allocator, j_text, update_ctx, 2); } TEST_F(TestJsonBin, test_nested_append_update) { ObArenaAllocator allocator(ObModIds::TEST); common::ObString j_text("{ \"name\" : \"Mike\", \"age\" : 30, \"like\" : [] , \"name1\" : \"Mike1\", \"name2\" : \"Mike2\",\"name3\" : \"Mike3\",\"name4\" : \"Mike4\",\"name5\" : \"Mike5\"}"); std::vector> updates; updates.push_back({ObString("$.like"), ObString("[1, 2, 3]")}); updates.push_back({ObString("$.like[1]"), ObString("{\"K\":\"V\"}")}); json_set(allocator, j_text, updates); } TEST_F(TestJsonBin, test_nested_append_update_2) { ObArenaAllocator allocator(ObModIds::TEST); common::ObString j_text("{ \"name\" : \"Mike\", \"age\" : 30, \"like\" : [] , \"name1\" : \"Mike1\", \"name2\" : \"Mike2\",\"name3\" : \"Mike3\",\"name4\" : \"Mike4\",\"name5\" : \"Mike5\"}"); std::vector> updates; updates.push_back({ObString("$.like"), ObString("[\"x\", [\"a\", \"b\", \"c\"], \"z\"]")}); updates.push_back({ObString("$.like[1][1]"), ObString("{\"K\":\"V\"}")}); json_set(allocator, j_text, updates); } TEST_F(TestJsonBin, test_array_remove) { ObArenaAllocator allocator(ObModIds::TEST); common::ObString j_text("{ \"name\" : \"Mike\", \"age\" : 30, \"like\" : [1, 2, 3] }"); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); common::ObString path_str("$.like[1]"); ObJsonPath test_path(path_str, &allocator); ASSERT_EQ(OB_SUCCESS, test_path.parse_path()); ObJsonSeekResult hit; int cnt = test_path.path_node_cnt(); ASSERT_EQ(OB_SUCCESS, j_bin->seek(test_path, cnt, false, false, hit)); ASSERT_EQ(1, hit.size()); ObIJsonBase *j_child_bin = hit[0]; ObIJsonBase *j_parent_bin = nullptr; ASSERT_EQ(OB_SUCCESS, j_child_bin->get_parent(j_parent_bin)); ASSERT_NE(nullptr, j_parent_bin); ASSERT_EQ(OB_SUCCESS, j_parent_bin->array_remove(1)); ASSERT_FALSE(update_ctx.is_rebuild_all_); ASSERT_EQ(1, update_ctx.binary_diffs_.count()); check_diff_valid(allocator, result, update_ctx); ASSERT_EQ(OB_SUCCESS, bin->lookup(ObString("like"))); ASSERT_EQ(ObJsonNodeType::J_ARRAY, bin->json_type()); ObJsonBuffer j_bin_buffer(&allocator); ASSERT_EQ(OB_SUCCESS, bin->print(j_bin_buffer, false)); ASSERT_EQ("[1, 3]", std::string(j_bin_buffer.ptr(), j_bin_buffer.length())); } TEST_F(TestJsonBin, test_array_remove_2) { ObArenaAllocator allocator(ObModIds::TEST); common::ObString j_text("[ \"name\" , \"Mike\", \"age\" , 30, \"like\", [1, 2, 3] ]"); ObIJsonBase *j_bin = nullptr; ASSERT_EQ(OB_SUCCESS, ObJsonBaseFactory::get_json_base(&allocator, j_text, ObJsonInType::JSON_TREE, ObJsonInType::JSON_BIN, j_bin)); ObJsonBin *bin = static_cast(j_bin); bin->set_seek_flag(false); ASSERT_EQ(OB_SUCCESS, init_update_ctx(allocator, bin)); ObJsonBinUpdateCtx &update_ctx = *bin->get_update_ctx(); common::ObString result; ASSERT_EQ(OB_SUCCESS, j_bin->get_raw_binary(result, &allocator)); ASSERT_EQ(OB_SUCCESS, j_bin->array_remove(1)); ASSERT_TRUE(update_ctx.is_rebuild_all_); ASSERT_EQ(ObJsonNodeType::J_ARRAY, j_bin->json_type()); ObJsonBuffer j_bin_buffer(&allocator); ASSERT_EQ(OB_SUCCESS, bin->print(j_bin_buffer, false)); ASSERT_EQ("[\"name\", \"age\", 30, \"like\", [1, 2, 3]]", std::string(j_bin_buffer.ptr(), j_bin_buffer.length())); } } // namespace common } // namespace oceanbase int main(int argc, char** argv) { oceanbase::common::ObLogger::get_logger().set_log_level("INFO"); OB_LOGGER.set_log_level("INFO"); ::testing::InitGoogleTest(&argc, argv); /* system("rm -f test_json_bin.log"); OB_LOGGER.set_file_name("test_json_bin.log"); OB_LOGGER.set_log_level("INFO"); */ return RUN_ALL_TESTS(); }