[CP]: Oracle json bugfix
This commit is contained in:
parent
a52b801e5f
commit
c8647966da
86
deps/oblib/src/lib/json_type/ob_json_base.cpp
vendored
86
deps/oblib/src/lib/json_type/ob_json_base.cpp
vendored
@ -2147,53 +2147,63 @@ bool ObIJsonBase::is_real_json_null(const ObIJsonBase* ptr) const
|
||||
return ret_bool;
|
||||
}
|
||||
|
||||
int ObIJsonBase::trans_json_node(ObIAllocator* allocator, ObIJsonBase* &left, ObIJsonBase* &right) const
|
||||
// left is scalar, right is ans of subpath
|
||||
int ObIJsonBase::trans_json_node(ObIAllocator* allocator, ObIJsonBase* &scalar, ObIJsonBase* &path_res) const
|
||||
{
|
||||
INIT_SUCC(ret);
|
||||
ObJsonNodeType left_type = left->json_type();
|
||||
ObJsonNodeType right_type = right->json_type();
|
||||
// 左边的需要根据右边的类型转换
|
||||
ObJsonNodeType left_type = scalar->json_type();
|
||||
ObJsonNodeType right_type = path_res->json_type();
|
||||
if (left_type == ObJsonNodeType::J_STRING) {
|
||||
ObString str(left->get_data_length(), left->get_data());
|
||||
ObString str(scalar->get_data_length(), scalar->get_data());
|
||||
if (is_json_number(right_type)) {
|
||||
// fail is normal
|
||||
ret = trans_to_json_number(allocator, str, left);
|
||||
ret = trans_to_json_number(allocator, str, scalar);
|
||||
} else if (right_type == ObJsonNodeType::J_DATE
|
||||
|| right_type == ObJsonNodeType::J_DATETIME
|
||||
|| right_type == ObJsonNodeType::J_TIME
|
||||
|| right_type == ObJsonNodeType::J_ORACLEDATE) {
|
||||
ret = trans_to_date_timestamp(allocator, str, left, true);
|
||||
ret = trans_to_date_timestamp(allocator, str, scalar, true);
|
||||
} else if (right_type == ObJsonNodeType::J_TIMESTAMP
|
||||
|| right_type == ObJsonNodeType::J_OTIMESTAMP
|
||||
|| right_type == ObJsonNodeType::J_OTIMESTAMPTZ) {
|
||||
ret = trans_to_date_timestamp(allocator, str, left, false);
|
||||
ret = trans_to_date_timestamp(allocator, str, scalar, false);
|
||||
} else if (right_type == ObJsonNodeType::J_BOOLEAN) {
|
||||
ret = trans_to_boolean(allocator, str, left);
|
||||
// when scalar is string, path_res is boolean, case compare
|
||||
if (str.case_compare("true") == 0 || str.case_compare("false") == 0) {
|
||||
ret = trans_to_boolean(allocator, str, scalar);
|
||||
} else {
|
||||
ret = OB_NOT_SUPPORTED;
|
||||
}
|
||||
} else if (right_type != ObJsonNodeType::J_ARRAY && right_type != ObJsonNodeType::J_OBJECT) {
|
||||
ret = ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("CAN'T TRANS", K(ret));
|
||||
}
|
||||
// 右边需要根据左边的转换
|
||||
} else if (left_type == ObJsonNodeType::J_NULL) {
|
||||
// return error code, mean can't cast, return false ans directly
|
||||
ret = OB_NOT_SUPPORTED;
|
||||
} else if (right_type == ObJsonNodeType::J_STRING) {
|
||||
ObString str(right->get_data_length(), right->get_data());
|
||||
ObString str(path_res->get_data_length(), path_res->get_data());
|
||||
if (is_json_number(left_type)) {
|
||||
// fail is normal
|
||||
ret = trans_to_json_number(allocator, str, right);
|
||||
ret = trans_to_json_number(allocator, str, path_res);
|
||||
} else if (left_type == ObJsonNodeType::J_DATE
|
||||
|| left_type == ObJsonNodeType::J_DATETIME
|
||||
|| left_type == ObJsonNodeType::J_TIME
|
||||
|| left_type == ObJsonNodeType::J_ORACLEDATE) {
|
||||
ret = trans_to_date_timestamp(allocator, str, right, true);
|
||||
ret = trans_to_date_timestamp(allocator, str, path_res, true);
|
||||
} else if (left_type == ObJsonNodeType::J_TIMESTAMP
|
||||
|| left_type == ObJsonNodeType::J_OTIMESTAMP
|
||||
|| left_type == ObJsonNodeType::J_OTIMESTAMPTZ) {
|
||||
ret = trans_to_date_timestamp(allocator, str, right, false);
|
||||
ret = trans_to_date_timestamp(allocator, str, path_res, false);
|
||||
} else if (left_type == ObJsonNodeType::J_BOOLEAN) {
|
||||
ret = trans_to_boolean(allocator, str, right);
|
||||
ret = trans_to_boolean(allocator, str, path_res);
|
||||
} else if (left_type != ObJsonNodeType::J_ARRAY && left_type != ObJsonNodeType::J_OBJECT) {
|
||||
ret = ret = OB_INVALID_ARGUMENT;
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("CAN'T TRANS", K(ret));
|
||||
}
|
||||
} else if (left_type == ObJsonNodeType::J_BOOLEAN || is_json_number(left_type)) {
|
||||
// scalar is boolean or number, and path_res is not string, return false
|
||||
ret = OB_NOT_SUPPORTED;
|
||||
} else {
|
||||
// do nothing
|
||||
LOG_WARN("CAN'T TRANS", K(ret));
|
||||
@ -2247,7 +2257,7 @@ int ObIJsonBase::cmp_to_right_recursively(ObIAllocator* allocator, const ObJsonB
|
||||
// 但只要有一个找到,且为123或"123"则为true
|
||||
ObIJsonBase* left = jb_ptr;
|
||||
ObIJsonBase* right = right_arg;
|
||||
if (OB_FAIL(trans_json_node(allocator, left, right))) {
|
||||
if (OB_FAIL(trans_json_node(allocator, right, left))) {
|
||||
// fail is normal, it is not an error.
|
||||
ret = OB_SUCCESS;
|
||||
cmp_result = false;
|
||||
@ -2270,7 +2280,7 @@ int ObIJsonBase::cmp_to_right_recursively(ObIAllocator* allocator, const ObJsonB
|
||||
// 不相同的类型,同上
|
||||
ObIJsonBase* left = hit[i];
|
||||
ObIJsonBase* right = right_arg;
|
||||
if (OB_FAIL(trans_json_node(allocator, left, right))) {
|
||||
if (OB_FAIL(trans_json_node(allocator, right, left))) {
|
||||
// fail is normal, it is not an error.
|
||||
ret = OB_SUCCESS;
|
||||
cmp_result = false;
|
||||
@ -2291,7 +2301,6 @@ int ObIJsonBase::cmp_to_right_recursively(ObIAllocator* allocator, const ObJsonB
|
||||
}
|
||||
|
||||
// for compare ——> ( scalar/sql_var, subpath)
|
||||
// 左边调用compare,右边是数组时自动解包
|
||||
// 只要有一个结果为true则返回true,找不到或结果为false均返回false
|
||||
int ObIJsonBase::cmp_to_left_recursively(ObIAllocator* allocator, const ObJsonBaseVector& hit,
|
||||
const ObJsonPathNodeType node_type,
|
||||
@ -2310,44 +2319,7 @@ int ObIJsonBase::cmp_to_left_recursively(ObIAllocator* allocator, const ObJsonBa
|
||||
} else if (hit[i]->json_type() == ObJsonNodeType::J_NULL && !is_real_json_null(hit[i])) {
|
||||
cmp_result = false;
|
||||
} else {
|
||||
// error is ok
|
||||
// if is array, compare with every node
|
||||
// but only autowrap once
|
||||
if (hit[i]->json_type() == ObJsonNodeType::J_ARRAY) {
|
||||
uint64_t size = hit[i]->element_count();
|
||||
ObIJsonBase *jb_ptr = NULL;
|
||||
for (uint32_t array_i = 0; array_i < size && !cmp_result && OB_SUCC(ret); ++array_i) {
|
||||
jb_ptr = NULL; // reset jb_ptr to NULL
|
||||
ret = hit[i]->get_array_element(array_i, jb_ptr);
|
||||
int cmp_res = -3;
|
||||
// 类型相同可以直接用compare函数比较
|
||||
if(OB_FAIL(ret) || OB_ISNULL(jb_ptr)) {
|
||||
ret = OB_ERR_NULL_VALUE;
|
||||
LOG_WARN("compare value is null.", K(ret));
|
||||
} else if (is_same_type(left_arg, jb_ptr)) {
|
||||
if (OB_SUCC(left_arg->compare((*jb_ptr), cmp_res, true))) {
|
||||
cmp_based_on_node_type(node_type, cmp_res, cmp_result);
|
||||
}
|
||||
} else {
|
||||
// 不相同的类型,oracle会将string类型转换为对应类型再进行比较
|
||||
// 转换或比较失败也正常,并不报错
|
||||
// 例如: [*].a == 123
|
||||
// 里面可能有多个元素无法转换成数字或无法和数字比较甚至找不到.a
|
||||
// 但只要有一个找到,且为123或"123"则为true
|
||||
ObIJsonBase* left = left_arg;
|
||||
ObIJsonBase* right = jb_ptr;
|
||||
if (OB_FAIL(trans_json_node(allocator, left, right))) {
|
||||
// fail is normal, it is not an error.
|
||||
ret = OB_SUCCESS;
|
||||
cmp_result = false;
|
||||
} else if (OB_SUCC(left->compare((*right), cmp_res, true))) {
|
||||
cmp_based_on_node_type(node_type, cmp_res, cmp_result);
|
||||
} else {
|
||||
cmp_result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (hit[i]->json_type() == ObJsonNodeType::J_OBJECT) {
|
||||
if (hit[i]->json_type() == ObJsonNodeType::J_OBJECT || hit[i]->json_type() == ObJsonNodeType::J_ARRAY) {
|
||||
cmp_result = false;
|
||||
} else {
|
||||
int cmp_res = -3;
|
||||
|
271
deps/oblib/src/lib/json_type/ob_json_path.cpp
vendored
271
deps/oblib/src/lib/json_type/ob_json_path.cpp
vendored
@ -786,13 +786,16 @@ int ObJsonPath::change_json_expr_res_type_if_need(common::ObIAllocator &allocato
|
||||
switch (func_node->get_node_type()) {
|
||||
case JPN_BOOLEAN :
|
||||
case JPN_BOOL_ONLY : {
|
||||
ret_node.type_ = T_CAST_ARGUMENT;
|
||||
ret_node.value_ = 0;
|
||||
ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] = T_VARCHAR;
|
||||
ret_node.int16_values_[OB_NODE_CAST_COLL_IDX] = 0;
|
||||
ret_node.int32_values_[OB_NODE_CAST_C_LEN_IDX] = 20;
|
||||
ret_node.length_semantics_ = 0;
|
||||
ret_node.is_hidden_const_ = 1;
|
||||
if (json_expr_flag == OPT_JSON_QUERY && ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] == T_JSON) { // do nothing
|
||||
} else {
|
||||
ret_node.type_ = T_CAST_ARGUMENT;
|
||||
ret_node.value_ = 0;
|
||||
ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] = T_VARCHAR;
|
||||
ret_node.int16_values_[OB_NODE_CAST_COLL_IDX] = 0;
|
||||
ret_node.int32_values_[OB_NODE_CAST_C_LEN_IDX] = 20;
|
||||
ret_node.length_semantics_ = 0;
|
||||
ret_node.is_hidden_const_ = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JPN_DATE : {
|
||||
@ -824,14 +827,16 @@ int ObJsonPath::change_json_expr_res_type_if_need(common::ObIAllocator &allocato
|
||||
case JPN_NUMBER :
|
||||
case JPN_FLOOR :
|
||||
case JPN_CEILING : {
|
||||
ret_node.value_ = 0;
|
||||
if (ret_node.type_ == T_NULL) {
|
||||
if (ret_node.type_ == T_NULL
|
||||
|| (json_expr_flag == OPT_JSON_QUERY && ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] == T_JSON)) {
|
||||
ret_node.value_ = 0;
|
||||
ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] = T_VARCHAR;
|
||||
ret_node.int16_values_[OB_NODE_CAST_COLL_IDX] = 0;
|
||||
ret_node.int32_values_[OB_NODE_CAST_C_LEN_IDX] = 4000;
|
||||
ret_node.length_semantics_ = 0;
|
||||
ret_node.is_hidden_const_ = 1;
|
||||
} else {
|
||||
ret_node.value_ = 0;
|
||||
ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] = T_NUMBER;
|
||||
ret_node.int16_values_[OB_NODE_CAST_N_PREC_IDX] = -1; /* precision */
|
||||
ret_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX] = -85; /* scale */
|
||||
@ -855,24 +860,29 @@ int ObJsonPath::change_json_expr_res_type_if_need(common::ObIAllocator &allocato
|
||||
case JPN_TYPE:
|
||||
case JPN_STR_ONLY :
|
||||
case JPN_STRING : {
|
||||
ret_node.type_ = T_CAST_ARGUMENT;
|
||||
ret_node.value_ = 0;
|
||||
ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] = T_VARCHAR;
|
||||
ret_node.int16_values_[OB_NODE_CAST_COLL_IDX] = 0;
|
||||
ret_node.int32_values_[OB_NODE_CAST_C_LEN_IDX] = 4000;
|
||||
ret_node.length_semantics_ = 0;
|
||||
ret_node.is_hidden_const_ = 1;
|
||||
if (json_expr_flag == OPT_JSON_QUERY && ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] == T_JSON) {
|
||||
} else {
|
||||
ret_node.type_ = T_CAST_ARGUMENT;
|
||||
ret_node.value_ = 0;
|
||||
ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] = T_VARCHAR;
|
||||
ret_node.int16_values_[OB_NODE_CAST_COLL_IDX] = 0;
|
||||
ret_node.int32_values_[OB_NODE_CAST_C_LEN_IDX] = 4000;
|
||||
ret_node.length_semantics_ = 0;
|
||||
ret_node.is_hidden_const_ = 1;
|
||||
}
|
||||
}
|
||||
case JPN_UPPER:
|
||||
case JPN_LOWER: {
|
||||
ret_node.type_ = T_CAST_ARGUMENT;
|
||||
ret_node.value_ = 0;
|
||||
ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] = T_VARCHAR;
|
||||
ret_node.int16_values_[OB_NODE_CAST_COLL_IDX] = 0;
|
||||
ret_node.int32_values_[OB_NODE_CAST_C_LEN_IDX] = 75;
|
||||
ret_node.length_semantics_ = 0;
|
||||
ret_node.is_hidden_const_ = 1;
|
||||
break;
|
||||
if (json_expr_flag == OPT_JSON_QUERY && ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] == T_JSON) {
|
||||
} else {
|
||||
ret_node.type_ = T_CAST_ARGUMENT;
|
||||
ret_node.value_ = 0;
|
||||
ret_node.int16_values_[OB_NODE_CAST_TYPE_IDX] = T_VARCHAR;
|
||||
ret_node.int16_values_[OB_NODE_CAST_COLL_IDX] = 0;
|
||||
ret_node.int32_values_[OB_NODE_CAST_C_LEN_IDX] = 75;
|
||||
ret_node.length_semantics_ = 0;
|
||||
ret_node.is_hidden_const_ = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default : {
|
||||
@ -2123,7 +2133,7 @@ int ObJsonPath::parse_name_with_rapidjson(char*& str, uint64_t& len)
|
||||
}
|
||||
|
||||
// if keyname without double quote, end with ' ', '.', '[', '*'
|
||||
bool ObJsonPathUtil::is_mysql_terminator(char ch)
|
||||
bool ObJsonPathUtil::is_key_name_terminator(char ch)
|
||||
{
|
||||
bool ret_bool = false;
|
||||
switch (ch) {
|
||||
@ -2143,6 +2153,18 @@ bool ObJsonPathUtil::is_mysql_terminator(char ch)
|
||||
ret_bool = true;
|
||||
break;
|
||||
}
|
||||
case '(': {
|
||||
ret_bool = true;
|
||||
break;
|
||||
}
|
||||
case '?': {
|
||||
ret_bool = true;
|
||||
break;
|
||||
}
|
||||
case '-': {
|
||||
ret_bool = true;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
@ -2150,98 +2172,6 @@ bool ObJsonPathUtil::is_mysql_terminator(char ch)
|
||||
return ret_bool;
|
||||
}
|
||||
|
||||
// process JPN_MEMBER get keyname
|
||||
// @param[in,out] name Keyname
|
||||
// @param[in] is_quoted
|
||||
// @return the error code.
|
||||
int ObJsonPath::get_mysql_origin_key_name(char*& str, uint64_t& length, bool is_quoted)
|
||||
{
|
||||
INIT_SUCC(ret);
|
||||
uint64_t start = 0;
|
||||
uint64_t end = 0;
|
||||
|
||||
int len = expression_.length();
|
||||
|
||||
if (index_ < len) {
|
||||
if (is_quoted) {
|
||||
// with quote, check quote
|
||||
if (expression_[index_] == ObJsonPathItem::DOUBLE_QUOTE) {
|
||||
start = index_;
|
||||
++index_;
|
||||
|
||||
while (index_ < len && end == 0) {
|
||||
if (expression_[index_] == '\\') {
|
||||
index_ += 2;
|
||||
} else if (expression_[index_] == ObJsonPathItem::DOUBLE_QUOTE) {
|
||||
end = index_;
|
||||
++index_;
|
||||
} else {
|
||||
++index_;
|
||||
}
|
||||
}
|
||||
|
||||
if (end == 0 && index_ == len) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("should end with DOUBLE_QUOTE!", K(ret), K(index_), K(expression_));
|
||||
}
|
||||
} else {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("should start with DOUBLE_QUOTE!", K(ret), K(index_), K(expression_));
|
||||
}
|
||||
} else {
|
||||
start = index_;
|
||||
while (index_ < len && end == 0) {
|
||||
if (ObJsonPathUtil::is_mysql_terminator(expression_[index_])) {
|
||||
end = index_ - 1;
|
||||
} else {
|
||||
++index_;
|
||||
}
|
||||
}
|
||||
if (index_ == len) {
|
||||
end = index_ - 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = OB_ARRAY_OUT_OF_RANGE;
|
||||
LOG_WARN("index out of range!", K(ret), K(index_), K(expression_));
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
if (end < start) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("get keyname: end<start", K(ret), K(start), K(end), K(expression_));
|
||||
} else {
|
||||
len = end - start + 1;
|
||||
char* start_ptr = expression_.ptr() + start;
|
||||
if (!is_quoted) {
|
||||
length = len + 2;
|
||||
str = static_cast<char*> (allocator_->alloc(length));
|
||||
if (OB_ISNULL(str)) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("fail to allocate memory for member_name.",
|
||||
K(ret), K(len),KCSTRING(start_ptr));
|
||||
} else {
|
||||
str[0] = ObJsonPathItem::DOUBLE_QUOTE;
|
||||
MEMCPY(str + 1, start_ptr, len);
|
||||
str[len + 1] = ObJsonPathItem::DOUBLE_QUOTE;
|
||||
}
|
||||
} else {
|
||||
length = len;
|
||||
str = static_cast<char*> (allocator_->alloc(length));
|
||||
if (OB_ISNULL(str)) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("fail to allocate memory for member_name.",
|
||||
K(ret), K(len),KCSTRING(start_ptr));
|
||||
} else {
|
||||
MEMCPY(str, start_ptr, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// parse JPN_MEMBER_WILDCARD
|
||||
// @return the error code.
|
||||
int ObJsonPath::parse_member_wildcard_node()
|
||||
@ -2331,9 +2261,11 @@ int ObJsonPath::parse_mysql_member_node()
|
||||
|
||||
char* name = nullptr;
|
||||
uint64_t name_len = 0;
|
||||
bool is_func = false;
|
||||
bool with_escape = false;
|
||||
// get name
|
||||
// add double quote for rapidjson requires
|
||||
if (OB_FAIL(get_mysql_origin_key_name(name, name_len, is_quoted))) {
|
||||
if (OB_FAIL(get_origin_key_name(name, name_len, is_quoted, is_func, with_escape))) {
|
||||
LOG_WARN("fail to get keyname!", K(ret), K(index_), K(expression_));
|
||||
} else {
|
||||
if (OB_FAIL(parse_name_with_rapidjson(name, name_len))) {
|
||||
@ -2431,6 +2363,31 @@ bool ObJsonPathUtil::is_scalar(const ObJsonPathNodeType node_type)
|
||||
return ret_bool;
|
||||
}
|
||||
|
||||
bool ObJsonPathUtil::is_escape(char ch)
|
||||
{
|
||||
return (('\n' == ch) || (ch == '\t') || (ch == '\r') || (ch == '\f') || (ch == '\e'));
|
||||
}
|
||||
int ObJsonPathUtil::append_character_of_escape(ObJsonBuffer& buf, char ch)
|
||||
{
|
||||
INIT_SUCC(ret);
|
||||
if ('\n' == ch) {
|
||||
ret = buf.append("n");
|
||||
} else if ('\t' == ch) {
|
||||
ret = buf.append("t");
|
||||
} else if ('\r' == ch) {
|
||||
ret = buf.append("r");
|
||||
} else if ('\f' == ch) {
|
||||
ret = buf.append("f");
|
||||
} else if ('\e' == ch) {
|
||||
ret = buf.append("e");
|
||||
} else {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("should be escape", K(ch), K(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void ObJsonPathUtil::skip_whitespace(const ObString &path, uint64_t& idx)
|
||||
{
|
||||
while (idx < path.length() && ObJsonPathUtil::is_whitespace(path[idx])) {
|
||||
@ -3039,7 +2996,7 @@ bool ObJsonPathUtil::is_oracle_keyname(const char* name, uint64_t length)
|
||||
// @param[in,out] name Keyname
|
||||
// @param[in] is_quoted
|
||||
// @return the error code.
|
||||
int ObJsonPath::get_oracle_origin_key_name(char*& str, uint64_t& length, bool is_quoted, bool& is_func)
|
||||
int ObJsonPath::get_origin_key_name(char*& str, uint64_t& length, bool is_quoted, bool& is_func, bool& with_escape)
|
||||
{
|
||||
INIT_SUCC(ret);
|
||||
uint64_t start = 0;
|
||||
@ -3060,6 +3017,9 @@ int ObJsonPath::get_oracle_origin_key_name(char*& str, uint64_t& length, bool is
|
||||
} else if (expression_[index_] == ObJsonPathItem::DOUBLE_QUOTE) {
|
||||
end = index_;
|
||||
++index_;
|
||||
} else if (ObJsonPathUtil::is_escape(expression_[index_])) {
|
||||
with_escape = true;
|
||||
++index_;
|
||||
} else {
|
||||
++index_;
|
||||
}
|
||||
@ -3074,35 +3034,28 @@ int ObJsonPath::get_oracle_origin_key_name(char*& str, uint64_t& length, bool is
|
||||
LOG_WARN("should start with DOUBLE_QUOTE!", K(ret), K(index_), K(expression_));
|
||||
}
|
||||
} else {
|
||||
if (ObJsonPathUtil::letter_or_not(expression_[index_]) || (expression_[index_] == '_')) {
|
||||
// without '""'
|
||||
start = index_;
|
||||
++index_;
|
||||
while (index_ < len) {
|
||||
if (!(ObJsonPathUtil::letter_or_not(expression_[index_])
|
||||
|| ObJsonPathUtil::is_digit(expression_[index_])
|
||||
|| (expression_[index_] == '_'))) {
|
||||
start = index_;
|
||||
if (ObJsonPathUtil::is_digit(expression_[index_])) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("shouldn't start with number!", K(ret), K(index_), K(expression_));
|
||||
} else {
|
||||
while (index_ < len && end == 0) {
|
||||
if (ObJsonPathUtil::is_key_name_terminator(expression_[index_])) {
|
||||
end = index_ - 1;
|
||||
break;
|
||||
} else {
|
||||
++index_;
|
||||
}
|
||||
}
|
||||
|
||||
if (index_ == len) {
|
||||
end = index_ - 1;
|
||||
} else {
|
||||
ObJsonPathUtil::skip_whitespace(expression_, index_);
|
||||
// fun_name + ()
|
||||
if (index_ < expression_.length()) {
|
||||
if (expression_[index_] == '(') {
|
||||
if (index_ < expression_.length() && expression_[index_] == '(') {
|
||||
is_func = true;
|
||||
}
|
||||
}//now, index could equal to len
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("wrong keyname!", K(ret), K(start), K(end), K(expression_));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -3115,11 +3068,11 @@ int ObJsonPath::get_oracle_origin_key_name(char*& str, uint64_t& length, bool is
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("get keyname: end<start", K(ret), K(start), K(end), K(expression_));
|
||||
} else {
|
||||
len = end-start + 1;
|
||||
len = end - start + 1;
|
||||
char* start_ptr = expression_.ptr() + start;
|
||||
// no "", could be function name
|
||||
if ((!is_quoted) && (!is_func)) {
|
||||
length = len+2;
|
||||
length = len + 2;
|
||||
str = static_cast<char*> (allocator_->alloc(length));
|
||||
if (OB_ISNULL(str)) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
@ -3182,6 +3135,31 @@ int ObJsonPath::parse_func_node(char*& name, uint64_t& len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObJsonPath::deal_with_escape(char* &str, uint64_t& len)
|
||||
{
|
||||
INIT_SUCC(ret);
|
||||
ObJsonBuffer buf(allocator_);
|
||||
for (int i = 0; i < len && OB_SUCC(ret); ++i) {
|
||||
char* tmp = str + i;
|
||||
if (OB_ISNULL(tmp)) {
|
||||
} else if (ObJsonPathUtil::is_escape(*tmp)) {
|
||||
if (OB_FAIL(buf.append("\\"))) {
|
||||
LOG_WARN("fail to append \\.", K(i), K(ret));
|
||||
} else if (OB_FAIL(ObJsonPathUtil::append_character_of_escape(buf, *tmp))) {
|
||||
LOG_WARN("fail to append_character_of_escape.", K(*tmp), K(i), K(ret));
|
||||
}
|
||||
} else {
|
||||
ret = buf.append(tmp, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
str = buf.ptr();
|
||||
len = buf.length();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// parse JPN_ORACLE_MEMBER
|
||||
// @return the error code.
|
||||
int ObJsonPath::parse_oracle_member_node()
|
||||
@ -3191,6 +3169,7 @@ int ObJsonPath::parse_oracle_member_node()
|
||||
if (index_ < expression_.length()) {
|
||||
bool is_quoted = false;
|
||||
bool is_func = false;
|
||||
bool with_escape = false;
|
||||
|
||||
// check double quote
|
||||
if (expression_[index_] == ObJsonPathItem::DOUBLE_QUOTE) is_quoted = true;
|
||||
@ -3199,12 +3178,19 @@ int ObJsonPath::parse_oracle_member_node()
|
||||
uint64_t name_len = 0;
|
||||
// get name
|
||||
// add double quote for rapidjson requires
|
||||
if (OB_FAIL(get_oracle_origin_key_name(name, name_len, is_quoted, is_func))) {
|
||||
if (OB_FAIL(get_origin_key_name(name, name_len, is_quoted, is_func, with_escape))) {
|
||||
LOG_WARN("fail to get keyname!", K(ret), K(index_), K(expression_));
|
||||
} else if (is_quoted || (!is_func)) {
|
||||
// with "", must be member node
|
||||
if (OB_FAIL(parse_name_with_rapidjson(name, name_len))) {
|
||||
LOG_WARN("fail to parse name with rapidjson",K(ret), K(index_), K(expression_),K(name));
|
||||
if (lib::is_oracle_mode() && with_escape && OB_FAIL(ObJsonPath::deal_with_escape(name, name_len))) {
|
||||
LOG_WARN("fail to deal escape!", K(ret), K(index_), K(expression_));
|
||||
} else if (OB_FAIL(parse_name_with_rapidjson(name, name_len))) {
|
||||
LOG_WARN("fail to parse name with rapidjson",
|
||||
K(ret), K(index_), K(expression_),KCSTRING(name));
|
||||
} else if (!is_quoted) {
|
||||
if (!ObJsonPathUtil::is_ecmascript_identifier(name, name_len)) {
|
||||
LOG_WARN("the key name isn't ECMAScript identifier!",
|
||||
K(ret), KCSTRING(name));
|
||||
}
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret)) {
|
||||
@ -3932,7 +3918,8 @@ int ObJsonPath::parse_comp_string_num(ObJsonPathFilterNode* filter_comp_node, bo
|
||||
char* str = nullptr;
|
||||
uint64_t name_len = 0;
|
||||
bool is_func = false;
|
||||
if (OB_FAIL(get_oracle_origin_key_name(str, name_len, true, is_func))) {
|
||||
bool with_escape = false;
|
||||
if (OB_FAIL(get_origin_key_name(str, name_len, true, is_func, with_escape))) {
|
||||
LOG_WARN("fail to get string scalar",K(ret), K(index_), K(expression_),K(str));
|
||||
} else {
|
||||
if (OB_ISNULL(str)) {
|
||||
|
8
deps/oblib/src/lib/json_type/ob_json_path.h
vendored
8
deps/oblib/src/lib/json_type/ob_json_path.h
vendored
@ -359,8 +359,8 @@ private:
|
||||
bool& from_end1, bool& from_end2);
|
||||
int add_single_array_node(bool is_cell_type, uint64_t& index1, uint64_t& index2,
|
||||
bool& from_end1, bool& from_end2);
|
||||
int get_mysql_origin_key_name(char* &str, uint64_t& length, bool is_quoted);
|
||||
int get_oracle_origin_key_name(char* &str, uint64_t& length, bool is_quoted, bool& is_func);
|
||||
int get_origin_key_name(char* &str, uint64_t& length, bool is_quoted, bool& is_func, bool& with_escape);
|
||||
int deal_with_escape(char* &str, uint64_t& length);
|
||||
int parse_name_with_rapidjson(char*& str, uint64_t& len);
|
||||
int parse_func_node(char*& name, uint64_t& len);
|
||||
int get_char_comparison_type(ObJsonPathFilterNode* filter_comp_node);
|
||||
@ -455,7 +455,7 @@ public:
|
||||
static bool is_oracle_keyname(const char* name, uint64_t length);
|
||||
// add quote and
|
||||
static int double_quote(ObString &name, ObJsonBuffer* tmp_name);
|
||||
static bool is_mysql_terminator(char ch);
|
||||
static bool is_key_name_terminator(char ch);
|
||||
static bool is_begin_field_name(char ch);
|
||||
static bool is_end_of_comparission(char ch);
|
||||
static bool letter_or_not(char ch);
|
||||
@ -480,6 +480,8 @@ public:
|
||||
bool auto_wrap);
|
||||
|
||||
static bool is_letter(unsigned codepoint, const char* ori, uint64_t start, uint64_t end);
|
||||
static bool is_escape(char ch);
|
||||
static int append_character_of_escape(ObJsonBuffer& buf, char ch);
|
||||
static bool is_connector_punctuation(unsigned codepoint);
|
||||
static bool unicode_combining_mark(unsigned codepoint);
|
||||
static bool is_utf8_unicode_charator(const char* ori, uint64_t& start, int64_t len);
|
||||
|
@ -92,14 +92,6 @@ int ObExprJsonEqual::eval_json_equal(const ObExpr &expr, ObEvalCtx &ctx, ObDatum
|
||||
uint8_t option_on_error = 0;
|
||||
// json数据解析出错或非标量,此时根据on error参数返回结果
|
||||
bool is_cover_by_error = false;
|
||||
bool both_json = false;
|
||||
|
||||
// 检查是否均为 json 类型,如果均为json类型,标量相比不报错
|
||||
// 只要有一个参数不是json类型,标量相比就会报错
|
||||
if (expr.args_[0]->datum_meta_.type_ == ObJsonType
|
||||
|| expr.args_[1]->datum_meta_.type_ == ObJsonType) {
|
||||
both_json = true;
|
||||
}
|
||||
|
||||
ObExpr *json_arg_l = expr.args_[0];
|
||||
ObObjType val_type_l = json_arg_l->datum_meta_.type_;
|
||||
@ -116,8 +108,9 @@ int ObExprJsonEqual::eval_json_equal(const ObExpr &expr, ObEvalCtx &ctx, ObDatum
|
||||
json_candidate, is_null_result))) {
|
||||
if (ret == OB_ERR_JSON_SYNTAX_ERROR) is_cover_by_error = true;
|
||||
LOG_WARN("get_json_doc failed", K(ret));
|
||||
} else if(!is_null_result && !both_json && (is_json_scalar(json_target)
|
||||
|| is_json_scalar(json_candidate))) {
|
||||
// if is scalar, must be json type
|
||||
} else if(!is_null_result && ((is_json_scalar(json_target) && expr.args_[0]->datum_meta_.type_ != ObJsonType)
|
||||
|| (is_json_scalar(json_candidate) && expr.args_[1]->datum_meta_.type_ != ObJsonType))) {
|
||||
ret = OB_ERR_JSON_SYNTAX_ERROR;
|
||||
is_cover_by_error = true;
|
||||
LOG_USER_ERROR(OB_ERR_JSON_SYNTAX_ERROR);
|
||||
|
@ -5718,7 +5718,7 @@ int ObRawExprResolverImpl::process_json_query_node(const ParseNode *node, ObRawE
|
||||
}
|
||||
// pre check default returning type with item method
|
||||
if (OB_SUCC(ret)) {
|
||||
if (returning_type->type_ == T_NULL) {
|
||||
if (returning_type->type_ == T_NULL || returning_type->int16_values_[OB_NODE_CAST_TYPE_IDX] == T_JSON) {
|
||||
ObString path_str(node->children_[1]->text_len_, node->children_[1]->raw_text_);
|
||||
if (OB_FAIL(ObJsonPath::change_json_expr_res_type_if_need(ctx_.expr_factory_.get_allocator(), path_str, const_cast<ParseNode&>(*returning_type), OPT_JSON_QUERY))) {
|
||||
LOG_WARN("set return type by path item method fail", K(ret), K(path_str));
|
||||
|
@ -54,9 +54,9 @@ TEST_F(TestJsonPath, test_is_mysql_terminator_mysql)
|
||||
for(int i = 0; i < sizeof(ch); ++i)
|
||||
{
|
||||
if (i <= 3) {
|
||||
ASSERT_EQ(true, ObJsonPathUtil::is_mysql_terminator(ch[i]));
|
||||
ASSERT_EQ(true, ObJsonPathUtil::is_key_name_terminator(ch[i]));
|
||||
} else {
|
||||
ASSERT_EQ(false, ObJsonPathUtil::is_mysql_terminator(ch[i]));
|
||||
ASSERT_EQ(false, ObJsonPathUtil::is_key_name_terminator(ch[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user