mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Merge branch '10.3' into 10.4
This commit is contained in:
@ -2146,6 +2146,331 @@ null_return:
|
||||
}
|
||||
|
||||
|
||||
static int copy_value_patch(String *str, json_engine_t *je)
|
||||
{
|
||||
int first_key= 1;
|
||||
|
||||
if (je->value_type != JSON_VALUE_OBJECT)
|
||||
{
|
||||
const uchar *beg, *end;
|
||||
|
||||
beg= je->value_begin;
|
||||
|
||||
if (!json_value_scalar(je))
|
||||
{
|
||||
if (json_skip_level(je))
|
||||
return 1;
|
||||
end= je->s.c_str;
|
||||
}
|
||||
else
|
||||
end= je->value_end;
|
||||
|
||||
if (append_simple(str, beg, end-beg))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* JSON_VALUE_OBJECT */
|
||||
|
||||
if (str->append("{", 1))
|
||||
return 1;
|
||||
while (json_scan_next(je) == 0 && je->state != JST_OBJ_END)
|
||||
{
|
||||
const uchar *key_start;
|
||||
/* Loop through the Json_1 keys and compare with the Json_2 keys. */
|
||||
DBUG_ASSERT(je->state == JST_KEY);
|
||||
key_start= je->s.c_str;
|
||||
|
||||
if (json_read_value(je))
|
||||
return 1;
|
||||
|
||||
if (je->value_type == JSON_VALUE_NULL)
|
||||
continue;
|
||||
|
||||
if (!first_key)
|
||||
{
|
||||
if (str->append(", ", 2))
|
||||
return 3;
|
||||
}
|
||||
else
|
||||
first_key= 0;
|
||||
|
||||
if (str->append("\"", 1) ||
|
||||
append_simple(str, key_start, je->value_begin - key_start) ||
|
||||
copy_value_patch(str, je))
|
||||
return 1;
|
||||
}
|
||||
if (str->append("}", 1))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int do_merge_patch(String *str, json_engine_t *je1, json_engine_t *je2,
|
||||
bool *empty_result)
|
||||
{
|
||||
if (json_read_value(je1) || json_read_value(je2))
|
||||
return 1;
|
||||
|
||||
if (je1->value_type == JSON_VALUE_OBJECT &&
|
||||
je2->value_type == JSON_VALUE_OBJECT)
|
||||
{
|
||||
json_engine_t sav_je1= *je1;
|
||||
json_engine_t sav_je2= *je2;
|
||||
|
||||
int first_key= 1;
|
||||
json_string_t key_name;
|
||||
size_t sav_len;
|
||||
bool mrg_empty;
|
||||
|
||||
*empty_result= FALSE;
|
||||
json_string_set_cs(&key_name, je1->s.cs);
|
||||
|
||||
if (str->append("{", 1))
|
||||
return 3;
|
||||
while (json_scan_next(je1) == 0 &&
|
||||
je1->state != JST_OBJ_END)
|
||||
{
|
||||
const uchar *key_start, *key_end;
|
||||
/* Loop through the Json_1 keys and compare with the Json_2 keys. */
|
||||
DBUG_ASSERT(je1->state == JST_KEY);
|
||||
key_start= je1->s.c_str;
|
||||
do
|
||||
{
|
||||
key_end= je1->s.c_str;
|
||||
} while (json_read_keyname_chr(je1) == 0);
|
||||
|
||||
if (je1->s.error)
|
||||
return 1;
|
||||
|
||||
sav_len= str->length();
|
||||
|
||||
if (!first_key)
|
||||
{
|
||||
if (str->append(", ", 2))
|
||||
return 3;
|
||||
*je2= sav_je2;
|
||||
}
|
||||
|
||||
if (str->append("\"", 1) ||
|
||||
append_simple(str, key_start, key_end - key_start) ||
|
||||
str->append("\":", 2))
|
||||
return 3;
|
||||
|
||||
while (json_scan_next(je2) == 0 &&
|
||||
je2->state != JST_OBJ_END)
|
||||
{
|
||||
int ires;
|
||||
DBUG_ASSERT(je2->state == JST_KEY);
|
||||
json_string_set_str(&key_name, key_start, key_end);
|
||||
if (!json_key_matches(je2, &key_name))
|
||||
{
|
||||
if (je2->s.error || json_skip_key(je2))
|
||||
return 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Json_2 has same key as Json_1. Merge them. */
|
||||
if ((ires= do_merge_patch(str, je1, je2, &mrg_empty)))
|
||||
return ires;
|
||||
|
||||
if (mrg_empty)
|
||||
str->length(sav_len);
|
||||
else
|
||||
first_key= 0;
|
||||
|
||||
goto merged_j1;
|
||||
}
|
||||
|
||||
if (je2->s.error)
|
||||
return 2;
|
||||
|
||||
key_start= je1->s.c_str;
|
||||
/* Just append the Json_1 key value. */
|
||||
if (json_skip_key(je1))
|
||||
return 1;
|
||||
if (append_simple(str, key_start, je1->s.c_str - key_start))
|
||||
return 3;
|
||||
first_key= 0;
|
||||
|
||||
merged_j1:
|
||||
continue;
|
||||
}
|
||||
|
||||
*je2= sav_je2;
|
||||
/*
|
||||
Now loop through the Json_2 keys.
|
||||
Skip if there is same key in Json_1
|
||||
*/
|
||||
while (json_scan_next(je2) == 0 &&
|
||||
je2->state != JST_OBJ_END)
|
||||
{
|
||||
const uchar *key_start, *key_end;
|
||||
DBUG_ASSERT(je2->state == JST_KEY);
|
||||
key_start= je2->s.c_str;
|
||||
do
|
||||
{
|
||||
key_end= je2->s.c_str;
|
||||
} while (json_read_keyname_chr(je2) == 0);
|
||||
|
||||
if (je2->s.error)
|
||||
return 1;
|
||||
|
||||
*je1= sav_je1;
|
||||
while (json_scan_next(je1) == 0 &&
|
||||
je1->state != JST_OBJ_END)
|
||||
{
|
||||
DBUG_ASSERT(je1->state == JST_KEY);
|
||||
json_string_set_str(&key_name, key_start, key_end);
|
||||
if (!json_key_matches(je1, &key_name))
|
||||
{
|
||||
if (je1->s.error || json_skip_key(je1))
|
||||
return 2;
|
||||
continue;
|
||||
}
|
||||
if (json_skip_key(je2) ||
|
||||
json_skip_level(je1))
|
||||
return 1;
|
||||
goto continue_j2;
|
||||
}
|
||||
|
||||
if (je1->s.error)
|
||||
return 2;
|
||||
|
||||
|
||||
sav_len= str->length();
|
||||
|
||||
if (!first_key && str->append(", ", 2))
|
||||
return 3;
|
||||
|
||||
if (str->append("\"", 1) ||
|
||||
append_simple(str, key_start, key_end - key_start) ||
|
||||
str->append("\":", 2))
|
||||
return 3;
|
||||
|
||||
if (json_read_value(je2))
|
||||
return 1;
|
||||
|
||||
if (je2->value_type == JSON_VALUE_NULL)
|
||||
str->length(sav_len);
|
||||
else
|
||||
{
|
||||
if (copy_value_patch(str, je2))
|
||||
return 1;
|
||||
first_key= 0;
|
||||
}
|
||||
|
||||
continue_j2:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str->append("}", 1))
|
||||
return 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!json_value_scalar(je1) && json_skip_level(je1))
|
||||
return 1;
|
||||
|
||||
*empty_result= je2->value_type == JSON_VALUE_NULL;
|
||||
if (!(*empty_result) && copy_value_patch(str, je2))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
String *Item_func_json_merge_patch::val_str(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
json_engine_t je1, je2;
|
||||
String *js1= args[0]->val_json(&tmp_js1), *js2=NULL;
|
||||
uint n_arg;
|
||||
bool empty_result, merge_to_null;
|
||||
|
||||
merge_to_null= args[0]->null_value;
|
||||
|
||||
for (n_arg=1; n_arg < arg_count; n_arg++)
|
||||
{
|
||||
js2= args[n_arg]->val_json(&tmp_js2);
|
||||
if (args[n_arg]->null_value)
|
||||
{
|
||||
merge_to_null= true;
|
||||
goto cont_point;
|
||||
}
|
||||
|
||||
json_scan_start(&je2, js2->charset(),(const uchar *) js2->ptr(),
|
||||
(const uchar *) js2->ptr() + js2->length());
|
||||
|
||||
if (merge_to_null)
|
||||
{
|
||||
if (json_read_value(&je2))
|
||||
goto error_return;
|
||||
if (je2.value_type == JSON_VALUE_OBJECT)
|
||||
{
|
||||
merge_to_null= true;
|
||||
goto cont_point;
|
||||
}
|
||||
merge_to_null= false;
|
||||
str->set(js2->ptr(), js2->length(), js2->charset());
|
||||
goto cont_point;
|
||||
}
|
||||
|
||||
str->set_charset(js1->charset());
|
||||
str->length(0);
|
||||
|
||||
|
||||
json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(),
|
||||
(const uchar *) js1->ptr() + js1->length());
|
||||
|
||||
if (do_merge_patch(str, &je1, &je2, &empty_result))
|
||||
goto error_return;
|
||||
|
||||
if (empty_result)
|
||||
str->append("null");
|
||||
|
||||
cont_point:
|
||||
{
|
||||
/* Swap str and js1. */
|
||||
if (str == &tmp_js1)
|
||||
{
|
||||
str= js1;
|
||||
js1= &tmp_js1;
|
||||
}
|
||||
else
|
||||
{
|
||||
js1= str;
|
||||
str= &tmp_js1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (merge_to_null)
|
||||
goto null_return;
|
||||
|
||||
json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(),
|
||||
(const uchar *) js1->ptr() + js1->length());
|
||||
str->length(0);
|
||||
str->set_charset(js1->charset());
|
||||
if (json_nice(&je1, str, Item_func_json_format::LOOSE))
|
||||
goto error_return;
|
||||
|
||||
null_value= 0;
|
||||
return str;
|
||||
|
||||
error_return:
|
||||
if (je1.s.error)
|
||||
report_json_error(js1, &je1, 0);
|
||||
if (je2.s.error)
|
||||
report_json_error(js2, &je2, n_arg);
|
||||
null_return:
|
||||
null_value= 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool Item_func_json_length::fix_length_and_dec()
|
||||
{
|
||||
if (arg_count > 1)
|
||||
|
Reference in New Issue
Block a user