From b8a77289639a3b10ada64cf892f02b5cecdb1603 Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Tue, 27 Feb 2024 19:43:51 +0530 Subject: [PATCH] MDEV-32854: Make JSON_DEPTH_LIMIT unlimited The initial hard capped limit on the depth was 32. It was implemented using static arrays of relevant type and size 32. Hence, to implement unlimited depth, dynamic array on mem_root was implemented which grows by 3200 as needed. Relevant arrays were replaced with this dynamic array. --- include/json_lib.h | 59 +- include/my_sys.h | 80 +++ mysql-test/main/func_json.result | 26 +- mysql-test/main/func_json.test | 6 +- mysql-test/main/json_equals.result | 2 +- mysql-test/main/mdev_32854.result | 454 +++++++++++++ mysql-test/main/mdev_32854.test | 113 ++++ mysys/array.c | 123 ++++ sql/item_geofunc.cc | 11 +- sql/item_geofunc.h | 12 +- sql/item_jsonfunc.cc | 976 ++++++++++++++++++++------- sql/item_jsonfunc.h | 207 ++++-- sql/item_vectorfunc.cc | 6 +- sql/item_vectorfunc.h | 9 + sql/json_schema.cc | 459 +++++++++---- sql/json_schema.h | 244 ++++--- sql/json_schema_helper.cc | 6 +- sql/json_schema_helper.h | 4 +- sql/json_table.cc | 59 +- sql/json_table.h | 5 +- sql/opt_histogram_json.cc | 7 + sql/opt_histogram_json.h | 1 + sql/sql_acl.cc | 17 +- sql/sql_class.cc | 1 + storage/columnstore/columnstore | 2 +- strings/json_lib.c | 541 ++++++++++----- strings/json_normalize.c | 105 +-- unittest/json_lib/json_lib-t.c | 118 ++-- unittest/json_lib/json_normalize-t.c | 122 ++-- unittest/strings/json-t.c | 32 +- 30 files changed, 2922 insertions(+), 885 deletions(-) create mode 100644 mysql-test/main/mdev_32854.result create mode 100644 mysql-test/main/mdev_32854.test 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(); }