From 02fdf0530ca96b6e81afa6e6fcaa6d1a673f946a Mon Sep 17 00:00:00 2001 From: Abhishek Bansal Date: Tue, 3 Mar 2026 13:24:25 +0530 Subject: [PATCH 1/5] MDEV-38033: JSON_SCHEMA_VALID returns wrong result for array of objects (11.4 backport from 12.3) Fix a bug in Json_schema_items::validate where it was missing a json_skip_level() call. Without this skip, the validator would incorrectly recurse into non-scalar array elements (like objects) and try to validate their internal keys/values against the array's item schema. --- mysql-test/main/func_json.result | 47 +++++++++++++++++++++++++++++- mysql-test/main/func_json.test | 49 +++++++++++++++++++++++++++++++- sql/json_schema.cc | 5 ++++ 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index f91fcb3273ef2..3583b94742b39 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -5553,4 +5553,49 @@ full overlap jai ["2"] ["0"] NULL ["2"] ["2"] ["2"] DROP TABLE t1; -# End of 11.4 Test +# +# MDEV-38033: JSON_SCHEMA_VALID function returning wrong result +# +SET @schema= ' +{ + "type": "object", + "properties": + { + "id": { + "type": "string", + "minLength": 1 + }, + "arr_fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field1": { + "type": "string" + }, + "field2": { + "type": "number" + } + }, + "required": ["field1"] + } + } + } +}'; +SET @value= ' +{ + "id": "zero", + "arr_fields": [ + { + "field1": "A", + "field2": 123 + }, + { + "field1": "B" + } + ] +}'; +SELECT JSON_SCHEMA_VALID(@schema, @value); +JSON_SCHEMA_VALID(@schema, @value) +1 +# End of 11.4 tests diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index 6d53d00d33d50..835f06be44850 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -4329,4 +4329,51 @@ SELECT full, overlap, json_array_intersect(full, overlap) as jai from t1; DROP TABLE t1; ---echo # End of 11.4 Test +--echo # +--echo # MDEV-38033: JSON_SCHEMA_VALID function returning wrong result +--echo # + +SET @schema= ' +{ + "type": "object", + "properties": + { + "id": { + "type": "string", + "minLength": 1 + }, + "arr_fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field1": { + "type": "string" + }, + "field2": { + "type": "number" + } + }, + "required": ["field1"] + } + } + } +}'; + +SET @value= ' +{ + "id": "zero", + "arr_fields": [ + { + "field1": "A", + "field2": 123 + }, + { + "field1": "B" + } + ] +}'; + +SELECT JSON_SCHEMA_VALID(@schema, @value); + +--echo # End of 11.4 tests diff --git a/sql/json_schema.cc b/sql/json_schema.cc index dd5862acb1761..1ea2ee5c112bc 100644 --- a/sql/json_schema.cc +++ b/sql/json_schema.cc @@ -1218,6 +1218,11 @@ bool Json_schema_items::validate(const json_engine_t *je, count++; if (validate_schema_items(&curr_je, &items_schema)) return true; + if (!json_value_scalar(&curr_je)) + { + if (json_skip_level(&curr_je)) + return true; + } } return is_false ? (!count ? false : true) : false; From 5e7e08e9bd17578805b97c087e6cdd0cbaa2bf20 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 29 Jun 2026 10:24:39 +1000 Subject: [PATCH 2/5] MDEV-28404 json killed_ptr cleanup Since 24ee5fd6bf6065ea693287e5705f3e26bb85f9fc the result of the killed_ptr is part of the je->s.error after json_scan_next. --- sql/item_jsonfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 1afe23481afa2..403ea6491a36d 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -444,7 +444,7 @@ static int json_nice(json_engine_t *je, String *nice_js, }; } while (json_scan_next(je) == 0); - return je->s.error || *je->killed_ptr; + return je->s.error; error: return 1; From 48fe46372fc5aabd299f9a52c3353188f0cca38c Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 29 Jun 2026 10:57:35 +1000 Subject: [PATCH 3/5] MDEV-40185: JSON_ARRAY_INTERSECT / JSON_OBJECT_FILTER_KEYS error handling JSON_ARRAY_INTERSECT had an obvious flaw that the arguments may have been swapped internally in fix_length_and_dec resulting in the error messaging being for the wrong argument. Fixed by keeping track of being swapped. JSON_ARRAY_INTERSECT called prepare_json_and_create_hash from the fix_length_and_dec. It the server can take errors at this point but if warnings are generated, there must be a return value. The handling of error message is implemented in multiple functions. Item_func_json_array_intersect::prepare_json_and_create_hash (and similar in Item_func_json_object_filter_keys::fix_length_and_dec), We handle rjson_read errors, and errors to arguments are forced to a syntax error. create_hash, used by JSON_ARRAY_INTERSECT and JSON_OBJECT_FILTER_KEYS ,if returning a true value, has either a JS error, or a memory allocation error. Because this is pre-val_str() these need to be errors. Once its an error null_value= 1 is required. create_hash needs to handle json parsing errors, potentially being killed or a timeout occurring too. It makes sense to handle the other arguments in val_str() as an error too for consistency. JSON_OBJECT_TO_ARRAY now results in syntax warning on parsing a non-object augment. --- mysql-test/main/func_json.result | 33 +++----- mysql-test/main/func_json.test | 11 ++- sql/item_jsonfunc.cc | 127 +++++++++++++++++++++++-------- sql/item_jsonfunc.h | 7 +- 4 files changed, 124 insertions(+), 54 deletions(-) diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index 3583b94742b39..eba79e41305c2 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -5383,10 +5383,7 @@ json_array_intersect(@obj1, @obj2) SET @obj1= '[1, 2, 3, 3, 3.0, "abc", true, true, {"key1":"val1" ]'; SET @obj2= '[3.0, 3, 5, "abc", "abc", true, {"key2":"val2"}, {"key1":"val1"}, {"key1":"val2"}]'; select json_array_intersect(@obj1, @obj2); -json_array_intersect(@obj1, @obj2) -[3.0, 3, "abc", true] -Warnings: -Warning 4038 Syntax error in JSON text in argument 1 to function 'json_array_intersect' at position 53 +ERROR HY000: Syntax error in JSON text in argument 1 to function 'json_array_intersect' at position 53 # Checking incorrect type for input SET @obj1= '{"key1": "val1"}'; SET @arr1= '[ 1, 2, 3 ]'; @@ -5394,17 +5391,13 @@ SET @num1= '2'; SET @str1= '"abc"'; SET @bool1= 'true'; select json_array_intersect(@obj1, @arr1); -json_array_intersect(@obj1, @arr1) -NULL +ERROR HY000: Syntax error in JSON text in argument 1 to function 'json_array_intersect' at position 1 select json_array_intersect(@arr1, @obj1); -json_array_intersect(@arr1, @obj1) -NULL +ERROR HY000: Syntax error in JSON text in argument 2 to function 'json_array_intersect' at position 1 select json_array_intersect(@arr1, @num1); -json_array_intersect(@arr1, @num1) -NULL +ERROR HY000: Syntax error in JSON text in argument 2 to function 'json_array_intersect' at position 1 select json_array_intersect(@num1, @bool1); -json_array_intersect(@num1, @bool1) -NULL +ERROR HY000: Syntax error in JSON text in argument 1 to function 'json_array_intersect' at position 1 # JSON_OBJECT_FILTER_KEYS() SET @obj1= '{ "a": 1, "b": 2, "c": 3}'; SET @obj2= '{"b" : 10, "c": 20, "d": 30}'; @@ -5428,16 +5421,13 @@ JSON_OBJECT_FILTER_KEYS(@obj1, @arr1) NULL # Incorrect type in input returns NULL SELECT JSON_OBJECT_FILTER_KEYS(@obj1, @obj1); -JSON_OBJECT_FILTER_KEYS(@obj1, @obj1) -NULL +ERROR HY000: Syntax error in JSON text in argument 2 to function 'json_object_filter_keys' at position 1 SELECT JSON_OBJECT_FILTER_KEYS(@arr1, @arr1); -JSON_OBJECT_FILTER_KEYS(@arr1, @arr1) -NULL +ERROR HY000: Syntax error in JSON text in argument 1 to function 'json_object_filter_keys' at position 1 SET @obj1= '{ "a": 1, "b": {"key1": {"key2":"val2"}}, "c": [1, 2, 3] }'; SET @scalar1='2'; SELECT JSON_OBJECT_FILTER_KEYS(@obj1, @scalar1); -JSON_OBJECT_FILTER_KEYS(@obj1, @scalar1) -NULL +ERROR HY000: Syntax error in JSON text in argument 2 to function 'json_object_filter_keys' at position 1 # Checking syntax error SET @obj1= '{ "a": 1, "b": 2, "c": 3}'; SET @obj2= '{"b" : 10, "c": 20, "d" 30}'; @@ -5448,9 +5438,8 @@ Warnings: Warning 4038 Syntax error in JSON text in argument 1 to function 'json_keys' at position 25 SET @obj1= '{ "a": 1, "b": {"key1": {"key2":"val2"}}, "c": [1, 2, 3] }'; SET @arr2= '[ "key2", "key1", "b" '; -SELECT JSON_OBJECT_FILTER_KEYS(@obj1, @arr1); -JSON_OBJECT_FILTER_KEYS(@obj1, @arr1) -NULL +SELECT JSON_OBJECT_FILTER_KEYS(@obj1, @arr2); +ERROR HY000: Unexpected end of JSON text in argument 2 to function 'json_object_filter_keys' # JSON_OBJECT_TO_ARRAY() SET @obj1= '{ "a": [1, 2, 3], "b": { "key1":"val1", "key2": {"key3":"val3"} }, "c": 3, "d" : 1, "e": "xyz", "f": true, "g" : null}'; SELECT JSON_OBJECT_TO_ARRAY(@obj1); @@ -5472,6 +5461,8 @@ SET @arr1= '[1, 2, 3]'; SELECT JSON_OBJECT_TO_ARRAY(@arr1); JSON_OBJECT_TO_ARRAY(@arr1) NULL +Warnings: +Warning 4038 Syntax error in JSON text in argument 1 to function 'json_object_to_array' at position 1 # # MDEV-31411: JSON_ARRAY_INTERSECT/JSON_OBJECT_FILTER_KEYS should fetch # data from a table similar to other JSON functions diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index 835f06be44850..2eb5f33bc73e6 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -4181,6 +4181,7 @@ select json_array_intersect(@obj1, @obj2); --echo # Checking Syntax error for JSON_ARRAY_INTERSECT() SET @obj1= '[1, 2, 3, 3, 3.0, "abc", true, true, {"key1":"val1" ]'; SET @obj2= '[3.0, 3, 5, "abc", "abc", true, {"key2":"val2"}, {"key1":"val1"}, {"key1":"val2"}]'; +--error ER_JSON_SYNTAX select json_array_intersect(@obj1, @obj2); --echo # Checking incorrect type for input @@ -4189,9 +4190,13 @@ SET @arr1= '[ 1, 2, 3 ]'; SET @num1= '2'; SET @str1= '"abc"'; SET @bool1= 'true'; +--error ER_JSON_SYNTAX select json_array_intersect(@obj1, @arr1); +--error ER_JSON_SYNTAX select json_array_intersect(@arr1, @obj1); +--error ER_JSON_SYNTAX select json_array_intersect(@arr1, @num1); +--error ER_JSON_SYNTAX select json_array_intersect(@num1, @bool1); @@ -4215,11 +4220,14 @@ SELECT JSON_OBJECT_FILTER_KEYS(@obj1, @arr1); --echo # Incorrect type in input returns NULL +--error ER_JSON_SYNTAX SELECT JSON_OBJECT_FILTER_KEYS(@obj1, @obj1); +--error ER_JSON_SYNTAX SELECT JSON_OBJECT_FILTER_KEYS(@arr1, @arr1); SET @obj1= '{ "a": 1, "b": {"key1": {"key2":"val2"}}, "c": [1, 2, 3] }'; SET @scalar1='2'; +--error ER_JSON_SYNTAX SELECT JSON_OBJECT_FILTER_KEYS(@obj1, @scalar1); --echo # Checking syntax error @@ -4230,7 +4238,8 @@ SELECT JSON_OBJECT_FILTER_KEYS (@obj1, json_array_intersect(json_keys(@obj1), js SET @obj1= '{ "a": 1, "b": {"key1": {"key2":"val2"}}, "c": [1, 2, 3] }'; SET @arr2= '[ "key2", "key1", "b" '; -SELECT JSON_OBJECT_FILTER_KEYS(@obj1, @arr1); +--error ER_JSON_EOS +SELECT JSON_OBJECT_FILTER_KEYS(@obj1, @arr2); --echo # JSON_OBJECT_TO_ARRAY() diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 403ea6491a36d..f5aeabde810d2 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -455,6 +455,9 @@ static int json_nice(json_engine_t *je, String *nice_js, report_json_error_ex(js->ptr(), je, func_name(), n_param, \ Sql_condition::WARN_LEVEL_WARN) +#define report_json_error_level(js, je, n_param, level) \ + report_json_error_ex(js->ptr(), je, func_name(), n_param, level) + void report_json_error_ex(const char *js, json_engine_t *je, const char *fname, int n_param, Sql_condition::enum_warning_level lv) @@ -5377,7 +5380,7 @@ static bool create_hash(json_engine_t *value, HASH *items, bool &item_hash_inite } } } - return false; + return value->s.error != 0; } @@ -5415,12 +5418,13 @@ static my_bool restore_entry(void *element, void *arg) If the outermost layer of JSON is an array, the intersection of arrays is independent of order. Create a hash containing all elements in the array, - itterate over another array and add the common elements + iterate over another array and add the common elements to the result. RETURN FALSE - if two array documents have intersection TRUE - If two array documents do not have intersection + or an error. */ bool Item_func_json_array_intersect:: get_intersect_between_arrays(String *str, json_engine_t *value, @@ -5439,13 +5443,18 @@ bool Item_func_json_array_intersect:: DYNAMIC_STRING norm_val; if (json_read_value(value) || - get_current_value(value, value_start, value_len) || - init_dynamic_string(&norm_val, NULL, 0, 0)) + get_current_value(value, value_start, value_len)) goto error; + if (init_dynamic_string(&norm_val, NULL, 0, 0)) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + goto error; + } if (json_normalize(&norm_val, (const char*) value_start, value_len, value->s.cs)) { + value->s.error= JE_SYN; /* temp until json_normalize takes value arg */ dynstr_free(&norm_val); goto error; } @@ -5453,6 +5462,7 @@ bool Item_func_json_array_intersect:: char *new_entry= (char*)malloc(norm_val.length+1); if (!new_entry) { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); dynstr_free(&norm_val); goto error; } @@ -5476,6 +5486,7 @@ bool Item_func_json_array_intersect:: temp_str.append(','); if (my_hash_delete(items, found) || my_hash_insert(seen, (const uchar *)found)) { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); free(new_entry); goto error; } @@ -5483,9 +5494,9 @@ bool Item_func_json_array_intersect:: free(new_entry); } - res= false; + res= value->s.error != 0; - if (has_value) + if (has_value && !res) { temp_str.chop(); /* remove last comma because there are no values after that. */ temp_str.append(']'); @@ -5521,7 +5532,8 @@ String* Item_func_json_array_intersect::val_str(String *str) free_root(&hash_root, MYF(0)); root_inited= false; item_hash_inited= false; - prepare_json_and_create_hash(&je1, js1); + if (prepare_json_and_create_hash(&je1, js1)) + goto null_return; } if (!is_array || args[1]->null_value) @@ -5533,8 +5545,14 @@ String* Item_func_json_array_intersect::val_str(String *str) json_scan_start(&je2, js2->charset(), (const uchar *) js2->ptr(), (const uchar *) js2->ptr() + js2->length()); - if (json_read_value(&je2) || je2.value_type != JSON_VALUE_ARRAY) - goto error_return; + if (json_read_value(&je2)) + goto je2_error_return; + + if (je2.value_type != JSON_VALUE_ARRAY) + { + je2.s.error= JE_SYN; + goto je2_error_return; + } if (get_intersect_between_arrays(str, &je2, &items, &seen)) goto error_return; @@ -5545,7 +5563,11 @@ String* Item_func_json_array_intersect::val_str(String *str) (const uchar *) str->ptr() + str->length()); str= &tmp_js1; if (json_nice(&res_je, str, Item_func_json_format::LOOSE)) - goto error_return; + { + /* technically an output rather than arg */ + report_json_error(str, &res_je, 0); + goto null_return; + } null_value= 0; return str; @@ -5557,7 +5579,9 @@ String* Item_func_json_array_intersect::val_str(String *str) error_return: if (je2.s.error) - report_json_error(js2, &je2, 1); +je2_error_return: + report_json_error_level(js2, &je2, swapped ? 0 : 1, + Sql_condition::WARN_LEVEL_ERROR); null_return: null_value= 1; return NULL; @@ -5573,20 +5597,35 @@ bool Item_func_json_array_intersect::prepare_json_and_create_hash(json_engine_t if (my_hash_init(PSI_INSTRUMENT_ME, &seen, je1->s.cs, 0, 0, 0, get_key_name, NULL, 0)) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); return true; + } seen_hash_inited= true; if (!root_inited) init_alloc_root(PSI_NOT_INSTRUMENTED, &hash_root, 1024, 0, MYF(0)); root_inited= true; - if (json_read_value(je1) - || !(is_array= (je1->value_type == JSON_VALUE_ARRAY)) || - create_hash(je1, &items, item_hash_inited, &hash_root)) - { - if (je1->s.error) - report_json_error(js, je1, 0); - } + if (json_read_value(je1)) + goto je_error; + + if (!(is_array= (je1->value_type == JSON_VALUE_ARRAY))) + { + je1->s.error= JE_SYN; + goto je_error; + } + + if (create_hash(je1, &items, item_hash_inited, &hash_root)) + { + if (je1->s.error) +je_error: + report_json_error_level(js, je1, swapped ? 1 : 0, + Sql_condition::WARN_LEVEL_ERROR); + else + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return true; + } return false; } @@ -5600,6 +5639,7 @@ bool Item_func_json_array_intersect::fix_length_and_dec(THD *thd) { if (args[1]->const_item()) { + swapped= true; std::swap(args[0], args[1]); } else @@ -5613,6 +5653,7 @@ bool Item_func_json_array_intersect::fix_length_and_dec(THD *thd) if (js1 && prepare_json_and_create_hash(&je1, js1)) { + null_value= 1; return TRUE; } @@ -5685,7 +5726,7 @@ static bool filter_keys(json_engine_t *je1, String *str, HASH items) } } - res= false; + res= je1->s.error != 0; if (has_value) { @@ -5714,11 +5755,17 @@ String* Item_func_json_object_filter_keys::val_str(String *str) json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(), (const uchar *) js1->ptr() + js1->length()); - if (json_read_value(&je1) || je1.value_type != JSON_VALUE_OBJECT) - goto error_return; + if (json_read_value(&je1)) + goto je1_error_return; - if(filter_keys(&je1, str, items)) - goto null_return; + if (je1.value_type != JSON_VALUE_OBJECT) + { + je1.s.error= JE_SYN; + goto je1_error_return; + } + + if (filter_keys(&je1, str, items)) + goto error_return; if (str->length()) { @@ -5726,7 +5773,12 @@ String* Item_func_json_object_filter_keys::val_str(String *str) (const uchar *) str->ptr() + str->length()); str= &tmp_js1; if (json_nice(&res_je, str, Item_func_json_format::LOOSE)) - goto error_return; + { + if (res_je.s.error) + report_json_error_level(str, &res_je, 1, + Sql_condition::WARN_LEVEL_ERROR); + goto null_return; + } null_value= 0; return str; @@ -5736,10 +5788,11 @@ String* Item_func_json_object_filter_keys::val_str(String *str) goto null_return; } - error_return: if (je1.s.error) - report_json_error(js1, &je1, 0); +je1_error_return: + report_json_error_level(js1, &je1, 0, + Sql_condition::WARN_LEVEL_ERROR); null_return: null_value= 1; return NULL; @@ -5763,11 +5816,22 @@ bool Item_func_json_object_filter_keys::fix_length_and_dec(THD *thd) init_alloc_root(PSI_NOT_INSTRUMENTED, &hash_root, 1024, 0, MYF(0)); root_inited= true; - if (json_read_value(&je2) || je2.value_type != JSON_VALUE_ARRAY || - create_hash(&je2, &items, hash_inited, &hash_root)) + if (json_read_value(&je2)) + goto je_error; + if (je2.value_type != JSON_VALUE_ARRAY) + { + je2.s.error= JE_SYN; + goto je_error; + } + + if (create_hash(&je2, &items, hash_inited, &hash_root)) { if (je2.s.error) - report_json_error(js2, &je2, 0); +je_error: + report_json_error_level(js2, &je2, 1, + Sql_condition::WARN_LEVEL_ERROR); + else + my_error(ER_OUT_OF_RESOURCES, MYF(0)); null_value= 1; return FALSE; } @@ -5858,7 +5922,10 @@ String* Item_func_json_object_to_array::val_str(String *str) if (json_read_value(&je)) goto error_return; if (je.value_type != JSON_VALUE_OBJECT) - goto null_return; + { + je.s.error= JE_SYN; + goto error_return; + } if (convert_to_array(&je, str)) goto error_return; diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index 32fc77ddef1a8..bbcdadfd8488c 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -939,11 +939,14 @@ class Item_func_json_array_intersect: public Item_str_func bool item_hash_inited, seen_hash_inited, root_inited; HASH items, seen; MEM_ROOT hash_root; - bool parse_for_each_row, is_array; + bool parse_for_each_row, is_array, swapped; public: Item_func_json_array_intersect(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) - { item_hash_inited= seen_hash_inited= root_inited= parse_for_each_row= is_array= false; } + { + item_hash_inited= seen_hash_inited= root_inited= parse_for_each_row= + is_array= swapped= false; + } String *val_str(String *) override; bool fix_length_and_dec(THD *thd) override; LEX_CSTRING func_name_cstring() const override From 195ea5487f03c344ab1ebef8defd735609b8fa76 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 29 Jun 2026 11:06:39 +1000 Subject: [PATCH 4/5] MDEV-39742 11.4 JSON functions not interuptable The JSON functions added in 11.4 where not interuptable with a KILL QUERY or exceeding the max_statement_time. * JSON_ARRAY_INTERSECT * JSON_OBJECT_FILTER_KEYS * JSON_OBJECT_TO_ARRAY * JSON_SCHEMA_VALID This behaviour is corrected by setting the killed_ptr of the json_engine_t structure. JSON_KEY_VALUE was added in 11.4, however as it doesn't call json_next_value(), its processing doesn't check the killed pointer of the json engine. So its quick anyway. --- mysql-test/main/func_json_notembedded.result | 6 ++++++ mysql-test/main/func_json_notembedded.test | 3 +++ sql/item_jsonfunc.cc | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/mysql-test/main/func_json_notembedded.result b/mysql-test/main/func_json_notembedded.result index b49b79feed70c..3fce3763272ab 100644 --- a/mysql-test/main/func_json_notembedded.result +++ b/mysql-test/main/func_json_notembedded.result @@ -16,6 +16,8 @@ select json_array_append(@arr, '$[0]', 1); ERROR 70100: Query execution was interrupted (max_statement_time exceeded) select json_array_insert(@arr, '$[0]', 1); ERROR 70100: Query execution was interrupted (max_statement_time exceeded) +select json_array_intersect(@arr, @arr); +ERROR 70100: Query execution was interrupted (max_statement_time exceeded) select json_insert(@obj, '$.meta', 1); ERROR 70100: Query execution was interrupted (max_statement_time exceeded) select json_compact(@arr); @@ -40,10 +42,14 @@ select json_merge_patch(@obj, @obj); ERROR 70100: Query execution was interrupted (max_statement_time exceeded) select json_merge_preserve(@obj, @arr); ERROR 70100: Query execution was interrupted (max_statement_time exceeded) +select json_object_filter_keys(@obj, @arr); +ERROR 70100: Query execution was interrupted (max_statement_time exceeded) select json_remove(@obj,'$.foo'); ERROR 70100: Query execution was interrupted (max_statement_time exceeded) select json_replace(@obj,'$.foo',1); ERROR 70100: Query execution was interrupted (max_statement_time exceeded) +select json_schema_valid(@obj, '{"type":"object"}'); +ERROR 70100: Query execution was interrupted (max_statement_time exceeded) select json_set(@arr,'$[1000]',1); ERROR 70100: Query execution was interrupted (max_statement_time exceeded) select ST_AsTEXT(ST_GeomFromGeoJSON(JSON_OBJECT("type", "Point", "coordinates", @arr),2)) as exp; diff --git a/mysql-test/main/func_json_notembedded.test b/mysql-test/main/func_json_notembedded.test index bf5cc4d91cc98..7cd92fc831d16 100644 --- a/mysql-test/main/func_json_notembedded.test +++ b/mysql-test/main/func_json_notembedded.test @@ -21,6 +21,7 @@ SET @old_debug= @@debug_dbug; SET debug_dbug='+d,json_pause_execution'; select json_array_append(@arr, '$[0]', 1); select json_array_insert(@arr, '$[0]', 1); +select json_array_intersect(@arr, @arr); select json_insert(@obj, '$.meta', 1); select json_compact(@arr); select json_contains(@obj, '"d"', '$.c'); @@ -33,8 +34,10 @@ select json_loose(@arr); select json_merge(@obj, @arr); select json_merge_patch(@obj, @obj); select json_merge_preserve(@obj, @arr); +select json_object_filter_keys(@obj, @arr); select json_remove(@obj,'$.foo'); select json_replace(@obj,'$.foo',1); +select json_schema_valid(@obj, '{"type":"object"}'); select json_set(@arr,'$[1000]',1); select ST_AsTEXT(ST_GeomFromGeoJSON(JSON_OBJECT("type", "Point", "coordinates", @arr),2)) as exp; enable_abort_on_error; diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index f5aeabde810d2..ce751bfeedf19 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -5072,6 +5072,7 @@ bool Item_func_json_overlaps::fix_length_and_dec(THD *thd) bool Item_func_json_schema_valid::val_bool() { + THD *thd; json_engine_t ve; int is_valid= 1; @@ -5095,6 +5096,9 @@ bool Item_func_json_schema_valid::val_bool() json_scan_start(&ve, val->charset(), (const uchar *) val->ptr(), (const uchar *) val->end()); + thd= current_thd; + ve.killed_ptr= (uint32_t *) &thd->killed; + JSON_DO_PAUSE_EXECUTION(thd, 0.0002); if (json_read_value(&ve)) goto end; @@ -5512,6 +5516,7 @@ bool Item_func_json_array_intersect:: String* Item_func_json_array_intersect::val_str(String *str) { + THD *thd; DBUG_ASSERT(fixed()); json_engine_t je2, res_je, je1; @@ -5544,6 +5549,8 @@ String* Item_func_json_array_intersect::val_str(String *str) json_scan_start(&je2, js2->charset(), (const uchar *) js2->ptr(), (const uchar *) js2->ptr() + js2->length()); + thd= current_thd; + je2.killed_ptr= (uint32_t *) &thd->killed; if (json_read_value(&je2)) goto je2_error_return; @@ -5561,6 +5568,7 @@ String* Item_func_json_array_intersect::val_str(String *str) { json_scan_start(&res_je, str->charset(), (const uchar *) str->ptr(), (const uchar *) str->ptr() + str->length()); + res_je.killed_ptr= (uint32_t *) &thd->killed; str= &tmp_js1; if (json_nice(&res_je, str, Item_func_json_format::LOOSE)) { @@ -5589,8 +5597,11 @@ String* Item_func_json_array_intersect::val_str(String *str) bool Item_func_json_array_intersect::prepare_json_and_create_hash(json_engine_t *je1, String *js) { + THD *thd= current_thd; + JSON_DO_PAUSE_EXECUTION(thd, 0.0002); json_scan_start(je1, js->charset(), (const uchar *) js->ptr(), (const uchar *) js->ptr() + js->length()); + je1->killed_ptr= (uint32_t *) &thd->killed; /* Scan value uses the hash table to get the intersection of two arrays. */ @@ -5741,6 +5752,7 @@ static bool filter_keys(json_engine_t *je1, String *str, HASH items) String* Item_func_json_object_filter_keys::val_str(String *str) { + THD *thd; DBUG_ASSERT(fixed()); json_engine_t je1, res_je; @@ -5754,6 +5766,8 @@ String* Item_func_json_object_filter_keys::val_str(String *str) json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(), (const uchar *) js1->ptr() + js1->length()); + thd= current_thd; + je1.killed_ptr= (uint32_t *) &thd->killed; if (json_read_value(&je1)) goto je1_error_return; @@ -5771,6 +5785,7 @@ String* Item_func_json_object_filter_keys::val_str(String *str) { json_scan_start(&res_je, str->charset(), (const uchar *) str->ptr(), (const uchar *) str->ptr() + str->length()); + res_je.killed_ptr= (uint32_t *) &thd->killed; str= &tmp_js1; if (json_nice(&res_je, str, Item_func_json_format::LOOSE)) { @@ -5905,6 +5920,7 @@ static bool convert_to_array(json_engine_t *je, String *str) String* Item_func_json_object_to_array::val_str(String *str) { + THD *thd; DBUG_ASSERT(fixed()); json_engine_t je; @@ -5918,6 +5934,9 @@ String* Item_func_json_object_to_array::val_str(String *str) json_scan_start(&je, js1->charset(),(const uchar *) js1->ptr(), (const uchar *) js1->ptr() + js1->length()); + thd= current_thd; + je.killed_ptr= (uint32_t *) &thd->killed; + JSON_DO_PAUSE_EXECUTION(thd, 0.0002); if (json_read_value(&je)) goto error_return; From b609be5bf54db20ebfac6c5c08c820e64c157089 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 29 Jun 2026 11:10:54 +1000 Subject: [PATCH 5/5] json_key_value - simplify error handling Same result, just consolidating the implementation. --- sql/item_jsonfunc.cc | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index ce751bfeedf19..f3e5363ba1e5c 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -5302,21 +5302,16 @@ String* Item_func_json_key_value::val_str(String *str) json_scan_start(&je, tmp_str.charset(), (const uchar *) tmp_str.ptr(), (const uchar *) tmp_str.ptr() + tmp_str.length()); if (json_read_value(&je)) - { - report_json_error(str, &je, 0); - goto return_null; - } + goto return_error; str->length(0); if (get_key_value(&je, str)) - { - report_json_error(str, &je, 0); - goto return_null; - } + goto return_error; return str; +return_error: + report_json_error(str, &je, 0); -return_null: null_value= 1; return NULL; }