diff --git a/client/mysqltest.c b/client/mysqltest.c index 0558df7a568..a0c75511dc9 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1647,19 +1647,20 @@ int do_sleep(struct st_query *query, my_bool real_sleep) char *p= query->first_argument; char *sleep_start, *sleep_end= query->end; double sleep_val; - char *cmd = (real_sleep ? "real_sleep" : "sleep"); while (my_isspace(charset_info, *p)) p++; if (!*p) - die("Missing argument to %s", cmd); + die("Missing argument to %.*s", query->first_word_len, query->query); sleep_start= p; /* Check that arg starts with a digit, not handled by my_strtod */ if (!my_isdigit(charset_info, *sleep_start)) - die("Invalid argument to %s \"%s\"", cmd, query->first_argument); + die("Invalid argument to %.*s \"%s\"", query->first_word_len, query->query, + query->first_argument); sleep_val= my_strtod(sleep_start, &sleep_end, &error); if (error) - die("Invalid argument to %s \"%s\"", cmd, query->first_argument); + die("Invalid argument to %.*s \"%s\"", query->first_word_len, query->query, + query->first_argument); /* Fixed sleep time selected by --sleep option */ if (opt_sleep && !real_sleep) @@ -2529,8 +2530,8 @@ my_bool end_of_query(int c) size size of the buffer i.e max size to read DESCRIPTION - This function actually reads several lines an adds them to the - buffer buf. It will continue to read until it finds what it believes + This function actually reads several lines and adds them to the + buffer buf. It continues to read until it finds what it believes is a complete query. Normally that means it will read lines until it reaches the @@ -3760,7 +3761,7 @@ static void handle_no_error(struct st_query *q) command - currrent command pointer query - query string to execute query_len - length query string to execute - ds - output buffer wherte to store result form query + ds - output buffer where to store result form query RETURN VALUE error - function will not return @@ -3778,7 +3779,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, DBUG_PRINT("query", ("'%-.60s'", query)); /* - Init a new stmt if it's not alreday one created for this connectoon + Init a new stmt if it's not already one created for this connection */ if(!(stmt= cur_con->stmt)) { @@ -3867,7 +3868,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, goto end; } - /* If we got here the statement was both executed and read succeesfully */ + /* If we got here the statement was both executed and read successfully */ handle_no_error(command); if (!disable_result_log) { @@ -4594,7 +4595,7 @@ int main(int argc, char **argv) case Q_QUERY_HORIZONTAL: { my_bool old_display_result_vertically= display_result_vertically; - /* fix up query pointer if this is * first iteration for this line */ + /* fix up query pointer if this is first iteration for this line */ if (q->query == q->query_buf) q->query += q->first_word_len + 1; display_result_vertically= (q->type==Q_QUERY_VERTICAL); @@ -4639,15 +4640,15 @@ int main(int argc, char **argv) case Q_SEND: if (!q->query[q->first_word_len]) { - /* This happens when we use 'send' on it's own line */ + /* This happens when we use 'send' on its own line */ q_send_flag=1; break; } - /* fix up query pointer if this is * first iteration for this line */ + /* fix up query pointer if this is first iteration for this line */ if (q->query == q->query_buf) q->query += q->first_word_len; /* - run_query() can execute a query partially, depending on the flags + run_query() can execute a query partially, depending on the flags. QUERY_SEND flag without QUERY_REAP tells it to just send the query and read the result some time later when reap instruction is given on this connection. @@ -4731,7 +4732,7 @@ int main(int argc, char **argv) break; case Q_ENABLE_PARSING: /* - Ensure we don't get parsing_disabled < 0 as this would accidently + Ensure we don't get parsing_disabled < 0 as this would accidentally disable code we don't want to have disabled */ if (parsing_disabled > 0) @@ -4777,9 +4778,9 @@ int main(int argc, char **argv) start_lineno= 0; /* - The whole test has been executed _sucessfully_ - Time to compare result or save it to record file - The entire output from test is now kept in ds_res + The whole test has been executed _sucessfully_. + Time to compare result or save it to record file. + The entire output from test is now kept in ds_res. */ if (ds_res.length) { @@ -5509,7 +5510,7 @@ static int get_next_bit(REP_SET *set,uint lastpos) } /* find if there is a same set in sets. If there is, use it and - free given set, else put in given set in sets and return it's + free given set, else put in given set in sets and return its position */ static int find_set(REP_SETS *sets,REP_SET *find) @@ -5528,7 +5529,7 @@ static int find_set(REP_SETS *sets,REP_SET *find) /* find if there is a found_set with same table_offset & found_offset If there is return offset to it, else add new offset and return pos. - Pos returned is -offset-2 in found_set_structure because it's is + Pos returned is -offset-2 in found_set_structure because it is saved in set->next and set->next[] >= 0 points to next set and set->next[] == -1 is reserved for end without replaces. */ diff --git a/mysql-test/README.stress b/mysql-test/README.stress index 001ecceef1b..6be4e9a0236 100644 --- a/mysql-test/README.stress +++ b/mysql-test/README.stress @@ -2,114 +2,118 @@ Overview -------- -Stress script is designed to perform testsing of mysql server in -multi-thread environment. +The stress script is designed to perform testing of the MySQL server in +a multi-threaded environment. -Stress script allows: +All functionality regarding stress testing is implemented in the +mysql-stress-test.pl script. + +The stress script allows: - - to use for stress testing mysqltest binary as test engine - - to use for stress testing both regular test suite and any - additional test suites (e.g. mysql-test-extra-5.0) - - to specify files with lists of tests both for initialization of - stress db and for further testing itself - - to define number of threads that will be concurrently used in testing - - to define limitations for test run. e.g. number of tests or loops - for execution or duration of testing, delay between test executions, etc. - - to get readable log file which can be used for identification of - errors arose during testing + - To stress test the mysqltest binary test engine. + - To stress test the regular test suite and any additional test suites + (such as mysql-test-extra-5.0). + - To specify files with lists of tests both for initialization of + stress db and for further testing itself. + - To define the number of threads to be concurrently used in testing. + - To define limitations for the test run. such as the number of tests or + loops for execution or duration of testing, delay between test + executions, and so forth. + - To get a readable log file that can be used for identification of + errors that occur during testing. -All functionality regarding stress testing was implemeted in -mysql-stress-test.pl script and there are two ways to run stress test: +There are two ways to run the mysql-stress-test.pl script: - - for most cases it is enough to use options below for starting of - stress test from mysql-test-run wrapper. In this case server will - be run automatically, all preparation steps will be performed - and after that stress test will be started. + - For most cases, it is enough to use the options below for starting + the stress test from the mysql-test-run wrapper. In this case, the + server is run automatically, all preparation steps are performed, + and after that the stress test is started. - - in advanced case one can run mysql-stress-test.pl script directly. - But it requires to perform some preparation steps and to specify a - bunch of options as well so this way may look a bit complicate. + - In advanced case, you can run the mysql-stress-test.pl script directly. + But this requires that you perform some preparation steps and to specify + a bunch of options as well, so this invocation method may be a bit + complicated. Usage ----- -Below is list of stress test specific options for mysql-test-run: +The following mysql-test-run options are specific to stress-testing: --stress Enable stress mode --stress-suite= - Test suite name that will be used in stress testing. - We assume that all suites are located in mysql-test/suite directory + Test suite name to use in stress testing. We assume that all suites + are located in the mysql-test/suite directory. There is one special suite name - that corresponds - to regular test suite located in mysql-test directory. + to the regular test suite located in the mysql-test directory. --stress-threads= - Number of threads that will be used in stress testing + The number of threads to use in stress testing. --stress-tests-file= - Filename with list of tests(without .test suffix) that will be used in - stress testing. Default filename is stress_tests.txt and default + The file that contains the list of tests (without .test suffix) to use in + stress testing. The default filename is stress_tests.txt and the default location of this file is suite//stress_tests.txt --stress-init-file= - Filename with list of tests(without .test suffix) that will be used in - stress testing for initialization of stress db. These tests will be - executed only once before starting of test itself. Default filename - is stress_init.txt and default location of this file is + The file that contains list of tests (without .test suffix) to use in + stress testing for initialization of the stress db. These tests will be + executed only once before starting the test itself. The default filename + is stress_init.txt and the default location of this file is suite//stress_init.txt --stress-mode= Possible values are: random(default), seq - There are two possible modes which affect order of selecting of tests + There are two possible modes that affect the order of test selection from the list: - - in random mode tests will be selected in random order - - in seq mode each thread will execute tests in the loop one by one as - they specified in the list file. + - In random mode, tests are selected in random order + - In seq mode, each thread executes tests in a loop one by one in + the order specified in the list file. ---stress-test-count= +--stress-test-count= Total number of tests that will be executed concurrently by all threads ---stress-loop-count= +--stress-loop-count= Total number of loops in seq mode that will be executed concurrently by all threads ---stress-test-duration= +--stress-test-duration= Duration of stress testing in seconds Examples -------- -1. Example of simple command line to start stress test: +1. Example of a simple command line to start a stress test: mysql-test-run --stress alias -Runs stress test with default values for number of threads and number of tests, -with test 'alias' from suite 'main'. +Runs a stress test with default values for number of threads and number +of tests, with test 'alias' from suite 'main'. 2. Using in stress testing tests from other suites: - mysql-test-run --stress --stress-threads=10 --stress-test-count=1000 \ --stress-suite=example --stress-tests-file=testslist.txt - Will run stress test with 10 threads, will execute 1000 tests by all - threads, test will be used from suite 'example', list of test will be + Runs a stress test with 10 threads, executes 1000 tests by all + threads, tests are used from suite 'example', the list of tests is taken from file 'testslist.txt' - mysql-test-run --stress --stress-threads=10 --stress-test-count=1000 \ --stress-suite=example sum_distinct - Will run stress test with 10 threads, will execute 1000 tests by all - threads, test will be used from suite 'example', list of test contains - only one test 'sum_distinct' + Runs stress test with 10 threads, executes 1000 tests by all + threads, tests are used from suite 'example', the list of tests + contains only one test 'sum_distinct' 3. Debugging of issues found with stress test - Right now stress test is not fully integrated in mysql-test-run - and does not support --gdb option so to debug issue found with stress - test you have to start separately mysql server under debuger and then - run stress test as: + Right now, the stress test is not fully integrated in mysql-test-run + and does not support the --gdb option. To debug issues found with the + stress test, you must start the MySQL server separately under a debugger + and then run the stress test like this: - mysql-test-run --extern --stress --stress-threads=10 \ --stress-test-count=1000 --stress-suite=example \ diff --git a/mysql-test/mysql-stress-test.pl b/mysql-test/mysql-stress-test.pl index 899dd06a746..3061506da51 100755 --- a/mysql-test/mysql-stress-test.pl +++ b/mysql-test/mysql-stress-test.pl @@ -14,16 +14,17 @@ # # Design of stress script should allow one: # -# - to use for stress testing mysqltest binary as test engine -# - to use for stress testing both regular test suite and any -# additional test suites (e.g. mysql-test-extra-5.0) -# - to specify files with lists of tests both for initialization of -# stress db and for further testing itself -# - to define number of threads that will be concurrently used in testing -# - to define limitations for test run. e.g. number of tests or loops -# for execution or duration of testing, delay between test executions, etc. -# - to get readable log file which can be used for identification of -# errors arose during testing +# - To stress test the mysqltest binary test engine. +# - To stress test the regular test suite and any additional test suites +# (such as mysql-test-extra-5.0). +# - To specify files with lists of tests both for initialization of +# stress db and for further testing itself. +# - To define the number of threads to be concurrently used in testing. +# - To define limitations for the test run. such as the number of tests or +# loops for execution or duration of testing, delay between test +# executions, and so forth. +# - To get a readable log file that can be used for identification of +# errors that occur during testing. # # Basic scenarios: # diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 35292b31982..e6a22867db6 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -4801,4 +4801,60 @@ date_format(t3.d, pDateFormat) count(*) 2005-02 2 drop table t3| drop procedure bug17476| +drop table if exists t3| +drop procedure if exists bug16887| +create table t3 ( c varchar(1) )| +insert into t3 values +(' '),('.'),(';'),(','),('-'),('_'),('('),(')'),('/'),('\\')| +create procedure bug16887() +begin +declare i int default 10; +again: +while i > 0 do +begin +declare breakchar varchar(1); +declare done int default 0; +declare t3_cursor cursor for select c from t3; +declare continue handler for not found set done = 1; +set i = i - 1; +select i; +if i = 3 then +iterate again; +end if; +open t3_cursor; +loop +fetch t3_cursor into breakchar; +if done = 1 then +begin +close t3_cursor; +iterate again; +end; +end if; +end loop; +end; +end while; +end| +call bug16887()| +i +9 +i +8 +i +7 +i +6 +i +5 +i +4 +i +3 +i +2 +i +1 +i +0 +drop table t3| +drop procedure bug16887| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 9376ba717a5..e6823693b3d 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5638,6 +5638,7 @@ drop function bug17615| drop table t3| +# # BUG#17476: Stored procedure not returning data when it is called first # time per connection # @@ -5662,6 +5663,60 @@ drop table t3| drop procedure bug17476| +# +# BUG#16887: Cursor causes server segfault +# +--disable_warnings +drop table if exists t3| +drop procedure if exists bug16887| +--enable_warnings + +create table t3 ( c varchar(1) )| + +insert into t3 values + (' '),('.'),(';'),(','),('-'),('_'),('('),(')'),('/'),('\\')| + +create procedure bug16887() +begin + declare i int default 10; + + again: + while i > 0 do + begin + declare breakchar varchar(1); + declare done int default 0; + declare t3_cursor cursor for select c from t3; + declare continue handler for not found set done = 1; + + set i = i - 1; + select i; + + if i = 3 then + iterate again; + end if; + + open t3_cursor; + + loop + fetch t3_cursor into breakchar; + + if done = 1 then + begin + close t3_cursor; + iterate again; + end; + end if; + end loop; + end; + end while; +end| + +call bug16887()| + +drop table t3| +drop procedure bug16887| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index a8bd8cd2aa0..f69053a7c88 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -122,30 +122,38 @@ sp_pcontext::pop_context() } uint -sp_pcontext::diff_handlers(sp_pcontext *ctx) +sp_pcontext::diff_handlers(sp_pcontext *ctx, bool exclusive) { uint n= 0; sp_pcontext *pctx= this; + sp_pcontext *last_ctx= NULL; while (pctx && pctx != ctx) { n+= pctx->m_handlers; + last_ctx= pctx; pctx= pctx->parent_context(); } if (pctx) - return n; + return (exclusive && last_ctx ? n - last_ctx->m_handlers : n); return 0; // Didn't find ctx } uint -sp_pcontext::diff_cursors(sp_pcontext *ctx) +sp_pcontext::diff_cursors(sp_pcontext *ctx, bool exclusive) { + uint n= 0; sp_pcontext *pctx= this; + sp_pcontext *last_ctx= NULL; while (pctx && pctx != ctx) + { + n+= pctx->m_cursor.elements; + last_ctx= pctx; pctx= pctx->parent_context(); + } if (pctx) - return ctx->current_cursors() - pctx->current_cursors(); + return (exclusive && last_ctx ? n - last_ctx->m_cursor.elements : n); return 0; // Didn't find ctx } diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index d1cd7b964c2..872c7c1d505 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -119,11 +119,15 @@ class sp_pcontext : public Sql_alloc return m_parent; } + /* + Number of handlers/cursors to pop between this context and 'ctx'. + If 'exclusive' is true, don't count the last block we are leaving; + this is used for LEAVE where we will jump to the cpop/hpop instructions. + */ uint - diff_handlers(sp_pcontext *ctx); - + diff_handlers(sp_pcontext *ctx, bool exclusive); uint - diff_cursors(sp_pcontext *ctx); + diff_cursors(sp_pcontext *ctx, bool exclusive); // diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d6d2939bed3..468ade1bbbd 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2080,10 +2080,10 @@ sp_proc_stmt: uint ip= sp->instructions(); uint n; - n= ctx->diff_handlers(lab->ctx); + n= ctx->diff_handlers(lab->ctx, TRUE); /* Exclusive the dest. */ if (n) sp->add_instr(new sp_instr_hpop(ip++, ctx, n)); - n= ctx->diff_cursors(lab->ctx); + n= ctx->diff_cursors(lab->ctx, TRUE); /* Exclusive the dest. */ if (n) sp->add_instr(new sp_instr_cpop(ip++, ctx, n)); i= new sp_instr_jump(ip, ctx); @@ -2109,10 +2109,10 @@ sp_proc_stmt: uint ip= sp->instructions(); uint n; - n= ctx->diff_handlers(lab->ctx); + n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */ if (n) sp->add_instr(new sp_instr_hpop(ip++, ctx, n)); - n= ctx->diff_cursors(lab->ctx); + n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */ if (n) sp->add_instr(new sp_instr_cpop(ip++, ctx, n)); i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */