Commit bc10f58a authored by Sergei Golubchik's avatar Sergei Golubchik

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
parent bae9fb59
......@@ -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;
......
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
#
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 @@ static int json_nice(json_engine_t *je, String *nice_js,
};
} 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 @@ String *Item_func_json_array_append::val_str(String *str)
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 @@ String *Item_func_json_merge::val_str(String *str)
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 @@ 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 (json_nice(&je1, str, Item_func_json_format::LOOSE))
goto error_return;
......@@ -2541,6 +2558,7 @@ String *Item_func_json_merge_patch::val_str(String *str)
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 @@ 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 (json_nice(&je, str, Item_func_json_format::LOOSE))
goto js_error;
......@@ -3005,6 +3026,7 @@ String *Item_func_json_insert::val_str(String *str)
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 @@ 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;
if (json_nice(&je, str, Item_func_json_format::LOOSE))
goto js_error;
......@@ -3189,6 +3214,7 @@ String *Item_func_json_remove::val_str(String *str)
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);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment