diff --git a/mysql-test/main/func_json_notembedded.result b/mysql-test/main/func_json_notembedded.result index 756d2e85f7c..ba4d38dd623 100644 --- a/mysql-test/main/func_json_notembedded.result +++ b/mysql-test/main/func_json_notembedded.result @@ -10,6 +10,8 @@ select length(@obj), length(@arr); length(@obj) length(@arr) 5000009 5000009 set max_statement_time=0.0001; +SET @old_debug= @@debug_dbug; +SET debug_dbug='+d,debug_max_statement_time exceeded'; select json_array_append(@arr, '$[0]', 1); ERROR 70100: Query execution was interrupted (max_statement_time exceeded) select json_array_insert(@arr, '$[0]', 1); @@ -34,6 +36,7 @@ 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) +SET debug_dbug= @old_debug; disconnect u; connection default; set global max_allowed_packet=default; diff --git a/mysql-test/main/func_json_notembedded.test b/mysql-test/main/func_json_notembedded.test index 893b248301c..1e05571e16f 100644 --- a/mysql-test/main/func_json_notembedded.test +++ b/mysql-test/main/func_json_notembedded.test @@ -1,6 +1,7 @@ source include/have_profiling.inc; source include/not_embedded.inc; source include/no_valgrind_without_big.inc; +source include/have_debug.inc; set global max_allowed_packet=1073741824; connect u,localhost,root; @@ -16,6 +17,8 @@ select length(@obj), length(@arr); set max_statement_time=0.0001; disable_abort_on_error; +SET @old_debug= @@debug_dbug; +SET debug_dbug='+d,debug_max_statement_time exceeded'; select json_array_append(@arr, '$[0]', 1); select json_array_insert(@arr, '$[0]', 1); select json_insert(@obj, '$.meta', 1); @@ -29,6 +32,7 @@ select json_remove(@obj,'$.foo'); select json_replace(@obj,'$.foo',1); select json_set(@arr,'$[1000]',1); enable_abort_on_error; +SET debug_dbug= @old_debug; disconnect u; connection default; set global max_allowed_packet=default; diff --git a/sql/item_func.cc b/sql/item_func.cc index 0d798847a5a..f2d35887c14 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -72,6 +72,9 @@ bool check_reserved_words(const LEX_CSTRING *name) return FALSE; } +void pause_execution(THD *thd, double timeout); +static int do_pause(THD *thd, Interruptible_wait *timed_cond, + mysql_cond_t *cond, double timeout); /** Test if the sum of arguments overflows the ulonglong range. @@ -4612,32 +4615,7 @@ longlong Item_func_sleep::val_int() if (timeout < 0.00001) return 0; - timed_cond.set_timeout((ulonglong) (timeout * 1000000000.0)); - - mysql_cond_init(key_item_func_sleep_cond, &cond, NULL); - mysql_mutex_lock(&LOCK_item_func_sleep); - - THD_STAGE_INFO(thd, stage_user_sleep); - thd->mysys_var->current_mutex= &LOCK_item_func_sleep; - thd->mysys_var->current_cond= &cond; - - error= 0; - thd_wait_begin(thd, THD_WAIT_SLEEP); - while (!thd->killed) - { - error= timed_cond.wait(&cond, &LOCK_item_func_sleep); - if (error == ETIMEDOUT || error == ETIME) - break; - error= 0; - } - thd_wait_end(thd); - mysql_mutex_unlock(&LOCK_item_func_sleep); - mysql_mutex_lock(&thd->mysys_var->mutex); - thd->mysys_var->current_mutex= 0; - thd->mysys_var->current_cond= 0; - mysql_mutex_unlock(&thd->mysys_var->mutex); - - mysql_cond_destroy(&cond); + error= do_pause(thd, &timed_cond, &cond, timeout); #ifdef ENABLED_DEBUG_SYNC DBUG_EXECUTE_IF("sleep_inject_query_done_debug_sync", { @@ -7358,3 +7336,43 @@ void fix_rownum_pointers(THD *thd, SELECT_LEX *select_lex, ha_rows *ptr) ((Item_func_rownum*) item)->store_pointer_to_row_counter(ptr); } } + +static int do_pause(THD *thd, Interruptible_wait *timed_cond, mysql_cond_t *cond, double timeout) +{ + int error= 0; + timed_cond->set_timeout((ulonglong) (timeout * 1000000000.0)); + + mysql_cond_init(key_item_func_sleep_cond, cond, NULL); + mysql_mutex_lock(&LOCK_item_func_sleep); + + THD_STAGE_INFO(thd, stage_user_sleep); + thd->mysys_var->current_mutex= &LOCK_item_func_sleep; + thd->mysys_var->current_cond= cond; + + thd_wait_begin(thd, THD_WAIT_SLEEP); + while (!thd->killed) + { + error= timed_cond->wait(cond, &LOCK_item_func_sleep); + if (error == ETIMEDOUT || error == ETIME) + break; + error= 0; + } + thd_wait_end(thd); + mysql_mutex_unlock(&LOCK_item_func_sleep); + mysql_mutex_lock(&thd->mysys_var->mutex); + thd->mysys_var->current_mutex= 0; + thd->mysys_var->current_cond= 0; + mysql_mutex_unlock(&thd->mysys_var->mutex); + + mysql_cond_destroy(cond); + + return error; +} + +void pause_execution(THD *thd, double timeout) +{ + Interruptible_wait timed_cond(thd); + mysql_cond_t cond; + + do_pause(thd, &timed_cond, &cond, timeout); +} diff --git a/sql/item_func.h b/sql/item_func.h index 0f34f3f6c0e..749c8fc4dd4 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -4312,6 +4312,7 @@ public: { return get_item_copy(thd, this); } }; +class Interruptible_wait; Item *get_system_var(THD *thd, enum_var_type var_type, const LEX_CSTRING *name, const LEX_CSTRING *component); diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index f5d321b57e1..603e8220aed 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -29,6 +29,23 @@ static int dbug_json_check_min_stack_requirement() } #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 + compiler to optimize out stack_used_up. Since alloca() + here depends on stack_used_up, it doesnt get executed + correctly and causes json_debug_nonembedded to fail + ( --error ER_STACK_OVERRUN_NEED_MORE does not occur). +*/ + +#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 character set. @@ -1965,6 +1982,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; @@ -2123,6 +2142,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)) @@ -2528,6 +2549,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; @@ -2837,6 +2860,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; @@ -3129,6 +3154,8 @@ 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(); @@ -3423,6 +3450,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;