diff --git a/include/json_lib.h b/include/json_lib.h index c619ad9d915..13fbfed0186 100644 --- a/include/json_lib.h +++ b/include/json_lib.h @@ -7,8 +7,27 @@ extern "C" { #endif -#define JSON_DEPTH_LIMIT 32 +#define JSON_DEPTH_DEFAULT 32 +#define JSON_DEPTH_LIMIT 32 /* Still used in columnstore. */ +#define JSON_DEPTH_INC JSON_DEPTH_DEFAULT*100 +/* + Because this array will store approximate two arrays of + type json_path_step_t and one or two integer arrays, + each of average 70 elements. So this size should suffice. +*/ +#define BLOCK_SIZE_JSON_DYN_ARRAY 4096 + +#define get_json_step(p,s) if (p->last_step_idx < (int)(p->steps.max_element)) \ + s= ((json_path_step_t*)(p->steps.buffer))+p->last_step_idx; \ + else \ + s= (json_path_step_t*) mem_root_dynamic_array_resize_and_get_val(&p->steps, p->last_step_idx); + +#define set_json_array_value_ptr(idx, max_element, dyn_arr_ptr, val) \ + if ((size_t)(idx) < (max_element)) \ + memcpy((dyn_arr_ptr)->buffer + (dyn_arr_ptr)->size_of_element * (idx), &(val), sizeof(val)); \ + else \ + mem_root_dynamic_array_resize_and_set_val((dyn_arr_ptr), &(val), (idx)); /* When error happens, the c_next of the JSON engine contains the character that caused the error, and the c_str is the position @@ -28,7 +47,7 @@ enum json_errors { JE_ESCAPING= -6, /* Error in the escaping. */ - JE_DEPTH= -7, /* The limit on the JSON depth was overrun. */ + JE_DEPTH= -7, /* The limit on the JSON depth was overrun. Still used in columnstore*/ }; @@ -104,8 +123,8 @@ typedef struct st_json_path_step_t typedef struct st_json_path_t { json_string_t s; /* The string to be parsed. */ - json_path_step_t steps[JSON_DEPTH_LIMIT]; /* Steps of the path. */ - json_path_step_t *last_step; /* Points to the last step. */ + MEM_ROOT_DYNAMIC_ARRAY steps; /* Steps of the path. */ + int last_step_idx; int mode_strict; /* TRUE if the path specified as 'strict' */ enum json_path_step_types types_used; /* The '|' of all step's 'type'-s */ @@ -225,8 +244,8 @@ typedef struct st_json_engine_t const uchar *value_end; /* Points to the next character after the value. */ int value_len; /* The length of the value. Does not count quotations for */ /* string constants. */ - - int stack[JSON_DEPTH_LIMIT]; /* Keeps the stack of nested JSON structures. */ + /* Keeps the stack of nested JSON structures. */ + MEM_ROOT_DYNAMIC_ARRAY stack; int stack_p; /* The 'stack' pointer. */ volatile uchar *killed_ptr; } json_engine_t; @@ -341,6 +360,13 @@ int json_skip_level_and_count(json_engine_t *j, int *n_items_skipped); */ #define json_value_scalar(je) ((je)->value_type > JSON_VALUE_ARRAY) +#define report_json_error(js, je, n_param) \ + report_json_error_ex(js->ptr(), je, func_name(), n_param, \ + Sql_condition::WARN_LEVEL_WARN) + +#define report_path_error(js, je, n_param) \ + report_path_error_ex(js->ptr(), je, func_name(), n_param,\ + Sql_condition::WARN_LEVEL_WARN) /* Look for the JSON PATH in the json string. @@ -350,7 +376,7 @@ int json_skip_level_and_count(json_engine_t *j, int *n_items_skipped); initialized with the JSON string, and the json_path_t with the JSON path appropriately. The 'p_cur_step' should point at the first step of the path. - The 'array_counters' is the array of JSON_DEPTH_LIMIT size. + The 'array_counters' is the array of 'curr_json_depth_limit' size. It stores the array counters of the parsed JSON. If function returns 0, it means it found the match. The position of the match is je->s.c_str. Then we can call the json_find_path() @@ -360,7 +386,7 @@ int json_skip_level_and_count(json_engine_t *j, int *n_items_skipped); */ int json_find_path(json_engine_t *je, json_path_t *p, json_path_step_t **p_cur_step, - int *array_counters); + MEM_ROOT_DYNAMIC_ARRAY *array_counters); typedef struct st_json_find_paths_t @@ -369,7 +395,7 @@ typedef struct st_json_find_paths_t json_path_t *paths; uint cur_depth; uint *path_depths; - int array_counters[JSON_DEPTH_LIMIT]; + MEM_ROOT_DYNAMIC_ARRAY array_counters; } json_find_paths_t; @@ -431,17 +457,22 @@ int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs, int json_get_path_next(json_engine_t *je, json_path_t *p); int json_path_compare(const json_path_t *a, const json_path_t *b, - enum json_value_types vt, const int* array_size_counter); + enum json_value_types vt, + MEM_ROOT_DYNAMIC_ARRAY* array_size_counter); -int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs); +int json_valid(const char *js, size_t js_len, + CHARSET_INFO *cs, json_engine_t *je); -int json_locate_key(const char *js, const char *js_end, +int json_locate_key(json_engine_t *je, const char *js, const char *js_end, const char *kname, const char **key_start, const char **key_end, int *comma_pos); int json_normalize(DYNAMIC_STRING *result, - const char *s, size_t size, CHARSET_INFO *cs); + const char *s, size_t size, CHARSET_INFO *cs, + MEM_ROOT *current_mem_root, + json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack); int json_skip_array_and_count(json_engine_t *j, int* n_item); @@ -450,6 +481,8 @@ inline static int json_scan_ended(json_engine_t *j) return (j->state == JST_ARRAY_END && j->stack_p == 0); } +void initJsonArray(MEM_ROOT *mem_root, MEM_ROOT_DYNAMIC_ARRAY *mem_root_array, size_t size, void *buffer, myf myflag); + #ifdef __cplusplus } #endif diff --git a/include/my_sys.h b/include/my_sys.h index faf2e7ec5c8..2f0f41214b4 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -89,6 +89,7 @@ C_MODE_START #define MY_FREE_ON_ERROR 128U /* my_realloc() ; Free old ptr on error */ #define MY_DONT_OVERWRITE_FILE 2048U /* my_copy: Don't overwrite file */ #define MY_THREADSAFE 2048U /* my_seek(): lock fd mutex */ +#define MY_BUFFER_NO_RESIZE 512U #define MY_SYNC 4096U /* my_copy(): sync dst file */ #define MY_SYNC_DIR 32768U /* my_create/delete/rename: sync directory */ #define MY_THREAD_SPECIFIC 0x10000U /* my_malloc(): thread specific */ @@ -362,6 +363,17 @@ typedef struct st_dynamic_array myf malloc_flags; } DYNAMIC_ARRAY; +typedef struct st_mem_root_dynamic_array +{ + MEM_ROOT *mem_root; + uchar *buffer; + size_t elements, max_element; + size_t alloc_increment; + size_t size_of_element; + PSI_memory_key m_psi_key; + myf malloc_flags; +} MEM_ROOT_DYNAMIC_ARRAY; + typedef struct st_dynamic_array_append { @@ -1176,6 +1188,74 @@ extern void thd_increment_bytes_sent(void *thd, size_t length); extern void thd_increment_bytes_received(void *thd, size_t length); extern void thd_increment_net_big_packet_count(void *thd, size_t length); +extern int mem_root_dynamic_array_init(MEM_ROOT *mem_root, + PSI_memory_key psi_key, + MEM_ROOT_DYNAMIC_ARRAY *array, + size_t element_size, void *init_buffer, + size_t init_alloc, + size_t alloc_increment, + myf my_flags); +int mem_root_allocate_dynamic(MEM_ROOT *mem_root, + MEM_ROOT_DYNAMIC_ARRAY *array, + size_t idx); +extern void* mem_root_dynamic_array_get_val(MEM_ROOT_DYNAMIC_ARRAY *array, size_t idx); +extern void mem_root_dynamic_array_reset(MEM_ROOT_DYNAMIC_ARRAY *array); +extern int mem_root_dynamic_array_resize_not_allowed(MEM_ROOT_DYNAMIC_ARRAY *array); +extern void mem_root_dynamic_array_copy_values(MEM_ROOT_DYNAMIC_ARRAY *dest, MEM_ROOT_DYNAMIC_ARRAY *src); +static inline int mem_root_dynamic_array_set_val(MEM_ROOT_DYNAMIC_ARRAY *array, + const void *element, size_t idx) +{ + DBUG_ASSERT(idx < array->max_element); + + memcpy(array->buffer+(idx * array->size_of_element), element, + array->size_of_element); + return TRUE; +} +static inline int mem_root_dynamic_array_resize_and_set_val(MEM_ROOT_DYNAMIC_ARRAY *array, + const void *element, size_t idx) +{ + if (array->malloc_flags & MY_BUFFER_NO_RESIZE) + return TRUE; + + if (idx >= array->max_element) + { + if (mem_root_allocate_dynamic(array->mem_root, array, idx)) + return 1; + array->elements++; + } + + /* + Ensure the array size has increased and the index is + now well within the array bounds. + */ + DBUG_ASSERT(idx < array->max_element); + + memcpy(array->buffer+(idx * array->size_of_element), element, + array->size_of_element); + + return FALSE; +} + +static inline void* mem_root_dynamic_array_resize_and_get_val(MEM_ROOT_DYNAMIC_ARRAY *array, size_t idx) +{ + if (array->malloc_flags & MY_BUFFER_NO_RESIZE) + return NULL; + + if (idx >= array->max_element) + { + if (mem_root_allocate_dynamic(array->mem_root, array, idx)) + return NULL; + } + + /* + Ensure the array size has increased and the index is + now well within the array bounds. + */ + DBUG_ASSERT(idx < array->max_element); + + return mem_root_dynamic_array_get_val(array, idx); +} + #include #ifdef HAVE_PSI_INTERFACE diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index e4e26cd2cce..cf23fc7641e 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -640,24 +640,20 @@ ex set @save_max_allowed_packet=@@max_allowed_packet; set @save_net_buffer_length=@@net_buffer_length; set @@global.net_buffer_length=1024; -set @@global.max_allowed_packet=2048; +set @@global.max_allowed_packet=4096; connect newconn, localhost, root,,; show variables like 'net_buffer_length'; Variable_name Value net_buffer_length 1024 show variables like 'max_allowed_packet'; Variable_name Value -max_allowed_packet 2048 +max_allowed_packet 4096 select json_array(repeat('a',1024),repeat('a',1024)) as ex; ex -NULL -Warnings: -Warning 1301 Result of json_array() was larger than max_allowed_packet (2048) - truncated +["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"] select json_object("a", repeat('a',1024),"b", repeat('a',1024)) as ex; ex -NULL -Warnings: -Warning 1301 Result of json_object() was larger than max_allowed_packet (2048) - truncated +{"a": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "b": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"} connection default; set @@global.max_allowed_packet = @save_max_allowed_packet; set @@global.net_buffer_length = @save_net_buffer_length; @@ -4842,16 +4838,16 @@ JSON_SCHEMA_VALID(@schema_array, '[') 0 Warnings: Warning 4037 Unexpected end of JSON text in argument 2 to function 'json_schema_valid' -SELECT JSON_SCHEMA_VALID(repeat('[', 100000), json_object()); -JSON_SCHEMA_VALID(repeat('[', 100000), json_object()) +SELECT JSON_SCHEMA_VALID(repeat('[', 100), json_object()); +JSON_SCHEMA_VALID(repeat('[', 100), json_object()) NULL Warnings: -Warning 4040 Limit of 32 on JSON nested structures depth is reached in argument 1 to function 'json_schema_valid' at position 32 -SELECT JSON_SCHEMA_VALID(json_object(), repeat('[', 10000000)); -JSON_SCHEMA_VALID(json_object(), repeat('[', 10000000)) +Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_schema_valid' +SELECT JSON_SCHEMA_VALID(json_object(), repeat('[', 100)); +JSON_SCHEMA_VALID(json_object(), repeat('[', 100)) 0 Warnings: -Warning 4040 Limit of 32 on JSON nested structures depth is reached in argument 2 to function 'json_schema_valid' at position 32 +Warning 4037 Unexpected end of JSON text in argument 2 to function 'json_schema_valid' # # MDEV-30677: Incorrect result for "SELECT JSON_SCHEMA_VALID('{}', NULL)" # @@ -4895,6 +4891,8 @@ NULL SELECT JSON_KEY_VALUE('', '$.a'); JSON_KEY_VALUE('', '$.a') NULL +Warnings: +Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_key_value' SELECT JSON_KEY_VALUE('[1,2,3]', ''); JSON_KEY_VALUE('[1,2,3]', '') NULL diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index 453ede9e26b..6728dddcca5 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -310,7 +310,7 @@ set @save_max_allowed_packet=@@max_allowed_packet; set @save_net_buffer_length=@@net_buffer_length; set @@global.net_buffer_length=1024; -set @@global.max_allowed_packet=2048; +set @@global.max_allowed_packet=4096; --connect (newconn, localhost, root,,) show variables like 'net_buffer_length'; @@ -3800,10 +3800,10 @@ SET @schema_array= '{"type":"array"}'; SELECT JSON_SCHEMA_VALID(@schema_array, '['); --disable_view_protocol -SELECT JSON_SCHEMA_VALID(repeat('[', 100000), json_object()); +SELECT JSON_SCHEMA_VALID(repeat('[', 100), json_object()); --enable_view_protocol -SELECT JSON_SCHEMA_VALID(json_object(), repeat('[', 10000000)); +SELECT JSON_SCHEMA_VALID(json_object(), repeat('[', 100)); --echo # --echo # MDEV-30677: Incorrect result for "SELECT JSON_SCHEMA_VALID('{}', NULL)" diff --git a/mysql-test/main/json_equals.result b/mysql-test/main/json_equals.result index a9a828af8cf..2450774e21d 100644 --- a/mysql-test/main/json_equals.result +++ b/mysql-test/main/json_equals.result @@ -65,7 +65,7 @@ select json_equals('{"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"ob select json_equals('{"obj":{"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"key": "value"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}', '{"obj":{"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"obj": {"key": "value"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}') as 32_levels; 32_levels -NULL +1 # # test values from different charset # (UTF-8 two-bytes vs. latin1 single high-byte) diff --git a/mysql-test/main/mdev_32854.result b/mysql-test/main/mdev_32854.result new file mode 100644 index 00000000000..39ae825e8d1 --- /dev/null +++ b/mysql-test/main/mdev_32854.result @@ -0,0 +1,454 @@ +SET @json_doc_obj_lev45_valid='{ "level1": { "level2": { "level3": { "level4": { "level5": { "level6": { "level7": { "level8": { "level9": { "level10": { "level11": { "level12": { "level13": { "level14": { "level15": { "level16": { "level17": { "level18": { "level19": { "level20": { "level21": { "level22": { "level23": { "level24": { "level25": { "level26": { "level27": { "level28": { "level29": { "level30": { "level31": { "level32": { "level33": { "level34": { "level35": { "level36": { "level37": { "level38": { "level39": { "level40": { "level41": { "level42": { "level43": { "level44": { "level45": "This is level 45" } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } }'; +SET @json_doc_arr_lev45_valid='[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'; +CREATE TABLE t1 (val JSON); +INSERT INTO t1 VALUES (@json_doc_arr_lev45_valid), ('[1, 2, 10,3, [4, 5, 6, [7, 8, 9]]]'); +SELECT JSON_ARRAY(@json_doc_arr_lev45_valid, 1, 2, 3); +JSON_ARRAY(@json_doc_arr_lev45_valid, 1, 2, 3) +["[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]", 1, 2, 3] +SELECT JSON_ARRAY (@json_doc_obj_lev45_valid, '{"key1":1, "key2":2}'); +JSON_ARRAY (@json_doc_obj_lev45_valid, '{"key1":1, "key2":2}') +["{ \"level1\": { \"level2\": { \"level3\": { \"level4\": { \"level5\": { \"level6\": { \"level7\": { \"level8\": { \"level9\": { \"level10\": { \"level11\": { \"level12\": { \"level13\": { \"level14\": { \"level15\": { \"level16\": { \"level17\": { \"level18\": { \"level19\": { \"level20\": { \"level21\": { \"level22\": { \"level23\": { \"level24\": { \"level25\": { \"level26\": { \"level27\": { \"level28\": { \"level29\": { \"level30\": { \"level31\": { \"level32\": { \"level33\": { \"level34\": { \"level35\": { \"level36\": { \"level37\": { \"level38\": { \"level39\": { \"level40\": { \"level41\": { \"level42\": { \"level43\": { \"level44\": { \"level45\": \"This is level 45\" } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } }", "{\"key1\":1, \"key2\":2}"] +SELECT JSON_ARRAYAGG(val) FROM t1; +JSON_ARRAYAGG(val) +[[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],[1, 2, 10,3, [4, 5, 6, [7, 8, 9]]]] +SELECT JSON_ARRAY_APPEND(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]', false) AS result; +result +[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45, false]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] +SELECT JSON_ARRAY_INSERT(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]', false) AS result; +result +[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, false, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] +SELECT JSON_ARRAY_INTERSECT(@json_doc_arr_lev45_valid, '[1, [2, [3]]]'); +JSON_ARRAY_INTERSECT(@json_doc_arr_lev45_valid, '[1, [2, [3]]]') +[1] +SELECT JSON_COMPACT(@json_doc_obj_lev45_valid); +JSON_COMPACT(@json_doc_obj_lev45_valid) +{"level1":{"level2":{"level3":{"level4":{"level5":{"level6":{"level7":{"level8":{"level9":{"level10":{"level11":{"level12":{"level13":{"level14":{"level15":{"level16":{"level17":{"level18":{"level19":{"level20":{"level21":{"level22":{"level23":{"level24":{"level25":{"level26":{"level27":{"level28":{"level29":{"level30":{"level31":{"level32":{"level33":{"level34":{"level35":{"level36":{"level37":{"level38":{"level39":{"level40":{"level41":{"level42":{"level43":{"level44":{"level45":"This is level 45"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} +SELECT JSON_COMPACT(@json_doc_arr_lev45_valid); +JSON_COMPACT(@json_doc_arr_lev45_valid) +[1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,[15,[16,[17,[18,[19,[20,[21,[22,[23,[24,[25,[26,[27,[28,[29,[30,[31,[32,[33,[34,[35,[36,[37,[38,[39,[40,[41,[42,[43,[44,[45,45,45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] +SELECT JSON_CONTAINS(@json_doc_obj_lev45_valid, ' { "level45": "This is level 45" }', '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); +JSON_CONTAINS(@json_doc_obj_lev45_valid, ' { "level45": "This is level 45" }', '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level2 +1 +SELECT JSON_CONTAINS(@json_doc_arr_lev45_valid, '[45, 45, 45]', '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +JSON_CONTAINS(@json_doc_arr_lev45_valid, '[45, 45, 45]', '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]') +1 +SELECT JSON_CONTAINS_PATH(@json_doc_arr_lev45_valid, 'all', '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +JSON_CONTAINS_PATH(@json_doc_arr_lev45_valid, 'all', '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]') +1 +SELECT JSON_CONTAINS_PATH(@json_doc_obj_lev45_valid, 'all', '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); +JSON_CONTAINS_PATH(@json_doc_obj_lev45_valid, 'all', '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26. +1 +SELECT JSON_DEPTH(@json_doc_arr_lev45_valid); +JSON_DEPTH(@json_doc_arr_lev45_valid) +46 +SELECT JSON_DEPTH(@json_doc_obj_lev45_valid); +JSON_DEPTH(@json_doc_obj_lev45_valid) +46 +SELECT JSON_DETAILED(@json_doc_obj_lev45_valid); +JSON_DETAILED(@json_doc_obj_lev45_valid) +{ + "level1": + { + "level2": + { + "level3": + { + "level4": + { + "level5": + { + "level6": + { + "level7": + { + "level8": + { + "level9": + { + "level10": + { + "level11": + { + "level12": + { + "level13": + { + "level14": + { + "level15": + { + "level16": + { + "level17": + { + "level18": + { + "level19": + { + "level20": + { + "level21": + { + "level22": + { + "level23": + { + "level24": + { + "level25": + { + "level26": + { + "level27": + { + "level28": + { + "level29": + { + "level30": + { + "level31": + { + "level32": + { + "level33": + { + "level34": + { + "level35": + { + "level36": + { + "level37": + { + "level38": + { + "level39": + { + "level40": + { + "level41": + { + "level42": + { + "level43": + { + "level44": + { + "level45": "This is level 45" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } +} +SELECT JSON_DETAILED(@json_doc_arr_lev45_valid); +JSON_DETAILED(@json_doc_arr_lev45_valid) +[ + 1, + [ + 2, + [ + 3, + [ + 4, + [ + 5, + [ + 6, + [ + 7, + [ + 8, + [ + 9, + [ + 10, + [ + 11, + [ + 12, + [ + 13, + [ + 14, + [ + 15, + [ + 16, + [ + 17, + [ + 18, + [ + 19, + [ + 20, + [ + 21, + [ + 22, + [ + 23, + [ + 24, + [ + 25, + [ + 26, + [ + 27, + [ + 28, + [ + 29, + [ + 30, + [ + 31, + [ + 32, + [ + 33, + [ + 34, + [ + 35, + [ + 36, + [ + 37, + [ + 38, + [ + 39, + [ + 40, + [ + 41, + [ + 42, + [ + 43, + [ + 44, + [ + 45, + 45, + 45 + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] +] +SELECT JSON_EQUALS(@json_doc_arr_lev45_valid, @json_doc_arr_lev45_valid); +JSON_EQUALS(@json_doc_arr_lev45_valid, @json_doc_arr_lev45_valid) +1 +SELECT JSON_EQUALS(@json_doc_obj_lev45_valid, @json_doc_obj_lev45_valid); +JSON_EQUALS(@json_doc_obj_lev45_valid, @json_doc_obj_lev45_valid) +1 +SELECT JSON_EXISTS(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +JSON_EXISTS(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]') +1 +SELECT JSON_EXISTS(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); +JSON_EXISTS(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level2 +1 +SELECT JSON_EXTRACT(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +JSON_EXTRACT(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]') +[45, 45, 45] +SELECT JSON_EXTRACT(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); +JSON_EXTRACT(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level +{"level45": "This is level 45"} +SELECT JSON_INSERT(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][3]', 46); +JSON_INSERT(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][3]', 46) +[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, [45, 46], 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] +SELECT JSON_KEY_VALUE(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); +JSON_KEY_VALUE(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.lev +[{"key": "level45", "value": "This is level 45"}] +SELECT JSON_KEYS(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); +JSON_KEYS(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28. +["level45"] +SELECT JSON_LENGTH(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); +JSON_LENGTH(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level2 +1 +SELECT JSON_LENGTH(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +JSON_LENGTH(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]') +1 +SELECT JSON_LOOSE(@json_doc_obj_lev45_valid); +JSON_LOOSE(@json_doc_obj_lev45_valid) +{"level1": {"level2": {"level3": {"level4": {"level5": {"level6": {"level7": {"level8": {"level9": {"level10": {"level11": {"level12": {"level13": {"level14": {"level15": {"level16": {"level17": {"level18": {"level19": {"level20": {"level21": {"level22": {"level23": {"level24": {"level25": {"level26": {"level27": {"level28": {"level29": {"level30": {"level31": {"level32": {"level33": {"level34": {"level35": {"level36": {"level37": {"level38": {"level39": {"level40": {"level41": {"level42": {"level43": {"level44": {"level45": "This is level 45"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} +SELECT JSON_LOOSE(@json_doc_arr_lev45_valid); +JSON_LOOSE(@json_doc_arr_lev45_valid) +[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] +SELECT JSON_MERGE(@json_doc_obj_lev45_valid, '{"key1":"val1", "key2":"val2"}'); +JSON_MERGE(@json_doc_obj_lev45_valid, '{"key1":"val1", "key2":"val2"}') +{"level1": {"level2": {"level3": {"level4": {"level5": {"level6": {"level7": {"level8": {"level9": {"level10": {"level11": {"level12": {"level13": {"level14": {"level15": {"level16": {"level17": {"level18": {"level19": {"level20": {"level21": {"level22": {"level23": {"level24": {"level25": {"level26": {"level27": {"level28": {"level29": {"level30": {"level31": {"level32": {"level33": {"level34": {"level35": {"level36": {"level37": {"level38": {"level39": {"level40": {"level41": {"level42": {"level43": {"level44": {"level45": "This is level 45"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, "key1": "val1", "key2": "val2"} +SELECT JSON_MERGE(@json_doc_arr_lev45_valid, '[1, 2, 3]'); +JSON_MERGE(@json_doc_arr_lev45_valid, '[1, 2, 3]') +[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], 1, 2, 3] +SELECT JSON_MERGE_PATCH(@json_doc_obj_lev45_valid, '{"key1":"val1", "key2":"val2"}'); +JSON_MERGE_PATCH(@json_doc_obj_lev45_valid, '{"key1":"val1", "key2":"val2"}') +{"level1": {"level2": {"level3": {"level4": {"level5": {"level6": {"level7": {"level8": {"level9": {"level10": {"level11": {"level12": {"level13": {"level14": {"level15": {"level16": {"level17": {"level18": {"level19": {"level20": {"level21": {"level22": {"level23": {"level24": {"level25": {"level26": {"level27": {"level28": {"level29": {"level30": {"level31": {"level32": {"level33": {"level34": {"level35": {"level36": {"level37": {"level38": {"level39": {"level40": {"level41": {"level42": {"level43": {"level44": {"level45": "This is level 45"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, "key1": "val1", "key2": "val2"} +SELECT JSON_MERGE_PATCH(@json_doc_arr_lev45_valid, '[1, 2, 3]'); +JSON_MERGE_PATCH(@json_doc_arr_lev45_valid, '[1, 2, 3]') +[1, 2, 3] +SELECT JSON_MERGE_PRESERVE(@json_doc_obj_lev45_valid, @json_doc_obj_lev45_valid); +JSON_MERGE_PRESERVE(@json_doc_obj_lev45_valid, @json_doc_obj_lev45_valid) +{"level1": {"level2": {"level3": {"level4": {"level5": {"level6": {"level7": {"level8": {"level9": {"level10": {"level11": {"level12": {"level13": {"level14": {"level15": {"level16": {"level17": {"level18": {"level19": {"level20": {"level21": {"level22": {"level23": {"level24": {"level25": {"level26": {"level27": {"level28": {"level29": {"level30": {"level31": {"level32": {"level33": {"level34": {"level35": {"level36": {"level37": {"level38": {"level39": {"level40": {"level41": {"level42": {"level43": {"level44": {"level45": ["This is level 45", "This is level 45"]}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} +SELECT JSON_MERGE_PRESERVE(@json_doc_arr_lev45_valid, @json_doc_arr_lev45_valid); +JSON_MERGE_PRESERVE(@json_doc_arr_lev45_valid, @json_doc_arr_lev45_valid) +[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]], 1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] +SELECT JSON_NORMALIZE(@json_doc_arr_lev45_valid); +JSON_NORMALIZE(@json_doc_arr_lev45_valid) +[1.0E0,[2.0E0,[3.0E0,[4.0E0,[5.0E0,[6.0E0,[7.0E0,[8.0E0,[9.0E0,[1.0E1,[1.1E1,[1.2E1,[1.3E1,[1.4E1,[1.5E1,[1.6E1,[1.7E1,[1.8E1,[1.9E1,[2.0E1,[2.1E1,[2.2E1,[2.3E1,[2.4E1,[2.5E1,[2.6E1,[2.7E1,[2.8E1,[2.9E1,[3.0E1,[3.1E1,[3.2E1,[3.3E1,[3.4E1,[3.5E1,[3.6E1,[3.7E1,[3.8E1,[3.9E1,[4.0E1,[4.1E1,[4.2E1,[4.3E1,[4.4E1,[4.5E1,4.5E1,4.5E1]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] +SELECT JSON_OBJECT('level1', @json_doc_obj_lev45_valid); +JSON_OBJECT('level1', @json_doc_obj_lev45_valid) +{"level1": "{ \"level1\": { \"level2\": { \"level3\": { \"level4\": { \"level5\": { \"level6\": { \"level7\": { \"level8\": { \"level9\": { \"level10\": { \"level11\": { \"level12\": { \"level13\": { \"level14\": { \"level15\": { \"level16\": { \"level17\": { \"level18\": { \"level19\": { \"level20\": { \"level21\": { \"level22\": { \"level23\": { \"level24\": { \"level25\": { \"level26\": { \"level27\": { \"level28\": { \"level29\": { \"level30\": { \"level31\": { \"level32\": { \"level33\": { \"level34\": { \"level35\": { \"level36\": { \"level37\": { \"level38\": { \"level39\": { \"level40\": { \"level41\": { \"level42\": { \"level43\": { \"level44\": { \"level45\": \"This is level 45\" } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } }"} +SELECT JSON_OBJECT_FILTER_KEYS(@json_doc_obj_lev45_valid, '["level1"]'); +JSON_OBJECT_FILTER_KEYS(@json_doc_obj_lev45_valid, '["level1"]') +{"level1": {"level2": {"level3": {"level4": {"level5": {"level6": {"level7": {"level8": {"level9": {"level10": {"level11": {"level12": {"level13": {"level14": {"level15": {"level16": {"level17": {"level18": {"level19": {"level20": {"level21": {"level22": {"level23": {"level24": {"level25": {"level26": {"level27": {"level28": {"level29": {"level30": {"level31": {"level32": {"level33": {"level34": {"level35": {"level36": {"level37": {"level38": {"level39": {"level40": {"level41": {"level42": {"level43": {"level44": {"level45": "This is level 45"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} +SELECT JSON_OBJECT_TO_ARRAY(@json_doc_obj_lev45_valid); +JSON_OBJECT_TO_ARRAY(@json_doc_obj_lev45_valid) +[["level1", {"level2": {"level3": {"level4": {"level5": {"level6": {"level7": {"level8": {"level9": {"level10": {"level11": {"level12": {"level13": {"level14": {"level15": {"level16": {"level17": {"level18": {"level19": {"level20": {"level21": {"level22": {"level23": {"level24": {"level25": {"level26": {"level27": {"level28": {"level29": {"level30": {"level31": {"level32": {"level33": {"level34": {"level35": {"level36": {"level37": {"level38": {"level39": {"level40": {"level41": {"level42": {"level43": {"level44": {"level45": "This is level 45"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}]] +CREATE TABLE t2 (val1 VARCHAR(10), val2 JSON); +INSERT INTO t2 VALUES('level0', @json_doc_obj_lev45_valid); +SELECT JSON_OBJECTAGG(val1, val2) FROM t2; +JSON_OBJECTAGG(val1, val2) +{"level0":{ "level1": { "level2": { "level3": { "level4": { "level5": { "level6": { "level7": { "level8": { "level9": { "level10": { "level11": { "level12": { "level13": { "level14": { "level15": { "level16": { "level17": { "level18": { "level19": { "level20": { "level21": { "level22": { "level23": { "level24": { "level25": { "level26": { "level27": { "level28": { "level29": { "level30": { "level31": { "level32": { "level33": { "level34": { "level35": { "level36": { "level37": { "level38": { "level39": { "level40": { "level41": { "level42": { "level43": { "level44": { "level45": "This is level 45" } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } }} +SELECT JSON_OVERLAPS(@json_doc_obj_lev45_valid,'{ "level44": { "level45": "This is level 45" } }'); +JSON_OVERLAPS(@json_doc_obj_lev45_valid,'{ "level44": { "level45": "This is level 45" } }') +0 +SELECT JSON_QUERY(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +JSON_QUERY(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]') +[45, 45, 45] +SELECT JSON_QUOTE(@json_doc_obj_lev45_valid); +JSON_QUOTE(@json_doc_obj_lev45_valid) +"{ \"level1\": { \"level2\": { \"level3\": { \"level4\": { \"level5\": { \"level6\": { \"level7\": { \"level8\": { \"level9\": { \"level10\": { \"level11\": { \"level12\": { \"level13\": { \"level14\": { \"level15\": { \"level16\": { \"level17\": { \"level18\": { \"level19\": { \"level20\": { \"level21\": { \"level22\": { \"level23\": { \"level24\": { \"level25\": { \"level26\": { \"level27\": { \"level28\": { \"level29\": { \"level30\": { \"level31\": { \"level32\": { \"level33\": { \"level34\": { \"level35\": { \"level36\": { \"level37\": { \"level38\": { \"level39\": { \"level40\": { \"level41\": { \"level42\": { \"level43\": { \"level44\": { \"level45\": \"This is level 45\" } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } }" +SELECT JSON_QUOTE(@json_doc_arr_lev45_valid); +JSON_QUOTE(@json_doc_arr_lev45_valid) +"[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" +SET @json_removed= JSON_REMOVE(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39'); +SET @json_removed= JSON_REMOVE(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +SELECT @json_removed; +@json_removed +[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] +SET @json_schema= '{"type": "object", "properties": { "level1": { "type": "object", "properties": { "level2": { "type": "object", "properties": { "level3": { "type": "object", "properties": { "level4": { "type": "object", "properties": { "level5": { "type": "object", "properties": { "level6": { "type": "object", "properties": { "level7": { "type": "object", "properties": { "level8": { "type": "object", "properties": { "level9": { "type": "object", "properties": { "level10": { "type": "object", "properties": { "level11": { "type": "object", "properties": { "level12": { "type": "object", "properties": { "level13": { "type": "object", "properties": { "level14": { "type": "object", "properties": { "level15": { "type": "object", "properties": { "level16": { "type": "object", "properties": { "level17": { "type": "object", "properties": { "level18": { "type": "object", "properties": { "level19": { "type": "object", "properties": { "level20": { "type": "object", "properties": { "level21": { "type": "object", "properties": { "level22": { "type": "object", "properties": { "level23": { "type": "object", "properties": { "level24": { "type": "object", "properties": { "level25": { "type": "object", "properties": { "level26": { "type": "object", "properties": { "level27": { "type": "object", "properties": { "level28": { "type": "object", "properties": { "level29": { "type": "object", "properties": { "level30": { "type": "object", "properties": { "level31": { "type": "object", "properties": { "level32": { "type": "object", "properties": { "level33": { "type": "object", "properties": { "level34": { "type": "object", "properties": { "level35": { "type": "object", "properties": { "level36": { "type": "object", "properties": { "level37": { "type": "object", "properties": { "level38": { "type": "object", "properties": { "level39": { "type": "object", "properties": { "level40": { "type": "object", "properties": { "level41": { "type": "object", "properties": { "level42": { "type": "object", "properties": { "level43": { "type": "object", "properties": { "level44": { "type": "object", "properties": { "level45": { "type": "string", "const": "This is level 45" } }, "required": ["level45"] } }, "required": ["level44"] } }, "required": ["level43"] } }, "required": ["level42"] } }, "required": ["level41"] } }, "required": ["level40"] } }, "required": ["level39"] } }, "required": ["level38"] } }, "required": ["level37"] } }, "required": ["level36"] } }, "required": ["level35"] } }, "required": ["level34"] } }, "required": ["level33"] } }, "required": ["level32"] } }, "required": ["level31"] } }, "required": ["level30"] } }, "required": ["level29"] } }, "required": ["level28"] } }, "required": ["level27"] } }, "required": ["level26"] } }, "required": ["level25"] } }, "required": ["level24"] } }, "required": ["level23"] } }, "required": ["level22"] } }, "required": ["level21"] } }, "required": ["level20"] } }, "required": ["level19"] } }, "required": ["level18"] } }, "required": ["level17"] } }, "required": ["level16"] } }, "required": ["level15"] } }, "required": ["level14"] } }, "required": ["level13"] } }, "required": ["level12"] } }, "required": ["level11"] } }, "required": ["level10"] } }, "required": ["level9"] } }, "required": ["level8"] } }, "required": ["level7"] } }, "required": ["level6"] } }, "required": ["level5"] } }, "required": ["level4"] } }, "required": ["level3"] } }, "required": ["level2"] } }, "required": ["level1"] }'; +SELECT JSON_SCHEMA_VALID(@json_schema, @json_doc_obj_lev45_valid) AS found_path; +found_path +1 +SELECT JSON_SCHEMA_VALID(@json_schema, @json_doc_obj_lev45_valid2); +JSON_SCHEMA_VALID(@json_schema, @json_doc_obj_lev45_valid2) +NULL +SELECT JSON_SEARCH(@json_doc_obj_lev45_valid,'one', 'This is level 45'); +JSON_SEARCH(@json_doc_obj_lev45_valid,'one', 'This is level 45') +"$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44.level45" +SET @json_updated = JSON_SET(@json_doc_obj_lev45_valid, +'$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41', +'Updated value'); +SELECT @json_updated; +@json_updated +{"level1": {"level2": {"level3": {"level4": {"level5": {"level6": {"level7": {"level8": {"level9": {"level10": {"level11": {"level12": {"level13": {"level14": {"level15": {"level16": {"level17": {"level18": {"level19": {"level20": {"level21": {"level22": {"level23": {"level24": {"level25": {"level26": {"level27": {"level28": {"level29": {"level30": {"level31": {"level32": {"level33": {"level34": {"level35": {"level36": {"level37": {"level38": {"level39": {"level40": {"level41": "Updated value"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} +SELECT JSON_TYPE(@json_doc_obj_lev45_valid); +JSON_TYPE(@json_doc_obj_lev45_valid) +OBJECT +SELECT JSON_TYPE(@json_doc_arr_lev45_valid); +JSON_TYPE(@json_doc_arr_lev45_valid) +ARRAY +SELECT JSON_UNQUOTE(JSON_QUOTE(@json_doc_obj_lev45_valid)); +JSON_UNQUOTE(JSON_QUOTE(@json_doc_obj_lev45_valid)) +{ "level1": { "level2": { "level3": { "level4": { "level5": { "level6": { "level7": { "level8": { "level9": { "level10": { "level11": { "level12": { "level13": { "level14": { "level15": { "level16": { "level17": { "level18": { "level19": { "level20": { "level21": { "level22": { "level23": { "level24": { "level25": { "level26": { "level27": { "level28": { "level29": { "level30": { "level31": { "level32": { "level33": { "level34": { "level35": { "level36": { "level37": { "level38": { "level39": { "level40": { "level41": { "level42": { "level43": { "level44": { "level45": "This is level 45" } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } +SELECT JSON_UNQUOTE(JSON_QUOTE(@json_doc_arr_lev45_valid)); +JSON_UNQUOTE(JSON_QUOTE(@json_doc_arr_lev45_valid)) +[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] +SELECT JSON_VALID(@json_doc_obj_lev45_valid); +JSON_VALID(@json_doc_obj_lev45_valid) +1 +SELECT JSON_VALID(@json_doc_arr_lev45_valid); +JSON_VALID(@json_doc_arr_lev45_valid) +1 +SELECT JSON_VALUE(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44.level45'); +JSON_VALUE(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28 +This is level 45 +SELECT JSON_VALUE(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +JSON_VALUE(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]') +45 +DROP TABLE t1 ,t2; diff --git a/mysql-test/main/mdev_32854.test b/mysql-test/main/mdev_32854.test new file mode 100644 index 00000000000..4332736f448 --- /dev/null +++ b/mysql-test/main/mdev_32854.test @@ -0,0 +1,113 @@ +SET @json_doc_obj_lev45_valid='{ "level1": { "level2": { "level3": { "level4": { "level5": { "level6": { "level7": { "level8": { "level9": { "level10": { "level11": { "level12": { "level13": { "level14": { "level15": { "level16": { "level17": { "level18": { "level19": { "level20": { "level21": { "level22": { "level23": { "level24": { "level25": { "level26": { "level27": { "level28": { "level29": { "level30": { "level31": { "level32": { "level33": { "level34": { "level35": { "level36": { "level37": { "level38": { "level39": { "level40": { "level41": { "level42": { "level43": { "level44": { "level45": "This is level 45" } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } }'; + +SET @json_doc_arr_lev45_valid='[1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, [15, [16, [17, [18, [19, [20, [21, [22, [23, [24, [25, [26, [27, [28, [29, [30, [31, [32, [33, [34, [35, [36, [37, [38, [39, [40, [41, [42, [43, [44, [45, 45, 45]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]'; + +CREATE TABLE t1 (val JSON); +INSERT INTO t1 VALUES (@json_doc_arr_lev45_valid), ('[1, 2, 10,3, [4, 5, 6, [7, 8, 9]]]'); + +SELECT JSON_ARRAY(@json_doc_arr_lev45_valid, 1, 2, 3); +SELECT JSON_ARRAY (@json_doc_obj_lev45_valid, '{"key1":1, "key2":2}'); + +SELECT JSON_ARRAYAGG(val) FROM t1; + +SELECT JSON_ARRAY_APPEND(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]', false) AS result; + +SELECT JSON_ARRAY_INSERT(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]', false) AS result; + +SELECT JSON_ARRAY_INTERSECT(@json_doc_arr_lev45_valid, '[1, [2, [3]]]'); + +SELECT JSON_COMPACT(@json_doc_obj_lev45_valid); +SELECT JSON_COMPACT(@json_doc_arr_lev45_valid); + +SELECT JSON_CONTAINS(@json_doc_obj_lev45_valid, ' { "level45": "This is level 45" }', '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); +SELECT JSON_CONTAINS(@json_doc_arr_lev45_valid, '[45, 45, 45]', '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); + +SELECT JSON_CONTAINS_PATH(@json_doc_arr_lev45_valid, 'all', '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +SELECT JSON_CONTAINS_PATH(@json_doc_obj_lev45_valid, 'all', '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); + +SELECT JSON_DEPTH(@json_doc_arr_lev45_valid); +SELECT JSON_DEPTH(@json_doc_obj_lev45_valid); + +SELECT JSON_DETAILED(@json_doc_obj_lev45_valid); +SELECT JSON_DETAILED(@json_doc_arr_lev45_valid); + +SELECT JSON_EQUALS(@json_doc_arr_lev45_valid, @json_doc_arr_lev45_valid); +SELECT JSON_EQUALS(@json_doc_obj_lev45_valid, @json_doc_obj_lev45_valid); + +SELECT JSON_EXISTS(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +SELECT JSON_EXISTS(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); + +SELECT JSON_EXTRACT(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +SELECT JSON_EXTRACT(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); + +SELECT JSON_INSERT(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][3]', 46); + +SELECT JSON_KEY_VALUE(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); + +SELECT JSON_KEYS(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); + +SELECT JSON_LENGTH(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44'); +SELECT JSON_LENGTH(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); + +SELECT JSON_LOOSE(@json_doc_obj_lev45_valid); +SELECT JSON_LOOSE(@json_doc_arr_lev45_valid); + +SELECT JSON_MERGE(@json_doc_obj_lev45_valid, '{"key1":"val1", "key2":"val2"}'); +SELECT JSON_MERGE(@json_doc_arr_lev45_valid, '[1, 2, 3]'); + +SELECT JSON_MERGE_PATCH(@json_doc_obj_lev45_valid, '{"key1":"val1", "key2":"val2"}'); +SELECT JSON_MERGE_PATCH(@json_doc_arr_lev45_valid, '[1, 2, 3]'); + +SELECT JSON_MERGE_PRESERVE(@json_doc_obj_lev45_valid, @json_doc_obj_lev45_valid); +SELECT JSON_MERGE_PRESERVE(@json_doc_arr_lev45_valid, @json_doc_arr_lev45_valid); + +SELECT JSON_NORMALIZE(@json_doc_arr_lev45_valid); + +SELECT JSON_OBJECT('level1', @json_doc_obj_lev45_valid); + +SELECT JSON_OBJECT_FILTER_KEYS(@json_doc_obj_lev45_valid, '["level1"]'); + +SELECT JSON_OBJECT_TO_ARRAY(@json_doc_obj_lev45_valid); + +CREATE TABLE t2 (val1 VARCHAR(10), val2 JSON); +INSERT INTO t2 VALUES('level0', @json_doc_obj_lev45_valid); + +SELECT JSON_OBJECTAGG(val1, val2) FROM t2; + +SELECT JSON_OVERLAPS(@json_doc_obj_lev45_valid,'{ "level44": { "level45": "This is level 45" } }'); + +SELECT JSON_QUERY(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); + +SELECT JSON_QUOTE(@json_doc_obj_lev45_valid); +SELECT JSON_QUOTE(@json_doc_arr_lev45_valid); + +SET @json_removed= JSON_REMOVE(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39'); +SET @json_removed= JSON_REMOVE(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); +SELECT @json_removed; + +SET @json_schema= '{"type": "object", "properties": { "level1": { "type": "object", "properties": { "level2": { "type": "object", "properties": { "level3": { "type": "object", "properties": { "level4": { "type": "object", "properties": { "level5": { "type": "object", "properties": { "level6": { "type": "object", "properties": { "level7": { "type": "object", "properties": { "level8": { "type": "object", "properties": { "level9": { "type": "object", "properties": { "level10": { "type": "object", "properties": { "level11": { "type": "object", "properties": { "level12": { "type": "object", "properties": { "level13": { "type": "object", "properties": { "level14": { "type": "object", "properties": { "level15": { "type": "object", "properties": { "level16": { "type": "object", "properties": { "level17": { "type": "object", "properties": { "level18": { "type": "object", "properties": { "level19": { "type": "object", "properties": { "level20": { "type": "object", "properties": { "level21": { "type": "object", "properties": { "level22": { "type": "object", "properties": { "level23": { "type": "object", "properties": { "level24": { "type": "object", "properties": { "level25": { "type": "object", "properties": { "level26": { "type": "object", "properties": { "level27": { "type": "object", "properties": { "level28": { "type": "object", "properties": { "level29": { "type": "object", "properties": { "level30": { "type": "object", "properties": { "level31": { "type": "object", "properties": { "level32": { "type": "object", "properties": { "level33": { "type": "object", "properties": { "level34": { "type": "object", "properties": { "level35": { "type": "object", "properties": { "level36": { "type": "object", "properties": { "level37": { "type": "object", "properties": { "level38": { "type": "object", "properties": { "level39": { "type": "object", "properties": { "level40": { "type": "object", "properties": { "level41": { "type": "object", "properties": { "level42": { "type": "object", "properties": { "level43": { "type": "object", "properties": { "level44": { "type": "object", "properties": { "level45": { "type": "string", "const": "This is level 45" } }, "required": ["level45"] } }, "required": ["level44"] } }, "required": ["level43"] } }, "required": ["level42"] } }, "required": ["level41"] } }, "required": ["level40"] } }, "required": ["level39"] } }, "required": ["level38"] } }, "required": ["level37"] } }, "required": ["level36"] } }, "required": ["level35"] } }, "required": ["level34"] } }, "required": ["level33"] } }, "required": ["level32"] } }, "required": ["level31"] } }, "required": ["level30"] } }, "required": ["level29"] } }, "required": ["level28"] } }, "required": ["level27"] } }, "required": ["level26"] } }, "required": ["level25"] } }, "required": ["level24"] } }, "required": ["level23"] } }, "required": ["level22"] } }, "required": ["level21"] } }, "required": ["level20"] } }, "required": ["level19"] } }, "required": ["level18"] } }, "required": ["level17"] } }, "required": ["level16"] } }, "required": ["level15"] } }, "required": ["level14"] } }, "required": ["level13"] } }, "required": ["level12"] } }, "required": ["level11"] } }, "required": ["level10"] } }, "required": ["level9"] } }, "required": ["level8"] } }, "required": ["level7"] } }, "required": ["level6"] } }, "required": ["level5"] } }, "required": ["level4"] } }, "required": ["level3"] } }, "required": ["level2"] } }, "required": ["level1"] }'; +SELECT JSON_SCHEMA_VALID(@json_schema, @json_doc_obj_lev45_valid) AS found_path; +SELECT JSON_SCHEMA_VALID(@json_schema, @json_doc_obj_lev45_valid2); + + + +SELECT JSON_SEARCH(@json_doc_obj_lev45_valid,'one', 'This is level 45'); + +SET @json_updated = JSON_SET(@json_doc_obj_lev45_valid, + '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41', + 'Updated value'); +SELECT @json_updated; + +SELECT JSON_TYPE(@json_doc_obj_lev45_valid); +SELECT JSON_TYPE(@json_doc_arr_lev45_valid); + +SELECT JSON_UNQUOTE(JSON_QUOTE(@json_doc_obj_lev45_valid)); +SELECT JSON_UNQUOTE(JSON_QUOTE(@json_doc_arr_lev45_valid)); + +SELECT JSON_VALID(@json_doc_obj_lev45_valid); +SELECT JSON_VALID(@json_doc_arr_lev45_valid); + +SELECT JSON_VALUE(@json_doc_obj_lev45_valid, '$.level1.level2.level3.level4.level5.level6.level7.level8.level9.level10.level11.level12.level13.level14.level15.level16.level17.level18.level19.level20.level21.level22.level23.level24.level25.level26.level27.level28.level29.level30.level31.level32.level33.level34.level35.level36.level37.level38.level39.level40.level41.level42.level43.level44.level45'); +SELECT JSON_VALUE(@json_doc_arr_lev45_valid, '$[1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1][1]'); + +DROP TABLE t1 ,t2; diff --git a/mysys/array.c b/mysys/array.c index 36619e82be4..a39370e0221 100644 --- a/mysys/array.c +++ b/mysys/array.c @@ -411,3 +411,126 @@ void freeze_size(DYNAMIC_ARRAY *array) array->max_element= elements; } } + +int mem_root_dynamic_array_resize_not_allowed(MEM_ROOT_DYNAMIC_ARRAY *array) +{ + return (array->malloc_flags & MY_BUFFER_NO_RESIZE); +} + +int mem_root_dynamic_array_init(MEM_ROOT *current_mem_root, + PSI_memory_key psi_key, + MEM_ROOT_DYNAMIC_ARRAY *array, + size_t element_size, void *init_buffer, + size_t init_alloc, size_t alloc_increment, + myf my_flags) +{ + DBUG_ENTER("init_mem_root_dynamic_array"); + + array->elements=0; + array->max_element=init_alloc; + array->alloc_increment=alloc_increment; + array->size_of_element=element_size; + array->m_psi_key= psi_key; + array->malloc_flags= my_flags; + array->mem_root= current_mem_root; + + if ((array->buffer= (uchar*)init_buffer)) + { + array->malloc_flags|= MY_INIT_BUFFER_USED; + memset(array->buffer, 0, array->size_of_element*array->max_element); + DBUG_RETURN(FALSE); + } + + if (!alloc_increment && !(my_flags & MY_BUFFER_NO_RESIZE)) + { + alloc_increment=MY_MAX((8192-MALLOC_OVERHEAD)/element_size,16); + if (init_alloc > 8 && alloc_increment > init_alloc * 2) + alloc_increment=init_alloc*2; + } + + /* + Since the dynamic array is usable even if allocation fails here malloc + should not throw an error + */ + if (init_alloc && + !(array->buffer= (uchar*) alloc_root(array->mem_root, + array->size_of_element* + array->max_element))) + array->max_element=0; + memset(array->buffer, 0, array->size_of_element*array->max_element); + + DBUG_RETURN(FALSE); +} + +void mem_root_dynamic_array_reset(MEM_ROOT_DYNAMIC_ARRAY *array) +{ + memset(array->buffer, 0, (array->size_of_element)*(array->max_element)); +} + + +int mem_root_allocate_dynamic(MEM_ROOT *mem_root, + MEM_ROOT_DYNAMIC_ARRAY *array, + size_t idx) +{ + DBUG_ENTER("allocate_dynamic"); + + if (idx >= array->max_element) + { + size_t size; + uchar *new_ptr; + + size= (idx + array->alloc_increment); + if (array->malloc_flags & MY_INIT_BUFFER_USED) + { + /* + In this senerio, the buffer is statically preallocated, + so we have to create an all-new malloc since we overflowed + */ + if (!(new_ptr= (uchar *) alloc_root(mem_root, + size * array->size_of_element))) + DBUG_RETURN(0); + array->malloc_flags&= ~MY_INIT_BUFFER_USED; + } + else if (!(new_ptr= (uchar*) alloc_root(mem_root, size*array->size_of_element))) + DBUG_RETURN(TRUE); + /* copy old elements first. */ + memcpy(new_ptr, array->buffer, + array->max_element * array->size_of_element); + /* set the remainging memory to 0. */ + memset(new_ptr+((array->max_element) * array->size_of_element), 0, + array->alloc_increment*array->size_of_element); + array->buffer= new_ptr; + array->max_element= size; + } + DBUG_RETURN(FALSE); +} + +/* + Note: If these two are merged, the resultant function will have to have + a conditional block of code. Now, these are called in recursive functions. + and although in non-recursive case it would probably not matter much, + calling functions with conditional block recursively introduces performance + delay. + + Hence, to avoid the performance issue, where we know for sure + that there will be no need to resize, directly get value. And + in other places where there might be a need to resize the array, + use the one with resize. +*/ +inline void* mem_root_dynamic_array_get_val(MEM_ROOT_DYNAMIC_ARRAY *array, size_t idx) +{ + void* element_ptr; + + DBUG_ASSERT(idx < array->max_element); + + // Calculate the pointer to the desired element in the array + element_ptr = array->buffer + (idx * array->size_of_element); + return element_ptr; +} + +inline void mem_root_dynamic_array_copy_values(MEM_ROOT_DYNAMIC_ARRAY *dest, MEM_ROOT_DYNAMIC_ARRAY *src) +{ + size_t number_of_elements= dest->max_element < src->max_element ? dest->max_element : src->max_element; + + memcpy(dest->buffer, src->buffer, dest->size_of_element * number_of_elements); +} diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index ba9c8f06ae0..d1dfe21e49c 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -124,6 +124,16 @@ String *Item_func_geometry_from_wkb::val_str(String *str) return str; } +bool Item_func_geometry_from_json::fix_length_and_dec(THD *thd) +{ + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, + sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + + return Item_geometry_func::fix_length_and_dec(thd); +} + String *Item_func_geometry_from_json::val_str(String *str) { @@ -132,7 +142,6 @@ String *Item_func_geometry_from_json::val_str(String *str) String *js= args[0]->val_str_ascii(&tmp_js); uint32 srid= 0; longlong options= 0; - json_engine_t je; if ((null_value= args[0]->null_value)) return 0; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 9ef9052d5a9..ea8804b43bc 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -248,6 +248,10 @@ public: class Item_func_geometry_from_json: public Item_geometry_func { String tmp_js; + json_engine_t je; + MEM_ROOT current_mem_root; + int mem_root_inited; + bool check_arguments() const override { // TODO: check with Alexey, for better args[1] and args[2] type control @@ -255,16 +259,18 @@ class Item_func_geometry_from_json: public Item_geometry_func check_argument_types_traditional_scalar(1, MY_MIN(3, arg_count)); } public: - Item_func_geometry_from_json(THD *thd, Item *js): Item_geometry_func(thd, js) {} + Item_func_geometry_from_json(THD *thd, Item *js): Item_geometry_func(thd, js) + { mem_root_inited= false; } Item_func_geometry_from_json(THD *thd, Item *js, Item *opt): - Item_geometry_func(thd, js, opt) {} + Item_geometry_func(thd, js, opt) { mem_root_inited= false; } Item_func_geometry_from_json(THD *thd, Item *js, Item *opt, Item *srid): - Item_geometry_func(thd, js, opt, srid) {} + Item_geometry_func(thd, js, opt, srid) { mem_root_inited= false; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("st_geomfromgeojson") }; return name; } + bool fix_length_and_dec(THD *thd) override; String *val_str(String *) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 50c72f506b3..1c86ee059fa 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -15,6 +15,7 @@ #include "mariadb.h" +#include "mysqld.h" #include "sql_priv.h" #include "sql_class.h" #include "item.h" @@ -22,8 +23,11 @@ #include "json_schema_helper.h" static bool get_current_value(json_engine_t *, const uchar *&, size_t &); -static bool check_overlaps(json_engine_t *, json_engine_t *, bool); -static int json_find_overlap_with_object(json_engine_t *, json_engine_t *, bool); +static int check_overlaps(json_engine_t *, json_engine_t *, bool, MEM_ROOT*, json_engine_t *temp_je, MEM_ROOT_DYNAMIC_ARRAY *stack); +static int json_find_overlap_with_object(json_engine_t *, + json_engine_t *, bool, MEM_ROOT*, + json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack); #ifndef DBUG_OFF int dbug_json_check_min_stack_requirement() @@ -175,13 +179,16 @@ static int append_tab(String *js, int depth, int tab_size) return 0; } -int json_path_parts_compare( - const json_path_step_t *a, const json_path_step_t *a_end, - const json_path_step_t *b, const json_path_step_t *b_end, - enum json_value_types vt, const int *array_sizes) +int json_path_parts_compare(const MEM_ROOT_DYNAMIC_ARRAY *a_arr, + const json_path_step_t *a, + const json_path_step_t *a_end, + const MEM_ROOT_DYNAMIC_ARRAY *b_arr, + const json_path_step_t *b, + const json_path_step_t *b_end, + enum json_value_types vt, + MEM_ROOT_DYNAMIC_ARRAY *array_sizes) { int res, res2; - const json_path_step_t *temp_b= b; DBUG_EXECUTE_IF("json_check_min_stack_requirement", return dbug_json_check_min_stack_requirement();); @@ -211,23 +218,46 @@ int json_path_parts_compare( { int res= 0, corrected_n_item_a= 0; if (array_sizes) - corrected_n_item_a= a->n_item < 0 ? - array_sizes[b-temp_b] + a->n_item : a->n_item; + { + corrected_n_item_a= a->n_item; + if (corrected_n_item_a < 0) + { + auto temp= (json_path_step_t *) (b_arr->buffer) + 1; + auto value_ptr= ((int *) array_sizes->buffer) + (b - temp); + if (value_ptr) + { + corrected_n_item_a += *value_ptr; + } + } + } if (a->type & JSON_PATH_ARRAY_RANGE) { int corrected_n_item_end_a= 0; if (array_sizes) - corrected_n_item_end_a= a->n_item_end < 0 ? - array_sizes[b-temp_b] + a->n_item_end : - a->n_item_end; + { + corrected_n_item_end_a= a->n_item_end; + if (corrected_n_item_end_a < 0) + { + auto temp= (json_path_step_t *) (b_arr->buffer) + 1; + auto value_ptr= ((int *) array_sizes->buffer) + (b - temp); + if (value_ptr) + { + corrected_n_item_end_a += *value_ptr; + } + } + } res= b->n_item >= corrected_n_item_a && - b->n_item <= corrected_n_item_end_a; + b->n_item <= corrected_n_item_end_a; } else + { res= corrected_n_item_a == b->n_item; + } - if ((a->type & JSON_PATH_WILD) || res) + if (res || (a->type & JSON_PATH_WILD)) + { goto step_fits; + } goto step_failed; } if ((a->type & JSON_PATH_WILD) == 0 && a->n_item == 0) @@ -253,43 +283,39 @@ step_failed: continue; step_fits: - b++; + b++; if (!(a->type & JSON_PATH_DOUBLE_WILD)) { - a++; + a++; continue; } /* Double wild handling needs recursions. */ - res= json_path_parts_compare(a+1, a_end, b, b_end, vt, - array_sizes ? array_sizes + (b - temp_b) : - NULL); + res= json_path_parts_compare(a_arr, a+1, a_end, b_arr, b, b_end, + vt, array_sizes); if (res == 0) return 0; - res2= json_path_parts_compare(a, a_end, b, b_end, vt, - array_sizes ? array_sizes + (b - temp_b) : - NULL); + res2= json_path_parts_compare(a_arr, a, a_end, b_arr, b, b_end, vt, + array_sizes); return (res2 >= 0) ? res2 : res; step_fits_autowrap: if (!(a->type & JSON_PATH_DOUBLE_WILD)) { - a++; + a++; continue; } /* Double wild handling needs recursions. */ - res= json_path_parts_compare(a+1, a_end, b+1, b_end, vt, - array_sizes ? array_sizes + (b - temp_b) : - NULL); + res= json_path_parts_compare(a_arr, a+1, a_end, b_arr, b+1, b_end, vt, + array_sizes); if (res == 0) return 0; - res2= json_path_parts_compare(a, a_end, b+1, b_end, vt, - array_sizes ? array_sizes + (b - temp_b) : - NULL); + res2= json_path_parts_compare(a_arr, a, a_end, b_arr, b+1, b_end, vt, + array_sizes); return (res2 >= 0) ? res2 : res; @@ -300,10 +326,19 @@ step_fits_autowrap: int json_path_compare(const json_path_t *a, const json_path_t *b, - enum json_value_types vt, const int *array_size) + enum json_value_types vt, + MEM_ROOT_DYNAMIC_ARRAY *array_size) { - return json_path_parts_compare(a->steps+1, a->last_step, - b->steps+1, b->last_step, vt, array_size); + json_path_step_t *a_init= (json_path_step_t*)(a->steps.buffer), + *b_init= (json_path_step_t*)(b->steps.buffer), + *a_last_step= (json_path_step_t*)(a->steps.buffer)+ a->last_step_idx, + *b_last_step= (json_path_step_t*)(b->steps.buffer) + b->last_step_idx; + + return + json_path_parts_compare(&(a->steps), a_init + 1, + a_last_step, + &(b->steps), b_init + 1, + b_last_step, vt, array_size); } @@ -455,6 +490,9 @@ error: } +#define report_path_error(js, je, n_param) \ + report_path_error_ex(js->ptr(), je, func_name(), n_param,\ + Sql_condition::WARN_LEVEL_WARN) #define report_json_error(js, je, n_param) \ report_json_error_ex(js->ptr(), je, func_name(), n_param, \ Sql_condition::WARN_LEVEL_WARN) @@ -518,10 +556,6 @@ void report_json_error_ex(const char *js, json_engine_t *je, #define SHOULD_END_WITH_ARRAY 2 #define TRIVIAL_PATH_NOT_ALLOWED 3 -#define report_path_error(js, je, n_param) \ - report_path_error_ex(js->ptr(), je, func_name(), n_param,\ - Sql_condition::WARN_LEVEL_WARN) - void report_path_error_ex(const char *ps, json_path_t *p, const char *fname, int n_param, Sql_condition::enum_warning_level lv) @@ -591,6 +625,19 @@ static int path_setup_nwc(json_path_t *p, CHARSET_INFO *i_cs, return 1; } +bool Item_func_json_valid::fix_length_and_dec(THD *thd) +{ + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + + if (Item_bool_func::fix_length_and_dec(thd)) + return TRUE; + + set_maybe_null(); + + return FALSE; +} bool Item_func_json_valid::val_bool() { @@ -599,12 +646,19 @@ bool Item_func_json_valid::val_bool() if ((null_value= args[0]->null_value)) return 0; - return json_valid(js->ptr(), js->length(), js->charset()); + return json_valid(js->ptr(), js->length(), js->charset(), &je); } bool Item_func_json_equals::fix_length_and_dec(THD *thd) { + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &temp_je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &stack, sizeof(struct json_norm_value*), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + if (Item_bool_func::fix_length_and_dec(thd)) return TRUE; set_maybe_null(); @@ -615,7 +669,6 @@ bool Item_func_json_equals::fix_length_and_dec(THD *thd) bool Item_func_json_equals::val_bool() { longlong result= 0; - String a_tmp, b_tmp; String *a= args[0]->val_json(&a_tmp); @@ -642,13 +695,15 @@ bool Item_func_json_equals::val_bool() goto end; } - if (json_normalize(&a_res, a->ptr(), a->length(), a->charset())) + if (json_normalize(&a_res, a->ptr(), a->length(), + a->charset(), current_thd->mem_root, &temp_je, &stack)) { null_value= 1; goto end; } - if (json_normalize(&b_res, b->ptr(), b->length(), b->charset())) + if (json_normalize(&b_res, b->ptr(), b->length(), + b->charset(), current_thd->mem_root, &temp_je, &stack)) { null_value= 1; goto end; @@ -669,14 +724,23 @@ bool Item_func_json_exists::fix_length_and_dec(THD *thd) return TRUE; set_maybe_null(); path.set_constant_flag(args[1]->const_item()); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &path.p.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); return FALSE; } bool Item_func_json_exists::val_bool() { - json_engine_t je; - int array_counters[JSON_DEPTH_LIMIT]; + json_path_step_t *tmp_ptr= NULL; String *js= args[0]->val_json(&tmp_js); @@ -700,8 +764,9 @@ bool Item_func_json_exists::val_bool() json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), (const uchar *) js->ptr() + js->length()); - path.cur_step= path.p.steps; - if (json_find_path(&je, &path.p, &path.cur_step, array_counters)) + path.cur_step= &path.p.steps; + tmp_ptr= (json_path_step_t*)(path.cur_step->buffer); + if (json_find_path(&je, &path.p, &(tmp_ptr), &json_depth_array)) { if (je.s.error) goto err_return; @@ -718,30 +783,78 @@ err_return: bool Item_func_json_value::fix_length_and_dec(THD *thd) { + func_name_str= {STRING_WITH_LEN("json_value") }; + collation.set(args[0]->collation); max_length= args[0]->max_length; set_constant_flag(args[1]->const_item()); set_maybe_null(); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + Json_path_extractor::init_json_engine_stack(thd->mem_root); + return FALSE; } +String *Item_func_json_value::val_str(String *to) +{ + null_value= Json_path_extractor::extract(current_thd->mem_root, to, args[0], + args[1], + collation.collation, + &json_depth_array, + &func_name_str); + return null_value ? NULL : to; +} + bool Item_func_json_query::fix_length_and_dec(THD *thd) { + func_name_str= {STRING_WITH_LEN("json_query") }; + collation.set(args[0]->collation); max_length= args[0]->max_length; set_constant_flag(args[1]->const_item()); set_maybe_null(); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + Json_path_extractor::init_json_engine_stack(current_thd->mem_root); + return FALSE; } - -bool Json_path_extractor::extract(String *str, Item *item_js, Item *item_jp, - CHARSET_INFO *cs) +String *Item_func_json_query::val_str(String *to) { - String *js= item_js->val_json(&tmp_js); + null_value= Json_path_extractor::extract(current_thd->mem_root, to, args[0], + args[1], + collation.collation, + &json_depth_array, + &func_name_str); + return null_value ? NULL : to; + } + +void Json_path_extractor::init_json_engine_stack(MEM_ROOT *current_mem_root) +{ + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &p.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); +} + +bool Json_path_extractor::extract(MEM_ROOT *mem_root, String *str, + Item *item_js, Item *item_jp, + CHARSET_INFO *cs, + MEM_ROOT_DYNAMIC_ARRAY *array_counters, + LEX_CSTRING *func_name_str) +{ +String *js= item_js->val_json(&tmp_js); + json_path_step_t *tmp_ptr= NULL; int error= 0; - int array_counters[JSON_DEPTH_LIMIT]; if (!parsed) { @@ -749,36 +862,46 @@ bool Json_path_extractor::extract(String *str, Item *item_js, Item *item_jp, if (s_p && json_path_setup(&p, s_p->charset(), (const uchar *) s_p->ptr(), (const uchar *) s_p->ptr() + s_p->length())) + { return true; + } parsed= constant; } if (item_js->null_value || item_jp->null_value) return true; - Json_engine_scan je(*js); + json_scan_start(&je, js->charset(), (const uchar*)js->ptr(), + (const uchar*)js->end()); str->length(0); str->set_charset(cs); - cur_step= p.steps; + cur_step= &p.steps; + tmp_ptr= (json_path_step_t*)(p.steps.buffer); continue_search: - if (json_find_path(&je, &p, &cur_step, array_counters)) - return true; + if (json_find_path(&je, &p, &tmp_ptr, array_counters)) + goto error_return; if (json_read_value(&je)) - return true; + goto error_return; if (je.value_type == JSON_VALUE_NULL) - return true; + goto error_return; if (unlikely(check_and_get_value(&je, str, &error))) { if (error) - return true; + goto error_return; goto continue_search; } return false; + +error_return: + report_json_error_ex(js->ptr(), (json_engine_t*)&je, + (const char*)func_name_str->str , 0, + Sql_condition::WARN_LEVEL_WARN); + return true; } @@ -889,8 +1012,12 @@ String *Item_func_json_quote::val_str(String *str) bool Item_func_json_unquote::fix_length_and_dec(THD *thd) { collation.set(&my_charset_utf8mb4_bin, DERIVATION_CAST, MY_REPERTOIRE_ASCII); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); max_length= args[0]->max_char_length() * collation.collation->mbmaxlen; set_maybe_null(); + return FALSE; } @@ -919,7 +1046,6 @@ error: String *Item_func_json_unquote::val_str(String *str) { - json_engine_t je; int c_len= JSON_ERROR_OUT_OF_SPACE; String *js; @@ -967,14 +1093,15 @@ error: } -static int alloc_tmp_paths(THD *thd, uint n_paths, - json_path_with_flags **paths, String **tmp_paths) +static int alloc_tmp_paths(uint n_paths, + json_path_with_flags **paths, + String **tmp_paths) { if (n_paths > 0) { if (*tmp_paths == 0) { - MEM_ROOT *root= thd->active_stmt_arena_to_use()->mem_root; + MEM_ROOT *root= _current_thd()->active_stmt_arena_to_use()->mem_root; *paths= (json_path_with_flags *) alloc_root(root, sizeof(json_path_with_flags) * n_paths); @@ -1016,6 +1143,7 @@ Item_json_str_multipath::~Item_json_str_multipath() } + bool Item_json_str_multipath::fix_fields(THD *thd, Item **ref) { if (!tmp_paths) @@ -1034,7 +1162,7 @@ bool Item_json_str_multipath::fix_fields(THD *thd, Item **ref) */ n_paths= get_n_paths(); - if (alloc_tmp_paths(thd, n_paths, &paths, &tmp_paths)) + if (alloc_tmp_paths(n_paths, &paths, &tmp_paths)) return true; } @@ -1049,6 +1177,10 @@ bool Item_json_str_multipath::fix_fields(THD *thd, Item **ref) return Item_str_func::fix_fields(thd, ref); } +bool Item_json_str_multipath::fix_length_and_dec(THD *thd) +{ + return false; +} bool Item_func_json_extract::fix_length_and_dec(THD *thd) { @@ -1057,13 +1189,35 @@ bool Item_func_json_extract::fix_length_and_dec(THD *thd) mark_constant_paths(paths, args+1, arg_count-1); set_maybe_null(); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &sav_je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + + for (uint n_arg=1; n_arg < arg_count; n_arg++) + { + json_path_with_flags *c_path= paths + n_arg - 1; + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &(c_path->p.steps), sizeof(json_path_step_t), + NULL, JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + } + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &p.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return FALSE; } 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) + MEM_ROOT_DYNAMIC_ARRAY *array_size_counter) { int count_path= 0; for (; n_paths > 0; n_paths--, paths_list++) @@ -1077,7 +1231,7 @@ static int path_exact(const json_path_with_flags *paths_list, int n_paths, static bool path_ok(const json_path_with_flags *paths_list, int n_paths, const json_path_t *p, json_value_types vt, - const int *array_size_counter) + MEM_ROOT_DYNAMIC_ARRAY *array_size_counter) { for (; n_paths > 0; n_paths--, paths_list++) { @@ -1093,14 +1247,11 @@ String *Item_func_json_extract::read_json(String *str, char **out_val, int *value_len) { String *js= args[0]->val_json(&tmp_js); - json_engine_t je, sav_je; - json_path_t p; const uchar *value; int not_first_value= 0, count_path= 0; uint n_arg; size_t v_len; int possible_multiple_values; - int array_size_counter[JSON_DEPTH_LIMIT]; uint has_negative_path= 0; if ((null_value= args[0]->null_value)) @@ -1150,13 +1301,15 @@ String *Item_func_json_extract::read_json(String *str, while (json_get_path_next(&je, &p) == 0) { + int tmp= 0; if (has_negative_path && je.value_type == JSON_VALUE_ARRAY && - json_skip_array_and_count(&je, - array_size_counter + (p.last_step - p.steps))) + (json_skip_array_and_count(&je, &tmp) || + mem_root_dynamic_array_resize_and_set_val(&json_depth_array, &tmp, + p.last_step_idx))) goto error; if (!(count_path= path_exact(paths, arg_count-1, &p, je.value_type, - array_size_counter))) + &json_depth_array))) continue; value= je.value_begin; @@ -1352,8 +1505,23 @@ bool Item_func_json_contains::fix_length_and_dec(THD *thd) a2_constant= args[1]->const_item(); a2_parsed= FALSE; set_maybe_null(); + if (arg_count > 2) path.set_constant_flag(args[2]->const_item()); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &(path.p.steps), sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &ve.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return Item_bool_func::fix_length_and_dec(thd); } @@ -1376,14 +1544,21 @@ static int find_key_in_object(json_engine_t *j, json_string_t *key) } -static int check_contains(json_engine_t *js, json_engine_t *value) +int Item_func_json_contains::check_contains(json_engine_t *js, + json_engine_t *value) { - json_engine_t loc_js; bool set_js; + json_engine_t loc_js; + mem_root_dynamic_array_init(current_thd->mem_root, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED, + &loc_js.stack, sizeof(int), &loc_js_stack_buffer, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + DBUG_EXECUTE_IF("json_check_min_stack_requirement", return dbug_json_check_min_stack_requirement();); if (check_stack_overrun(current_thd, STACK_MIN_SIZE , NULL)) + { return 1; + } switch (js->value_type) { @@ -1392,7 +1567,9 @@ static int check_contains(json_engine_t *js, json_engine_t *value) json_string_t key_name; if (value->value_type != JSON_VALUE_OBJECT) + { return FALSE; + } loc_js= *js; set_js= FALSE; @@ -1409,7 +1586,9 @@ static int check_contains(json_engine_t *js, json_engine_t *value) } while (json_read_keyname_chr(value) == 0); if (unlikely(value->s.error) || json_read_value(value)) + { return FALSE; + } if (set_js) *js= loc_js; @@ -1420,7 +1599,9 @@ static int check_contains(json_engine_t *js, json_engine_t *value) if (!find_key_in_object(js, &key_name) || json_read_value(js) || !check_contains(js, value)) + { return FALSE; + } } return value->state == JST_OBJ_END && !json_skip_level(js); @@ -1435,7 +1616,9 @@ static int check_contains(json_engine_t *js, json_engine_t *value) int c_level, v_scalar; DBUG_ASSERT(js->state == JST_VALUE); if (json_read_value(js)) + { return FALSE; + } if (!(v_scalar= json_value_scalar(js))) c_level= json_get_level(js); @@ -1448,12 +1631,16 @@ static int check_contains(json_engine_t *js, json_engine_t *value) if (check_contains(js, value)) { if (json_skip_level(js)) + { return FALSE; + } return TRUE; } if (unlikely(value->s.error) || unlikely(js->s.error) || (!v_scalar && json_skip_to_level(js, c_level))) + { return FALSE; + } } return FALSE; } @@ -1464,21 +1651,27 @@ static int check_contains(json_engine_t *js, json_engine_t *value) { DBUG_ASSERT(value->state == JST_VALUE); if (json_read_value(value)) + { return FALSE; + } if (set_js) *js= loc_js; else set_js= TRUE; if (!check_contains(js, value)) + { return FALSE; + } } return value->state == JST_ARRAY_END; case JSON_VALUE_STRING: if (value->value_type != JSON_VALUE_STRING) + { return FALSE; + } /* TODO: make proper json-json comparison here that takes excipient into account. @@ -1498,8 +1691,9 @@ static int check_contains(json_engine_t *js, json_engine_t *value) return (fabs(d_j - d_v) < 1e-12); } else + { return FALSE; - + } default: break; } @@ -1518,7 +1712,7 @@ static int check_contains(json_engine_t *js, json_engine_t *value) bool Item_func_json_contains::val_bool() { String *js= args[0]->val_json(&tmp_js); - json_engine_t je, ve; + json_path_step_t *tmp_ptr= NULL; int result; if ((null_value= args[0]->null_value)) @@ -1541,7 +1735,6 @@ bool Item_func_json_contains::val_bool() if (arg_count>2) /* Path specified. */ { - int array_counters[JSON_DEPTH_LIMIT]; if (!path.parsed) { String *s_p= args[2]->val_str(&tmp_path); @@ -1557,8 +1750,10 @@ bool Item_func_json_contains::val_bool() if (args[2]->null_value) goto return_null; - path.cur_step= path.p.steps; - if (json_find_path(&je, &path.p, &path.cur_step, array_counters)) + path.cur_step= &path.p.steps; + tmp_ptr= (json_path_step_t*)(path.p.steps.buffer); + if (json_find_path(&je, &path.p, + &tmp_ptr, &json_depth_array)) { if (je.s.error) { @@ -1577,6 +1772,7 @@ bool Item_func_json_contains::val_bool() goto error; result= check_contains(&je, &ve); + if (unlikely(je.s.error || ve.s.error)) goto error; @@ -1601,9 +1797,10 @@ bool Item_func_json_contains_path::fix_fields(THD *thd, Item **ref) */ if (!tmp_paths) { - if (alloc_tmp_paths(thd, arg_count-2, &paths, &tmp_paths) || - (p_found= (bool *) alloc_root(thd->active_stmt_arena_to_use()->mem_root, - (arg_count-2)*sizeof(bool))) == NULL) + if (alloc_tmp_paths(arg_count-2, &paths, &tmp_paths) || + (p_found=(bool *) + alloc_root(_current_thd()->active_stmt_arena_to_use()->mem_root, + (arg_count-2)*sizeof(bool))) == NULL) return true; } @@ -1616,7 +1813,27 @@ bool Item_func_json_contains_path::fix_length_and_dec(THD *thd) ooa_constant= args[1]->const_item(); ooa_parsed= FALSE; set_maybe_null(); + mark_constant_paths(paths, args+2, arg_count-2); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &(p.steps), sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + for (uint n_arg=2; n_arg < arg_count; n_arg++) + { + json_path_with_flags *c_path= paths + n_arg - 2; + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &c_path->p.steps, + sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + } + return Item_bool_func::fix_length_and_dec(thd); } @@ -1664,8 +1881,7 @@ static int parse_one_or_all(const Item_func *f, Item *ooa_arg, #ifdef DUMMY longlong Item_func_json_contains_path::val_int() { - String *js= args[0]->val_json(&tmp_js); - json_engine_t je; + String *js= args[0]->val_json(&tmp_js); uint n_arg; longlong result; @@ -1678,7 +1894,6 @@ longlong Item_func_json_contains_path::val_int() result= !mode_one; for (n_arg=2; n_arg < arg_count; n_arg++) { - int array_counters[JSON_DEPTH_LIMIT]; json_path_with_flags *c_path= paths + n_arg - 2; if (!c_path->parsed) { @@ -1702,7 +1917,7 @@ longlong Item_func_json_contains_path::val_int() json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), (const uchar *) js->ptr() + js->length()); - c_path->cur_step= c_path->p.steps; + c_path->cur_step= (json_path_step_t*)(c_path->p.steps.buffer); if (json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters)) { /* Path wasn't found. */ @@ -1736,13 +1951,10 @@ return_null: bool Item_func_json_contains_path::val_bool() { String *js= args[0]->val_json(&tmp_js); - json_engine_t je; uint n_arg; longlong result; - json_path_t p; int n_found; LINT_INIT(n_found); - int array_sizes[JSON_DEPTH_LIMIT]; uint has_negative_path= 0; if ((null_value= args[0]->null_value)) @@ -1789,9 +2001,15 @@ bool Item_func_json_contains_path::val_bool() result= 0; while (json_get_path_next(&je, &p) == 0) { - int n_path= arg_count - 2; + int n_path= arg_count - 2, value= 0, *value_ptr= NULL; + + value_ptr= (int*)(json_depth_array.buffer)+(p.last_step_idx); if (has_negative_path && je.value_type == JSON_VALUE_ARRAY && - json_skip_array_and_count(&je, array_sizes + (p.last_step - p.steps))) + (json_skip_array_and_count(&je, + value_ptr ? value_ptr : &value) || + mem_root_dynamic_array_resize_and_set_val(&json_depth_array, + value_ptr ? value_ptr : &value, + p.last_step_idx))) { result= 1; break; @@ -1800,7 +2018,8 @@ bool Item_func_json_contains_path::val_bool() json_path_with_flags *c_path= paths; for (; n_path > 0; n_path--, c_path++) { - if (json_path_compare(&c_path->p, &p, je.value_type, array_sizes) >= 0) + if (json_path_compare(&c_path->p, &p, je.value_type, + &json_depth_array) >= 0) { if (mode_one) { @@ -1967,7 +2186,9 @@ bool Item_func_json_array::fix_length_and_dec(THD *thd) ulonglong char_length= 2; uint n_arg; - result_limit= 0; + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); if (arg_count == 0) { @@ -1979,6 +2200,8 @@ bool Item_func_json_array::fix_length_and_dec(THD *thd) return FALSE; } + result_limit= 0; + if (agg_arg_charsets_for_string_result(collation, args, arg_count)) return TRUE; @@ -2003,6 +2226,7 @@ bool Item_func_json_array::fix_length_and_dec(THD *thd) fix_char_length_ulonglong(char_length); tmp_val.set_charset(collation.collation); + return FALSE; } @@ -2050,7 +2274,6 @@ 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; @@ -2064,16 +2287,33 @@ bool Item_func_json_array_append::fix_length_and_dec(THD *thd) static_cast(args[n_arg+1]->max_char_length()) + 4; } + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + + for (uint n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++) + { + json_path_with_flags *c_path= paths + n_path; + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &c_path->p.steps, + sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + } + fix_char_length_ulonglong(char_length); set_maybe_null(); + return FALSE; } String *Item_func_json_array_append::val_str(String *str) { - json_engine_t je; String *js= args[0]->val_json(&tmp_js); + json_path_step_t *tmp_ptr; uint n_arg, n_path; size_t str_rest_len; const uchar *ar_end; @@ -2086,7 +2326,6 @@ String *Item_func_json_array_append::val_str(String *str) for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++) { - int array_counters[JSON_DEPTH_LIMIT]; json_path_with_flags *c_path= paths + n_path; if (!c_path->parsed) { @@ -2107,9 +2346,10 @@ String *Item_func_json_array_append::val_str(String *str) (const uchar *) js->ptr() + js->length()); je.killed_ptr= (uchar*)&thd->killed; - c_path->cur_step= c_path->p.steps; - - if (json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters)) + c_path->cur_step= &c_path->p.steps; + tmp_ptr= (json_path_step_t*)(c_path->p.steps.buffer); + if (json_find_path(&je, &c_path->p, + &tmp_ptr, &json_depth_array)) { if (je.s.error) goto js_error; @@ -2204,8 +2444,7 @@ return_null: String *Item_func_json_array_insert::val_str(String *str) { - json_engine_t je; - String *js= args[0]->val_str(&tmp_js); + String *js= args[0]->val_str(&tmp_js); uint n_arg, n_path; THD *thd= current_thd; @@ -2218,7 +2457,6 @@ String *Item_func_json_array_insert::val_str(String *str) for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++) { - int array_counters[JSON_DEPTH_LIMIT]; json_path_with_flags *c_path= paths + n_path; const char *item_pos; int n_item, corrected_n_item; @@ -2229,8 +2467,9 @@ String *Item_func_json_array_insert::val_str(String *str) if (s_p && (path_setup_nwc(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(), (const uchar *) s_p->ptr() + s_p->length()) || - c_path->p.last_step - 1 < c_path->p.steps || - c_path->p.last_step->type != JSON_PATH_ARRAY)) + (((json_path_step_t*) (c_path->p.steps.buffer)) + + (c_path->p.last_step_idx) -1) < ((json_path_step_t*)(c_path->p.steps.buffer)) || + ((json_path_step_t*)(c_path->p.steps.buffer) + c_path->p.last_step_idx)->type != JSON_PATH_ARRAY)) { if (c_path->p.s.error == 0) c_path->p.s.error= SHOULD_END_WITH_ARRAY; @@ -2239,8 +2478,7 @@ String *Item_func_json_array_insert::val_str(String *str) goto return_null; } - c_path->parsed= c_path->constant; - c_path->p.last_step--; + c_path->p.last_step_idx--; } if (args[n_arg]->null_value) goto return_null; @@ -2249,9 +2487,9 @@ String *Item_func_json_array_insert::val_str(String *str) (const uchar *) js->ptr() + js->length()); je.killed_ptr= (uchar*)&thd->killed; - c_path->cur_step= c_path->p.steps; - - if (json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters)) + c_path->cur_step= &c_path->p.steps; + json_path_step_t *tmp_step= (json_path_step_t*)(c_path->cur_step->buffer); + if (json_find_path(&je, &c_path->p, &tmp_step, &json_depth_array)) { if (je.s.error) goto js_error; @@ -2271,7 +2509,7 @@ String *Item_func_json_array_insert::val_str(String *str) item_pos= 0; n_item= 0; - corrected_n_item= c_path->p.last_step[1].n_item; + corrected_n_item= ((json_path_step_t*)(c_path->p.steps.buffer) +(c_path->p.last_step_idx))[1].n_item; if (corrected_n_item < 0) { int array_size; @@ -2649,11 +2887,19 @@ continue_j2: return 0; } +bool Item_func_json_merge::fix_length_and_dec(THD *thd) +{ + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je2.stack, + sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return Item_func_json_array::fix_length_and_dec(thd); +} + String *Item_func_json_merge::val_str(String *str) { DBUG_ASSERT(fixed()); - json_engine_t je1, je2; String *js1= args[0]->val_json(&tmp_js1), *js2=NULL; uint n_arg; THD *thd= current_thd; @@ -2673,15 +2919,15 @@ String *Item_func_json_merge::val_str(String *str) if (args[n_arg]->null_value) goto null_return; - json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(), + json_scan_start(&je, js1->charset(),(const uchar *) js1->ptr(), (const uchar *) js1->ptr() + js1->length()); - je1.killed_ptr= (uchar*)&thd->killed; + je.killed_ptr= (uchar*)&thd->killed; json_scan_start(&je2, js2->charset(),(const uchar *) js2->ptr(), (const uchar *) js2->ptr() + js2->length()); je2.killed_ptr= (uchar*)&thd->killed; - if (do_merge(str, &je1, &je2)) + if (do_merge(str, &je, &je2)) goto error_return; { @@ -2699,18 +2945,18 @@ String *Item_func_json_merge::val_str(String *str) } } - json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(), + json_scan_start(&je, js1->charset(),(const uchar *) js1->ptr(), (const uchar *) js1->ptr() + js1->length()); - je1.killed_ptr= (uchar*)&thd->killed; - if (json_nice(&je1, str, Item_func_json_format::LOOSE)) + je.killed_ptr= (uchar*)&thd->killed; + if (json_nice(&je, 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 (je.s.error) + report_json_error(js1, &je, 0); if (je2.s.error) report_json_error(js2, &je2, n_arg); thd->check_killed(); // to get the error message right @@ -2964,7 +3210,6 @@ continue_j2: String *Item_func_json_merge_patch::val_str(String *str) { DBUG_ASSERT(fixed()); - json_engine_t je1, je2; String *js1= args[0]->val_json(&tmp_js1), *js2=NULL; uint n_arg; bool empty_result, merge_to_null; @@ -2973,7 +3218,7 @@ String *Item_func_json_merge_patch::val_str(String *str) JSON_DO_PAUSE_EXECUTION(thd, 0.0002); /* To report errors properly if some JSON is invalid. */ - je1.s.error= je2.s.error= 0; + je.s.error= je2.s.error= 0; merge_to_null= args[0]->null_value; for (n_arg=1; n_arg < arg_count; n_arg++) @@ -3005,11 +3250,11 @@ String *Item_func_json_merge_patch::val_str(String *str) str->length(0); - json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(), + json_scan_start(&je, js1->charset(),(const uchar *) js1->ptr(), (const uchar *) js1->ptr() + js1->length()); - je1.killed_ptr= (uchar*)&thd->killed; + je.killed_ptr= (uchar*)&thd->killed; - if (do_merge_patch(str, &je1, &je2, &empty_result)) + if (do_merge_patch(str, &je, &je2, &empty_result)) goto error_return; if (empty_result) @@ -3034,18 +3279,18 @@ cont_point: if (merge_to_null) goto null_return; - json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(), + json_scan_start(&je, js1->charset(),(const uchar *) js1->ptr(), (const uchar *) js1->ptr() + js1->length()); - je1.killed_ptr= (uchar*)&thd->killed; - if (json_nice(&je1, str, Item_func_json_format::LOOSE)) + je.killed_ptr= (uchar*)&thd->killed; + if (json_nice(&je, 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 (je.s.error) + report_json_error(js1, &je, 0); if (je2.s.error) report_json_error(js2, &je2, n_arg); thd->check_killed(); // to get the error message right @@ -3061,6 +3306,20 @@ bool Item_func_json_length::fix_length_and_dec(THD *thd) path.set_constant_flag(args[1]->const_item()); set_maybe_null(); max_length= 10; + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, + sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &(path.p.steps), + sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, + sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return FALSE; } @@ -3068,9 +3327,8 @@ bool Item_func_json_length::fix_length_and_dec(THD *thd) longlong Item_func_json_length::val_int() { String *js= args[0]->val_json(&tmp_js); - json_engine_t je; + json_path_step_t *tmp_ptr= NULL; uint length= 0; - int array_counters[JSON_DEPTH_LIMIT]; int err; if ((null_value= args[0]->null_value)) @@ -3097,8 +3355,9 @@ longlong Item_func_json_length::val_int() if (args[1]->null_value) goto null_return; - path.cur_step= path.p.steps; - if (json_find_path(&je, &path.p, &path.cur_step, array_counters)) + path.cur_step= &path.p.steps; + tmp_ptr= (json_path_step_t*)(path.cur_step->buffer); + if (json_find_path(&je, &path.p, &tmp_ptr, &json_depth_array)) { if (je.s.error) goto err_return; @@ -3148,11 +3407,19 @@ null_return: return 0; } +bool Item_func_json_depth::fix_length_and_dec(THD *thd) +{ + max_length= 10; + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return false; +} longlong Item_func_json_depth::val_int() { String *js= args[0]->val_json(&tmp_js); - json_engine_t je; uint depth= 0, c_depth= 0; bool inc_depth= TRUE; @@ -3206,6 +3473,11 @@ bool Item_func_json_type::fix_length_and_dec(THD *thd) collation.set(&my_charset_utf8mb3_general_ci); max_length= 12 * collation.collation->mbmaxlen; set_maybe_null(); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return FALSE; } @@ -3213,13 +3485,11 @@ bool Item_func_json_type::fix_length_and_dec(THD *thd) String *Item_func_json_type::val_str(String *str) { String *js= args[0]->val_json(&tmp_js); - json_engine_t je; const char *type; if ((null_value= args[0]->null_value)) return 0; - json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), (const uchar *) js->ptr() + js->length()); @@ -3270,11 +3540,25 @@ bool Item_func_json_insert::fix_length_and_dec(THD *thd) uint n_arg; ulonglong char_length; - JSON_DO_PAUSE_EXECUTION(thd, 0.0002); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); collation.set(args[0]->collation); char_length= args[0]->max_char_length(); + for (uint n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++) + { + json_path_with_flags *c_path= paths + n_path; + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &c_path->p.steps, + sizeof(json_path_step_t), + NULL, JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + } + for (n_arg= 1; n_arg < arg_count; n_arg+= 2) { paths[n_arg/2].set_constant_flag(args[n_arg]->const_item()); @@ -3294,8 +3578,8 @@ bool Item_func_json_insert::fix_length_and_dec(THD *thd) String *Item_func_json_insert::val_str(String *str) { - json_engine_t je; String *js= args[0]->val_json(&tmp_js); + json_path_step_t *tmp_ptr= NULL; uint n_arg, n_path; json_string_t key_name; THD *thd= current_thd; @@ -3311,10 +3595,9 @@ String *Item_func_json_insert::val_str(String *str) for (n_arg=1, n_path=0; n_arg < arg_count; n_arg+=2, n_path++) { - int array_counters[JSON_DEPTH_LIMIT]; json_path_with_flags *c_path= paths + n_path; const char *v_to; - json_path_step_t *lp; + json_path_step_t *lp= NULL, *last_step=NULL, *initial_step= NULL; int corrected_n_item; if (!c_path->parsed) @@ -3331,7 +3614,7 @@ String *Item_func_json_insert::val_str(String *str) } /* We search to the last step. */ - c_path->p.last_step--; + c_path->p.last_step_idx--; } c_path->parsed= c_path->constant; } @@ -3342,13 +3625,22 @@ String *Item_func_json_insert::val_str(String *str) (const uchar *) js->ptr() + js->length()); je.killed_ptr= (uchar*)&thd->killed; - if (c_path->p.last_step < c_path->p.steps) + initial_step= (json_path_step_t*)(c_path->p.steps.buffer); + if (c_path->p.last_step_idx < 0) + { + last_step= (json_path_step_t*)(c_path->p.steps.buffer)-1; + } + else + { + last_step= (json_path_step_t*)(c_path->p.steps.buffer) + (c_path->p.last_step_idx); + } + if (last_step < initial_step) goto v_found; - c_path->cur_step= c_path->p.steps; - - if (c_path->p.last_step >= c_path->p.steps && - json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters)) + c_path->cur_step= &(c_path->p.steps); + tmp_ptr= initial_step; + if (last_step >= initial_step && + json_find_path(&je, &c_path->p, &tmp_ptr, &json_depth_array)) { if (je.s.error) goto js_error; @@ -3358,7 +3650,8 @@ String *Item_func_json_insert::val_str(String *str) if (json_read_value(&je)) goto js_error; - lp= c_path->p.last_step+1; + lp= (json_path_step_t*) + (c_path->p.steps.buffer)+(c_path->p.last_step_idx+1); if (lp->type & JSON_PATH_ARRAY) { int n_item= 0; @@ -3550,16 +3843,31 @@ bool Item_func_json_remove::fix_length_and_dec(THD *thd) collation.set(args[0]->collation); max_length= args[0]->max_length; + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + for (uint n_arg=1, n_path=0; n_arg < arg_count; n_arg++, n_path++) + { + json_path_with_flags *c_path= paths + n_path; + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &c_path->p.steps, sizeof(json_path_step_t), + NULL, JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + } + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mark_constant_paths(paths, args+1, arg_count-1); set_maybe_null(); + return FALSE; } String *Item_func_json_remove::val_str(String *str) { - json_engine_t je; String *js= args[0]->val_json(&tmp_js); + json_path_step_t *tmp_ptr= NULL; uint n_arg, n_path; json_string_t key_name; THD *thd= current_thd; @@ -3567,8 +3875,7 @@ String *Item_func_json_remove::val_str(String *str) DBUG_ASSERT(fixed()); JSON_DO_PAUSE_EXECUTION(thd, 0.0002); - - if (args[0]->null_value) + if (!js || args[0]->null_value) goto null_return; str->set_charset(js->charset()); @@ -3576,7 +3883,6 @@ String *Item_func_json_remove::val_str(String *str) for (n_arg=1, n_path=0; n_arg < arg_count; n_arg++, n_path++) { - int array_counters[JSON_DEPTH_LIMIT]; json_path_with_flags *c_path= paths + n_path; const char *rem_start= 0, *rem_end; json_path_step_t *lp; @@ -3585,6 +3891,7 @@ String *Item_func_json_remove::val_str(String *str) if (!c_path->parsed) { String *s_p= args[n_arg]->val_str(tmp_paths+n_path); + st_json_path_step_t* last_step= NULL, *initial_step= NULL; if (s_p) { if (path_setup_nwc(&c_path->p,s_p->charset(), @@ -3596,8 +3903,19 @@ String *Item_func_json_remove::val_str(String *str) } /* We search to the last step. */ - c_path->p.last_step--; - if (c_path->p.last_step < c_path->p.steps) + c_path->p.last_step_idx--; + initial_step= (json_path_step_t*)(c_path->p.steps.buffer); + + if (c_path->p.last_step_idx < 0) + { + last_step= (json_path_step_t*)(c_path->p.steps.buffer)-1; + } + else + { + last_step= (json_path_step_t*)(c_path->p.steps.buffer) + (c_path->p.last_step_idx); + } + + if (last_step < initial_step) { c_path->p.s.error= TRIVIAL_PATH_NOT_ALLOWED; report_path_error(s_p, &c_path->p, n_arg); @@ -3613,9 +3931,10 @@ String *Item_func_json_remove::val_str(String *str) (const uchar *) js->ptr() + js->length()); je.killed_ptr= (uchar*)&thd->killed; - c_path->cur_step= c_path->p.steps; + c_path->cur_step= &(c_path->p.steps); + tmp_ptr= (json_path_step_t*)(c_path->p.steps.buffer); - if (json_find_path(&je, &c_path->p, &c_path->cur_step, array_counters)) + if (json_find_path(&je, &c_path->p, &tmp_ptr, &json_depth_array)) { if (je.s.error) goto js_error; @@ -3625,7 +3944,8 @@ String *Item_func_json_remove::val_str(String *str) if (json_read_value(&je)) goto js_error; - lp= c_path->p.last_step+1; + lp= (json_path_step_t*) + (c_path->p.steps.buffer)+(c_path->p.last_step_idx+1); if (lp->type & JSON_PATH_ARRAY) { @@ -3752,9 +4072,20 @@ bool Item_func_json_keys::fix_length_and_dec(THD *thd) { collation.set(args[0]->collation); max_length= args[0]->max_length; + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &path.p.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); set_maybe_null(); if (arg_count > 1) path.set_constant_flag(args[1]->const_item()); + return FALSE; } @@ -3796,10 +4127,9 @@ static int check_key_in_list(String *res, String *Item_func_json_keys::val_str(String *str) { - json_engine_t je; String *js= args[0]->val_json(&tmp_js); + json_path_step_t *tmp_ptr= NULL; uint n_keys= 0; - int array_counters[JSON_DEPTH_LIMIT]; if ((args[0]->null_value)) goto null_return; @@ -3826,9 +4156,11 @@ String *Item_func_json_keys::val_str(String *str) if (args[1]->null_value) goto null_return; - path.cur_step= path.p.steps; + path.cur_step= &path.p.steps; + tmp_ptr= (json_path_step_t*)(path.cur_step->buffer); - if (json_find_path(&je, &path.p, &path.cur_step, array_counters)) + if (json_find_path(&je, &path.p, + &tmp_ptr, &json_depth_array)) { if (je.s.error) goto err_return; @@ -3865,12 +4197,14 @@ skip_search: key_len= (int)(key_end - key_start); if (!check_key_in_list(str, key_start, key_len)) - { + { if ((n_keys > 0 && str->append(", ", 2)) || str->append('"') || append_simple(str, key_start, key_len) || str->append('"')) - goto err_return; + { + goto err_return; + } n_keys++; } break; @@ -3924,6 +4258,7 @@ bool Item_func_json_search::fix_length_and_dec(THD *thd) It's rather difficult to estimate the length of the result. I believe arglen^2 is the reasonable upper limit. */ + if (args[0]->max_length > SQR_MAX_BLOB_WIDTH) max_length= MAX_BLOB_WIDTH; else @@ -3938,6 +4273,27 @@ bool Item_func_json_search::fix_length_and_dec(THD *thd) if (arg_count > 4) mark_constant_paths(paths, args+4, arg_count-4); set_maybe_null(); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &p.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &sav_path.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + for (uint n_arg=4; n_arg < arg_count; n_arg++) + { + json_path_with_flags *c_path= paths + n_arg - 4; + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &c_path->p.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + } + return FALSE; } @@ -3986,12 +4342,16 @@ int Item_func_json_search::compare_json_value_wild(json_engine_t *je, static int append_json_path(String *str, const json_path_t *p) { - const json_path_step_t *c; + json_path_step_t *c; if (str->append("\"$", 2)) return TRUE; - for (c= p->steps+1; c <= p->last_step; c++) + json_path_step_t *step= (json_path_step_t*) + (p->steps.buffer), + *last_step= (json_path_step_t*) + (p->steps.buffer) + p->last_step_idx; + for (c= step+1; c <= last_step; c++) { if (c->type & JSON_PATH_KEY) { @@ -4017,11 +4377,14 @@ String *Item_func_json_search::val_str(String *str) { String *js= args[0]->val_json(&tmp_js); String *s_str= args[2]->val_str(&tmp_path); - json_engine_t je; - json_path_t p, sav_path; uint n_arg; - int array_sizes[JSON_DEPTH_LIMIT]; uint has_negative_path= 0; + bool has_multi_value= false; + + temp.length(0); + + if (!js || !js->length()) + goto null_return; if (args[0]->null_value || args[2]->null_value) goto null_return; @@ -4061,31 +4424,29 @@ String *Item_func_json_search::val_str(String *str) while (json_get_path_next(&je, &p) == 0) { + int value= 0; if (has_negative_path && je.value_type == JSON_VALUE_ARRAY && - json_skip_array_and_count(&je, array_sizes + (p.last_step - p.steps))) + (json_skip_array_and_count(&je, &value) || + mem_root_dynamic_array_resize_and_set_val(&json_depth_array, &value, + p.last_step_idx))) goto js_error; if (json_value_scalar(&je)) { if ((arg_count < 5 || - path_ok(paths, arg_count - 4, &p, je.value_type, array_sizes)) && + path_ok(paths, arg_count - 4, &p, je.value_type, &json_depth_array)) && compare_json_value_wild(&je, s_str) != 0) { ++n_path_found; if (n_path_found == 1) { - sav_path= p; - sav_path.last_step= sav_path.steps + (p.last_step - p.steps); + if (append_json_path(&temp, &p)) + goto js_error; } else { - if (n_path_found == 2) - { - if (str->append('[') || - append_json_path(str, &sav_path)) - goto js_error; - } - if (str->append(", ", 2) || append_json_path(str, &p)) + has_multi_value= true; + if (temp.append(", ", 2) || append_json_path(&temp, &p)) goto js_error; } if (mode_one) @@ -4100,17 +4461,17 @@ String *Item_func_json_search::val_str(String *str) end: if (n_path_found == 0) goto null_return; - if (n_path_found == 1) + + if (has_multi_value) { - if (append_json_path(str, &sav_path)) - goto js_error; + str->append('['); + str->append(temp); + str->append(']'); } else { - if (str->append(']')) - goto js_error; + str->append(temp); } - null_value= 0; return str; @@ -4160,6 +4521,11 @@ bool Item_func_json_format::fix_length_and_dec(THD *thd) DBUG_ASSERT(0); }; set_maybe_null(); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return FALSE; } @@ -4167,7 +4533,6 @@ bool Item_func_json_format::fix_length_and_dec(THD *thd) String *Item_func_json_format::val_str(String *str) { String *js= args[0]->val_json(&tmp_js); - json_engine_t je; int tab_size= 4; THD *thd= current_thd; @@ -4221,6 +4586,9 @@ int Arg_comparator::compare_json_str_basic(Item *j, Item *s) int c_len; json_engine_t je; + mem_root_dynamic_array_init(current_thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); if ((js= j->val_str(&value1))) { json_scan_start(&je, js->charset(), (const uchar *) js->ptr(), @@ -4510,6 +4878,10 @@ String *Item_func_json_normalize::val_str(String *buf) String tmp; String *raw_json= args[0]->val_str(&tmp); + null_value= args[0]->null_value; + if (null_value) + return NULL; + DYNAMIC_STRING normalized_json; if (init_dynamic_string(&normalized_json, NULL, 0, 0)) { @@ -4517,13 +4889,10 @@ String *Item_func_json_normalize::val_str(String *buf) return NULL; } - null_value= args[0]->null_value; - if (null_value) - goto end; - if (json_normalize(&normalized_json, raw_json->ptr(), raw_json->length(), - raw_json->charset())) + raw_json->charset(), current_thd->mem_root, + &temp_je, &stack)) { null_value= 1; goto end; @@ -4544,6 +4913,16 @@ end: bool Item_func_json_normalize::fix_length_and_dec(THD *thd) { + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &stack, sizeof(struct json_norm_value*), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &temp_je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + collation.set(&my_charset_utf8mb4_bin); /* 0 becomes 0.0E0, thus one character becomes 5 chars */ fix_char_length_ulonglong((ulonglong) args[0]->max_char_length() * 5); @@ -4618,7 +4997,10 @@ static bool json_find_overlap_with_scalar(json_engine_t *js, json_engine_t *valu array is object, then compare the two objects entirely. If they are equal return true else return false. */ -static bool json_compare_arr_and_obj(json_engine_t *js, json_engine_t *value) +static bool json_compare_arr_and_obj(json_engine_t *js, json_engine_t *value, + MEM_ROOT *current_mem_root, + json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack) { st_json_engine_t loc_val= *value; while (json_scan_next(js) == 0 && js->state == JST_VALUE) @@ -4627,7 +5009,10 @@ static bool json_compare_arr_and_obj(json_engine_t *js, json_engine_t *value) return FALSE; if (js->value_type == JSON_VALUE_OBJECT) { - int res1= json_find_overlap_with_object(js, value, true); + int res1= json_find_overlap_with_object(js, value, true, + current_mem_root, + temp_je, + stack); if (res1) return TRUE; *value= loc_val; @@ -4639,7 +5024,9 @@ static bool json_compare_arr_and_obj(json_engine_t *js, json_engine_t *value) } -bool json_compare_arrays_in_order(json_engine_t *js, json_engine_t *value) +bool json_compare_arrays_in_order(json_engine_t *js, json_engine_t *value, + MEM_ROOT *current_mem_root, json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack) { bool res= false; while (json_scan_next(js) == 0 && json_scan_next(value) == 0 && @@ -4652,7 +5039,7 @@ bool json_compare_arrays_in_order(json_engine_t *js, json_engine_t *value) json_skip_current_level(js, value); return FALSE; } - res= check_overlaps(js, value, true); + res= check_overlaps(js, value, true, current_mem_root, temp_je, stack); if (!res) { json_skip_current_level(js, value); @@ -4667,12 +5054,14 @@ bool json_compare_arrays_in_order(json_engine_t *js, json_engine_t *value) static int json_find_overlap_with_array(json_engine_t *js, json_engine_t *value, - bool compare_whole) + bool compare_whole, + MEM_ROOT *current_mem_root, + json_engine_t *temp_je, MEM_ROOT_DYNAMIC_ARRAY *stack) { if (value->value_type == JSON_VALUE_ARRAY) { if (compare_whole) - return json_compare_arrays_in_order(js, value); + return json_compare_arrays_in_order(js, value, current_mem_root, temp_je, stack); json_engine_t loc_value= *value, current_js= *js; @@ -4687,7 +5076,7 @@ static int json_find_overlap_with_array(json_engine_t *js, json_engine_t *value, return FALSE; if (js->value_type == value->value_type) { - int res1= check_overlaps(js, value, true); + int res1= check_overlaps(js, value, true, current_mem_root, temp_je, stack); if (res1) return TRUE; } @@ -4711,14 +5100,17 @@ static int json_find_overlap_with_array(json_engine_t *js, json_engine_t *value, json_skip_current_level(js, value); return FALSE; } - return json_compare_arr_and_obj(js, value); + return json_compare_arr_and_obj(js, value, current_mem_root, temp_je, stack); } else return json_find_overlap_with_scalar(value, js); } -int compare_nested_object(json_engine_t *js, json_engine_t *value) +int compare_nested_object(json_engine_t *js, json_engine_t *value, + MEM_ROOT *current_mem_root, + json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack) { int result= 0; const char *value_begin= (const char*)value->s.c_str-1; @@ -4732,13 +5124,15 @@ int compare_nested_object(json_engine_t *js, json_engine_t *value) String b(js_begin, js_end-js_begin, js->s.cs); DYNAMIC_STRING a_res, b_res; - if (init_dynamic_string(&a_res, NULL, 4096, 1024) || - init_dynamic_string(&b_res, NULL, 4096, 1024)) + if (init_dynamic_string(&a_res, NULL, BLOCK_SIZE_JSON_DYN_ARRAY, 1024) || + init_dynamic_string(&b_res, NULL, BLOCK_SIZE_JSON_DYN_ARRAY, 1024)) { goto error; } - if (json_normalize(&a_res, a.ptr(), a.length(), value->s.cs) || - json_normalize(&b_res, b.ptr(), b.length(), value->s.cs)) + if (json_normalize(&a_res, a.ptr(), a.length(), value->s.cs, + current_mem_root, temp_je, stack) || + json_normalize(&b_res, b.ptr(), b.length(), value->s.cs, + current_mem_root, temp_je, stack)) { goto error; } @@ -4754,13 +5148,16 @@ int compare_nested_object(json_engine_t *js, json_engine_t *value) static int json_find_overlap_with_object(json_engine_t *js, json_engine_t *value, - bool compare_whole) + bool compare_whole, + MEM_ROOT *current_mem_root, + json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack) { if (value->value_type == JSON_VALUE_OBJECT) { if (compare_whole) { - return compare_nested_object(js, value); + return compare_nested_object(js, value, current_mem_root, temp_je, stack); } else { @@ -4799,7 +5196,7 @@ static int json_find_overlap_with_object(json_engine_t *js, json_engine_t *value to true. */ if (js->value_type == value->value_type) - found_value= check_overlaps(js, value, true); + found_value= check_overlaps(js, value, true, current_mem_root, temp_je, stack); if (found_value) { /* @@ -4853,7 +5250,7 @@ static int json_find_overlap_with_object(json_engine_t *js, json_engine_t *value json_skip_current_level(js, value); return FALSE; } - return json_compare_arr_and_obj(value, js); + return json_compare_arr_and_obj(value, js, current_mem_root, temp_je, stack); } return FALSE; } @@ -4909,7 +5306,10 @@ static int json_find_overlap_with_object(json_engine_t *js, json_engine_t *value FALSE - If two json documents do not overlap TRUE - if two json documents overlap */ -static bool check_overlaps(json_engine_t *js, json_engine_t *value, bool compare_whole) +static int check_overlaps(json_engine_t *js, json_engine_t *value, + bool compare_whole, MEM_ROOT *current_mem_root, + json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack) { DBUG_EXECUTE_IF("json_check_min_stack_requirement", return dbug_json_check_min_stack_requirement();); @@ -4919,9 +5319,12 @@ static bool check_overlaps(json_engine_t *js, json_engine_t *value, bool compare switch (js->value_type) { case JSON_VALUE_OBJECT: - return json_find_overlap_with_object(js, value, compare_whole); + return json_find_overlap_with_object(js, value, compare_whole, + current_mem_root, temp_je, + stack); case JSON_VALUE_ARRAY: - return json_find_overlap_with_array(js, value, compare_whole); + return json_find_overlap_with_array(js, value, compare_whole, + current_mem_root, temp_je, stack); default: return json_find_overlap_with_scalar(js, value); } @@ -4930,7 +5333,6 @@ static bool check_overlaps(json_engine_t *js, json_engine_t *value, bool compare bool Item_func_json_overlaps::val_bool() { String *js= args[0]->val_json(&tmp_js); - json_engine_t je, ve; int result; if ((null_value= args[0]->null_value)) @@ -4957,7 +5359,8 @@ bool Item_func_json_overlaps::val_bool() if (json_read_value(&je) || json_read_value(&ve)) goto error; - result= check_overlaps(&je, &ve, false); + result= check_overlaps(&je, &ve, false, current_thd->mem_root, &temp_je, &stack); + if (unlikely(je.s.error || ve.s.error)) goto error; @@ -4977,12 +5380,24 @@ bool Item_func_json_overlaps::fix_length_and_dec(THD *thd) a2_parsed= FALSE; set_maybe_null(); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &ve.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &temp_je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &stack, sizeof(struct json_norm_value*), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return Item_bool_func::fix_length_and_dec(thd); } bool Item_func_json_schema_valid::val_bool() { - json_engine_t ve; int is_valid= 1; if (!schema_parsed) @@ -5015,7 +5430,7 @@ bool Item_func_json_schema_valid::val_bool() Json_schema_keyword* curr_keyword= NULL; while ((curr_keyword=it++)) { - if (curr_keyword->validate(&ve, NULL, NULL)) + if (curr_keyword->validate(&ve, current_thd->mem_root, NULL, NULL)) { is_valid= 0; break; @@ -5059,9 +5474,14 @@ bool Item_func_json_schema_valid::fix_length_and_dec(THD *thd) String *js= NULL; + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &ve.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); if (!is_schema_constant) { - my_error(ER_JSON_NO_VARIABLE_SCHEMA, MYF(0)); null_value= 1; return 0; @@ -5076,8 +5496,9 @@ bool Item_func_json_schema_valid::fix_length_and_dec(THD *thd) } json_scan_start(&je, js->charset(), (const uchar *) js->ptr(), (const uchar *) js->ptr() + js->length()); - if (!create_object_and_handle_keyword(thd, &je, &keyword_list, - &all_keywords)) + if (!create_object_and_handle_keyword(thd, current_thd->mem_root, &je, + &keyword_list, + &all_keywords)) schema_parsed= true; else schema_parsed= false; @@ -5112,6 +5533,8 @@ void Item_func_json_schema_valid::cleanup() all_keywords.empty(); keyword_list.empty(); + Item_bool_func::cleanup(); + DBUG_VOID_RETURN; } @@ -5193,17 +5616,18 @@ error_return: String* Item_func_json_key_value::val_str(String *str) { - json_engine_t je; if ((null_value= args[0]->null_value) || - (null_value= args[1]->null_value)) + (null_value= args[1]->null_value)) { goto return_null; } - - null_value= Json_path_extractor::extract(&tmp_str, args[0], args[1], - collation.collation); - if (null_value) + null_value= Json_path_extractor::extract(current_thd->mem_root, &tmp_str, + args[0], args[1], + collation.collation, + &json_depth_array, + &func_name_str); + if (null_value) return NULL; json_scan_start(&je, tmp_str.charset(), (const uchar *) tmp_str.ptr(), @@ -5231,6 +5655,8 @@ return_null: bool Item_func_json_key_value::fix_length_and_dec(THD *thd) { + func_name_str= {STRING_WITH_LEN("json_key_value") }; + collation.set(args[0]->collation); tmp_str.set("", 0, collation.collation); @@ -5239,12 +5665,30 @@ bool Item_func_json_key_value::fix_length_and_dec(THD *thd) set_constant_flag(args[1]->const_item()); set_maybe_null(); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &json_depth_array, + sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &p.steps, + sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, + sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je_scan.stack, + sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + Json_path_extractor::init_json_engine_stack(current_thd->mem_root); return FALSE; } static bool create_hash(json_engine_t *value, HASH *items, bool &hash_inited, - MEM_ROOT *hash_root) + MEM_ROOT *hash_root, MEM_ROOT *current_mem_root, + json_engine_t *temp_je, MEM_ROOT_DYNAMIC_ARRAY *stack) { int level= value->stack_p; if (my_hash_init(PSI_INSTRUMENT_ME, items, value->s.cs, 0, 0, 0, @@ -5264,7 +5708,8 @@ static bool create_hash(json_engine_t *value, HASH *items, bool &hash_inited, return true; if (json_normalize(&norm_val, (const char*) value_start, - value_len, value->s.cs)) + value_len, value->s.cs, current_mem_root, + temp_je, stack)) { dynstr_free(&norm_val); return true; @@ -5332,7 +5777,10 @@ static bool get_current_value(json_engine_t *js, const uchar *&value_start, TRUE - If two array documents do not have intersection */ static bool get_intersect_between_arrays(String *str, json_engine_t *value, - HASH items) + HASH items, + MEM_ROOT *current_mem_root, + json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack) { bool res= true, has_value= false; int level= value->stack_p; @@ -5351,7 +5799,7 @@ static bool get_intersect_between_arrays(String *str, json_engine_t *value, goto error; if (json_normalize(&norm_val, (const char*) value_start, - value_len, value->s.cs)) + value_len, value->s.cs, current_mem_root, temp_je, stack)) { dynstr_free(&norm_val); goto error; @@ -5408,7 +5856,6 @@ String* Item_func_json_array_intersect::val_str(String *str) { DBUG_ASSERT(fixed()); - json_engine_t je2, res_je, je1; String *js2= args[1]->val_json(&tmp_js2), *js1= args[0]->val_json(&tmp_js1); if (parse_for_each_row) @@ -5417,9 +5864,9 @@ String* Item_func_json_array_intersect::val_str(String *str) goto null_return; if (hash_inited) my_hash_free(&items); - if (root_inited) + if (hash_root_inited) free_root(&hash_root, MYF(0)); - root_inited= false; + hash_root_inited= false; hash_inited= false; prepare_json_and_create_hash(&je1, js1); } @@ -5436,7 +5883,7 @@ String* Item_func_json_array_intersect::val_str(String *str) if (json_read_value(&je2) || je2.value_type != JSON_VALUE_ARRAY) goto error_return; - if (get_intersect_between_arrays(str, &je2, items)) + if (get_intersect_between_arrays(str, &je2, items, current_thd->mem_root, &temp_je, &stack)) goto error_return; if (str->length()) @@ -5471,12 +5918,12 @@ void Item_func_json_array_intersect::prepare_json_and_create_hash(json_engine_t Scan value uses the hash table to get the intersection of two arrays. */ - if (!root_inited) + if (!hash_root_inited) init_alloc_root(PSI_NOT_INSTRUMENTED, &hash_root, 1024, 0, MYF(0)); - root_inited= true; + hash_root_inited= true; if (json_read_value(je1) || je1->value_type != JSON_VALUE_ARRAY || - create_hash(je1, &items, hash_inited, &hash_root)) + create_hash(je1, &items, hash_inited, &hash_root, current_thd->mem_root, &temp_je, &stack)) { if (je1->s.error) report_json_error(js, je1, 0); @@ -5489,8 +5936,25 @@ void Item_func_json_array_intersect::prepare_json_and_create_hash(json_engine_t bool Item_func_json_array_intersect::fix_length_and_dec(THD *thd) { - json_engine_t je1; - String *js1; + String *js1= args[0]->val_json(&tmp_js1);; + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je1.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &res_je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je2.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &temp_je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &stack, sizeof(struct json_norm_value*), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); if (!args[0]->const_item()) { @@ -5504,9 +5968,7 @@ bool Item_func_json_array_intersect::fix_length_and_dec(THD *thd) goto end; } } - - js1= args[0]->val_json(&tmp_js1); - prepare_json_and_create_hash(&je1, js1); + prepare_json_and_create_hash(&je2, js1); end: set_maybe_null(); @@ -5590,7 +6052,6 @@ String* Item_func_json_object_filter_keys::val_str(String *str) { DBUG_ASSERT(fixed()); - json_engine_t je1, res_je; String *js1= args[0]->val_json(&tmp_js1); if (null_value || args[0]->null_value) @@ -5610,10 +6071,10 @@ String* Item_func_json_object_filter_keys::val_str(String *str) if (str->length()) { - json_scan_start(&res_je, str->charset(), (const uchar *) str->ptr(), + json_scan_start(&je_res, str->charset(), (const uchar *) str->ptr(), (const uchar *) str->ptr() + str->length()); str= &tmp_js1; - if (json_nice(&res_je, str, Item_func_json_format::LOOSE)) + if (json_nice(&je_res, str, Item_func_json_format::LOOSE)) goto error_return; null_value= 0; @@ -5637,7 +6098,22 @@ null_return: bool Item_func_json_object_filter_keys::fix_length_and_dec(THD *thd) { String *js2= args[1]->val_json(&tmp_js2); - json_engine_t je2; + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je1.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je_res.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &temp_je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &temp_je2.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &stack, sizeof(struct json_norm_value*), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); if (args[1]->null_value) { @@ -5645,17 +6121,17 @@ bool Item_func_json_object_filter_keys::fix_length_and_dec(THD *thd) return FALSE; } - json_scan_start(&je2, js2->charset(),(const uchar *) js2->ptr(), + json_scan_start(&temp_je, js2->charset(),(const uchar *) js2->ptr(), (const uchar *) js2->ptr() + js2->length()); - if (!root_inited) + if (!hash_root_inited) init_alloc_root(PSI_NOT_INSTRUMENTED, &hash_root, 1024, 0, MYF(0)); - root_inited= true; + hash_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(&temp_je) || temp_je.value_type != JSON_VALUE_ARRAY || + create_hash(&temp_je, &items, hash_inited, &hash_root, current_thd->mem_root, &temp_je2, &stack)) { - if (je2.s.error) - report_json_error(js2, &je2, 0); + if (temp_je.s.error) + report_json_error(js2, &temp_je, 0); null_value= 1; return FALSE; } @@ -5731,7 +6207,6 @@ String* Item_func_json_object_to_array::val_str(String *str) { DBUG_ASSERT(fixed()); - json_engine_t je; String *js1= args[0]->val_str(&tmp); if (args[0]->null_value) @@ -5780,5 +6255,10 @@ bool Item_func_json_object_to_array::fix_length_and_dec(THD *thd) { max_length= args[0]->max_length + (args[0]->max_length/2); set_maybe_null(); + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return FALSE; } diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index 2e7433b10f2..35dbf01885f 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -33,7 +33,7 @@ public: json_path_t p; bool constant; bool parsed; - json_path_step_t *cur_step; + MEM_ROOT_DYNAMIC_ARRAY *cur_step; void set_constant_flag(bool s_constant) { constant= s_constant; @@ -52,14 +52,16 @@ void report_json_error_ex(const char *js, json_engine_t *je, class Json_engine_scan: public json_engine_t { public: - Json_engine_scan(CHARSET_INFO *i_cs, const uchar *str, const uchar *end) + Json_engine_scan(MEM_ROOT *mem_root, CHARSET_INFO *i_cs, const uchar *str, + const uchar *end) { json_scan_start(this, i_cs, str, end); } - Json_engine_scan(const String &str) - :Json_engine_scan(str.charset(), (const uchar *) str.ptr(), - (const uchar *) str.end()) + Json_engine_scan(MEM_ROOT *mem_root, const String &str) + :Json_engine_scan(mem_root, str.charset(), (const uchar *) str.ptr(), + (const uchar *) str.end()) { } + Json_engine_scan(){} bool check_and_get_value_scalar(String *res, int *error); bool check_and_get_value_complex(String *res, int *error, json_value_types cur_value_type= @@ -70,11 +72,19 @@ public: class Json_path_extractor: public json_path_with_flags { protected: + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; String tmp_js, tmp_path; - virtual ~Json_path_extractor() { } + Json_engine_scan je; + ~Json_path_extractor() { } virtual bool check_and_get_value(Json_engine_scan *je, String *to, int *error)=0; - bool extract(String *to, Item *js, Item *jp, CHARSET_INFO *cs); + bool extract(MEM_ROOT *mem_root, String *to, Item *js, + Item *jp, CHARSET_INFO *cs, + MEM_ROOT_DYNAMIC_ARRAY *, + LEX_CSTRING *func_name); + void init_json_engine_stack(MEM_ROOT *mem_root); +public: + Json_path_extractor() {} }; @@ -82,22 +92,18 @@ class Item_func_json_valid: public Item_bool_func { protected: String tmp_value; + json_engine_t je; public: - Item_func_json_valid(THD *thd, Item *json) : Item_bool_func(thd, json) {} + Item_func_json_valid(THD *thd, Item *json) : + Item_bool_func(thd, json) {} bool val_bool() override; LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_valid") }; return name; } - bool fix_length_and_dec(THD *thd) override - { - if (Item_bool_func::fix_length_and_dec(thd)) - return TRUE; - set_maybe_null(); - return FALSE; - } + bool fix_length_and_dec(THD *thd) override; bool set_format_by_check_constraint(Send_field_extended_metadata *to) const override { @@ -112,9 +118,13 @@ public: class Item_func_json_equals: public Item_bool_func { +json_engine_t je1, je2, temp_je; +MEM_ROOT_DYNAMIC_ARRAY stack; + public: Item_func_json_equals(THD *thd, Item *a, Item *b): - Item_bool_func(thd, a, b) {} + Item_bool_func(thd, a, b) + {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_equals") }; @@ -130,12 +140,15 @@ public: class Item_func_json_exists: public Item_bool_func { protected: + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; json_path_with_flags path; String tmp_js, tmp_path; + json_engine_t je; public: Item_func_json_exists(THD *thd, Item *js, Item *i_path): - Item_bool_func(thd, js, i_path) {} + Item_bool_func(thd, js, i_path) + {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_exists") }; @@ -169,6 +182,7 @@ public: class Item_func_json_value: public Item_str_func, public Json_path_extractor { + LEX_CSTRING func_name_str; public: Item_func_json_value(THD *thd, Item *js, Item *i_path): @@ -179,12 +193,7 @@ public: return name; } bool fix_length_and_dec(THD *thd) override ; - String *val_str(String *to) override - { - null_value= Json_path_extractor::extract(to, args[0], args[1], - collation.collation); - return null_value ? NULL : to; - } + String *val_str(String *to) override; bool check_and_get_value(Json_engine_scan *je, String *res, int *error) override { @@ -198,21 +207,19 @@ public: class Item_func_json_query: public Item_json_func, public Json_path_extractor { + LEX_CSTRING func_name_str; + public: Item_func_json_query(THD *thd, Item *js, Item *i_path): - Item_json_func(thd, js, i_path) {} + Item_json_func(thd, js, i_path) + {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_query") }; return name; } bool fix_length_and_dec(THD *thd) override; - String *val_str(String *to) override - { - null_value= Json_path_extractor::extract(to, args[0], args[1], - collation.collation); - return null_value ? NULL : to; - } + String *val_str(String *to) override; bool check_and_get_value(Json_engine_scan *je, String *res, int *error) override { @@ -227,9 +234,11 @@ class Item_func_json_quote: public Item_str_func { protected: String tmp_s; + json_engine_t je; public: - Item_func_json_quote(THD *thd, Item *s): Item_str_func(thd, s) {} + Item_func_json_quote(THD *thd, Item *s): Item_str_func(thd, s) + {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_quote") }; @@ -244,11 +253,15 @@ public: class Item_func_json_unquote: public Item_str_func { +private: + json_engine_t je; + protected: String tmp_s; String *read_json(json_engine_t *je); public: - Item_func_json_unquote(THD *thd, Item *s): Item_str_func(thd, s) {} + Item_func_json_unquote(THD *thd, Item *s): Item_str_func(thd, s) + {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_unquote") }; @@ -266,6 +279,7 @@ class Item_json_str_multipath: public Item_json_func protected: json_path_with_flags *paths; String *tmp_paths; + private: /** Number of paths returned by calling virtual method get_n_paths() and @@ -282,10 +296,12 @@ private: uint n_paths; public: Item_json_str_multipath(THD *thd, List &list): - Item_json_func(thd, list), paths(NULL), tmp_paths(0), n_paths(0) {} - virtual ~Item_json_str_multipath(); + Item_json_func(thd, list), paths(NULL), tmp_paths(0), n_paths(0) + {} + ~Item_json_str_multipath(); bool fix_fields(THD *thd, Item **ref) override; + bool fix_length_and_dec(THD* thd) override; virtual uint get_n_paths() const = 0; }; @@ -293,12 +309,17 @@ public: class Item_func_json_extract: public Item_json_str_multipath { protected: + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; String tmp_js; + json_path_t p; + json_engine_t je, sav_je; + public: String *read_json(String *str, json_value_types *type, char **out_val, int *value_len); Item_func_json_extract(THD *thd, List &list): - Item_json_str_multipath(thd, list) {} + Item_json_str_multipath(thd, list) + {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_extract") }; @@ -319,14 +340,19 @@ public: class Item_func_json_contains: public Item_bool_func { protected: + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; String tmp_js; json_path_with_flags path; String tmp_path; bool a2_constant, a2_parsed; String tmp_val, *val; + json_engine_t je, ve; + int loc_js_stack_buffer[JSON_DEPTH_LIMIT]; + public: Item_func_json_contains(THD *thd, List &list): - Item_bool_func(thd, list) {} + Item_bool_func(thd, list) + {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_contains") }; @@ -336,22 +362,27 @@ public: bool val_bool() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } + int check_contains(json_engine_t *je, json_engine_t *ve); }; class Item_func_json_contains_path: public Item_bool_func { protected: + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; String tmp_js; json_path_with_flags *paths; String *tmp_paths; bool mode_one; bool ooa_constant, ooa_parsed; bool *p_found; + json_path_t p; + json_engine_t je; public: Item_func_json_contains_path(THD *thd, List &list): - Item_bool_func(thd, list), tmp_paths(0) {} + Item_bool_func(thd, list), tmp_paths(0) + {} virtual ~Item_func_json_contains_path(); LEX_CSTRING func_name_cstring() const override { @@ -371,11 +402,15 @@ class Item_func_json_array: public Item_json_func protected: String tmp_val; ulong result_limit; + json_engine_t je; + public: Item_func_json_array(THD *thd): - Item_json_func(thd) {} + Item_json_func(thd) + {result_limit= 0;} Item_func_json_array(THD *thd, List &list): - Item_json_func(thd, list) {} + Item_json_func(thd, list) + {} String *val_str(String *) override; bool fix_length_and_dec(THD *thd) override; LEX_CSTRING func_name_cstring() const override @@ -391,8 +426,12 @@ public: class Item_func_json_array_append: public Item_json_str_multipath { protected: + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; String tmp_js; String tmp_val; + json_engine_t je; + MEM_ROOT current_mem_root; + public: Item_func_json_array_append(THD *thd, List &list): Item_json_str_multipath(thd, list) {} @@ -447,6 +486,8 @@ class Item_func_json_merge: public Item_func_json_array { protected: String tmp_js1, tmp_js2; + json_engine_t je2; + public: Item_func_json_merge(THD *thd, List &list): Item_func_json_array(thd, list) {} @@ -456,6 +497,7 @@ public: static LEX_CSTRING name= {STRING_WITH_LEN("json_merge_preserve") }; return name; } + bool fix_length_and_dec(THD *thd) override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; @@ -478,6 +520,9 @@ public: class Item_func_json_normalize: public Item_json_func { +json_engine_t je, temp_je; +MEM_ROOT_DYNAMIC_ARRAY stack; + public: Item_func_json_normalize(THD *thd, Item *a): Item_json_func(thd, a) {} @@ -497,9 +542,12 @@ class Item_func_json_object_to_array: public Item_json_func { protected: String tmp; + json_engine_t je; + public: Item_func_json_object_to_array(THD *thd, Item *a): - Item_json_func(thd, a) {} + Item_json_func(thd, a) + {} String *val_str(String *) override; LEX_CSTRING func_name_cstring() const override { @@ -529,6 +577,9 @@ protected: json_path_with_flags path; String tmp_js; String tmp_path; + json_engine_t je; + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; + public: Item_func_json_length(THD *thd, List &list): Item_long_func(thd, list) {} @@ -550,14 +601,17 @@ class Item_func_json_depth: public Item_long_func { return args[0]->check_type_can_return_text(func_name_cstring()); } protected: String tmp_js; + json_engine_t je; + public: - Item_func_json_depth(THD *thd, Item *js): Item_long_func(thd, js) {} + Item_func_json_depth(THD *thd, Item *js): Item_long_func(thd, js) + {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_depth") }; return name; } - bool fix_length_and_dec(THD *thd) override { max_length= 10; return FALSE; } + bool fix_length_and_dec(THD *thd) override; longlong val_int() override; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } @@ -568,6 +622,8 @@ class Item_func_json_type: public Item_str_func { protected: String tmp_js; + json_engine_t je; + public: Item_func_json_type(THD *thd, Item *js): Item_str_func(thd, js) {} LEX_CSTRING func_name_cstring() const override @@ -588,6 +644,9 @@ protected: String tmp_js; String tmp_val; bool mode_insert, mode_replace; + json_engine_t je; + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; + public: Item_func_json_insert(bool i_mode, bool r_mode, THD *thd, List &list): Item_json_str_multipath(thd, list), @@ -612,9 +671,13 @@ class Item_func_json_remove: public Item_json_str_multipath { protected: String tmp_js; + json_engine_t je; + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; + public: Item_func_json_remove(THD *thd, List &list): - Item_json_str_multipath(thd, list) {} + Item_json_str_multipath(thd, list) + {} bool fix_length_and_dec(THD *thd) override; String *val_str(String *) override; uint get_n_paths() const override { return arg_count - 1; } @@ -633,6 +696,8 @@ class Item_func_json_keys: public Item_str_func protected: json_path_with_flags path; String tmp_js, tmp_path; + json_engine_t je; + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; public: Item_func_json_keys(THD *thd, List &list): @@ -652,12 +717,14 @@ public: class Item_func_json_search: public Item_json_str_multipath { protected: - String tmp_js, tmp_path, esc_value; + String tmp_js, tmp_path, esc_value, temp; bool mode_one; bool ooa_constant, ooa_parsed; int escape; int n_path_found; - json_path_t sav_path; + json_path_t p, sav_path; + json_engine_t je; + MEM_ROOT_DYNAMIC_ARRAY json_depth_array; int compare_json_value_wild(json_engine_t *je, const String *cmp_str); @@ -691,11 +758,15 @@ public: protected: formats fmt; String tmp_js; + json_engine_t je; + public: Item_func_json_format(THD *thd, Item *js, formats format): - Item_json_func(thd, js), fmt(format) {} + Item_json_func(thd, js), fmt(format) + {} Item_func_json_format(THD *thd, List &list): - Item_json_func(thd, list), fmt(DETAILED) {} + Item_json_func(thd, list), fmt(DETAILED) + {} LEX_CSTRING func_name_cstring() const override; bool fix_length_and_dec(THD *thd) override; @@ -807,6 +878,9 @@ class Item_func_json_overlaps: public Item_bool_func String tmp_js; bool a2_constant, a2_parsed; String tmp_val, *val; + json_engine_t je, ve, temp_je; + MEM_ROOT_DYNAMIC_ARRAY stack; + public: Item_func_json_overlaps(THD *thd, Item *a, Item *b): Item_bool_func(thd, a, b) @@ -829,6 +903,7 @@ class Item_func_json_schema_valid: public Item_bool_func String tmp_val, *val; List keyword_list; List all_keywords; + json_engine_t je, ve; public: Item_func_json_schema_valid(THD *thd, Item *a, Item *b): @@ -837,6 +912,7 @@ public: val= NULL; schema_parsed= false; set_maybe_null(); + } LEX_CSTRING func_name_cstring() const override { @@ -851,14 +927,16 @@ public: }; class Item_func_json_key_value: public Item_json_func, - public Json_path_extractor + public Json_path_extractor { - - String tmp_str; + String tmp_str, tmp_val; + json_engine_t je, je_scan; + LEX_CSTRING func_name_str; public: Item_func_json_key_value(THD *thd, Item *js, Item *i_path): - Item_json_func(thd, js, i_path) {} + Item_json_func(thd, js, i_path) + {} LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("json_key_value") }; @@ -882,13 +960,19 @@ class Item_func_json_array_intersect: public Item_str_func { protected: String tmp_js1, tmp_js2; - bool hash_inited, root_inited; + bool hash_inited, hash_root_inited; HASH items; MEM_ROOT hash_root; bool parse_for_each_row; + json_engine_t je1, je2, res_je, temp_je; + MEM_ROOT_DYNAMIC_ARRAY stack; + public: Item_func_json_array_intersect(THD *thd, Item *a, Item *b): - Item_str_func(thd, a, b) { hash_inited= root_inited= parse_for_each_row= false; } + Item_str_func(thd, a, b) + { + hash_inited= hash_root_inited= parse_for_each_row= false; + } String *val_str(String *) override; bool fix_length_and_dec(THD *thd) override; LEX_CSTRING func_name_cstring() const override @@ -903,8 +987,9 @@ public: Item_str_func::cleanup(); if (hash_inited) my_hash_free(&items); - if (root_inited) + if (hash_root_inited) free_root(&hash_root, MYF(0)); + Item_str_func::cleanup(); } void prepare_json_and_create_hash(json_engine_t *je1, String *js); }; @@ -913,12 +998,18 @@ class Item_func_json_object_filter_keys: public Item_str_func { protected: String tmp_js1, tmp_js2; - bool hash_inited, root_inited; + bool hash_inited, hash_root_inited; HASH items; MEM_ROOT hash_root; + json_engine_t je1, je_res, temp_je, temp_je2; + MEM_ROOT_DYNAMIC_ARRAY stack; + public: Item_func_json_object_filter_keys(THD *thd, Item *a, Item *b): - Item_str_func(thd, a, b) { hash_inited= root_inited= false; } + Item_str_func(thd, a, b) + { + hash_inited= hash_root_inited= false; + } String *val_str(String *) override; bool fix_length_and_dec(THD *thd) override; LEX_CSTRING func_name_cstring() const override @@ -931,11 +1022,11 @@ public: void cleanup() override { - Item_str_func::cleanup(); if (hash_inited) my_hash_free(&items); - if (root_inited) + if (hash_root_inited) free_root(&hash_root, MYF(0)); + Item_str_func::cleanup(); } }; diff --git a/sql/item_vectorfunc.cc b/sql/item_vectorfunc.cc index 13e458d7675..354405c3b5f 100644 --- a/sql/item_vectorfunc.cc +++ b/sql/item_vectorfunc.cc @@ -177,10 +177,15 @@ Item_func_vec_totext::Item_func_vec_totext(THD *thd, Item *a) Item_func_vec_fromtext::Item_func_vec_fromtext(THD *thd, Item *a) : Item_str_func(thd, a) { + mem_root_inited= false; } bool Item_func_vec_fromtext::fix_length_and_dec(THD *thd) { + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + decimals= 0; /* Worst case scenario, for a valid input we have a string of the form: [1,2,3,4,5,...] single digit numbers. @@ -193,7 +198,6 @@ bool Item_func_vec_fromtext::fix_length_and_dec(THD *thd) String *Item_func_vec_fromtext::val_str(String *buf) { - json_engine_t je; bool end_ok= false; String *value = args[0]->val_json(&tmp_js); diff --git a/sql/item_vectorfunc.h b/sql/item_vectorfunc.h index 4e3c52e5c2d..b5eac5637eb 100644 --- a/sql/item_vectorfunc.h +++ b/sql/item_vectorfunc.h @@ -90,6 +90,9 @@ public: class Item_func_vec_fromtext: public Item_str_func { String tmp_js; + MEM_ROOT current_mem_root; + bool mem_root_inited; + json_engine_t je; public: bool fix_length_and_dec(THD *thd) override; Item_func_vec_fromtext(THD *thd, Item *a); @@ -101,5 +104,11 @@ public: } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } + void cleanup() override + { + if (mem_root_inited) + free_root(¤t_mem_root, MYF(0)); + Item_str_func::cleanup(); + } }; #endif diff --git a/sql/json_schema.cc b/sql/json_schema.cc index 9cbc613d4d9..4f174fe1fe8 100644 --- a/sql/json_schema.cc +++ b/sql/json_schema.cc @@ -300,16 +300,18 @@ static st_json_schema_keyword_map empty_func_map= keyname, then we want to check if it validates for "patternProperties". In this case "patterProperties" will be alternate schema for "properties". */ -bool Json_schema_keyword::fall_back_on_alternate_schema(const json_engine_t - *je, - const uchar* k_start, - const uchar* k_end) +bool Json_schema_keyword:: + fall_back_on_alternate_schema(const json_engine_t *je, + MEM_ROOT *current_mem_root, + const uchar* k_start, + const uchar* k_end) { if (alternate_schema) { if (alternate_schema->allowed) { - if (alternate_schema->validate_as_alternate(je, k_start, k_end)) + if (alternate_schema->validate_as_alternate(je, k_start, k_end, + current_mem_root)) return true; } else @@ -318,7 +320,9 @@ bool Json_schema_keyword::fall_back_on_alternate_schema(const json_engine_t return false; } -bool Json_schema_annotation::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_annotation::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -362,7 +366,9 @@ bool Json_schema_annotation::handle_keyword(THD *thd, json_engine_t *je, return res; } -bool Json_schema_format::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_format::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -376,13 +382,16 @@ bool Json_schema_format::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_type::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { return !((1 << je->value_type) & type); } -bool Json_schema_type::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_type::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -411,6 +420,7 @@ bool Json_schema_type::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_const::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -419,7 +429,6 @@ bool Json_schema_const::validate(const json_engine_t *je, const char *start= (char*)curr_je.value; const char *end= (char*)curr_je.value+curr_je.value_len; json_engine_t temp_je= *je; - json_engine_t temp_je_2; String a_res("", 0, curr_je.s.cs); int err= 0; @@ -449,9 +458,11 @@ bool Json_schema_const::validate(const json_engine_t *je, curr_je= temp_je; return true; } - json_get_normalized_string(&temp_je_2, &a_res, &err); + json_get_normalized_string(&temp_je_2, &a_res, &err, current_mem_root, &temp_je_arg, &stack); if (err) - return true; + { + return true; + } } else a_res.append(val.ptr(), val.length(), temp_je.s.cs); @@ -459,13 +470,18 @@ bool Json_schema_const::validate(const json_engine_t *je, if (a_res.length() == strlen(const_json_value) && !strncmp((const char*)const_json_value, a_res.ptr(), a_res.length())) + { return false; + } return true; } + return false; } -bool Json_schema_const::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_const::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -476,6 +492,20 @@ bool Json_schema_const::handle_keyword(THD *thd, json_engine_t *je, String a_res("", 0, je->s.cs); int err; + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &temp_je.stack, + sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &temp_je_arg.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &stack, sizeof(struct json_norm_value*), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &temp_je_2.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + type= je->value_type; if (!json_value_scalar(je)) @@ -492,10 +522,14 @@ bool Json_schema_const::handle_keyword(THD *thd, json_engine_t *je, if (je->value_type != JSON_VALUE_STRING) { if (json_read_value(&temp_je)) + { return true; - json_get_normalized_string(&temp_je, &a_res, &err); + } + json_get_normalized_string(&temp_je, &a_res, &err, current_mem_root, &temp_je_arg, &stack); if (err) + { return true; + } } else a_res.append(val.ptr(), val.length(), je->s.cs); @@ -503,7 +537,9 @@ bool Json_schema_const::handle_keyword(THD *thd, json_engine_t *je, this->const_json_value= (char*)alloc_root(thd->mem_root, a_res.length()+1); if (!const_json_value) - return true; + { + return 1; + } const_json_value[a_res.length()]= '\0'; strncpy(const_json_value, (const char*)a_res.ptr(), a_res.length()); @@ -512,6 +548,7 @@ bool Json_schema_const::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_enum::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -530,7 +567,7 @@ bool Json_schema_enum::validate(const json_engine_t *je, else return false; } - json_get_normalized_string(&temp_je, &a_res, &err); + json_get_normalized_string(&temp_je, &a_res, &err, current_mem_root, &temp_je_arg, &stack); if (err) return true; @@ -543,13 +580,22 @@ bool Json_schema_enum::validate(const json_engine_t *je, return true; } -bool Json_schema_enum::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_enum::handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) { int count= 0; + + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &temp_je_arg.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &stack, sizeof(struct json_norm_value*), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + if (my_hash_init(PSI_INSTRUMENT_ME, &this->enum_values, je->s.cs, 1024, 0, 0, get_key_name, @@ -580,7 +626,7 @@ bool Json_schema_enum::handle_keyword(THD *thd, json_engine_t *je, int err= 1; String a_res("", 0, je->s.cs); - json_get_normalized_string(je, &a_res, &err); + json_get_normalized_string(je, &a_res, &err, current_mem_root, &temp_je_arg, &stack); if (err) return true; @@ -621,6 +667,7 @@ bool Json_schema_enum::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_maximum::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -635,7 +682,8 @@ bool Json_schema_maximum::validate(const json_engine_t *je, return (val <= value) ? false : true; } -bool Json_schema_maximum::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_maximum::handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -658,6 +706,7 @@ bool Json_schema_maximum::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_minimum::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -672,7 +721,8 @@ bool Json_schema_minimum::validate(const json_engine_t *je, return val >= value ? false : true; } -bool Json_schema_minimum::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_minimum::handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -695,6 +745,7 @@ bool Json_schema_minimum::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_ex_minimum::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -709,7 +760,9 @@ bool Json_schema_ex_minimum::validate(const json_engine_t *je, return (val > value) ? false : true; } -bool Json_schema_ex_minimum::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_ex_minimum::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -732,6 +785,7 @@ bool Json_schema_ex_minimum::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_ex_maximum::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -746,7 +800,9 @@ bool Json_schema_ex_maximum::validate(const json_engine_t *je, return (val < value) ? false : true; } -bool Json_schema_ex_maximum::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_ex_maximum::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -768,6 +824,7 @@ bool Json_schema_ex_maximum::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_multiple_of::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -785,7 +842,9 @@ bool Json_schema_multiple_of::validate(const json_engine_t *je, return val % multiple_of; } -bool Json_schema_multiple_of::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_multiple_of::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -811,6 +870,7 @@ bool Json_schema_multiple_of::handle_keyword(THD *thd, json_engine_t *je, bool Json_schema_max_len::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -819,7 +879,9 @@ bool Json_schema_max_len::validate(const json_engine_t *je, return (uint)(je->value_len) <= value ? false : true; } -bool Json_schema_max_len::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_max_len::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -846,6 +908,7 @@ bool Json_schema_max_len::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_min_len::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -854,7 +917,8 @@ bool Json_schema_min_len::validate(const json_engine_t *je, return (uint)(je->value_len) >= value ? false : true; } -bool Json_schema_min_len::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_min_len::handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -882,6 +946,7 @@ bool Json_schema_min_len::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_pattern::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -919,7 +984,8 @@ bool Json_schema_pattern::validate(const json_engine_t *je, return pattern_matches ? false : true; } -bool Json_schema_pattern::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_pattern::handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -942,6 +1008,7 @@ bool Json_schema_pattern::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_max_items::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -968,7 +1035,9 @@ bool Json_schema_max_items::validate(const json_engine_t *je, return count > value ? true : false; } -bool Json_schema_max_items::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_max_items::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -996,6 +1065,7 @@ bool Json_schema_max_items::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_min_items::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -1022,7 +1092,9 @@ bool Json_schema_min_items::validate(const json_engine_t *je, return count < value ? true : false; } -bool Json_schema_min_items::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_min_items::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -1049,11 +1121,13 @@ bool Json_schema_min_items::handle_keyword(THD *thd, json_engine_t *je, return false; } -bool Json_schema_max_contains::handle_keyword(THD *thd, json_engine_t *je, - const char* key_start, - const char* key_end, - List - *all_keywords) +bool Json_schema_max_contains::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, + const char* key_start, + const char* key_end, + List + *all_keywords) { int err= 0; @@ -1077,11 +1151,13 @@ bool Json_schema_max_contains::handle_keyword(THD *thd, json_engine_t *je, } -bool Json_schema_min_contains::handle_keyword(THD *thd, json_engine_t *je, - const char* key_start, - const char* key_end, - List - *all_keywords) +bool Json_schema_min_contains::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, + const char* key_start, + const char* key_end, + List + *all_keywords) { int err= 0; char *end; @@ -1106,11 +1182,13 @@ bool Json_schema_min_contains::handle_keyword(THD *thd, json_engine_t *je, bool Json_schema_contains::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { uint contains_count=0; - json_engine_t curr_je; curr_je= *je; + json_engine_t curr_je; + curr_je= *je; int level= je->stack_p; bool validated= true; @@ -1122,7 +1200,7 @@ bool Json_schema_contains::validate(const json_engine_t *je, if (json_read_value(&curr_je)) return true; validated= true; - if (validate_schema_items(&curr_je, &contains)) + if (validate_schema_items(&curr_je, current_mem_root, &contains)) validated= false; if (!json_value_scalar(&curr_je)) { @@ -1142,7 +1220,9 @@ bool Json_schema_contains::validate(const json_engine_t *je, return true; } -bool Json_schema_contains::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_contains::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -1153,15 +1233,17 @@ bool Json_schema_contains::handle_keyword(THD *thd, json_engine_t *je, my_error(ER_JSON_INVALID_VALUE_FOR_KEYWORD, MYF(0), "contains"); return true; } - return create_object_and_handle_keyword(thd, je, &contains, all_keywords); + return create_object_and_handle_keyword(thd, current_mem_root, je, + &contains, all_keywords); } -bool Json_schema_items::handle_keyword(THD *thd, json_engine_t *je, - const char* key_start, - const char* key_end, - List - *all_keywords) +bool Json_schema_items::handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, + const char* key_start, + const char* key_end, + List + *all_keywords) { if (je->value_type == JSON_VALUE_FALSE) { @@ -1170,7 +1252,8 @@ bool Json_schema_items::handle_keyword(THD *thd, json_engine_t *je, } if (je->value_type == JSON_VALUE_OBJECT) { - return create_object_and_handle_keyword(thd, je, &items_schema, + return create_object_and_handle_keyword(thd, current_mem_root, je, + &items_schema, all_keywords); } else if (je->value_type != JSON_VALUE_TRUE) @@ -1183,16 +1266,18 @@ bool Json_schema_items::handle_keyword(THD *thd, json_engine_t *je, bool Json_schema_items::validate_as_alternate(const json_engine_t *je, const uchar *k_start, - const uchar* k_end) + const uchar* k_end, + MEM_ROOT *current_mem_root) { /* The indexes in prefix array were less than that in the json array. So validate remaining using the json schema */ - return validate_schema_items(je, &items_schema); + return validate_schema_items(je, current_mem_root, &items_schema); } bool Json_schema_items::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -1216,7 +1301,7 @@ bool Json_schema_items::validate(const json_engine_t *je, if (json_read_value(&curr_je)) return true; count++; - if (validate_schema_items(&curr_je, &items_schema)) + if (validate_schema_items(&curr_je, current_mem_root, &items_schema)) return true; } @@ -1224,6 +1309,7 @@ bool Json_schema_items::validate(const json_engine_t *je, } bool Json_schema_prefix_items::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -1242,7 +1328,7 @@ bool Json_schema_prefix_items::validate(const json_engine_t *je, return true; if (!(curr_prefix=it1++)) { - if (fall_back_on_alternate_schema(&curr_je)) + if (fall_back_on_alternate_schema(&curr_je, current_mem_root)) return true; else { @@ -1255,7 +1341,8 @@ bool Json_schema_prefix_items::validate(const json_engine_t *je, } else { - if (validate_schema_items(&curr_je, &(*curr_prefix))) + if (validate_schema_items(&curr_je, current_mem_root, + &(*curr_prefix))) return true; if (!json_value_scalar(&curr_je)) { @@ -1267,36 +1354,48 @@ bool Json_schema_prefix_items::validate(const json_engine_t *je, return false; } -bool Json_schema_prefix_items::handle_keyword(THD *thd, json_engine_t *je, - const char* key_start, - const char* key_end, - List +bool Json_schema_prefix_items::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, + const char* key_start, + const char* key_end, + List *all_keywords) { + json_engine_t temp_je; + int level= je->stack_p; + if (je->value_type != JSON_VALUE_ARRAY) { my_error(ER_JSON_INVALID_VALUE_FOR_KEYWORD, MYF(0), "prefixItems"); return true; } - int level= je->stack_p; + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &temp_je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + while(json_scan_next(je)==0 && je->stack_p >= level) { - json_engine_t temp_je; char *begin, *end; int len; if (json_read_value(je)) + { return true; + } if (je->value_type != JSON_VALUE_OBJECT) { my_error(ER_JSON_INVALID_VALUE_FOR_KEYWORD, MYF(0), "items"); return true; } + begin= (char*)je->value; if (json_skip_level(je)) + { return true; + } end= (char*)je->s.c_str; len= (int)(end-begin); @@ -1307,10 +1406,15 @@ bool Json_schema_prefix_items::handle_keyword(THD *thd, json_engine_t *je, new (thd->mem_root) List; if (!keyword_list) + { return true; - if (create_object_and_handle_keyword(thd, &temp_je, keyword_list, + } + if (create_object_and_handle_keyword(thd, current_mem_root, + &temp_je, keyword_list, all_keywords)) + { return true; + } prefix_items.push_back(keyword_list, thd->mem_root); } @@ -1319,6 +1423,7 @@ bool Json_schema_prefix_items::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_unique_items::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -1343,7 +1448,7 @@ bool Json_schema_unique_items::validate(const json_engine_t *je, if (json_read_value(&curr_je)) goto end; - json_get_normalized_string(&curr_je, &a_res, &err); + json_get_normalized_string(&curr_je, &a_res, &err, current_mem_root, &temp_je_arg, &stack); if (err) goto end; @@ -1391,12 +1496,21 @@ bool Json_schema_unique_items::validate(const json_engine_t *je, return res; } -bool Json_schema_unique_items::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_unique_items::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) { + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &temp_je_arg.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &stack, sizeof(struct json_norm_value*), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + if (je->value_type == JSON_VALUE_TRUE) is_unique= true; else if (je->value_type == JSON_VALUE_FALSE) @@ -1411,6 +1525,7 @@ bool Json_schema_unique_items::handle_keyword(THD *thd, json_engine_t *je, bool Json_schema_max_prop::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -1442,7 +1557,9 @@ bool Json_schema_max_prop::validate(const json_engine_t *je, return properties_count > value ? true : false; } -bool Json_schema_max_prop::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_max_prop::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -1470,6 +1587,7 @@ bool Json_schema_max_prop::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_min_prop::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -1501,7 +1619,9 @@ bool Json_schema_min_prop::validate(const json_engine_t *je, return properties_count < value ? true : false; } -bool Json_schema_min_prop::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_min_prop::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -1529,6 +1649,7 @@ bool Json_schema_min_prop::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_required::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -1593,7 +1714,9 @@ bool Json_schema_required::validate(const json_engine_t *je, return res; } -bool Json_schema_required::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_required::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -1626,8 +1749,9 @@ bool Json_schema_required::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_dependent_required::validate(const json_engine_t *je, - const uchar *k_start, - const uchar* k_end) + MEM_ROOT *current_mem_root, + const uchar *k_start, + const uchar* k_end) { json_engine_t curr_je= *je; HASH properties; @@ -1706,11 +1830,13 @@ bool Json_schema_dependent_required::validate(const json_engine_t *je, return res; } -bool Json_schema_dependent_required::handle_keyword(THD *thd, json_engine_t *je, - const char* key_start, - const char* key_end, - List - *all_keywords) +bool Json_schema_dependent_required::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, + const char* key_start, + const char* key_end, + List + *all_keywords) { if (je->value_type == JSON_VALUE_OBJECT) { @@ -1789,6 +1915,7 @@ bool Json_schema_dependent_required::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_property_names::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -1823,7 +1950,7 @@ bool Json_schema_property_names::validate(const json_engine_t *je, Json_schema_keyword *curr_schema= NULL; while((curr_schema= it1++)) { - if (curr_schema->validate(&curr_je, k_start, k_end)) + if (curr_schema->validate(&curr_je, current_mem_root, k_start, k_end)) return true; } } @@ -1833,19 +1960,21 @@ bool Json_schema_property_names::validate(const json_engine_t *je, return false; } -bool Json_schema_property_names::handle_keyword(THD *thd, json_engine_t *je, - const char* key_start, - const char* key_end, - List - *all_keywords) +bool Json_schema_property_names::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, + const char* key_start, + const char* key_end, + List + *all_keywords) { if (je->value_type != JSON_VALUE_OBJECT) { my_error(ER_JSON_INVALID_VALUE_FOR_KEYWORD, MYF(0), "propertyNames"); return true; } - if (create_object_and_handle_keyword(thd, je, &property_names, - all_keywords)) + if (create_object_and_handle_keyword(thd, current_mem_root, je, + &property_names, all_keywords)) return true; return false; @@ -1859,6 +1988,7 @@ bool Json_schema_property_names::handle_keyword(THD *thd, json_engine_t *je, */ bool Json_schema_additional_and_unevaluated::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, json_engine_t *je, const char* key_start, const char* key_end, @@ -1872,7 +2002,8 @@ Json_schema_additional_and_unevaluated::handle_keyword(THD *thd, } else if (je->value_type == JSON_VALUE_OBJECT) { - return create_object_and_handle_keyword(thd, je, &schema_list, + return create_object_and_handle_keyword(thd, current_mem_root, je, + &schema_list, all_keywords); } if (je->value_type != JSON_VALUE_TRUE) @@ -1893,7 +2024,8 @@ Json_schema_additional_and_unevaluated::handle_keyword(THD *thd, */ bool Json_schema_properties::validate_as_alternate(const json_engine_t *je, const uchar* k_start, - const uchar* k_end) + const uchar* k_end, + MEM_ROOT *current_mem_root) { st_property *curr_property= NULL; json_engine_t curr_je= *je; @@ -1902,7 +2034,8 @@ bool Json_schema_properties::validate_as_alternate(const json_engine_t *je, (const uchar*)k_start, (size_t)(k_end-k_start)))) { - if (validate_schema_items(&curr_je, curr_property->curr_schema)) + if (validate_schema_items(&curr_je, current_mem_root, + curr_property->curr_schema)) return true; if (!json_value_scalar(&curr_je)) { @@ -1912,7 +2045,9 @@ bool Json_schema_properties::validate_as_alternate(const json_engine_t *je, } else { - if (alternate_schema && alternate_schema->validate_as_alternate(je, k_start, k_end)) + if (alternate_schema && alternate_schema->validate_as_alternate(je, k_start, + k_end, + current_mem_root)) { return true; } @@ -1924,11 +2059,12 @@ bool Json_schema_additional_and_unevaluated:: validate_as_alternate(const json_engine_t *je, const uchar* k_start, - const uchar* k_end) + const uchar* k_end, + MEM_ROOT *current_mem_root) { if (!allowed) return true; - return validate_schema_items(je, &schema_list); + return validate_schema_items(je, current_mem_root, &schema_list); } @@ -1937,6 +2073,7 @@ Json_schema_additional_and_unevaluated:: properties, patternProperties. */ bool Json_schema_unevaluated_properties::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -1955,7 +2092,7 @@ bool Json_schema_unevaluated_properties::validate(const json_engine_t *je, if (json_read_value(&curr_je)) return true; count++; - if (validate_schema_items(&curr_je, &schema_list)) + if (validate_schema_items(&curr_je, current_mem_root, &schema_list)) return true; } return has_false ? (!count ? false: true) : false; @@ -1966,6 +2103,7 @@ bool Json_schema_unevaluated_properties::validate(const json_engine_t *je, without existence of properties and patternProperties, */ bool Json_schema_additional_properties::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -1982,7 +2120,7 @@ bool Json_schema_additional_properties::validate(const json_engine_t *je, case JST_KEY: if (json_read_value(&curr_je)) return true; - if (validate_schema_items(&curr_je, &schema_list)) + if (validate_schema_items(&curr_je, current_mem_root, &schema_list)) return true; } } @@ -2000,12 +2138,14 @@ bool Json_schema_additional_properties::validate(const json_engine_t *je, So additional Properties on its own will not make sense. */ bool Json_schema_additional_items::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { return false; } bool Json_schema_unevaluated_items::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -2027,7 +2167,7 @@ bool Json_schema_unevaluated_items::validate(const json_engine_t *je, if (json_read_value(&curr_je)) return true; count++; - if (validate_schema_items(&curr_je, &schema_list)) + if (validate_schema_items(&curr_je, current_mem_root, &schema_list)) return true; } @@ -2035,6 +2175,7 @@ bool Json_schema_unevaluated_items::validate(const json_engine_t *je, } bool Json_schema_properties::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -2065,12 +2206,14 @@ bool Json_schema_properties::validate(const json_engine_t *je, (const uchar*)k_start, (size_t)(k_end-k_start)))) { - if (validate_schema_items(&curr_je, curr_property->curr_schema)) + if (validate_schema_items(&curr_je, current_mem_root, + curr_property->curr_schema)) return true; } else { - if (fall_back_on_alternate_schema(&curr_je, k_start, k_end)) + if (fall_back_on_alternate_schema(&curr_je, current_mem_root, + k_start, k_end)) return true; } if (!json_value_scalar(&curr_je)) @@ -2085,7 +2228,9 @@ bool Json_schema_properties::validate(const json_engine_t *je, return false; } -bool Json_schema_properties::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_properties::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -2136,7 +2281,7 @@ bool Json_schema_properties::handle_keyword(THD *thd, json_engine_t *je, curr_property->key_name[(int)(k_end-k_start)]= '\0'; strncpy((char*)curr_property->key_name, (const char*)k_start, (size_t)(k_end-k_start)); - if (create_object_and_handle_keyword(thd, je, + if (create_object_and_handle_keyword(thd, current_mem_root, je, curr_property->curr_schema, all_keywords)) return true; @@ -2153,7 +2298,8 @@ bool Json_schema_properties::handle_keyword(THD *thd, json_engine_t *je, bool Json_schema_pattern_properties:: validate_as_alternate(const json_engine_t *curr_je, const uchar *k_start, - const uchar* k_end) + const uchar* k_end, + MEM_ROOT *current_mem_root) { bool match_found= false; List_iterator it1 (pattern_properties); @@ -2171,14 +2317,15 @@ bool Json_schema_pattern_properties:: if (curr_pattern_property->re.match()) { match_found= true; - if (validate_schema_items(curr_je, curr_pattern_property->curr_schema)) + if (validate_schema_items(curr_je, current_mem_root, + curr_pattern_property->curr_schema)) return true; break; } } if (!match_found) { - if (fall_back_on_alternate_schema(curr_je)) + if (fall_back_on_alternate_schema(curr_je, current_mem_root)) return true; } return false; @@ -2186,6 +2333,7 @@ bool Json_schema_pattern_properties:: bool Json_schema_pattern_properties::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { @@ -2209,7 +2357,8 @@ bool Json_schema_pattern_properties::validate(const json_engine_t *je, } while (json_read_keyname_chr(&curr_je) == 0); str->str_value.set_or_copy_aligned((const char*)k_start, - (size_t)(k_end-k_start), curr_je.s.cs); + (size_t)(k_end-k_start), + curr_je.s.cs); if (json_read_value(&curr_je)) return true; @@ -2226,13 +2375,16 @@ bool Json_schema_pattern_properties::validate(const json_engine_t *je, if (curr_pattern_property->re.match()) { match_found= true; - if (validate_schema_items(&curr_je, curr_pattern_property->curr_schema)) + if (validate_schema_items(&curr_je, current_mem_root, + curr_pattern_property->curr_schema)) return true; } } if (!match_found) { - if (fall_back_on_alternate_schema(&curr_je, k_start, k_end)) + if (fall_back_on_alternate_schema(&curr_je, + current_mem_root, + k_start, k_end)) return true; } } @@ -2244,6 +2396,7 @@ bool Json_schema_pattern_properties::validate(const json_engine_t *je, bool Json_schema_pattern_properties::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, json_engine_t *je, const char* key_start, const char* key_end, @@ -2291,8 +2444,8 @@ bool Json_schema_pattern_properties::handle_keyword(THD *thd, if (curr_pattern_to_property->curr_schema) { - if (create_object_and_handle_keyword(thd, je, - curr_pattern_to_property->curr_schema, + if (create_object_and_handle_keyword(thd, current_mem_root, je, + curr_pattern_to_property->curr_schema, all_keywords)) return true; } @@ -2305,31 +2458,42 @@ bool Json_schema_pattern_properties::handle_keyword(THD *thd, return false; } -bool Json_schema_logic::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_logic::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) { + json_engine_t temp_je; + int level= je->stack_p; + + mem_root_dynamic_array_init(current_mem_root, PSI_INSTRUMENT_MEM, + &temp_je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + if (je->value_type != JSON_VALUE_ARRAY) { my_error(ER_JSON_INVALID_VALUE_FOR_KEYWORD, MYF(0), keyword_map->func_name.str); return true; } - int level= je->stack_p; while(json_scan_next(je)==0 && je->stack_p >= level) { - json_engine_t temp_je; char *begin, *end; int len; if (json_read_value(je)) + { return true; + } begin= (char*)je->value; if (json_skip_level(je)) + { return true; + } end= (char*)je->s.c_str; len= (int)(end-begin); @@ -2340,18 +2504,23 @@ bool Json_schema_logic::handle_keyword(THD *thd, json_engine_t *je, new (thd->mem_root) List; if (!keyword_list) + { return true; - if (create_object_and_handle_keyword(thd, &temp_je, keyword_list, + } + if (create_object_and_handle_keyword(thd, current_mem_root, + &temp_je, keyword_list, all_keywords)) + { return true; + } schema_items.push_back(keyword_list, thd->mem_root); } - return false; } bool Json_schema_logic::check_validation(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar *k_end) { @@ -2376,7 +2545,7 @@ bool Json_schema_logic::check_validation(const json_engine_t *je, { if (!curr_keyword->alternate_schema) curr_keyword->alternate_schema= curr_alternate_schema; - if (curr_keyword->validate(je)) + if (curr_keyword->validate(je, current_mem_root)) { validated= false; break; @@ -2396,13 +2565,15 @@ bool Json_schema_logic::check_validation(const json_engine_t *je, return false; } bool Json_schema_logic::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar* k_end) { - return check_validation(je, k_start, k_end); + return check_validation(je, current_mem_root, k_start, k_end); } -bool Json_schema_not::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_not::handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -2416,7 +2587,8 @@ bool Json_schema_not::handle_keyword(THD *thd, json_engine_t *je, return true; } - res= create_object_and_handle_keyword(thd, je, &schema_list, all_keywords); + res= create_object_and_handle_keyword(thd, current_mem_root, je, + &schema_list, all_keywords); schema_items.push_back(&schema_list, thd->mem_root); @@ -2425,6 +2597,7 @@ bool Json_schema_not::handle_keyword(THD *thd, json_engine_t *je, bool Json_schema_keyword::validate_schema_items(const json_engine_t *je, + MEM_ROOT *current_mem_root, List *schema_items) { @@ -2434,7 +2607,7 @@ bool Json_schema_keyword::validate_schema_items(const json_engine_t *je, while((curr_schema= it1++)) { - if (curr_schema->validate(&curr_je)) + if (curr_schema->validate(&curr_je, current_mem_root)) return true; } @@ -2442,18 +2615,19 @@ bool Json_schema_keyword::validate_schema_items(const json_engine_t *je, } bool Json_schema_conditional::validate(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar *k_start, const uchar *k_end) { if (if_cond) { - if (!if_cond->validate_schema_items(je, - if_cond->get_validation_keywords())) + if (!if_cond->validate_schema_items(je, current_mem_root, + if_cond->get_validation_keywords())) { if (then_cond) { - if (then_cond->validate_schema_items(je, - then_cond->get_validation_keywords())) + if (then_cond->validate_schema_items(je, current_mem_root, + then_cond->get_validation_keywords())) return true; } } @@ -2461,8 +2635,8 @@ bool Json_schema_conditional::validate(const json_engine_t *je, { if (else_cond) { - if (else_cond->validate_schema_items(je, - else_cond->get_validation_keywords())) + if (else_cond->validate_schema_items(je, current_mem_root, + else_cond->get_validation_keywords())) return true; } } @@ -2471,25 +2645,30 @@ bool Json_schema_conditional::validate(const json_engine_t *je, } -bool Json_schema_conditional::handle_keyword(THD *thd, json_engine_t *je, - const char* key_start, - const char* key_end, - List - *all_keywords) +bool Json_schema_conditional::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, + const char* key_start, + const char* key_end, + List + *all_keywords) { if (je->value_type != JSON_VALUE_OBJECT) { my_error(ER_JSON_INVALID_VALUE_FOR_KEYWORD, MYF(0), keyword_map->func_name.str); return true; } - return create_object_and_handle_keyword(thd, je, &conditions_schema, + return create_object_and_handle_keyword(thd, current_mem_root, je, + &conditions_schema, all_keywords); } -bool Json_schema_dependent_schemas::handle_keyword(THD *thd, json_engine_t *je, - const char* key_start, - const char* key_end, - List +bool Json_schema_dependent_schemas::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, + const char* key_start, + const char* key_end, + List *all_keywords) { if (je->value_type != JSON_VALUE_OBJECT) @@ -2536,7 +2715,7 @@ bool Json_schema_dependent_schemas::handle_keyword(THD *thd, json_engine_t *je, curr_property->key_name[(int)(k_end-k_start)]= '\0'; strncpy((char*)curr_property->key_name, (const char*)k_start, (size_t)(k_end-k_start)); - if (create_object_and_handle_keyword(thd, je, + if (create_object_and_handle_keyword(thd, current_mem_root, je, curr_property->curr_schema, all_keywords)) return true; @@ -2551,8 +2730,9 @@ bool Json_schema_dependent_schemas::handle_keyword(THD *thd, json_engine_t *je, } bool Json_schema_dependent_schemas::validate(const json_engine_t *je, - const uchar *k_start, - const uchar *k_end) + MEM_ROOT *current_mem_root, + const uchar *k_start, + const uchar *k_end) { json_engine_t curr_je= *je; @@ -2581,7 +2761,7 @@ bool Json_schema_dependent_schemas::validate(const json_engine_t *je, (const uchar*)k_start, (size_t)(k_end-k_start)))) { - if (validate_schema_items(je, curr_property->curr_schema)) + if (validate_schema_items(je, current_mem_root, curr_property->curr_schema)) return true; if (!json_value_scalar(&curr_je)) { @@ -2596,10 +2776,12 @@ bool Json_schema_dependent_schemas::validate(const json_engine_t *je, return false; } -bool Json_schema_media_string::handle_keyword(THD *thd, json_engine_t *je, - const char* key_start, - const char* key_end, - List +bool Json_schema_media_string::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, + const char* key_start, + const char* key_end, + List *all_keywords) { if (je->value_type != JSON_VALUE_STRING) @@ -2612,7 +2794,9 @@ bool Json_schema_media_string::handle_keyword(THD *thd, json_engine_t *je, return false; } -bool Json_schema_reference::handle_keyword(THD *thd, json_engine_t *je, +bool Json_schema_reference::handle_keyword(THD *thd, + MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List @@ -2776,7 +2960,8 @@ add_schema_interdependence(THD *thd, List *temporary, list. Once scanning is done, adjust the dependency if needed, and add the keywords in keyword_list */ -bool create_object_and_handle_keyword(THD *thd, json_engine_t *je, +bool create_object_and_handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, List *keyword_list, List *all_keywords) { @@ -2810,7 +2995,7 @@ bool create_object_and_handle_keyword(THD *thd, json_engine_t *je, key_start, key_end); if (all_keywords) all_keywords->push_back(curr_keyword, thd->mem_root); - if (curr_keyword->handle_keyword(thd, je, + if (curr_keyword->handle_keyword(thd, current_mem_root, je, (const char*)key_start, (const char*)key_end, all_keywords)) { diff --git a/sql/json_schema.h b/sql/json_schema.h index 28cd8b411b9..e1ded633080 100644 --- a/sql/json_schema.h +++ b/sql/json_schema.h @@ -43,10 +43,12 @@ class Json_schema_keyword : public Sql_alloc /* Called for each keyword on the current level. */ - virtual bool validate(const json_engine_t *je, const uchar *k_start= NULL, + virtual bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) { return false; } - virtual bool handle_keyword(THD *thd, json_engine_t *je, + virtual bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) @@ -62,15 +64,18 @@ class Json_schema_keyword : public Sql_alloc alternate_schema= schema; } virtual bool fall_back_on_alternate_schema(const json_engine_t *je, + MEM_ROOT *current_mem_root, const uchar* k_start= NULL, const uchar* k_end= NULL); virtual bool validate_as_alternate(const json_engine_t *je, - const uchar* k_start= NULL, - const uchar* k_end= NULL) + const uchar* k_start= NULL, + const uchar* k_end= NULL, + MEM_ROOT *current_mem_root= NULL) { return false; } virtual bool validate_schema_items(const json_engine_t *je, + MEM_ROOT *current_mem_root, List*schema_items); virtual void set_alternate_schema_choice(Json_schema_keyword *schema1, Json_schema_keyword *schema2) @@ -101,25 +106,29 @@ class Json_schema_additional_and_unevaluated : public Json_schema_keyword { allowed= allowed_val; } - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; - bool validate(const json_engine_t *je, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, const uchar *k_start= NULL, const uchar *k_end= NULL) override { return false; } - bool validate_as_alternate(const json_engine_t *je, const uchar *k_start, - const uchar *k_end) override; + bool validate_as_alternate(const json_engine_t *je, + const uchar *k_start, + const uchar *k_end, + MEM_ROOT *current_mem_root) override; }; class Json_schema_annotation : public Json_schema_keyword { public: - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -128,7 +137,8 @@ class Json_schema_annotation : public Json_schema_keyword class Json_schema_format : public Json_schema_keyword { public: - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -142,10 +152,10 @@ class Json_schema_type : public Json_schema_keyword uint type; public: - bool validate(const json_engine_t *je, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, json_engine_t *je, const char* key_start, const char* key_end, @@ -160,13 +170,16 @@ class Json_schema_const : public Json_schema_keyword { private: char *const_json_value; + json_engine_t temp_je_arg, temp_je_2; + MEM_ROOT_DYNAMIC_ARRAY stack; public: enum json_value_types type; - bool validate(const json_engine_t *je, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -182,12 +195,15 @@ class Json_schema_enum : public Json_schema_keyword private: HASH enum_values; uint enum_scalar; + json_engine_t temp_je_arg; + MEM_ROOT_DYNAMIC_ARRAY stack; public: - bool validate(const json_engine_t *je, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -204,10 +220,11 @@ class Json_schema_enum : public Json_schema_keyword class Json_schema_maximum : public Json_schema_keyword { public: - bool validate(const json_engine_t *je, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -216,10 +233,11 @@ class Json_schema_maximum : public Json_schema_keyword class Json_schema_minimum : public Json_schema_keyword { public: - bool validate(const json_engine_t *je, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -231,9 +249,11 @@ class Json_schema_multiple_of : public Json_schema_keyword longlong multiple_of; public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -242,9 +262,11 @@ class Json_schema_multiple_of : public Json_schema_keyword class Json_schema_ex_maximum : public Json_schema_keyword { public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -253,9 +275,11 @@ class Json_schema_ex_maximum : public Json_schema_keyword class Json_schema_ex_minimum : public Json_schema_keyword { public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -264,9 +288,11 @@ class Json_schema_ex_minimum : public Json_schema_keyword class Json_schema_max_len : public Json_schema_keyword { public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -275,9 +301,11 @@ class Json_schema_max_len : public Json_schema_keyword class Json_schema_min_len : public Json_schema_keyword { public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -291,9 +319,11 @@ class Json_schema_pattern : public Json_schema_keyword Item_string *str; public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -308,9 +338,11 @@ class Json_schema_pattern : public Json_schema_keyword class Json_schema_max_items : public Json_schema_keyword { public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -319,9 +351,11 @@ class Json_schema_max_items : public Json_schema_keyword class Json_schema_min_items : public Json_schema_keyword { public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -330,7 +364,8 @@ class Json_schema_min_items : public Json_schema_keyword class Json_schema_max_contains : public Json_schema_keyword { public: - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -339,7 +374,8 @@ class Json_schema_max_contains : public Json_schema_keyword class Json_schema_min_contains : public Json_schema_keyword { public: - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -356,9 +392,11 @@ class Json_schema_contains : public Json_schema_keyword Json_schema_keyword *max_contains; Json_schema_keyword *min_contains; - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -373,11 +411,15 @@ class Json_schema_unique_items : public Json_schema_keyword { private: bool is_unique; + json_engine_t temp_je_arg; + MEM_ROOT_DYNAMIC_ARRAY stack; public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -388,9 +430,11 @@ class Json_schema_prefix_items : public Json_schema_keyword { public: List prefix_items; - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -408,7 +452,8 @@ class Json_schema_unevaluated_items : { priority= 4; } - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; }; @@ -420,7 +465,8 @@ class Json_schema_additional_items : { priority= 3; } - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; }; @@ -434,14 +480,18 @@ class Json_schema_items : public Json_schema_keyword priority= 2; } void set_allowed(bool allowed_val) { allowed= allowed_val; } - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; - bool validate_as_alternate(const json_engine_t *je, const uchar *k_start, - const uchar *k_end) override; + bool validate_as_alternate(const json_engine_t *je, + const uchar *k_start, + const uchar *k_end, + MEM_ROOT *current_mem_root) override; }; @@ -451,9 +501,11 @@ class Json_schema_property_names : public Json_schema_keyword List property_names; public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -476,9 +528,11 @@ class Json_schema_properties : public Json_schema_keyword { priority= 1; } - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -487,8 +541,10 @@ class Json_schema_properties : public Json_schema_keyword if (is_hash_inited) my_hash_free(&properties); } - bool validate_as_alternate(const json_engine_t *je, const uchar *k_start, - const uchar *k_end) override; + bool validate_as_alternate(const json_engine_t *je, + const uchar *k_start, + const uchar *k_end, + MEM_ROOT *current_mem_root) override; }; class Json_schema_dependent_schemas : public Json_schema_keyword @@ -503,9 +559,11 @@ class Json_schema_dependent_schemas : public Json_schema_keyword if (is_hash_inited) my_hash_free(&properties); } - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -520,7 +578,8 @@ class Json_schema_additional_properties : { priority= 3; } - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; }; @@ -532,7 +591,8 @@ class Json_schema_unevaluated_properties : { priority= 4; } - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; }; @@ -550,9 +610,11 @@ class Json_schema_pattern_properties : public Json_schema_keyword List pattern_properties; public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -576,17 +638,21 @@ class Json_schema_pattern_properties : public Json_schema_keyword } } } - bool validate_as_alternate(const json_engine_t *je, const uchar *k_start, - const uchar *k_end) override; + bool validate_as_alternate(const json_engine_t *je, + const uchar *k_start, + const uchar *k_end, + MEM_ROOT *current_mem_root) override; }; class Json_schema_max_prop : public Json_schema_keyword { public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -595,9 +661,11 @@ class Json_schema_max_prop : public Json_schema_keyword class Json_schema_min_prop : public Json_schema_keyword { public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -609,9 +677,11 @@ class Json_schema_required : public Json_schema_keyword List required_properties; public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -629,9 +699,11 @@ class Json_schema_dependent_required : public Json_schema_keyword List dependent_required; public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -645,9 +717,11 @@ class Json_schema_logic : public Json_schema_keyword List schema_items; Json_schema_keyword *alternate_choice1, *alternate_choice2; public: - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -664,7 +738,9 @@ class Json_schema_logic : public Json_schema_keyword alternate_choice1= schema1; alternate_choice2= schema2; } - bool check_validation(const json_engine_t *je, const uchar *k_start= NULL, + bool check_validation(const json_engine_t *je, + MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL); }; @@ -677,7 +753,8 @@ class Json_schema_not : public Json_schema_logic { logic_flag= HAS_NOT; } - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -739,9 +816,11 @@ class Json_schema_conditional : public Json_schema_keyword then_cond= NULL; else_cond= NULL; } - bool validate(const json_engine_t *je, const uchar *k_start= NULL, + bool validate(const json_engine_t *je, MEM_ROOT *current_mem_root, + const uchar *k_start= NULL, const uchar *k_end= NULL) override; - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -775,7 +854,8 @@ class Json_schema_then : public Json_schema_conditional class Json_schema_media_string : public Json_schema_keyword { public: - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; @@ -784,13 +864,15 @@ class Json_schema_media_string : public Json_schema_keyword class Json_schema_reference : public Json_schema_keyword { public: - bool handle_keyword(THD *thd, json_engine_t *je, + bool handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, const char* key_start, const char* key_end, List *all_keywords) override; }; -bool create_object_and_handle_keyword(THD *thd, json_engine_t *je, +bool create_object_and_handle_keyword(THD *thd, MEM_ROOT *current_mem_root, + json_engine_t *je, List *keyword_list, List *all_keywords); const uchar *get_key_name_for_property(const void *key_name, size_t *length, diff --git a/sql/json_schema_helper.cc b/sql/json_schema_helper.cc index 5d4d04ae6c1..d06fea3a39f 100644 --- a/sql/json_schema_helper.cc +++ b/sql/json_schema_helper.cc @@ -59,7 +59,9 @@ const uchar *get_key_name(const void *key_name_, size_t *length, my_bool) } void json_get_normalized_string(json_engine_t *je, String *res, - int *error) + int *error, MEM_ROOT *current_mem_root, + json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack) { char *val_begin= (char*)je->value, *val_end= NULL; String val("",0,je->s.cs); @@ -83,7 +85,7 @@ void json_get_normalized_string(json_engine_t *je, String *res, je->value_type == JSON_VALUE_OBJECT) { if (json_normalize(&a_res, (const char*)val.ptr(), - val_end-val_begin, je->s.cs)) + val_end-val_begin, je->s.cs, current_mem_root, temp_je, stack)) goto error; } else if(je->value_type == JSON_VALUE_STRING) diff --git a/sql/json_schema_helper.h b/sql/json_schema_helper.h index d2accc9352f..50f334a8751 100644 --- a/sql/json_schema_helper.h +++ b/sql/json_schema_helper.h @@ -25,5 +25,7 @@ bool json_key_equals(const char* key, LEX_CSTRING val, int key_len); bool json_assign_type(uint *curr_type, json_engine_t *je); const uchar *get_key_name(const void *key_name, size_t *length, my_bool); void json_get_normalized_string(json_engine_t *je, String *res, - int *error); + int *error, MEM_ROOT *current_mem_root, + json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack); #endif diff --git a/sql/json_table.cc b/sql/json_table.cc index e9356d7e92e..d2a2f6c7e4d 100644 --- a/sql/json_table.cc +++ b/sql/json_table.cc @@ -188,6 +188,11 @@ class ha_json_table: public handler String *m_js; // The JSON document we're reading String m_tmps; // Buffer for the above + json_engine_t je; + MEM_ROOT_DYNAMIC_ARRAY array_counters; + MEM_ROOT current_mem_root; + bool mem_root_inited; + int fill_column_values(THD *thd, uchar * buf, uchar *pos); public: @@ -205,6 +210,8 @@ public: /* See ha_json_table::position for format definition */ ref_length= m_jt->m_columns.elements * 4; + mem_root_inited= false; + } ~ha_json_table() {} handler *clone(const char *name, MEM_ROOT *mem_root) override { return NULL; } @@ -251,6 +258,13 @@ public: buf->length(0); return TRUE; } + int ha_rnd_end() + { + DBUG_ENTER("ha_json_table::ha_rnd_end"); + if (mem_root_inited) + free_root(¤t_mem_root, MYF(0)); + DBUG_RETURN(handler::ha_rnd_end()); + } }; @@ -358,6 +372,13 @@ int ha_json_table::rnd_init(bool scan) (const uchar *) m_js->ptr(), (const uchar *) m_js->end()); } + mem_root_dynamic_array_init(current_thd->mem_root, PSI_INSTRUMENT_MEM, + &array_counters, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(current_thd->mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + DBUG_RETURN(0); } @@ -427,6 +448,19 @@ bool Json_table_nested_path::check_error(const char *str) return false; // Ok } +void Json_table_nested_path::init_json_engine() +{ + mem_root_dynamic_array_init(current_thd->mem_root, PSI_INSTRUMENT_MEM, + &m_engine.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(current_thd->mem_root, PSI_INSTRUMENT_MEM, + &m_cur_path.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(current_thd->mem_root, PSI_INSTRUMENT_MEM, + &m_path.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); +} + int ha_json_table::rnd_next(uchar *buf) { @@ -472,7 +506,7 @@ int ha_json_table::rnd_next(uchar *buf) int ha_json_table::fill_column_values(THD *thd, uchar * buf, uchar *pos) { - MY_BITMAP *orig_map= dbug_tmp_use_all_columns(table, &table->write_set); + MY_BITMAP *orig_map= dbug_tmp_use_all_columns(table, &table->write_set); int error= 0; Counting_error_handler er_handler; Field **f= table->field; @@ -538,13 +572,14 @@ int ha_json_table::fill_column_values(THD *thd, uchar * buf, uchar *pos) case Json_table_column::PATH: case Json_table_column::EXISTS_PATH: { - json_engine_t je; json_path_step_t *cur_step; - int array_counters[JSON_DEPTH_LIMIT]; int not_found; const uchar* node_start; const uchar* node_end; + mem_root_dynamic_array_reset(&array_counters); + mem_root_dynamic_array_reset(&je.stack); + /* Get the JSON context node that we will need to evaluate PATH or EXISTS against: @@ -564,8 +599,8 @@ int ha_json_table::fill_column_values(THD *thd, uchar * buf, uchar *pos) json_scan_start(&je, m_js->charset(), node_start, node_end); - cur_step= jc->m_path.steps; - not_found= json_find_path(&je, &jc->m_path, &cur_step, array_counters) || + cur_step= (json_path_step_t*)(jc->m_path.steps.buffer); + not_found= json_find_path(&je, &jc->m_path, &cur_step, &array_counters) || json_read_value(&je); if (jc->m_column_type == Json_table_column::EXISTS_PATH) @@ -608,7 +643,7 @@ int ha_json_table::fill_column_values(THD *thd, uchar * buf, uchar *pos) JSON_PATH_ARRAY_RANGE) && (json_scan_next(&je) || !json_find_path(&je, &jc->m_path, &cur_step, - array_counters))) + &array_counters))) { error= jc->m_on_error.respond(jc, *f, ER_JSON_TABLE_MULTIPLE_MATCHES); @@ -899,6 +934,10 @@ int Json_table_column::set(THD *thd, enum_type ctype, const LEX_CSTRING &path, { set(ctype); m_explicit_cs= cs; + + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &m_path.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); if (json_path_setup(&m_path, thd->variables.collation_connection, (const uchar *) path.str, (const uchar *)(path.str + path.length))) { @@ -924,6 +963,10 @@ int Json_table_column::set(THD *thd, enum_type ctype, const LEX_CSTRING &path, int Json_table_column::set(THD *thd, enum_type ctype, const LEX_CSTRING &path, const Lex_column_charset_collation_attrs_st &cl) { + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &m_path.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + if (cl.is_empty() || cl.is_contextually_typed_collate_default()) return set(thd, ctype, path, nullptr); @@ -1000,6 +1043,10 @@ int Json_table_column::print(THD *thd, Field **f, String *str) int Json_table_nested_path::set_path(THD *thd, const LEX_CSTRING &path) { + mem_root_dynamic_array_init(thd->mem_root, PSI_INSTRUMENT_MEM, + &m_path.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + if (json_path_setup(&m_path, thd->variables.collation_connection, (const uchar *) path.str, (const uchar *)(path.str + path.length))) { diff --git a/sql/json_table.h b/sql/json_table.h index e7e1489afb7..b0a8b2f4009 100644 --- a/sql/json_table.h +++ b/sql/json_table.h @@ -57,13 +57,16 @@ public: /*** Construction interface ***/ Json_table_nested_path(): m_null(TRUE), m_nested(NULL), m_next_nested(NULL) - {} + { + init_json_engine(); + } int set_path(THD *thd, const LEX_CSTRING &path); /*** Methods for performing a scan ***/ void scan_start(CHARSET_INFO *i_cs, const uchar *str, const uchar *end); int scan_next(); + void init_json_engine(); bool check_error(const char *str); /*** Members for getting the values we've scanned to ***/ diff --git a/sql/opt_histogram_json.cc b/sql/opt_histogram_json.cc index 66fdf9f87f8..a699dcb8b0e 100644 --- a/sql/opt_histogram_json.cc +++ b/sql/opt_histogram_json.cc @@ -761,8 +761,13 @@ bool Histogram_json_hb::parse(MEM_ROOT *mem_root, const char *db_name, double total_size; int end_element; bool end_assigned; + DBUG_ENTER("Histogram_json_hb::parse"); + mem_root_dynamic_array_init(mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + json_scan_start(&je, &my_charset_utf8mb4_bin, (const uchar*)hist_data, (const uchar*)hist_data+hist_data_len); @@ -812,7 +817,9 @@ bool Histogram_json_hb::parse(MEM_ROOT *mem_root, const char *db_name, { // Some unknown member. Skip it. if (json_skip_key(&je)) + { return 1; + } } } diff --git a/sql/opt_histogram_json.h b/sql/opt_histogram_json.h index a3e21a08aa7..6211edb7bf4 100644 --- a/sql/opt_histogram_json.h +++ b/sql/opt_histogram_json.h @@ -88,6 +88,7 @@ class Histogram_json_hb final : public Histogram_base std::vector buckets; std::string last_bucket_end_endp; + json_engine_t je; public: static constexpr const char* JSON_NAME="histogram_hb"; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 49ce8db0078..acce3624603 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1821,13 +1821,27 @@ class User_table_json: public User_table int value_len; const char *value_start; enum json_types value_type; + json_engine_t temp_je; + MEM_ROOT current_mem_root; + + init_alloc_root(PSI_INSTRUMENT_MEM, ¤t_mem_root, + BLOCK_SIZE_JSON_DYN_ARRAY, 0, MYF(0)); + + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &temp_je.stack, + sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + String str, *res= m_table->field[2]->val_str(&str); if (!res || !res->length()) (res= &str)->set(STRING_WITH_LEN("{}"), m_table->field[2]->charset()); value_type= json_get_object_key(res->ptr(), res->end(), key, &value_start, &value_len); if (value_type == JSV_BAD_JSON) + { + free_root(¤t_mem_root, MYF(0)); return value_type; // invalid + } StringBuffer json(res->charset()); json.copy(res->ptr(), value_start - res->ptr(), res->charset()); if (value_type == JSV_NOTHING) @@ -1846,8 +1860,9 @@ class User_table_json: public User_table if (!value_type && string) json.append('"'); json.append(value_start, res->end() - value_start); - DBUG_ASSERT(json_valid(json.ptr(), json.length(), json.charset())); + DBUG_ASSERT((json_valid(json.ptr(), json.length(), json.charset(), &temp_je))); m_table->field[2]->store(json.ptr(), json.length(), json.charset()); + free_root(¤t_mem_root, MYF(0)); return value_type; } bool set_str_value(const char *key, const char *val, size_t vlen) const diff --git a/sql/sql_class.cc b/sql/sql_class.cc index fcfb219870b..b6563830786 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4794,6 +4794,7 @@ void thd_increment_bytes_sent(void *thd, size_t length) } } + my_bool thd_net_is_killed(THD *thd) { return thd && thd->killed ? 1 : 0; diff --git a/storage/columnstore/columnstore b/storage/columnstore/columnstore index f33e9ce86c7..9fe37d5919f 160000 --- a/storage/columnstore/columnstore +++ b/storage/columnstore/columnstore @@ -1 +1 @@ -Subproject commit f33e9ce86c73f606dbef2d50cac8b92e393344ef +Subproject commit 9fe37d5919f2dd7eb31d1f23ec2439c4f2cb4928 diff --git a/strings/json_lib.c b/strings/json_lib.c index 43bc29811c0..bc9b06f06bc 100644 --- a/strings/json_lib.c +++ b/strings/json_lib.c @@ -139,60 +139,82 @@ static int syntax_error(json_engine_t *j) /* Value of object. */ static int mark_object(json_engine_t *j) { + int val= JST_OBJ_CONT; + j->state= JST_OBJ_START; - if (++j->stack_p < JSON_DEPTH_LIMIT) + ++j->stack_p; + if(mem_root_dynamic_array_resize_not_allowed(&j->stack) && + j->stack_p >= JSON_DEPTH_LIMIT) { - j->stack[j->stack_p]= JST_OBJ_CONT; - return 0; + j->s.error= JE_DEPTH; + return 1; } - j->s.error= JE_DEPTH; - return 1; + + set_json_array_value_ptr(j->stack_p, j->stack.max_element, &j->stack, val); + + return 0; } /* Read value of object. */ static int read_obj(json_engine_t *j) { + int val= JST_OBJ_CONT; j->state= JST_OBJ_START; j->value_type= JSON_VALUE_OBJECT; j->value= j->value_begin; - if (++j->stack_p < JSON_DEPTH_LIMIT) + ++j->stack_p; + if(mem_root_dynamic_array_resize_not_allowed(&j->stack) && + j->stack_p >= JSON_DEPTH_LIMIT) { - j->stack[j->stack_p]= JST_OBJ_CONT; - return 0; + j->s.error= JE_DEPTH; + return 1; } - j->s.error= JE_DEPTH; - return 1; + + set_json_array_value_ptr(j->stack_p, j->stack.max_element, &j->stack, val); + + return 0; } /* Value of array. */ static int mark_array(json_engine_t *j) { + int val= JST_ARRAY_CONT; j->state= JST_ARRAY_START; - if (++j->stack_p < JSON_DEPTH_LIMIT) + ++j->stack_p; + + if(mem_root_dynamic_array_resize_not_allowed(&j->stack) && + j->stack_p >= JSON_DEPTH_LIMIT) { - j->stack[j->stack_p]= JST_ARRAY_CONT; - j->value= j->value_begin; - return 0; + j->s.error= JE_DEPTH; + return 1; } - j->s.error= JE_DEPTH; - return 1; + + set_json_array_value_ptr(j->stack_p, j->stack.max_element, &j->stack, val); + + j->value= j->value_begin; + return 0; } /* Read value of object. */ static int read_array(json_engine_t *j) { + int val= JST_ARRAY_CONT; j->state= JST_ARRAY_START; j->value_type= JSON_VALUE_ARRAY; j->value= j->value_begin; - if (++j->stack_p < JSON_DEPTH_LIMIT) + ++j->stack_p; + if(mem_root_dynamic_array_resize_not_allowed(&j->stack) && + j->stack_p >= JSON_DEPTH_LIMIT) { - j->stack[j->stack_p]= JST_ARRAY_CONT; - return 0; + j->s.error= JE_DEPTH; + return 1; } - j->s.error= JE_DEPTH; - return 1; + + set_json_array_value_ptr(j->stack_p, j->stack.max_element, &j->stack, val); + + return 0; } @@ -368,7 +390,7 @@ int json_read_string_const_chr(json_string_t *js) static int skip_str_constant(json_engine_t *j) { - int t, c_len; + int t, c_len, *value_ptr= NULL; for (;;) { if ((c_len= json_next_char(&j->s)) > 0) @@ -393,7 +415,9 @@ static int skip_str_constant(json_engine_t *j) return j->s.error= json_eos(&j->s) ? JE_EOS : JE_BAD_CHR; } - j->state= j->stack[j->stack_p]; + value_ptr= ((int*)(j->stack.buffer) + (j->stack_p)); + j->state= value_ptr ? *value_ptr : 0; + return 0; } @@ -408,6 +432,7 @@ static int v_string(json_engine_t *j) /* Read scalar string. */ static int read_strn(json_engine_t *j) { + int *value_ptr= NULL; j->value= j->s.c_str; j->value_type= JSON_VALUE_STRING; j->value_escaped= 0; @@ -415,7 +440,8 @@ static int read_strn(json_engine_t *j) if (skip_str_constant(j)) return 1; - j->state= j->stack[j->stack_p]; + value_ptr= ((int*)(j->stack.buffer) + (j->stack_p)); + j->state= value_ptr ? *value_ptr : 0; j->value_len= (int)(j->s.c_str - j->value) - j->s.c_next_len; return 0; } @@ -512,7 +538,7 @@ static uint json_num_state_flags[NS_NUM_STATES]= static int skip_num_constant(json_engine_t *j) { int state= json_num_states[NS_GO][json_num_chr_map[j->s.c_next]]; - int c_len; + int c_len, *value_ptr= NULL; j->num_flags= 0; for (;;) @@ -535,7 +561,9 @@ static int skip_num_constant(json_engine_t *j) break; } - j->state= j->stack[j->stack_p]; + value_ptr= ((int*)(j->stack.buffer) + (j->stack_p)); + j->state= value_ptr ? *value_ptr : 0; + return 0; } @@ -586,9 +614,14 @@ static int skip_string_verbatim(json_string_t *s, const char *str) /* Scalar false. */ static int v_false(json_engine_t *j) { + int *value_ptr= NULL; + if (skip_string_verbatim(&j->s, "alse")) return 1; - j->state= j->stack[j->stack_p]; + + value_ptr= ((int*)(j->stack.buffer) + (j->stack_p)); + j->state= value_ptr ? *value_ptr : 0; + return json_scan_next(j); } @@ -596,9 +629,14 @@ static int v_false(json_engine_t *j) /* Scalar null. */ static int v_null(json_engine_t *j) { + int *value_ptr= NULL; + if (skip_string_verbatim(&j->s, "ull")) return 1; - j->state= j->stack[j->stack_p]; + + value_ptr= ((int*)(j->stack.buffer) + (j->stack_p)); + j->state= value_ptr ? *value_ptr : 0; + return json_scan_next(j); } @@ -606,9 +644,14 @@ static int v_null(json_engine_t *j) /* Scalar true. */ static int v_true(json_engine_t *j) { + int *value_ptr= NULL; + if (skip_string_verbatim(&j->s, "rue")) return 1; - j->state= j->stack[j->stack_p]; + + value_ptr= ((int*)(j->stack.buffer) + (j->stack_p)); + j->state= value_ptr ? *value_ptr : 0; + return json_scan_next(j); } @@ -616,9 +659,12 @@ static int v_true(json_engine_t *j) /* Read false. */ static int read_false(json_engine_t *j) { + int *value_ptr= NULL; + j->value_type= JSON_VALUE_FALSE; j->value= j->value_begin; - j->state= j->stack[j->stack_p]; + value_ptr= ((int*)(j->stack.buffer) + (j->stack_p)); + j->state= value_ptr ? *value_ptr : 0; j->value_len= 5; return skip_string_verbatim(&j->s, "alse"); } @@ -627,9 +673,12 @@ static int read_false(json_engine_t *j) /* Read null. */ static int read_null(json_engine_t *j) { + int *value_ptr= NULL; + j->value_type= JSON_VALUE_NULL; j->value= j->value_begin; - j->state= j->stack[j->stack_p]; + value_ptr= ((int*)(j->stack.buffer) + (j->stack_p)); + j->state= value_ptr ? *value_ptr : 0; j->value_len= 4; return skip_string_verbatim(&j->s, "ull"); } @@ -638,9 +687,12 @@ static int read_null(json_engine_t *j) /* Read true. */ static int read_true(json_engine_t *j) { + int *value_ptr= NULL; + j->value_type= JSON_VALUE_TRUE; j->value= j->value_begin; - j->state= j->stack[j->stack_p]; + value_ptr= ((int*)(j->stack.buffer) + (j->stack_p)); + j->state= value_ptr ? *value_ptr : 0; j->value_len= 4; return skip_string_verbatim(&j->s, "rue"); } @@ -808,9 +860,10 @@ int json_scan_start(json_engine_t *je, CHARSET_INFO *i_cs, const uchar *str, const uchar *end) { static const uchar no_time_to_die= 0; + int val= JST_DONE; json_string_setup(&je->s, i_cs, str, end); - je->stack[0]= JST_DONE; + *((int*)(je->stack.buffer))= val; je->stack_p= 0; je->state= JST_VALUE; je->killed_ptr = (uchar*)&no_time_to_die; @@ -865,7 +918,10 @@ static int skip_key(json_engine_t *j) run our 'state machine' accordingly. */ static int struct_end_eos(json_engine_t *j) -{ return json_actions[j->stack[j->stack_p]][C_EOS](j); } +{ + int *idx= ((int*)(j->stack.buffer) + (j->stack_p)); + return json_actions[idx ? *idx: 0][C_EOS](j); +} /* @@ -875,7 +931,10 @@ static int struct_end_eos(json_engine_t *j) run our 'state machine' accordingly. */ static int struct_end_cb(json_engine_t *j) -{ return json_actions[j->stack[j->stack_p]][C_RCURB](j); } +{ + int *idx= ((int*)(j->stack.buffer) + (j->stack_p)); + return json_actions[idx ? *idx : 0][C_RCURB](j); +} /* @@ -885,7 +944,10 @@ static int struct_end_cb(json_engine_t *j) run our 'state machine' accordingly. */ static int struct_end_qb(json_engine_t *j) -{ return json_actions[j->stack[j->stack_p]][C_RSQRB](j); } +{ + int *idx= ((int*)(j->stack.buffer) + (j->stack_p)); + return json_actions[idx ? *idx : 0][C_RSQRB](j); +} /* @@ -895,7 +957,10 @@ static int struct_end_qb(json_engine_t *j) run our 'state machine' accordingly. */ static int struct_end_cm(json_engine_t *j) -{ return json_actions[j->stack[j->stack_p]][C_COMMA](j); } +{ + int *idx= ((int*)(j->stack.buffer) + (j->stack_p)); + return json_actions[idx ? *idx : 0][C_COMMA](j); +} int json_read_keyname_chr(json_engine_t *j) @@ -1126,18 +1191,26 @@ static int json_path_transitions[N_PATH_STATES][N_PATH_CLASSES]= int json_path_setup(json_path_t *p, CHARSET_INFO *i_cs, const uchar *str, const uchar *end) { - int c_len, t_next, state= PS_GO, is_negative_index= 0, is_last= 0, + int c_len, t_next, state= PS_GO, is_negative_index= 0, is_last= 0, prev_value=0, is_to= 0, *cur_val; + json_path_step_t *curr_step= NULL, *last_step= NULL; + enum json_path_step_types double_wildcard= JSON_PATH_KEY_NULL; json_string_setup(&p->s, i_cs, str, end); - p->steps[0].type= JSON_PATH_ARRAY_WILD; - p->last_step= p->steps; + curr_step= (json_path_step_t*)(p->steps.buffer); + + last_step= curr_step; + curr_step->type= JSON_PATH_ARRAY_WILD; + p->last_step_idx= 0; + last_step->key= (const uchar*)""; p->mode_strict= FALSE; p->types_used= JSON_PATH_KEY_NULL; do { + json_path_step_t *last_step= + (json_path_step_t*)(p->steps.buffer) + p->last_step_idx; if ((c_len= json_next_char(&p->s)) <= 0) t_next= json_eos(&p->s) ? P_EOS : P_BAD; else @@ -1163,12 +1236,12 @@ int json_path_setup(json_path_t *p, continue; case PS_KWD: case PS_AWD: - p->last_step->type|= JSON_PATH_WILD; + last_step->type|= JSON_PATH_WILD; p->types_used|= JSON_PATH_WILD; continue; case PS_INT: - cur_val= is_to ? &(p->last_step->n_item_end) : - &(p->last_step->n_item); + cur_val= is_to ? &(last_step->n_item_end) : + &(last_step->n_item); if (is_last) { prev_value*= 10; @@ -1185,42 +1258,51 @@ int json_path_setup(json_path_t *p, } continue; case PS_EKYX: - p->last_step->key_end= p->s.c_str - c_len; + last_step->key_end= p->s.c_str - c_len; state= PS_PT; continue; case PS_EKY: - p->last_step->key_end= p->s.c_str - c_len; + last_step->key_end= p->s.c_str - c_len; state= PS_KEY; /* fall through */ case PS_KEY: - p->last_step++; + p->last_step_idx++; + if (mem_root_dynamic_array_resize_not_allowed(&p->steps) && + p->last_step_idx >= JSON_DEPTH_LIMIT) + return p->s.error= JE_DEPTH; + + get_json_step(p, last_step); + is_to= 0; prev_value= 0; is_negative_index= 0; is_last= 0; - if (p->last_step - p->steps >= JSON_DEPTH_LIMIT) - return p->s.error= JE_DEPTH; - p->types_used|= p->last_step->type= JSON_PATH_KEY | double_wildcard; + p->types_used|= last_step->type= JSON_PATH_KEY | double_wildcard; double_wildcard= JSON_PATH_KEY_NULL; /* fall through */ case PS_KEYX: - p->last_step->key= p->s.c_str; + last_step->key= p->s.c_str; continue; case PS_EAR: - p->last_step->key_end= p->s.c_str - c_len; + last_step->key_end= p->s.c_str - c_len; state= PS_AR; /* fall through */ case PS_AR: - p->last_step++; + p->last_step_idx++; + if (mem_root_dynamic_array_resize_not_allowed(&p->steps) && + p->last_step_idx >= JSON_DEPTH_LIMIT) + return p->s.error= JE_DEPTH; + + get_json_step(p, last_step); + + last_step->key= (const uchar*)""; is_last= 0; is_to= 0; prev_value= 0; is_negative_index= 0; - if (p->last_step - p->steps >= JSON_DEPTH_LIMIT) - return p->s.error= JE_DEPTH; - p->types_used|= p->last_step->type= JSON_PATH_ARRAY | double_wildcard; + p->types_used|= last_step->type= JSON_PATH_ARRAY | double_wildcard; double_wildcard= JSON_PATH_KEY_NULL; - p->last_step->n_item= 0; + last_step->n_item= 0; continue; case PS_ESC: if (json_handle_esc(&p->s)) @@ -1233,7 +1315,7 @@ int json_path_setup(json_path_t *p, state= PS_KNMX; continue; case PS_KOK: - p->last_step->key_end= p->s.c_str - c_len; + last_step->key_end= p->s.c_str - c_len; state= PS_OK; break; /* 'break' as the loop supposed to end after that. */ case PS_DWD: @@ -1249,9 +1331,9 @@ int json_path_setup(json_path_t *p, p->types_used|= JSON_PATH_NEGATIVE_INDEX; is_last= 1; if (is_to) - p->last_step->n_item_end= -1; + last_step->n_item_end= -1; else - p->last_step->n_item= -1; + last_step->n_item= -1; continue; case PS_T: if ((p->s.error= skip_string_verbatim(&p->s, "o"))) @@ -1260,8 +1342,8 @@ int json_path_setup(json_path_t *p, is_negative_index= 0; is_last= 0; prev_value= 0; - p->last_step->n_item_end= 0; - p->last_step->type|= JSON_PATH_ARRAY_RANGE; + last_step->n_item_end= 0; + last_step->type|= JSON_PATH_ARRAY_RANGE; p->types_used|= JSON_PATH_ARRAY_RANGE; continue; }; @@ -1332,11 +1414,22 @@ int json_skip_key(json_engine_t *j) step of the path. */ static int handle_match(json_engine_t *je, json_path_t *p, - json_path_step_t **p_cur_step, int *array_counters) + json_path_step_t **p_cur_step, + MEM_ROOT_DYNAMIC_ARRAY *array_counters) { - json_path_step_t *next_step= *p_cur_step + 1; + json_path_step_t *initial_step= + (json_path_step_t*)(p->steps.buffer), + *next_step= NULL, + *last_step= + (json_path_step_t*)(p->steps.buffer) + p->last_step_idx; + int value= 0; + size_t idx= 0; - DBUG_ASSERT(*p_cur_step < p->last_step); + idx= *p_cur_step - initial_step; + next_step= + (json_path_step_t*)(p->steps.buffer)+(idx+1); + + DBUG_ASSERT(*p_cur_step < last_step); if (json_read_value(je)) return 1; @@ -1345,7 +1438,8 @@ static int handle_match(json_engine_t *je, json_path_t *p, { while (next_step->type == JSON_PATH_ARRAY && next_step->n_item == 0) { - if (++next_step > p->last_step) + next_step++; + if (next_step > last_step) { je->s.c_str= je->value_begin; return 1; @@ -1359,8 +1453,13 @@ static int handle_match(json_engine_t *je, json_path_t *p, { do { - array_counters[next_step - p->steps]= SKIPPED_STEP_MARK; - if (++next_step > p->last_step) + int val= SKIPPED_STEP_MARK; + int idx= (int)(next_step-initial_step); + + set_json_array_value_ptr(idx, array_counters->max_element, array_counters, val); + + next_step++; + if (next_step > last_step) { je->s.c_str= je->value_begin; je->stack_p--; @@ -1373,7 +1472,8 @@ static int handle_match(json_engine_t *je, json_path_t *p, (int) (next_step->type & JSON_PATH_KEY_OR_ARRAY)) return json_skip_level(je); - array_counters[next_step - p->steps]= 0; + set_json_array_value_ptr((next_step-initial_step), array_counters->max_element, array_counters, value); + if (next_step->type & JSON_PATH_ARRAY) { int array_size; @@ -1389,7 +1489,7 @@ static int handle_match(json_engine_t *je, json_path_t *p, } array_size= -array_size; } - array_counters[next_step - p->steps]= array_size; + set_json_array_value_ptr((next_step-initial_step), array_counters->max_element, array_counters, array_size); } *p_cur_step= next_step; @@ -1416,16 +1516,20 @@ int json_key_matches(json_engine_t *je, json_string_t *k) int json_find_path(json_engine_t *je, json_path_t *p, json_path_step_t **p_cur_step, - int *array_counters) + MEM_ROOT_DYNAMIC_ARRAY *array_counters) { json_string_t key_name; - int res= 0; + int res= 0, value= 0, *value_ptr= NULL; json_string_set_cs(&key_name, p->s.cs); do { - json_path_step_t *cur_step= *p_cur_step; + json_path_step_t *cur_step= *p_cur_step, + *initial_step= + (json_path_step_t*)(p->steps.buffer), + *last_step= + (json_path_step_t*)(p->steps.buffer) + p->last_step_idx; switch (je->state) { case JST_KEY: @@ -1440,7 +1544,7 @@ int json_find_path(json_engine_t *je, continue; } } - if (cur_step == p->last_step || + if (cur_step == last_step || handle_match(je, p, p_cur_step, array_counters)) goto exit; break; @@ -1448,16 +1552,23 @@ int json_find_path(json_engine_t *je, DBUG_ASSERT(cur_step->type & JSON_PATH_ARRAY); if (cur_step->type & JSON_PATH_ARRAY_RANGE) { - res= (cur_step->n_item <= array_counters[cur_step - p->steps] && - cur_step->n_item_end >= array_counters[cur_step - p->steps]); - array_counters[cur_step - p->steps]++; + value_ptr= ((int*)(array_counters->buffer) + (cur_step - initial_step)); + res= (cur_step->n_item <= (value_ptr ? *value_ptr : 0) && + cur_step->n_item_end >= (value_ptr ? *value_ptr : 0)); + value= (value_ptr ? *value_ptr : 0) + 1; + + *((int*)(array_counters->buffer)+(cur_step-initial_step))= value; } else - res= cur_step->n_item == array_counters[cur_step - p->steps]++; - if ((cur_step->type & JSON_PATH_WILD) || res) + { + value= *((int*)(array_counters->buffer) + (cur_step - initial_step)); + res= cur_step->n_item == (value++); + *((int*)(array_counters->buffer)+(cur_step-initial_step))= value; + } + if (res || (cur_step->type & JSON_PATH_WILD)) { /* Array item matches. */ - if (cur_step == p->last_step || + if (cur_step == last_step || handle_match(je, p, p_cur_step, array_counters)) goto exit; } @@ -1468,8 +1579,11 @@ int json_find_path(json_engine_t *je, do { (*p_cur_step)--; - } while (*p_cur_step > p->steps && - array_counters[*p_cur_step - p->steps] == SKIPPED_STEP_MARK); + value_ptr= + (int*)(array_counters->buffer) + (*p_cur_step-initial_step); + value= value_ptr ? *value_ptr : 0; + } while (*p_cur_step > initial_step && + value == SKIPPED_STEP_MARK); break; case JST_ARRAY_END: (*p_cur_step)--; @@ -1502,7 +1616,8 @@ int json_find_paths_first(json_engine_t *je, json_find_paths_t *state, int json_find_paths_next(json_engine_t *je, json_find_paths_t *state) { uint p_c; - int path_found, no_match_found; + int path_found, no_match_found, val, *value_ptr= NULL; + do { switch (je->state) @@ -1514,8 +1629,10 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state) { json_path_step_t *cur_step; if (state->path_depths[p_c] < - state->cur_depth /* Path already failed. */ || - !((cur_step= state->paths[p_c].steps + state->cur_depth)->type & + state->cur_depth /* this Path already failed. */ || + !((cur_step= + ((json_path_step_t*) + (state->paths[p_c].steps.buffer) + (state->cur_depth)))->type & JSON_PATH_KEY)) continue; @@ -1527,7 +1644,9 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state) if (!json_key_matches(je, &key_name)) continue; } - if (cur_step == state->paths[p_c].last_step + state->cur_depth) + if (cur_step == + ((json_path_step_t*) + (state->paths[p_c].steps.buffer) + (state->cur_depth))) path_found= TRUE; else { @@ -1551,16 +1670,22 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state) no_match_found= TRUE; for (p_c=0; p_c < state->n_paths; p_c++) { - json_path_step_t *cur_step; + json_path_step_t *cur_step, *last_step; if (state->path_depths[p_c]< state->cur_depth /* Path already failed. */ || - !((cur_step= state->paths[p_c].steps + state->cur_depth)->type & + !((cur_step= + ((json_path_step_t*) + (state->paths[p_c].steps.buffer) + + (state->cur_depth)))->type & JSON_PATH_ARRAY)) continue; + value_ptr= (int*)(state->array_counters.buffer) + (state->cur_depth); if (cur_step->type & JSON_PATH_WILD || - cur_step->n_item == state->array_counters[state->cur_depth]) + cur_step->n_item == (value_ptr ? *value_ptr : 0)) { /* Array item matches. */ - if (cur_step == state->paths[p_c].last_step + state->cur_depth) + last_step= (json_path_step_t*) + (state->paths[p_c].steps.buffer) + (state->paths[p_c].last_step_idx); + if (cur_step == last_step + state->cur_depth) path_found= TRUE; else { @@ -1576,7 +1701,9 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state) if (no_match_found) json_skip_array_item(je); - state->array_counters[state->cur_depth]++; + value_ptr= (int*)(state->array_counters.buffer) + (state->cur_depth); + val= (value_ptr ? *value_ptr : 0)+1; + *(((int*)(state->array_counters.buffer))+state->cur_depth)= val; break; case JST_OBJ_START: case JST_ARRAY_START: @@ -1585,9 +1712,11 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state) if (state->path_depths[p_c] < state->cur_depth) /* Path already failed. */ continue; - if (state->paths[p_c].steps[state->cur_depth].type & - ((je->state == JST_OBJ_START) ? JSON_PATH_KEY : JSON_PATH_ARRAY)) + if (((json_path_step_t*)(state->paths[p_c].steps.buffer) + (state->cur_depth))->type & + ((je->state == JST_OBJ_START) ? JSON_PATH_KEY : JSON_PATH_ARRAY)) + { state->path_depths[p_c]++; + } } state->cur_depth++; break; @@ -1607,7 +1736,6 @@ int json_find_paths_next(json_engine_t *je, json_find_paths_t *state) }; } while (json_scan_next(je) == 0); - /* No luck. */ return 1; exit: @@ -1787,35 +1915,44 @@ int json_get_path_start(json_engine_t *je, CHARSET_INFO *i_cs, json_path_t *p) { json_scan_start(je, i_cs, str, end); - p->last_step= p->steps - 1; + p->last_step_idx= -1; return 0; } int json_get_path_next(json_engine_t *je, json_path_t *p) { - if (p->last_step < p->steps) + json_path_step_t *last_step= + (p->last_step_idx < 0) ? + ((json_path_step_t*) + (p->steps.buffer)-1): + ((json_path_step_t*) + (p->steps.buffer) + (p->last_step_idx)), + *initial_step= (json_path_step_t*) (p->steps.buffer); + if (last_step < initial_step) { if (json_read_value(je)) return 1; - p->last_step= p->steps; - p->steps[0].type= JSON_PATH_ARRAY_WILD; - p->steps[0].n_item= 0; + p->last_step_idx= 0; + initial_step->type= JSON_PATH_ARRAY_WILD; + initial_step->n_item= 0; return 0; } else { + last_step= (json_path_step_t*)(p->steps.buffer) + p->last_step_idx; if (json_value_scalar(je)) { - if (p->last_step->type & JSON_PATH_ARRAY) - p->last_step->n_item++; + if (last_step->type & JSON_PATH_ARRAY) + last_step->n_item++; } else { - p->last_step++; - p->last_step->type= (enum json_path_step_types) je->value_type; - p->last_step->n_item= 0; + p->last_step_idx++; + get_json_step(p, last_step); + last_step->type= (enum json_path_step_types) je->value_type; + last_step->n_item= 0; } if (json_scan_next(je)) @@ -1827,10 +1964,10 @@ int json_get_path_next(json_engine_t *je, json_path_t *p) switch (je->state) { case JST_KEY: - p->last_step->key= je->s.c_str; + last_step->key= je->s.c_str; do { - p->last_step->key_end= je->s.c_str; + last_step->key_end= je->s.c_str; } while (json_read_keyname_chr(je) == 0); if (je->s.error) return 1; @@ -1843,9 +1980,10 @@ int json_get_path_next(json_engine_t *je, json_path_t *p) return 0; case JST_OBJ_END: case JST_ARRAY_END: - p->last_step--; - if (p->last_step->type & JSON_PATH_ARRAY) - p->last_step->n_item++; + p->last_step_idx--; + last_step= (json_path_step_t*)(p->steps.buffer) + p->last_step_idx; + if (last_step->type & JSON_PATH_ARRAY) + last_step->n_item++; break; default: break; @@ -1889,48 +2027,68 @@ err_return: } +enum json_types json_type_int(json_engine_t *tmp, + const char *js, const char *js_end, + const char **value, int *value_len) +{ + enum json_types return_value; + + json_scan_start(tmp, &my_charset_utf8mb4_bin,(const uchar *) js, + (const uchar *) js_end); + return_value= smart_read_value(tmp, value, value_len); + + return return_value; +} + enum json_types json_type(const char *js, const char *js_end, const char **value, int *value_len) { json_engine_t je; + enum json_types return_value; + MEM_ROOT current_mem_root; - json_scan_start(&je, &my_charset_utf8mb4_bin,(const uchar *) js, - (const uchar *) js_end); + init_alloc_root(PSI_INSTRUMENT_MEM, ¤t_mem_root, + BLOCK_SIZE_JSON_DYN_ARRAY, 0, MYF(0)); - return smart_read_value(&je, value, value_len); + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return_value= json_type_int(&je, js, js_end, value, value_len); + + free_root(¤t_mem_root, MYF(0)); + + return return_value; } - -enum json_types json_get_array_item(const char *js, const char *js_end, - int n_item, - const char **value, int *value_len) +enum json_types json_get_array_item_int(json_engine_t *je, const char *js, + const char *js_end, int n_item, + const char **value, int *value_len) { - json_engine_t je; int c_item= 0; - json_scan_start(&je, &my_charset_utf8mb4_bin,(const uchar *) js, + json_scan_start(je, &my_charset_utf8mb4_bin,(const uchar *) js, (const uchar *) js_end); - if (json_read_value(&je) || - je.value_type != JSON_VALUE_ARRAY) + if (json_read_value(je) || + je->value_type != JSON_VALUE_ARRAY) goto err_return; - while (!json_scan_next(&je)) + while (!json_scan_next(je)) { - switch (je.state) + switch (je->state) { case JST_VALUE: if (c_item == n_item) - return smart_read_value(&je, value, value_len); + return smart_read_value(je, value, value_len); - if (json_skip_key(&je)) + if (json_skip_key(je)) goto err_return; c_item++; break; case JST_ARRAY_END: - *value= (const char *) (je.s.c_str - je.sav_c_len); + *value= (const char *) (je->s.c_str - je->sav_c_len); *value_len= c_item; return JSV_NOTHING; } @@ -1940,6 +2098,26 @@ err_return: return JSV_BAD_JSON; } +enum json_types json_get_array_item(const char *js, const char *js_end, int n_item, + const char **value, int *value_len) +{ + json_engine_t je; + enum json_types return_value; + MEM_ROOT current_mem_root; + + init_alloc_root(PSI_INSTRUMENT_MEM, ¤t_mem_root, + BLOCK_SIZE_JSON_DYN_ARRAY, 0, MYF(0)); + + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return_value= json_get_array_item_int(&je, js, js_end, n_item, value, value_len); + + free_root(¤t_mem_root, MYF(0)); + + return return_value; +} + /** Simple json lookup for a value by the key. @@ -1959,42 +2137,41 @@ err_return: or not JSON object. @retval JSV_NOTHING - no such key found. */ -enum json_types json_get_object_key(const char *js, const char *js_end, - const char *key, - const char **value, int *value_len) +enum json_types json_get_object_key_int(json_engine_t *je, const char *js, + const char *js_end, const char *key, + const char **value, int *value_len) { - const char *key_end= key + strlen(key); - json_engine_t je; + const char *key_end= key + strlen(key); json_string_t key_name; int n_keys= 0; json_string_set_cs(&key_name, &my_charset_utf8mb4_bin); - json_scan_start(&je, &my_charset_utf8mb4_bin,(const uchar *) js, + json_scan_start(je, &my_charset_utf8mb4_bin,(const uchar *) js, (const uchar *) js_end); - if (json_read_value(&je) || - je.value_type != JSON_VALUE_OBJECT) + if (json_read_value(je) || + je->value_type != JSON_VALUE_OBJECT) goto err_return; - while (!json_scan_next(&je)) + while (!json_scan_next(je)) { - switch (je.state) + switch (je->state) { case JST_KEY: n_keys++; json_string_set_str(&key_name, (const uchar *) key, (const uchar *) key_end); - if (json_key_matches(&je, &key_name)) - return smart_read_value(&je, value, value_len); + if (json_key_matches(je, &key_name)) + return smart_read_value(je, value, value_len); - if (json_skip_key(&je)) + if (json_skip_key(je)) goto err_return; break; case JST_OBJ_END: - *value= (const char *) (je.s.c_str - je.sav_c_len); + *value= (const char *) (je->s.c_str - je->sav_c_len); *value_len= n_keys; return JSV_NOTHING; } @@ -2004,6 +2181,28 @@ err_return: return JSV_BAD_JSON; } +enum json_types json_get_object_key(const char *js, const char *js_end, + const char *key, const char **value, + int *value_len) +{ + json_engine_t je; + enum json_types return_value; + MEM_ROOT current_mem_root; + + init_alloc_root(PSI_INSTRUMENT_MEM, ¤t_mem_root, + BLOCK_SIZE_JSON_DYN_ARRAY, 0, MYF(0)); + + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + return_value= json_get_object_key_int(&je, js, js_end, key, value, value_len); + + free_root(¤t_mem_root, MYF(0)); + + return return_value; + +} + enum json_types json_get_object_nkey(const char *js __attribute__((unused)), const char *js_end __attribute__((unused)), @@ -2015,6 +2214,15 @@ enum json_types json_get_object_nkey(const char *js __attribute__((unused)), { json_engine_t je; int keys_found= 0; + MEM_ROOT current_mem_root; + enum json_types return_value; + + init_alloc_root(PSI_INSTRUMENT_MEM, ¤t_mem_root, + BLOCK_SIZE_JSON_DYN_ARRAY, 0, MYF(0)); + + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); json_scan_start(&je, &my_charset_utf8mb4_bin,(const uchar *) js, (const uchar *) js_end); @@ -2034,7 +2242,9 @@ enum json_types json_get_object_nkey(const char *js __attribute__((unused)), while (json_read_keyname_chr(&je) == 0) *keyname_end= (char *) je.s.c_str; - return smart_read_value(&je, value, value_len); + return_value= smart_read_value(&je, value, value_len); + free_root(¤t_mem_root, MYF(0)); + return return_value; } keys_found++; @@ -2044,11 +2254,13 @@ enum json_types json_get_object_nkey(const char *js __attribute__((unused)), break; case JST_OBJ_END: + free_root(¤t_mem_root, MYF(0)); return JSV_NOTHING; } } err_return: + free_root(¤t_mem_root, MYF(0)); return JSV_BAD_JSON; } @@ -2058,14 +2270,14 @@ err_return: @retval 0 - success, json is well-formed @retval 1 - error, json is invalid */ -int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs) +int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs, json_engine_t *je) { - json_engine_t je; - json_scan_start(&je, cs, (const uchar *) js, (const uchar *) js + js_len); - while (json_scan_next(&je) == 0) /* no-op */ ; - return je.s.error == 0; -} + json_scan_start(je, cs, (const uchar *) js, (const uchar *) js + js_len); + while (json_scan_next(je) == 0) /* no-op */ ; + + return je->s.error == 0; +} /* Expects the JSON object as an js argument, and the key name. @@ -2081,47 +2293,48 @@ int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs) if no such key found *key_start is set to NULL. */ -int json_locate_key(const char *js, const char *js_end, +int json_locate_key(json_engine_t *je, const char *js, const char *js_end, const char *kname, const char **key_start, const char **key_end, int *comma_pos) { const char *kname_end= kname + strlen(kname); - json_engine_t je; json_string_t key_name; int t_next, c_len, match_result; json_string_set_cs(&key_name, &my_charset_utf8mb4_bin); - json_scan_start(&je, &my_charset_utf8mb4_bin,(const uchar *) js, + json_scan_start(je, &my_charset_utf8mb4_bin,(const uchar *) js, (const uchar *) js_end); - if (json_read_value(&je) || - je.value_type != JSON_VALUE_OBJECT) + if (json_read_value(je) || + je->value_type != JSON_VALUE_OBJECT) goto err_return; - *key_start= (const char *) je.s.c_str; + *key_start= (const char *) je->s.c_str; *comma_pos= 0; - while (!json_scan_next(&je)) + while (!json_scan_next(je)) { - switch (je.state) + switch (je->state) { case JST_KEY: json_string_set_str(&key_name, (const uchar *) kname, (const uchar *) kname_end); - match_result= json_key_matches(&je, &key_name); - if (json_skip_key(&je)) + match_result= json_key_matches(je, &key_name); + if (json_skip_key(je)) goto err_return; - get_first_nonspace(&je.s, &t_next, &c_len); - je.s.c_str-= c_len; + get_first_nonspace(&je->s, &t_next, &c_len); + je->s.c_str-= c_len; if (match_result) { - *key_end= (const char *) je.s.c_str; + *key_end= (const char *) je->s.c_str; if (*comma_pos == 1) + { return 0; + } DBUG_ASSERT(*comma_pos == 0); @@ -2137,13 +2350,13 @@ int json_locate_key(const char *js, const char *js_end, return 0; } - *key_start= (const char *) je.s.c_str; + *key_start= (const char *) je->s.c_str; *comma_pos= 1; break; case JST_OBJ_END: *key_start= NULL; - return 0; + return 0; } } @@ -2151,3 +2364,11 @@ err_return: return 1; } + +void initJsonArray(MEM_ROOT *mem_root, MEM_ROOT_DYNAMIC_ARRAY *mem_root_array, size_t size, void *buffer, myf myflag) +{ + mem_root_dynamic_array_init(mem_root, PSI_INSTRUMENT_MEM, + mem_root_array, size, buffer, + JSON_DEPTH_LIMIT, 0, MYF(myflag)); + return; +} diff --git a/strings/json_normalize.c b/strings/json_normalize.c index a7849d95b3c..5e2e9b43e86 100644 --- a/strings/json_normalize.c +++ b/strings/json_normalize.c @@ -644,87 +644,88 @@ json_norm_append_to_object(struct json_norm_value *val, static int -json_norm_parse(struct json_norm_value *root, json_engine_t *je) +json_norm_parse(struct json_norm_value *root, json_engine_t *je, MEM_ROOT *current_mem_root, MEM_ROOT_DYNAMIC_ARRAY *stack) { - size_t current; - struct json_norm_value *stack[JSON_DEPTH_LIMIT]; - int err= 0; + size_t current = 0; + int err = 0; DYNAMIC_STRING key; + struct json_norm_value* root_ptr = root; - err= init_dynamic_string(&key, NULL, 0, 0); + // Set the root pointer in the stack + mem_root_dynamic_array_set_val(stack, &root_ptr, current); + + err = init_dynamic_string(&key, NULL, 0, 0); if (err) + { goto json_norm_parse_end; - - memset(stack, 0x00, sizeof(stack)); - current= 0; - stack[current]= root; + } do { switch (je->state) { case JST_KEY: { - const uchar *key_start= je->s.c_str; + const uchar *key_start = je->s.c_str; const uchar *key_end; + struct json_norm_value* new_val_ptr= NULL; + struct json_norm_value** curr_val_ptr = + (struct json_norm_value**)(stack->buffer) + current; + struct json_norm_value* curr_val = *curr_val_ptr; + DBUG_ASSERT(curr_val->type == JSON_VALUE_OBJECT); - DBUG_ASSERT(stack[current]->type == JSON_VALUE_OBJECT); do { - key_end= je->s.c_str; + key_end = je->s.c_str; } while (json_read_keyname_chr(je) == 0); /* we have the key name */ /* reset the dynstr: */ dynstr_trunc(&key, key.length); - dynstr_append_mem(&key, (char *)key_start, (key_end - key_start)); + dynstr_append_mem(&key, (char*)key_start, (key_end - key_start)); /* After reading the key, we have a follow-up value. */ - err= json_read_value(je); + err = json_read_value(je); if (err) goto json_norm_parse_end; - err= json_norm_append_to_object(stack[current], &key, je); + err = json_norm_append_to_object(curr_val, &key, je); if (err) goto json_norm_parse_end; if (je->value_type == JSON_VALUE_ARRAY || je->value_type == JSON_VALUE_OBJECT) { - struct json_norm_kv *kv; - - err= ((current + 1) == JSON_DEPTH_LIMIT); - if (err) - goto json_norm_parse_end; - - kv= json_norm_object_get_last_element(&stack[current]->value.object); - stack[++current]= &kv->value; + struct json_norm_kv* kv; + kv = json_norm_object_get_last_element(&curr_val->value.object); + new_val_ptr = &kv->value; + mem_root_dynamic_array_resize_and_set_val(stack, &new_val_ptr, ++current); } break; } case JST_VALUE: { - struct json_norm_array *current_arr= &stack[current]->value.array; - err= json_read_value(je); + struct json_norm_value** curr_val_ptr = + (struct json_norm_value**)(stack->buffer) + current; + struct json_norm_value* curr_val = *curr_val_ptr; + struct json_norm_array* current_arr = &curr_val->value.array; + + err = json_read_value(je); if (err) goto json_norm_parse_end; - DBUG_ASSERT(stack[current]->type == JSON_VALUE_ARRAY); + DBUG_ASSERT(curr_val->type == JSON_VALUE_ARRAY); - err= json_norm_append_to_array(stack[current], je); + err = json_norm_append_to_array(curr_val, je); if (err) goto json_norm_parse_end; if (je->value_type == JSON_VALUE_ARRAY || je->value_type == JSON_VALUE_OBJECT) { - - err= ((current + 1) == JSON_DEPTH_LIMIT); - if (err) - goto json_norm_parse_end; - - stack[++current]= json_norm_array_get_last_element(current_arr); + struct json_norm_value* element = + json_norm_array_get_last_element(current_arr); + mem_root_dynamic_array_resize_and_set_val(stack, &element, ++current); } - break; } case JST_OBJ_START: @@ -736,14 +737,14 @@ json_norm_parse(struct json_norm_value *root, json_engine_t *je) --current; break; case JST_ARRAY_START: - /* parser found an array (the '[' in JSON) */ + /* parser found an array (the '[' in JSON) */ break; case JST_ARRAY_END: /* parser found the end of the array (the ']' in JSON) */ /* pop stack */ --current; break; - }; + } } while (json_scan_next(je) == 0); json_norm_parse_end: @@ -751,40 +752,47 @@ json_norm_parse_end: return err; } - static int json_norm_build(struct json_norm_value *root, - const char *s, size_t size, CHARSET_INFO *cs) + const char *s, size_t size, CHARSET_INFO *cs, + MEM_ROOT *current_mem_root, + json_engine_t *je, + MEM_ROOT_DYNAMIC_ARRAY *stack) { int err= 0; - json_engine_t je; DBUG_ASSERT(s); - memset(&je, 0x00, sizeof(je)); memset(root, 0x00, sizeof(struct json_norm_value)); root->type= JSON_VALUE_UNINITIALIZED; - err= json_scan_start(&je, cs, (const uchar *)s, (const uchar *)(s + size)); - if (json_read_value(&je)) + err= json_scan_start(je, cs, (const uchar *)s, (const uchar *)(s + size)); + if (json_read_value(je)) + { return err; - - err= json_norm_value_init(root, &je); + } + err= json_norm_value_init(root, je); if (root->type == JSON_VALUE_OBJECT || root->type == JSON_VALUE_ARRAY) { - err= json_norm_parse(root, &je); + err= json_norm_parse(root, je, current_mem_root, stack); if (err) + { return err; + } } + return err; } int json_normalize(DYNAMIC_STRING *result, - const char *s, size_t size, CHARSET_INFO *cs) + const char *s, size_t size, CHARSET_INFO *cs, + MEM_ROOT *current_mem_root, + json_engine_t *temp_je, + MEM_ROOT_DYNAMIC_ARRAY *stack) { int err= 0; uint convert_err= 0; @@ -827,13 +835,14 @@ json_normalize(DYNAMIC_STRING *result, } - if (!json_valid(in, in_size, &my_charset_utf8mb4_bin)) + if ((json_valid(in, in_size, &my_charset_utf8mb4_bin, temp_je) == 0)) { err= 1; goto json_normalize_end; } - err= json_norm_build(&root, in, in_size, &my_charset_utf8mb4_bin); + err= json_norm_build(&root, in, in_size, + &my_charset_utf8mb4_bin, current_mem_root, temp_je, stack); if (err) goto json_normalize_end; diff --git a/unittest/json_lib/json_lib-t.c b/unittest/json_lib/json_lib-t.c index 2511946f273..ca43a062762 100644 --- a/unittest/json_lib/json_lib-t.c +++ b/unittest/json_lib/json_lib-t.c @@ -38,28 +38,28 @@ struct st_parse_result }; -static void parse_json(const uchar *j, struct st_parse_result *result) +static void parse_json(const uchar *j, struct st_parse_result *result, json_engine_t *je) { - json_engine_t je; - bzero(result, sizeof(*result)); - if (json_scan_start(&je, ci, s_e(j))) + if (json_scan_start(je, ci, s_e(j))) return; do { result->n_steps++; - switch (je.state) + switch (je->state) { case JST_KEY: result->n_keys++; - while (json_read_keyname_chr(&je) == 0) + while (json_read_keyname_chr(je) == 0) { - result->keyname_csum^= je.s.c_next; + result->keyname_csum^= je->s.c_next; } - if (je.s.error) + if (je->s.error) + { return; + } break; case JST_VALUE: result->n_values++; @@ -73,9 +73,9 @@ static void parse_json(const uchar *j, struct st_parse_result *result) default: break; }; - } while (json_scan_next(&je) == 0); + } while (json_scan_next(je) == 0); - result->error= je.s.error; + result->error= je->s.error; } @@ -89,17 +89,17 @@ static const uchar *js3= (const uchar *) "{\"key1\":{\"ikey1\":321}," Test json_lib functions to parse JSON. */ static void -test_json_parsing() +test_json_parsing(json_engine_t *je) { struct st_parse_result r; - parse_json(js0, &r); + parse_json(js0, &r, je); ok(r.n_steps == 1 && r.n_values == 1, "simple value"); - parse_json(js1, &r); + parse_json(js1, &r, je); ok(r.n_steps == 5 && r.n_values == 3 && r.n_arrays == 1, "array"); - parse_json(js2, &r); + parse_json(js2, &r, je); ok(r.n_steps == 5 && r.n_keys == 2 && r.n_objects == 1 && r.keyname_csum == 3, "object"); - parse_json(js3, &r); + parse_json(js3, &r, je); ok(r.n_steps == 12 && r.n_keys == 3 && r.n_objects == 2 && r.n_arrays == 1 && r.keyname_csum == 44, "complex json"); @@ -111,18 +111,24 @@ static const uchar *p0= (const uchar *) "$.key1[12].*[*]"; Test json_lib functions to parse JSON path. */ static void -test_path_parsing() +test_path_parsing(json_path_t *p) { - json_path_t p; - if (json_path_setup(&p, ci, s_e(p0))) - return; - ok(p.last_step - p.steps == 4 && - p.steps[0].type == JSON_PATH_ARRAY_WILD && - p.steps[1].type == JSON_PATH_KEY && - p.steps[2].type == JSON_PATH_ARRAY && p.steps[2].n_item == 12 && - p.steps[3].type == JSON_PATH_KEY_WILD && - p.steps[4].type == JSON_PATH_ARRAY_WILD, + json_path_step_t *initial_step= NULL; + initial_step= (json_path_step_t*)(p->steps.buffer); + + if (json_path_setup(p, ci, s_e(p0))) + goto error; + + ok(p->last_step_idx == 4 && + (initial_step+0)->type == JSON_PATH_ARRAY_WILD && + (initial_step+1)->type == JSON_PATH_KEY && + (initial_step+2)->type == JSON_PATH_ARRAY && (initial_step+2)->n_item == 12 && + (initial_step+3)->type == JSON_PATH_KEY_WILD && + (initial_step+4)->type == JSON_PATH_ARRAY_WILD, "path"); + + error: + return; } @@ -134,53 +140,75 @@ static const uchar *fp0= (const uchar *) "$[*].k1"; Test json_lib functions to search through JSON. */ static void -test_search() +test_search(MEM_ROOT_DYNAMIC_ARRAY* array_counters, json_engine_t *je, json_path_t *p) { - json_engine_t je; - json_path_t p; - json_path_step_t *cur_step; + MEM_ROOT_DYNAMIC_ARRAY *cur_step; int n_matches, scal_values; - int array_counters[JSON_DEPTH_LIMIT]; + json_path_step_t *tmp_ptr= NULL; - if (json_scan_start(&je, ci, s_e(fj0)) || - json_path_setup(&p, ci, s_e(fp0))) - return; + if (json_scan_start(je, ci, s_e(fj0)) || + json_path_setup(p, ci, s_e(fp0))) + goto end; - cur_step= p.steps; + cur_step= &p->steps; n_matches= scal_values= 0; - while (json_find_path(&je, &p, &cur_step, array_counters) == 0) + tmp_ptr= (json_path_step_t*)(cur_step->buffer); + while (json_find_path(je, p, &tmp_ptr, array_counters) == 0) { n_matches++; - if (json_read_value(&je)) - return; - if (json_value_scalar(&je)) + if (json_read_value(je)) + goto end; + if (json_value_scalar(je)) { scal_values++; - if (json_scan_next(&je)) - return; + if (json_scan_next(je)) + goto end; } else { - if (json_skip_level(&je) || json_scan_next(&je)) - return; + if (json_skip_level(je) || json_scan_next(je)) + goto end; } } ok(n_matches == 3, "search"); + + end: + return; } int main() { + MEM_ROOT current_mem_root; + MEM_ROOT_DYNAMIC_ARRAY array_counters; + json_engine_t je; + json_path_t p; + + init_alloc_root(PSI_INSTRUMENT_MEM, ¤t_mem_root, + BLOCK_SIZE_JSON_DYN_ARRAY, 0, MYF(0)); + + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &array_counters, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &p.steps, sizeof(json_path_step_t), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + ci= &my_charset_utf8mb3_general_ci; plan(6); diag("Testing json_lib functions."); - test_json_parsing(); - test_path_parsing(); - test_search(); + test_json_parsing(&je); + test_path_parsing(&p); + test_search(&array_counters, &je, &p); + + free_root(¤t_mem_root, MYF(0)); return exit_status(); } diff --git a/unittest/json_lib/json_normalize-t.c b/unittest/json_lib/json_normalize-t.c index a7cf5d8e7e5..b1b17e19397 100644 --- a/unittest/json_lib/json_normalize-t.c +++ b/unittest/json_lib/json_normalize-t.c @@ -21,16 +21,17 @@ static void -check_json_normalize(const char *in, const char *expected) +check_json_normalize(const char *in, const char *expected, json_engine_t *je, MEM_ROOT_DYNAMIC_ARRAY *stack) { int err; DYNAMIC_STRING result; + MEM_ROOT current_mem_root; CHARSET_INFO *cs= &my_charset_utf8mb4_general_ci; init_dynamic_string(&result, NULL, 0, 0); - err= json_normalize(&result, in, strlen(in), cs); + err= json_normalize(&result, in, strlen(in), cs, ¤t_mem_root, je, stack); ok(err == 0, "normalize err: %d", err); @@ -43,36 +44,40 @@ check_json_normalize(const char *in, const char *expected) static void -test_json_normalize_invalid(void) +test_json_normalize_invalid(json_engine_t *je, MEM_ROOT_DYNAMIC_ARRAY *stack) { DYNAMIC_STRING result; + MEM_ROOT current_mem_root; CHARSET_INFO *cs= &my_charset_utf8mb4_general_ci; + init_alloc_root(PSI_INSTRUMENT_MEM, ¤t_mem_root, + BLOCK_SIZE_JSON_DYN_ARRAY, 0, MYF(0)); + init_dynamic_string(&result, NULL, 0, 0); - ok(json_normalize(&result, STRING_WITH_LEN(""), cs) != 0, + ok(json_normalize(&result, STRING_WITH_LEN(""), cs, ¤t_mem_root, je, stack) != 0, "expected normalized error"); dynstr_free(&result); init_dynamic_string(&result, NULL, 0, 0); - ok(json_normalize(&result, STRING_WITH_LEN("["), cs) != 0, + ok(json_normalize(&result, STRING_WITH_LEN("["), cs, ¤t_mem_root, je, stack) != 0, "expected normalized error"); dynstr_free(&result); init_dynamic_string(&result, NULL, 0, 0); - ok(json_normalize(&result, STRING_WITH_LEN("}"), cs) != 0, + ok(json_normalize(&result, STRING_WITH_LEN("}"), cs, ¤t_mem_root, je, stack) != 0, "expected normalized error"); dynstr_free(&result); init_dynamic_string(&result, NULL, 0, 0); - ok(json_normalize(&result, NULL, 0, cs) != 0, + ok(json_normalize(&result, NULL, 0, cs, ¤t_mem_root, je, stack) != 0, "expected normalized error"); dynstr_free(&result); } static void -test_json_normalize_single_kv(void) +test_json_normalize_single_kv(json_engine_t *je, MEM_ROOT_DYNAMIC_ARRAY *stack) { const char *in= "" "{\n" @@ -80,12 +85,12 @@ test_json_normalize_single_kv(void) "}\n"; const char *expected= "{\"foo\":\"value\"}"; - check_json_normalize(in, expected); + check_json_normalize(in, expected, je, stack); } static void -test_json_normalize_multi_kv(void) +test_json_normalize_multi_kv(json_engine_t *je, MEM_ROOT_DYNAMIC_ARRAY *stack) { const char *in= "" "{\n" @@ -94,42 +99,42 @@ test_json_normalize_multi_kv(void) "}\n"; const char *expected= "{\"bar\":\"baz\",\"foo\":\"value\"}"; - check_json_normalize(in, expected); + check_json_normalize(in, expected, je, stack); } static void -test_json_normalize_array(void) +test_json_normalize_array(json_engine_t *je, MEM_ROOT_DYNAMIC_ARRAY *stack) { const char *in= "[ \"a\", \"b\", true, false, null ]"; const char *expected= "[\"a\",\"b\",true,false,null]"; - check_json_normalize(in, expected); + check_json_normalize(in, expected, je, stack); } static void -test_json_normalize_values(void) +test_json_normalize_values(json_engine_t *je, MEM_ROOT_DYNAMIC_ARRAY *stack) { - check_json_normalize("\"foo\"", "\"foo\""); - check_json_normalize("true", "true"); - check_json_normalize("false", "false"); - check_json_normalize("null", "null"); - check_json_normalize("\"\"", "\"\""); - check_json_normalize("{}", "{}"); - check_json_normalize("[]", "[]"); - check_json_normalize("5", "5.0E0"); - check_json_normalize("5.1", "5.1E0"); - check_json_normalize("-5.1", "-5.1E0"); - check_json_normalize("12345.67890", "1.23456789E4"); - check_json_normalize("2.99792458e8", "2.99792458E8"); - check_json_normalize("6.02214076e23", "6.02214076E23"); - check_json_normalize("6.62607015e-34", "6.62607015E-34"); - check_json_normalize("-6.62607015e-34", "-6.62607015E-34"); + check_json_normalize("\"foo\"", "\"foo\"", je, stack); + check_json_normalize("true", "true", je, stack); + check_json_normalize("false", "false", je, stack); + check_json_normalize("null", "null", je, stack); + check_json_normalize("\"\"", "\"\"", je, stack); + check_json_normalize("{}", "{}", je, stack); + check_json_normalize("[]", "[]", je, stack); + check_json_normalize("5", "5.0E0", je, stack); + check_json_normalize("5.1", "5.1E0", je, stack); + check_json_normalize("-5.1", "-5.1E0", je, stack); + check_json_normalize("12345.67890", "1.23456789E4", je, stack); + check_json_normalize("2.99792458e8", "2.99792458E8", je, stack); + check_json_normalize("6.02214076e23", "6.02214076E23", je, stack); + check_json_normalize("6.62607015e-34", "6.62607015E-34", je, stack); + check_json_normalize("-6.62607015e-34", "-6.62607015E-34", je, stack); } static void -test_json_normalize_nested_objects(void) +test_json_normalize_nested_objects(json_engine_t *je, MEM_ROOT_DYNAMIC_ARRAY *stack) { const char *in = "" "{\n" @@ -140,12 +145,12 @@ test_json_normalize_nested_objects(void) const char *expected= "{\"foo\":{\"value\":true}," "\"wiz\":{\"alpha\":false,\"bang\":\"a\"}}"; - check_json_normalize(in, expected); + check_json_normalize(in, expected, je, stack); } static void -test_json_normalize_nested_arrays(void) +test_json_normalize_nested_arrays(json_engine_t *je, MEM_ROOT_DYNAMIC_ARRAY *stack) { const char *in = "" "[\n" @@ -154,12 +159,12 @@ test_json_normalize_nested_arrays(void) "]"; const char *expected= "[\"wiz\",[\"bang\",\"alpha\"]]"; - check_json_normalize(in, expected); + check_json_normalize(in, expected, je, stack); } static void -test_json_normalize_nested_deep(void) +test_json_normalize_nested_deep(json_engine_t *je, MEM_ROOT_DYNAMIC_ARRAY *stack) { const char *in = "" "{\n" @@ -184,7 +189,7 @@ test_json_normalize_nested_deep(void) "[-1.2E0,\"w\",\"x\"]" "]" "}"; - check_json_normalize(in, expected); + check_json_normalize(in, expected, je, stack); } @@ -194,24 +199,27 @@ json_normalize_number(DYNAMIC_STRING *out, const char *str, size_t str_len); static void -test_json_normalize_non_utf8(void) +test_json_normalize_non_utf8(json_engine_t *je, MEM_ROOT_DYNAMIC_ARRAY *stack) { int err; const char utf8[]= { 0x22, 0xC3, 0x8A, 0x22, 0x00 }; const char latin[] = { 0x22, 0xCA, 0x22, 0x00 }; DYNAMIC_STRING result; + MEM_ROOT current_mem_root; CHARSET_INFO *cs_utf8= &my_charset_utf8mb4_bin; CHARSET_INFO *cs_latin= &my_charset_latin1; init_dynamic_string(&result, NULL, 0, 0); - err= json_normalize(&result, utf8, strlen(utf8), cs_utf8); - ok(err == 0, "normalize err: %d", err); + init_alloc_root(PSI_INSTRUMENT_MEM, ¤t_mem_root, + BLOCK_SIZE_JSON_DYN_ARRAY, 0, MYF(0)); + err= json_normalize(&result, utf8, strlen(utf8), cs_utf8, ¤t_mem_root, je, stack); + ok(err == 0, "normalize err?"); ok((strcmp(utf8, result.str) == 0), "utf8 round trip"); dynstr_free(&result); init_dynamic_string(&result, NULL, 0, 0); - err= json_normalize(&result, latin, strlen(latin), cs_latin); - ok(err == 0, "normalize err: %d", err); + err= json_normalize(&result, latin, strlen(latin), cs_latin, ¤t_mem_root, je, stack); + ok(err == 0, "normalize err?"); ok((strcmp(utf8, result.str) == 0), "latin to utf8 round trip"); dynstr_free(&result); } @@ -243,8 +251,20 @@ check_number_normalize(const char *in, const char *expected) int main(int argc, char** argv) { - MY_INIT(argv[0]); + MEM_ROOT current_mem_root; + MEM_ROOT_DYNAMIC_ARRAY stack; + json_engine_t je; + init_alloc_root(PSI_INSTRUMENT_MEM, ¤t_mem_root, + BLOCK_SIZE_JSON_DYN_ARRAY, 0, MYF(0)); + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &je.stack, + sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &stack, + sizeof(struct json_norm_value*), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); plan(88); diag("Testing json_normalization."); @@ -268,15 +288,17 @@ main(int argc, char** argv) check_number_normalize("0000123.456000000e-9", "1.23456E-7"); check_number_normalize("0000123.456000000e+9", "1.23456E11"); - test_json_normalize_invalid(); - test_json_normalize_values(); - test_json_normalize_single_kv(); - test_json_normalize_multi_kv(); - test_json_normalize_array(); - test_json_normalize_nested_objects(); - test_json_normalize_nested_arrays(); - test_json_normalize_nested_deep(); - test_json_normalize_non_utf8(); + test_json_normalize_invalid(&je, &stack); + test_json_normalize_values(&je, &stack); + test_json_normalize_single_kv(&je, &stack); + test_json_normalize_multi_kv(&je, &stack); + test_json_normalize_array(&je, &stack); + test_json_normalize_nested_objects(&je, &stack); + test_json_normalize_nested_arrays(&je, &stack); + test_json_normalize_nested_deep(&je, &stack); + test_json_normalize_non_utf8(&je, &stack); + + free_root(¤t_mem_root, MYF(0)); my_end(MY_CHECK_ERROR); return exit_status(); diff --git a/unittest/strings/json-t.c b/unittest/strings/json-t.c index 7c5f7957d42..5977fd7bba3 100644 --- a/unittest/strings/json-t.c +++ b/unittest/strings/json-t.c @@ -58,12 +58,12 @@ void do_json_ar(int n, int type, const char *value) "%i: type=%u keys=%u end=\"%s\"", n, value_type, value_len, value_start); } -void do_json_locate(const char *json, const char *key, int from, int to, int cp) +void do_json_locate(json_engine_t *je, const char *json, const char *key, int from, int to, int cp) { const char *key_start, *key_end; int res, comma_pos; - res= json_locate_key(json, json + strlen(json), + res= json_locate_key(je, json, json + strlen(json), key, &key_start, &key_end, &comma_pos); if (key_start) ok(res == 0 && key_start - json == from && key_end - json == to && @@ -75,8 +75,18 @@ void do_json_locate(const char *json, const char *key, int from, int to, int cp) int main() { + json_engine_t je; + MEM_ROOT current_mem_root; + plan(18); + init_alloc_root(PSI_INSTRUMENT_MEM, ¤t_mem_root, + BLOCK_SIZE_JSON_DYN_ARRAY, 0, MYF(0)); + + mem_root_dynamic_array_init(¤t_mem_root, PSI_INSTRUMENT_MEM, + &je.stack, sizeof(int), NULL, + JSON_DEPTH_DEFAULT, JSON_DEPTH_INC, MYF(0)); + diag("%s", json); do_json("int", 4, "1"); do_json("str", 3, "foo bar"); @@ -90,14 +100,16 @@ int main() do_json_ar(3, 6, "false"); do_json_ar(4, 0, "1234"); - do_json_locate(json, "bool", 50, 63, 1); - do_json_locate(json, "int", 1, 9, 2); - do_json_locate(json, "array", 24, 50, 1); - do_json_locate(json_w, "bool", 43, 61, 1); - do_json_locate(json_w, "int", 1, 12, 2); - do_json_locate(json_w, "array", 11, 43, 1); - do_json_locate(json_w, "c", -1, -1, -1); - do_json_locate(json_1, "str", 1, 22, 0); + do_json_locate(&je, json, "bool", 50, 63, 1); + do_json_locate(&je, json, "int", 1, 9, 2); + do_json_locate(&je, json, "array", 24, 50, 1); + do_json_locate(&je, json_w, "bool", 43, 61, 1); + do_json_locate(&je, json_w, "int", 1, 12, 2); + do_json_locate(&je, json_w, "array", 11, 43, 1); + do_json_locate(&je, json_w, "c", -1, -1, -1); + do_json_locate(&je, json_1, "str", 1, 22, 0); + + free_root(¤t_mem_root, MYF(0)); return exit_status(); }