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