mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-24909 JSON functions don't respect KILL QUERY / max_statement_time limit
pass the pointer to thd->killed down to the json library, check it while scanning, use thd->check_killed() to generate the proper error message
This commit is contained in:
@ -222,6 +222,7 @@ typedef struct st_json_engine_t
|
||||
|
||||
int stack[JSON_DEPTH_LIMIT]; /* Keeps the stack of nested JSON structures. */
|
||||
int stack_p; /* The 'stack' pointer. */
|
||||
volatile uchar *killed_ptr;
|
||||
} json_engine_t;
|
||||
|
||||
|
||||
|
42
mysql-test/main/func_json_notembedded.result
Normal file
42
mysql-test/main/func_json_notembedded.result
Normal file
@ -0,0 +1,42 @@
|
||||
set global max_allowed_packet=1073741824;
|
||||
connect u,localhost,root;
|
||||
#
|
||||
# MDEV-24909 JSON functions don't respect KILL QUERY / max_statement_time limit
|
||||
#
|
||||
set group_concat_max_len= 4294967295;
|
||||
set @obj=concat_ws('','{', repeat('"a":"b",', 125000000/2), '"c":"d"}');
|
||||
set @arr=concat_ws('','[', repeat('1234567,', 125000000/2), '2345678]');
|
||||
select length(@obj), length(@arr);
|
||||
length(@obj) length(@arr)
|
||||
500000009 500000009
|
||||
set max_statement_time=0.0001;
|
||||
select json_array_append(@arr, '$[0]', 1);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_array_insert(@arr, '$[0]', 1);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_insert(@obj, '$.meta', 1);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_compact(@arr);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_detailed(@arr);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_loose(@arr);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_merge(@obj, @arr);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_merge_patch(@obj, @obj);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_merge_preserve(@obj, @arr);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_remove(@obj,'$.foo');
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_replace(@obj,'$.foo',1);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
select json_set(@arr,'$[1000]',1);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
disconnect u;
|
||||
connection default;
|
||||
set global max_allowed_packet=default;
|
||||
#
|
||||
# End of 10.6 tests
|
||||
#
|
37
mysql-test/main/func_json_notembedded.test
Normal file
37
mysql-test/main/func_json_notembedded.test
Normal file
@ -0,0 +1,37 @@
|
||||
source include/have_profiling.inc;
|
||||
source include/not_embedded.inc;
|
||||
|
||||
set global max_allowed_packet=1073741824;
|
||||
connect u,localhost,root;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-24909 JSON functions don't respect KILL QUERY / max_statement_time limit
|
||||
--echo #
|
||||
set group_concat_max_len= 4294967295;
|
||||
|
||||
set @obj=concat_ws('','{', repeat('"a":"b",', 125000000/2), '"c":"d"}');
|
||||
set @arr=concat_ws('','[', repeat('1234567,', 125000000/2), '2345678]');
|
||||
select length(@obj), length(@arr);
|
||||
|
||||
set max_statement_time=0.0001;
|
||||
disable_abort_on_error;
|
||||
select json_array_append(@arr, '$[0]', 1);
|
||||
select json_array_insert(@arr, '$[0]', 1);
|
||||
select json_insert(@obj, '$.meta', 1);
|
||||
select json_compact(@arr);
|
||||
select json_detailed(@arr);
|
||||
select json_loose(@arr);
|
||||
select json_merge(@obj, @arr);
|
||||
select json_merge_patch(@obj, @obj);
|
||||
select json_merge_preserve(@obj, @arr);
|
||||
select json_remove(@obj,'$.foo');
|
||||
select json_replace(@obj,'$.foo',1);
|
||||
select json_set(@arr,'$[1000]',1);
|
||||
enable_abort_on_error;
|
||||
disconnect u;
|
||||
connection default;
|
||||
set global max_allowed_packet=default;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.6 tests
|
||||
--echo #
|
@ -240,7 +240,7 @@ handle_value:
|
||||
};
|
||||
} while (json_scan_next(je) == 0);
|
||||
|
||||
return je->s.error;
|
||||
return je->s.error || *je->killed_ptr;
|
||||
|
||||
error:
|
||||
return 1;
|
||||
@ -1653,6 +1653,7 @@ String *Item_func_json_array_append::val_str(String *str)
|
||||
uint n_arg, n_path;
|
||||
size_t str_rest_len;
|
||||
const uchar *ar_end;
|
||||
THD *thd= current_thd;
|
||||
|
||||
DBUG_ASSERT(fixed());
|
||||
|
||||
@ -1680,6 +1681,7 @@ String *Item_func_json_array_append::val_str(String *str)
|
||||
|
||||
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||
(const uchar *) js->ptr() + js->length());
|
||||
je.killed_ptr= (uchar*)&thd->killed;
|
||||
|
||||
c_path->cur_step= c_path->p.steps;
|
||||
|
||||
@ -1760,6 +1762,7 @@ String *Item_func_json_array_append::val_str(String *str)
|
||||
|
||||
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||
(const uchar *) js->ptr() + js->length());
|
||||
je.killed_ptr= (uchar*)&thd->killed;
|
||||
if (json_nice(&je, str, Item_func_json_format::LOOSE))
|
||||
goto js_error;
|
||||
|
||||
@ -1769,6 +1772,7 @@ js_error:
|
||||
report_json_error(js, &je, 0);
|
||||
|
||||
return_null:
|
||||
thd->check_killed(); // to get the error message right
|
||||
null_value= 1;
|
||||
return 0;
|
||||
}
|
||||
@ -1779,6 +1783,7 @@ String *Item_func_json_array_insert::val_str(String *str)
|
||||
json_engine_t je;
|
||||
String *js= args[0]->val_json(&tmp_js);
|
||||
uint n_arg, n_path;
|
||||
THD *thd= current_thd;
|
||||
|
||||
DBUG_ASSERT(fixed());
|
||||
|
||||
@ -1816,6 +1821,7 @@ String *Item_func_json_array_insert::val_str(String *str)
|
||||
|
||||
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||
(const uchar *) js->ptr() + js->length());
|
||||
je.killed_ptr= (uchar*)&thd->killed;
|
||||
|
||||
c_path->cur_step= c_path->p.steps;
|
||||
|
||||
@ -1855,7 +1861,7 @@ String *Item_func_json_array_insert::val_str(String *str)
|
||||
goto js_error;
|
||||
}
|
||||
|
||||
if (unlikely(je.s.error))
|
||||
if (unlikely(je.s.error || *je.killed_ptr))
|
||||
goto js_error;
|
||||
|
||||
str->length(0);
|
||||
@ -1899,6 +1905,7 @@ String *Item_func_json_array_insert::val_str(String *str)
|
||||
|
||||
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||
(const uchar *) js->ptr() + js->length());
|
||||
je.killed_ptr= (uchar*)&thd->killed;
|
||||
if (json_nice(&je, str, Item_func_json_format::LOOSE))
|
||||
goto js_error;
|
||||
|
||||
@ -1907,6 +1914,7 @@ String *Item_func_json_array_insert::val_str(String *str)
|
||||
js_error:
|
||||
report_json_error(js, &je, 0);
|
||||
return_null:
|
||||
thd->check_killed(); // to get the error message right
|
||||
null_value= 1;
|
||||
return 0;
|
||||
}
|
||||
@ -2165,6 +2173,7 @@ String *Item_func_json_merge::val_str(String *str)
|
||||
json_engine_t je1, je2;
|
||||
String *js1= args[0]->val_json(&tmp_js1), *js2=NULL;
|
||||
uint n_arg;
|
||||
THD *thd= current_thd;
|
||||
LINT_INIT(js2);
|
||||
|
||||
if (args[0]->null_value)
|
||||
@ -2181,9 +2190,11 @@ String *Item_func_json_merge::val_str(String *str)
|
||||
|
||||
json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(),
|
||||
(const uchar *) js1->ptr() + js1->length());
|
||||
je1.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))
|
||||
goto error_return;
|
||||
@ -2205,6 +2216,7 @@ String *Item_func_json_merge::val_str(String *str)
|
||||
|
||||
json_scan_start(&je1, 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))
|
||||
goto error_return;
|
||||
|
||||
@ -2216,6 +2228,7 @@ error_return:
|
||||
report_json_error(js1, &je1, 0);
|
||||
if (je2.s.error)
|
||||
report_json_error(js2, &je2, n_arg);
|
||||
thd->check_killed(); // to get the error message right
|
||||
null_return:
|
||||
null_value= 1;
|
||||
return NULL;
|
||||
@ -2465,6 +2478,7 @@ String *Item_func_json_merge_patch::val_str(String *str)
|
||||
String *js1= args[0]->val_json(&tmp_js1), *js2=NULL;
|
||||
uint n_arg;
|
||||
bool empty_result, merge_to_null;
|
||||
THD *thd= current_thd;
|
||||
|
||||
/* To report errors properly if some JSON is invalid. */
|
||||
je1.s.error= je2.s.error= 0;
|
||||
@ -2481,6 +2495,7 @@ String *Item_func_json_merge_patch::val_str(String *str)
|
||||
|
||||
json_scan_start(&je2, js2->charset(),(const uchar *) js2->ptr(),
|
||||
(const uchar *) js2->ptr() + js2->length());
|
||||
je2.killed_ptr= (uchar*)&thd->killed;
|
||||
|
||||
if (merge_to_null)
|
||||
{
|
||||
@ -2502,6 +2517,7 @@ String *Item_func_json_merge_patch::val_str(String *str)
|
||||
|
||||
json_scan_start(&je1, js1->charset(),(const uchar *) js1->ptr(),
|
||||
(const uchar *) js1->ptr() + js1->length());
|
||||
je1.killed_ptr= (uchar*)&thd->killed;
|
||||
|
||||
if (do_merge_patch(str, &je1, &je2, &empty_result))
|
||||
goto error_return;
|
||||
@ -2530,6 +2546,7 @@ cont_point:
|
||||
|
||||
json_scan_start(&je1, 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))
|
||||
goto error_return;
|
||||
|
||||
@ -2541,6 +2558,7 @@ error_return:
|
||||
report_json_error(js1, &je1, 0);
|
||||
if (je2.s.error)
|
||||
report_json_error(js2, &je2, n_arg);
|
||||
thd->check_killed(); // to get the error message right
|
||||
null_return:
|
||||
null_value= 1;
|
||||
return NULL;
|
||||
@ -2777,6 +2795,7 @@ String *Item_func_json_insert::val_str(String *str)
|
||||
String *js= args[0]->val_json(&tmp_js);
|
||||
uint n_arg, n_path;
|
||||
json_string_t key_name;
|
||||
THD *thd= current_thd;
|
||||
|
||||
DBUG_ASSERT(fixed());
|
||||
|
||||
@ -2817,6 +2836,7 @@ String *Item_func_json_insert::val_str(String *str)
|
||||
|
||||
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||
(const uchar *) js->ptr() + js->length());
|
||||
je.killed_ptr= (uchar*)&thd->killed;
|
||||
|
||||
if (c_path->p.last_step < c_path->p.steps)
|
||||
goto v_found;
|
||||
@ -2998,6 +3018,7 @@ continue_point:
|
||||
|
||||
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||
(const uchar *) js->ptr() + js->length());
|
||||
je.killed_ptr= (uchar*)&thd->killed;
|
||||
if (json_nice(&je, str, Item_func_json_format::LOOSE))
|
||||
goto js_error;
|
||||
|
||||
@ -3005,6 +3026,7 @@ continue_point:
|
||||
|
||||
js_error:
|
||||
report_json_error(js, &je, 0);
|
||||
thd->check_killed(); // to get the error message right
|
||||
return_null:
|
||||
null_value= 1;
|
||||
return 0;
|
||||
@ -3028,6 +3050,7 @@ String *Item_func_json_remove::val_str(String *str)
|
||||
String *js= args[0]->val_json(&tmp_js);
|
||||
uint n_arg, n_path;
|
||||
json_string_t key_name;
|
||||
THD *thd= current_thd;
|
||||
|
||||
DBUG_ASSERT(fixed());
|
||||
|
||||
@ -3074,6 +3097,7 @@ String *Item_func_json_remove::val_str(String *str)
|
||||
|
||||
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||
(const uchar *) js->ptr() + js->length());
|
||||
je.killed_ptr= (uchar*)&thd->killed;
|
||||
|
||||
c_path->cur_step= c_path->p.steps;
|
||||
|
||||
@ -3182,6 +3206,7 @@ v_found:
|
||||
|
||||
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
|
||||
(const uchar *) js->ptr() + js->length());
|
||||
je.killed_ptr= (uchar*)&thd->killed;
|
||||
if (json_nice(&je, str, Item_func_json_format::LOOSE))
|
||||
goto js_error;
|
||||
|
||||
@ -3189,6 +3214,7 @@ v_found:
|
||||
return str;
|
||||
|
||||
js_error:
|
||||
thd->check_killed(); // to get the error message right
|
||||
report_json_error(js, &je, 0);
|
||||
null_return:
|
||||
null_value= 1;
|
||||
@ -3579,6 +3605,7 @@ 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;
|
||||
|
||||
if ((null_value= args[0]->null_value))
|
||||
return 0;
|
||||
@ -3602,11 +3629,13 @@ String *Item_func_json_format::val_str(String *str)
|
||||
|
||||
json_scan_start(&je, js->charset(), (const uchar *) js->ptr(),
|
||||
(const uchar *) js->ptr()+js->length());
|
||||
je.killed_ptr= (uchar*)&thd->killed;
|
||||
|
||||
if (json_nice(&je, str, fmt, tab_size))
|
||||
{
|
||||
null_value= 1;
|
||||
report_json_error(js, &je, 0);
|
||||
thd->check_killed(); // to get the error message right
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -807,10 +807,13 @@ static json_state_handler json_actions[NR_JSON_STATES][NR_C_CLASSES]=
|
||||
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;
|
||||
|
||||
json_string_setup(&je->s, i_cs, str, end);
|
||||
je->stack[0]= JST_DONE;
|
||||
je->stack_p= 0;
|
||||
je->state= JST_VALUE;
|
||||
je->killed_ptr = (uchar*)&no_time_to_die;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -971,7 +974,7 @@ int json_scan_next(json_engine_t *j)
|
||||
int t_next;
|
||||
|
||||
get_first_nonspace(&j->s, &t_next, &j->sav_c_len);
|
||||
return json_actions[j->state][t_next](j);
|
||||
return *j->killed_ptr || json_actions[j->state][t_next](j);
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user