From fcd345de485fc849fc6cf5177e680b3d423eb291 Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Fri, 10 Nov 2023 16:01:15 +0530 Subject: [PATCH] MDEV-32726: Fix failing test fir freebsd for json Json test about max statement time fails with freebsd because on some architectures the test might execute faster and the statement may not fail. To simulate failure regardless of architecture, introduce a wait of seconds longer than the max_statement_time. --- mysql-test/main/func_json_notembedded.result | 3 + mysql-test/main/func_json_notembedded.test | 4 ++ sql/item_func.cc | 70 ++++++++++++-------- sql/item_func.h | 1 + sql/item_jsonfunc.cc | 29 ++++++++ 5 files changed, 81 insertions(+), 26 deletions(-) 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;