diff --git a/client/mysqltest.c b/client/mysqltest.c index 0cad29bd8de..1b829861b59 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3056,12 +3056,6 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) goto end; } - if (handle_no_error(q)) - { - error= 1; - goto end; - } - if (!disable_result_log) { ulong affected_rows; /* Ok to be undef if 'disable_info' is set */ @@ -3106,12 +3100,9 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) MYSQL_RES *warn_res=0; uint count= mysql_warning_count(mysql); if (!mysql_real_query(mysql, "SHOW WARNINGS", 13)) - { warn_res= mysql_store_result(mysql); - } if (!warn_res) - verbose_msg("Warning count is %u but didn't get any warnings", - count); + die("Warning count is %u but didn't get any warnings", count); else { dynstr_append_mem(ds, "Warnings:\n", 10); @@ -3142,15 +3133,28 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) } else if (q->record_file[0]) { - error = check_result(ds, q->record_file, q->require_file); + error= check_result(ds, q->record_file, q->require_file); } if (res) mysql_free_result(res); last_result= 0; counter++; } while (!(err= mysql_next_result(mysql))); - if (err >= 1) - mysql_error(mysql); + if (err > 0) + { + /* We got an error from mysql_next_result, maybe expected */ + if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds)) + error= 1; + goto end; + } + + // If we come here the query is both executed and read successfully + if (handle_no_error(q)) + { + error= 1; + goto end; + } end: free_replace(); @@ -3203,8 +3207,7 @@ static int handle_error(const char *query, struct st_query *q, abort_not_supported_test(); if (q->abort_on_error) - die("query '%s' failed: %d: %s", query, - err_errno, err_error); + die("query '%s' failed: %d: %s", query, err_errno, err_error); for (i= 0 ; (uint) i < q->expected_errors ; i++) { @@ -3243,13 +3246,11 @@ static int handle_error(const char *query, struct st_query *q, if (i) { if (q->expected_errno[0].type == ERR_ERRNO) - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, err_errno, - q->expected_errno[0].code.errnum); + die("query '%s' failed with wrong errno %d instead of %d...", + q->query, err_errno, q->expected_errno[0].code.errnum); else - verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", - q->query, err_sqlstate, - q->expected_errno[0].code.sqlstate); + die("query '%s' failed with wrong sqlstate %s instead of %s...", + q->query, err_sqlstate, q->expected_errno[0].code.sqlstate); DBUG_RETURN(1); } @@ -3283,16 +3284,16 @@ static int handle_no_error(struct st_query *q) q->expected_errno[0].code.errnum != 0) { /* Error code we wanted was != 0, i.e. not an expected success */ - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); + die("query '%s' succeeded - should have failed with errno %d...", + q->query, q->expected_errno[0].code.errnum); DBUG_RETURN(1); } else if (q->expected_errno[0].type == ERR_SQLSTATE && strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) { /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ - verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...", - q->query, q->expected_errno[0].code.sqlstate); + die("query '%s' succeeded - should have failed with sqlstate %s...", + q->query, q->expected_errno[0].code.sqlstate); DBUG_RETURN(1); } @@ -3312,7 +3313,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) { int error= 0; /* Function return code if "goto end;" */ int err; /* Temporary storage of return code from calls */ - int query_len, got_error_on_execute; + int query_len; ulonglong num_rows; char *query; MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ @@ -3328,7 +3329,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) */ if (!(stmt= mysql_stmt_init(mysql))) die("unable init stmt structure"); - + if (q->type != Q_EVAL) { query= q->query; @@ -3369,30 +3370,21 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) if (err != 0) { - if (q->abort_on_error) - { - die("query '%s' failed: %d: %s", query, - mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); - } - else - { - /* - Preparing is part of normal execution and some errors may be expected - */ - error= handle_error(query, q, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), - ds); - goto end; - } + /* + Preparing is part of normal execution and some errors may be expected + */ + if (handle_error(query, q, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds)) + error= 1; + goto end; } /* We may have got warnings already, collect them if any */ - /* FIXME we only want this if the statement succeeds I think */ if (!disable_ps_warnings) run_query_stmt_handle_warnings(mysql, ds); /* - No need to call mysql_stmt_bind_param() because we have no + No need to call mysql_stmt_bind_param() because we have no parameter markers. To optimize performance we use a global 'stmt' that is initiated @@ -3401,24 +3393,13 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) prepared statement. */ - if ((got_error_on_execute= mysql_stmt_execute(stmt)) != 0) /* 0 == Success */ + if (mysql_stmt_execute(stmt) != 0) /* 0 == Success */ { - if (q->abort_on_error) - { - /* We got an error, unexpected */ - die("unable to execute statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, mysql_stmt_error(stmt), - mysql_stmt_errno(stmt), got_error_on_execute); - } - else - { - /* We got an error, maybe expected */ - error= handle_error(query, q, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), - ds); - goto end; - } + /* We got an error, maybe expected */ + if (handle_error(query, q, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds)) + error= 1; + goto end; } /* @@ -3428,11 +3409,10 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) */ { my_bool one= 1; - if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, - (void*) &one) != 0) + if ((err= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, + (void*) &one)) != 0) die("unable to set stmt attribute " - "'STMT_ATTR_UPDATE_MAX_LENGTH': %s (returned=%d)", - query, err); + "'STMT_ATTR_UPDATE_MAX_LENGTH' err: %d", err); } /* @@ -3441,22 +3421,11 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) */ if ((err= mysql_stmt_store_result(stmt)) != 0) { - if (q->abort_on_error) - { - /* We got an error, unexpected */ - die("unable to execute statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, mysql_stmt_error(stmt), - mysql_stmt_errno(stmt), got_error_on_execute); - } - else - { - /* We got an error, maybe expected */ - error= handle_error(query, q, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), - ds); - goto end; - } + /* We got an error, maybe expected */ + if(handle_error(query, q, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds)) + error = 1; + goto end; } /* If we got here the statement was both executed and read succeesfully */ @@ -3480,8 +3449,6 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) MYSQL_FIELD *field= mysql_fetch_fields(res); uint num_fields= mysql_num_fields(res); - /* FIXME check error from the above? */ - if (display_metadata) run_query_display_metadata(field, num_fields, ds); @@ -3634,9 +3601,6 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) mysql_free_result(res); /* Free normal result set with meta data */ last_result= 0; /* FIXME have no idea what this is about... */ - if (err >= 1) - mysql_error(mysql); /* FIXME strange, has no effect... */ - end: free_replace(); last_result=0; @@ -3727,8 +3691,8 @@ static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds) { MYSQL_RES *warn_res= mysql_store_result(mysql); if (!warn_res) - verbose_msg("Warning count is %u but didn't get any warnings", - count); + die("Warning count is %u but didn't get any warnings", + count); else { dynstr_append_mem(ds, "Warnings:\n", 10); diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index c643a5ae647..36618140306 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -134,7 +134,6 @@ select 1146 as "after_!errno_masked_error" ; after_!errno_masked_error 1146 mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1000... -mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1000... garbage ; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 select 1064 as "after_--enable_abort_on_error" ; @@ -143,7 +142,6 @@ after_--enable_abort_on_error select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1064... -mysqltest: At line 1: query 'select 3 from t1' failed: 1146: Table 'test.t1' doesn't exist hello hello ;;;;;;;; diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 0efd5ac1566..f2c3e617144 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1057,42 +1057,64 @@ create table t1 (s1 int)// create procedure f1 () begin select sql_cache * from t1; select sql_cache * from t1; +select sql_cache * from t1; +end;// +create procedure f2 () begin +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +end;// +create procedure f3 () begin +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +end;// +create procedure f4 () begin +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +select sql_cache * from t1 where s1=1; end;// call f1(); s1 -show status like "Qcache_queries_in_cache"; -Variable_name Value -Qcache_queries_in_cache 1 -show status like "Qcache_inserts"; -Variable_name Value -Qcache_inserts 1 -show status like "Qcache_hits"; -Variable_name Value -Qcache_hits 1 -call f1(); +s1 s1 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 1 +Qcache_queries_in_cache 3 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 1 +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +call f1(); +s1 +s1 +s1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 3 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 show status like "Qcache_hits"; Variable_name Value Qcache_hits 3 call f1(); s1 +s1 +s1 select sql_cache * from t1; s1 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 2 +Qcache_queries_in_cache 4 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 2 +Qcache_inserts 4 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 5 +Qcache_hits 6 insert into t1 values (1); select sql_cache * from t1; s1 @@ -1102,28 +1124,150 @@ Variable_name Value Qcache_queries_in_cache 1 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 3 +Qcache_inserts 5 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 5 +Qcache_hits 6 call f1(); s1 1 +s1 +1 +s1 +1 call f1(); s1 1 +s1 +1 +s1 +1 select sql_cache * from t1; s1 1 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 2 +Qcache_queries_in_cache 4 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 4 +Qcache_inserts 8 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 9 +Qcache_hits 10 +flush query cache; +reset query cache; +flush status; +select sql_cache * from t1; +s1 +1 +select sql_cache * from t1 where s1=1; +s1 +1 +call f1(); +s1 +1 +s1 +1 +s1 +1 +call f2(); +s1 +1 +s1 +1 +call f3(); +s1 +1 +s1 +1 +call f4(); +s1 +1 +s1 +1 +s1 +1 +s1 +1 +s1 +1 +call f4(); +s1 +1 +s1 +1 +s1 +1 +s1 +1 +s1 +1 +call f3(); +s1 +1 +s1 +1 +call f2(); +s1 +1 +s1 +1 +select sql_cache * from t1 where s1=1; +s1 +1 +insert into t1 values (2); +call f1(); +s1 +1 +2 +s1 +1 +2 +s1 +1 +2 +select sql_cache * from t1 where s1=1; +s1 +1 +select sql_cache * from t1; +s1 +1 +2 +call f1(); +s1 +1 +2 +s1 +1 +2 +s1 +1 +2 +call f3(); +s1 +1 +2 +s1 +1 +call f3(); +s1 +1 +2 +s1 +1 +call f1(); +s1 +1 +2 +s1 +1 +2 +s1 +1 +2 drop procedure f1; +drop procedure f2; +drop procedure f3; +drop procedure f4; drop table t1; set GLOBAL query_cache_size=0; diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 17a2050437f..05b6a2788ea 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -692,6 +692,7 @@ END P1| call SP001(); TEMP_SUM 0 +ERROR 24000: Cursor is not open drop procedure SP001; drop table t1, t2; drop function if exists bug11394| diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 822c27fe40d..c21d6c46b6c 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -776,6 +776,7 @@ delimiter ;// # # query in QC from normal execution and SP (BUG#6897) +# improved to also test BUG#3583 and BUG#12990 # flush query cache; reset query cache; @@ -785,6 +786,22 @@ create table t1 (s1 int)// create procedure f1 () begin select sql_cache * from t1; select sql_cache * from t1; +select sql_cache * from t1; +end;// +create procedure f2 () begin +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +end;// +create procedure f3 () begin +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +end;// +create procedure f4 () begin +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +select sql_cache * from t1 where s1=1; end;// delimiter ;// call f1(); @@ -811,7 +828,32 @@ select sql_cache * from t1; show status like "Qcache_queries_in_cache"; show status like "Qcache_inserts"; show status like "Qcache_hits"; +flush query cache; +reset query cache; +flush status; +select sql_cache * from t1; +select sql_cache * from t1 where s1=1; +call f1(); +call f2(); +call f3(); +call f4(); +call f4(); +call f3(); +call f2(); +select sql_cache * from t1 where s1=1; +insert into t1 values (2); +call f1(); +select sql_cache * from t1 where s1=1; +select sql_cache * from t1; +call f1(); +call f3(); +call f3(); +call f1(); + drop procedure f1; +drop procedure f2; +drop procedure f3; +drop procedure f4; drop table t1; set GLOBAL query_cache_size=0; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 40f59f3f124..fa74c318db3 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -991,6 +991,7 @@ P1: BEGIN SELECT 'end of proc'; END P1| delimiter ;| +--error 1326 call SP001(); drop procedure SP001; drop table t1, t2; @@ -1187,7 +1188,30 @@ delimiter ;| create trigger bug12712 before insert on t1 for each row set session autocommit = 0; - +# +# BUG#9367: Stored procedures: client hang after "show warnings" +# +--disable_parsing +--disable_warnings +drop procedure if exists bug9367; +--enable_warnings +create table t1 (s1 int); +select s1 from t1; +delimiter |; +create procedure bug9367() +begin + declare v int; + declare c cursor for select s1 from t1; + open c; + show warnings; + fetch c into v; + select v; +end| +delimiter ;| +call bug9367(); +drop procedure bug9367; +drop table t1; +--enable_parsing # # BUG#NNNN: New bug synopsis # diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7a3c5547232..b15b1682d69 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -544,6 +544,7 @@ struct Query_cache_query_flags unsigned int client_long_flag:1; unsigned int client_protocol_41:1; unsigned int more_results_exists:1; + unsigned int pkt_nr; uint character_set_client_num; uint character_set_results_num; uint collation_connection_num; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 492d9b99d88..1ca9db44cc7 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -801,6 +801,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) CLIENT_PROTOCOL_41); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); + flags.pkt_nr= net->pkt_nr; flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= @@ -814,12 +815,13 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) flags.sql_mode= thd->variables.sql_mode; flags.max_sort_length= thd->variables.max_sort_length; flags.group_concat_max_len= thd->variables.group_concat_max_len; - DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, \ + DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \ CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", (int)flags.client_long_flag, (int)flags.client_protocol_41, (int)flags.more_results_exists, + flags.pkt_nr, flags.character_set_client_num, flags.character_set_results_num, flags.collation_connection_num, @@ -1019,6 +1021,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) CLIENT_PROTOCOL_41); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); + flags.pkt_nr= thd->net.pkt_nr; flags.character_set_client_num= thd->variables.character_set_client->number; flags.character_set_results_num= (thd->variables.character_set_results ? @@ -1030,12 +1033,13 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) flags.sql_mode= thd->variables.sql_mode; flags.max_sort_length= thd->variables.max_sort_length; flags.group_concat_max_len= thd->variables.group_concat_max_len; - DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, \ + DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \ CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \ sql mode: 0x%lx, sort len: %lu, conncat len: %lu", (int)flags.client_long_flag, (int)flags.client_protocol_41, (int)flags.more_results_exists, + flags.pkt_nr, flags.character_set_client_num, flags.character_set_results_num, flags.collation_connection_num, diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 69ccbe690db..e8fb8d9ce16 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -440,7 +440,8 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db); error= 0; - send_ok(thd); + if (!silent) + send_ok(thd); goto exit; } else