diff options
Diffstat (limited to 'sql/item_jsonfunc.cc')
-rw-r--r-- | sql/item_jsonfunc.cc | 143 |
1 files changed, 98 insertions, 45 deletions
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 97d7b89f..87197371 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -20,6 +20,17 @@ #include "item.h" #include "sql_parse.h" // For check_stack_overrun +#ifndef DBUG_OFF +static int dbug_json_check_min_stack_requirement() +{ + my_error(ER_STACK_OVERRUN_NEED_MORE, MYF(ME_FATAL), + my_thread_stack_size, my_thread_stack_size, STACK_MIN_SIZE); + return 1; +} +#endif + +extern void pause_execution(THD *thd, double timeout); + /* Allocating memory and *also* using it (reading and writing from it) because some build instructions cause @@ -28,12 +39,12 @@ correctly and causes json_debug_nonembedded to fail ( --error ER_STACK_OVERRUN_NEED_MORE does not occur). */ -#define ALLOCATE_MEM_ON_STACK(A) do \ - { \ - uchar *array= (uchar*)alloca(A); \ - bzero(array, A); \ - my_checksum(0, array, A); \ - } while(0) + +#define JSON_DO_PAUSE_EXECUTION(A, B) do \ + { \ + DBUG_EXECUTE_IF("json_pause_execution", \ + { pause_execution(A, B); }); \ + } while(0) /* Compare ASCII string against the string with the specified @@ -152,11 +163,8 @@ int json_path_parts_compare( const json_path_step_t *temp_b= b; DBUG_EXECUTE_IF("json_check_min_stack_requirement", - { - long arbitrary_var; - long stack_used_up= (available_stack_size(current_thd->thread_stack, &arbitrary_var)); - ALLOCATE_MEM_ON_STACK(my_thread_stack_size-stack_used_up-STACK_MIN_SIZE); - }); + return dbug_json_check_min_stack_requirement();); + if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) return 1; @@ -845,7 +853,7 @@ bool Item_func_json_unquote::fix_length_and_dec(THD *thd) { collation.set(&my_charset_utf8mb3_general_ci, DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); - max_length= args[0]->max_length; + max_length= args[0]->max_char_length() * collation.collation->mbmaxlen; set_maybe_null(); return FALSE; } @@ -998,16 +1006,17 @@ bool Item_func_json_extract::fix_length_and_dec(THD *thd) } -static bool path_exact(const json_path_with_flags *paths_list, int n_paths, +static int path_exact(const json_path_with_flags *paths_list, int n_paths, const json_path_t *p, json_value_types vt, const int *array_size_counter) { + int count_path= 0; for (; n_paths > 0; n_paths--, paths_list++) { if (json_path_compare(&paths_list->p, p, vt, array_size_counter) == 0) - return TRUE; + count_path++; } - return FALSE; + return count_path; } @@ -1032,7 +1041,7 @@ String *Item_func_json_extract::read_json(String *str, json_engine_t je, sav_je; json_path_t p; const uchar *value; - int not_first_value= 0; + int not_first_value= 0, count_path= 0; uint n_arg; size_t v_len; int possible_multiple_values; @@ -1091,7 +1100,8 @@ String *Item_func_json_extract::read_json(String *str, array_size_counter + (p.last_step - p.steps))) goto error; - if (!path_exact(paths, arg_count-1, &p, je.value_type, array_size_counter)) + if (!(count_path= path_exact(paths, arg_count-1, &p, je.value_type, + array_size_counter))) continue; value= je.value_begin; @@ -1121,9 +1131,12 @@ String *Item_func_json_extract::read_json(String *str, je= sav_je; } - if ((not_first_value && str->append(", ", 2)) || - str->append((const char *) value, v_len)) - goto error; /* Out of memory. */ + for (int count= 0; count < count_path; count++) + { + if (str->append((const char *) value, v_len) || + str->append(", ", 2)) + goto error; /* Out of memory. */ + } not_first_value= 1; @@ -1144,6 +1157,11 @@ String *Item_func_json_extract::read_json(String *str, goto return_null; } + if (str->length()>2) + { + str->chop(); + str->chop(); + } if (possible_multiple_values && str->append(']')) goto error; /* Out of memory. */ @@ -1306,11 +1324,7 @@ static int check_contains(json_engine_t *js, json_engine_t *value) json_engine_t loc_js; bool set_js; DBUG_EXECUTE_IF("json_check_min_stack_requirement", - { - long arbitrary_var; - long stack_used_up= (available_stack_size(current_thd->thread_stack, &arbitrary_var)); - ALLOCATE_MEM_ON_STACK(my_thread_stack_size-stack_used_up-STACK_MIN_SIZE); - }); + return dbug_json_check_min_stack_requirement();); if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) return 1; @@ -1912,7 +1926,23 @@ bool Item_func_json_array::fix_length_and_dec(THD *thd) return TRUE; for (n_arg=0 ; n_arg < arg_count ; n_arg++) - char_length+= static_cast<ulonglong>(args[n_arg]->max_char_length()) + 4; + { + ulonglong arg_length; + Item *arg= args[n_arg]; + + if (arg->result_type() == STRING_RESULT && + !Type_handler_json_common::is_json_type_handler(arg->type_handler())) + arg_length= arg->max_char_length() * 2; /*escaping possible */ + else if (arg->type_handler()->is_bool_type()) + arg_length= 5; + else + arg_length= arg->max_char_length(); + + if (arg_length < 4) + arg_length= 4; /* can be 'null' */ + + char_length+= arg_length + 4; + } fix_char_length_ulonglong(char_length); tmp_val.set_charset(collation.collation); @@ -1962,6 +1992,8 @@ err_return: bool Item_func_json_array_append::fix_length_and_dec(THD *thd) { + JSON_DO_PAUSE_EXECUTION(thd, 0.0002); + uint n_arg; ulonglong char_length; @@ -2120,6 +2152,8 @@ String *Item_func_json_array_insert::val_str(String *str) uint n_arg, n_path; THD *thd= current_thd; + JSON_DO_PAUSE_EXECUTION(thd, 0.0002); + DBUG_ASSERT(fixed()); if ((null_value= args[0]->null_value)) @@ -2309,13 +2343,8 @@ err_return: static int do_merge(String *str, json_engine_t *je1, json_engine_t *je2) { - DBUG_EXECUTE_IF("json_check_min_stack_requirement", - { - long arbitrary_var; - long stack_used_up= (available_stack_size(current_thd->thread_stack, &arbitrary_var)); - ALLOCATE_MEM_ON_STACK(my_thread_stack_size-stack_used_up-STACK_MIN_SIZE); - }); + return dbug_json_check_min_stack_requirement();); if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) return 1; @@ -2530,6 +2559,8 @@ String *Item_func_json_merge::val_str(String *str) THD *thd= current_thd; LINT_INIT(js2); + JSON_DO_PAUSE_EXECUTION(thd, 0.0002); + if (args[0]->null_value) goto null_return; @@ -2654,11 +2685,7 @@ static int do_merge_patch(String *str, json_engine_t *je1, json_engine_t *je2, bool *empty_result) { DBUG_EXECUTE_IF("json_check_min_stack_requirement", - { - long arbitrary_var; - long stack_used_up= (available_stack_size(current_thd->thread_stack, &arbitrary_var)); - ALLOCATE_MEM_ON_STACK(my_thread_stack_size-stack_used_up-STACK_MIN_SIZE); - }); + return dbug_json_check_min_stack_requirement();); if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) return 1; @@ -2843,6 +2870,8 @@ String *Item_func_json_merge_patch::val_str(String *str) bool empty_result, merge_to_null; THD *thd= current_thd; + JSON_DO_PAUSE_EXECUTION(thd, 0.0002); + /* To report errors properly if some JSON is invalid. */ je1.s.error= je2.s.error= 0; merge_to_null= args[0]->null_value; @@ -3120,6 +3149,12 @@ String *Item_func_json_type::val_str(String *str) break; } + /* ensure the json is at least valid. */ + while(json_scan_next(&je) == 0) {} + + if (je.s.error) + goto error; + str->set(type, strlen(type), &my_charset_utf8mb3_general_ci); return str; @@ -3135,14 +3170,20 @@ bool Item_func_json_insert::fix_length_and_dec(THD *thd) uint n_arg; ulonglong char_length; + JSON_DO_PAUSE_EXECUTION(thd, 0.0002); + collation.set(args[0]->collation); char_length= args[0]->max_char_length(); for (n_arg= 1; n_arg < arg_count; n_arg+= 2) { paths[n_arg/2].set_constant_flag(args[n_arg]->const_item()); - char_length+= - static_cast<ulonglong>(args[n_arg+1]->max_char_length()) + 4; + /* + In the resulting JSON we can insert the property + name from the path, and the value itself. + */ + char_length+= args[n_arg/2]->max_char_length() + 6; + char_length+= args[n_arg/2+1]->max_char_length() + 4; } fix_char_length_ulonglong(char_length); @@ -3425,6 +3466,8 @@ String *Item_func_json_remove::val_str(String *str) DBUG_ASSERT(fixed()); + JSON_DO_PAUSE_EXECUTION(thd, 0.0002); + if (args[0]->null_value) goto null_return; @@ -3476,6 +3519,7 @@ String *Item_func_json_remove::val_str(String *str) { if (je.s.error) goto js_error; + continue; } if (json_read_value(&je)) @@ -3987,7 +4031,20 @@ bool Item_func_json_format::fix_length_and_dec(THD *thd) { decimals= 0; collation.set(args[0]->collation); - max_length= args[0]->max_length; + switch (fmt) + { + case COMPACT: + max_length= args[0]->max_length; + break; + case LOOSE: + max_length= args[0]->max_length * 2; + break; + case DETAILED: + max_length= MAX_BLOB_WIDTH; + break; + default: + DBUG_ASSERT(0); + }; set_maybe_null(); return FALSE; } @@ -4705,11 +4762,7 @@ int json_find_overlap_with_object(json_engine_t *js, json_engine_t *value, int check_overlaps(json_engine_t *js, json_engine_t *value, bool compare_whole) { DBUG_EXECUTE_IF("json_check_min_stack_requirement", - { - long arbitrary_var; - long stack_used_up= (available_stack_size(current_thd->thread_stack, &arbitrary_var)); - ALLOCATE_MEM_ON_STACK(my_thread_stack_size-stack_used_up-STACK_MIN_SIZE); - }); + return dbug_json_check_min_stack_requirement();); if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) return 1; |