diff options
author | unknown <kostja@bodhi.(none)> | 2007-12-15 16:59:43 +0300 |
---|---|---|
committer | unknown <kostja@bodhi.(none)> | 2007-12-15 16:59:43 +0300 |
commit | cb48c979e506b1df3e314745bb5974e1b6cfeb41 (patch) | |
tree | 478d4e5aed82ca23a53a9264eb04f9131c5a43f9 | |
parent | cfd4951d1f33334b529dbb1ca0b1a1bed28cfbb3 (diff) | |
parent | 0a578711a2e44dcb6bfe6c1491b3b8e799ae13b8 (diff) | |
download | mariadb-git-cb48c979e506b1df3e314745bb5974e1b6cfeb41.tar.gz |
Merge bk-internal.mysql.com:/home/bk/mysql-5.1
into bodhi.(none):/opt/local/work/mysql-5.1-runtime
sql/ha_ndbcluster.cc:
Auto merged
sql/ha_ndbcluster_binlog.cc:
Auto merged
sql/mysqld.cc:
Auto merged
72 files changed, 5593 insertions, 632 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c index 18212430147..e0662fc2251 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -8018,7 +8018,6 @@ REPLACE *init_replace(char * *from, char * *to,uint count, if (!len) { errno=EINVAL; - my_message(0,"No to-string for last from-string",MYF(ME_BELL)); DBUG_RETURN(0); } states+=len+1; diff --git a/include/mysql_com.h b/include/mysql_com.h index aef7c7c0584..7eefad44716 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -203,14 +203,10 @@ typedef struct st_net { unsigned int *return_status; unsigned char reading_or_writing; char save_char; - my_bool no_send_ok; /* For SPs and other things that do multiple stmts */ + my_bool unused0; /* Please remove with the next incompatible ABI change. */ my_bool unused; /* Please remove with the next incompatible ABI change */ my_bool compress; - /* - Set if OK packet is already sent, and we do not need to send error - messages - */ - my_bool no_send_error; + my_bool unused1; /* Please remove with the next incompatible ABI change. */ /* Pointer to query object in query cache, do not equal NULL (0) for queries in cache that have not stored its results yet @@ -221,11 +217,14 @@ typedef struct st_net { functions and methods to maintain proper locking. */ unsigned char *query_cache_query; - unsigned int last_errno; - unsigned char error; - my_bool report_error; /* We should report error (we have unreported error) */ + unsigned int client_last_errno; + unsigned char error; + my_bool unused2; /* Please remove with the next incompatible ABI change. */ my_bool return_errno; - char last_error[MYSQL_ERRMSG_SIZE], sqlstate[SQLSTATE_LENGTH+1]; + /** Client library error message buffer. Actually belongs to struct MYSQL. */ + char client_last_error[MYSQL_ERRMSG_SIZE]; + /** Client library sqlstate buffer. Set along with the error message. */ + char sqlstate[SQLSTATE_LENGTH+1]; void *extension; } NET; diff --git a/include/mysql_h.ic b/include/mysql_h.ic index 4bedb9e8050..4f138d9a229 100644 --- a/include/mysql_h.ic +++ b/include/mysql_h.ic @@ -537,16 +537,16 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned unsigned int * return_status; unsigned char reading_or_writing; char save_char; - my_bool no_send_ok; + my_bool unused0; my_bool unused; my_bool compress; - my_bool no_send_error; + my_bool unused1; unsigned char * query_cache_query; - unsigned int last_errno; + unsigned int client_last_errno; unsigned char error; - my_bool report_error; + my_bool unused2; my_bool return_errno; - char last_error[512]; + char client_last_error[512]; char sqlstate[(5 + 1)]; void * extension; }; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index bf5dd7d63eb..f5ac1c09248 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -440,11 +440,11 @@ static void expand_error(MYSQL* mysql, int error) char tmp[MYSQL_ERRMSG_SIZE]; char *p; uint err_length; - strmake(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE-1); - p = strmake(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE-1); - err_length= (uint) (p - mysql->net.last_error); + strmake(tmp, mysql->net.client_last_error, MYSQL_ERRMSG_SIZE-1); + p = strmake(mysql->net.client_last_error, ER(error), MYSQL_ERRMSG_SIZE-1); + err_length= (uint) (p - mysql->net.client_last_error); strmake(p, tmp, MYSQL_ERRMSG_SIZE-1 - err_length); - mysql->net.last_errno = error; + mysql->net.client_last_errno = error; } /* @@ -870,9 +870,10 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename) VOID(my_net_write(net,(const uchar*) "",0)); /* Server needs one packet */ net_flush(net); strmov(net->sqlstate, unknown_sqlstate); - net->last_errno= (*options->local_infile_error)(li_ptr, - net->last_error, - sizeof(net->last_error)-1); + net->client_last_errno= + (*options->local_infile_error)(li_ptr, + net->client_last_error, + sizeof(net->client_last_error)-1); goto err; } @@ -899,9 +900,10 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename) if (readcount < 0) { - net->last_errno= (*options->local_infile_error)(li_ptr, - net->last_error, - sizeof(net->last_error)-1); + net->client_last_errno= + (*options->local_infile_error)(li_ptr, + net->client_last_error, + sizeof(net->client_last_error)-1); goto err; } @@ -1395,7 +1397,7 @@ const char *cli_read_statistics(MYSQL *mysql) if (!mysql->net.read_pos[0]) { set_mysql_error(mysql, CR_WRONG_HOST_INFO, unknown_sqlstate); - return mysql->net.last_error; + return mysql->net.client_last_error; } return (char*) mysql->net.read_pos; } @@ -1406,7 +1408,7 @@ mysql_stat(MYSQL *mysql) { DBUG_ENTER("mysql_stat"); if (simple_command(mysql,COM_STATISTICS,0,0,0)) - DBUG_RETURN(mysql->net.last_error); + DBUG_RETURN(mysql->net.client_last_error); DBUG_RETURN((*mysql->methods->read_statistics)(mysql)); } @@ -1771,7 +1773,7 @@ static my_bool my_realloc_str(NET *net, ulong length) if (res) { strmov(net->sqlstate, unknown_sqlstate); - strmov(net->last_error, ER(net->last_errno)); + strmov(net->client_last_error, ER(net->client_last_errno)); } net->write_pos= net->buff+ buf_length; } @@ -1822,13 +1824,15 @@ void set_stmt_error(MYSQL_STMT * stmt, int errcode, void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net) { DBUG_ENTER("set_stmt_errmsg"); - DBUG_PRINT("enter", ("error: %d/%s '%s'", net->last_errno, net->sqlstate, - net->last_error)); + DBUG_PRINT("enter", ("error: %d/%s '%s'", + net->client_last_errno, + net->sqlstate, + net->client_last_error)); DBUG_ASSERT(stmt != 0); - stmt->last_errno= net->last_errno; - if (net->last_error && net->last_error[0]) - strmov(stmt->last_error, net->last_error); + stmt->last_errno= net->client_last_errno; + if (net->client_last_error && net->client_last_error[0]) + strmov(stmt->last_error, net->client_last_error); strmov(stmt->sqlstate, net->sqlstate); DBUG_VOID_RETURN; diff --git a/libmysql/manager.c b/libmysql/manager.c index 53ffffa55c0..27d35758f3e 100644 --- a/libmysql/manager.c +++ b/libmysql/manager.c @@ -160,7 +160,7 @@ MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con, msg_len=strlen(msg_buf); if (my_net_write(&con->net,(uchar*) msg_buf,msg_len) || net_flush(&con->net)) { - con->last_errno=con->net.last_errno; + con->last_errno=con->net.client_last_errno; strmov(con->last_error,"Write error on socket"); goto err; } diff --git a/libmysqld/emb_qcache.cc b/libmysqld/emb_qcache.cc index 6693627e05e..fdd7f8ed776 100644 --- a/libmysqld/emb_qcache.cc +++ b/libmysqld/emb_qcache.cc @@ -482,7 +482,7 @@ int emb_load_querycache_result(THD *thd, Querycache_stream *src) *prev_row= NULL; data->embedded_info->prev_ptr= prev_row; return_ok: - send_eof(thd); + net_send_eof(thd, thd->server_status, thd->total_warn_count); DBUG_RETURN(0); err: DBUG_RETURN(1); diff --git a/libmysqld/emb_qcache.h b/libmysqld/emb_qcache.h index a303273f7de..67413739f2c 100644 --- a/libmysqld/emb_qcache.h +++ b/libmysqld/emb_qcache.h @@ -79,3 +79,4 @@ public: uint emb_count_querycache_size(THD *thd); int emb_load_querycache_result(THD *thd, Querycache_stream *src); void emb_store_querycache_result(Querycache_stream *dst, THD* thd); +void net_send_eof(THD *thd, uint server_status, uint total_warn_count); diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 2c4f49050b2..b467345b5d5 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -61,8 +61,8 @@ void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data) { NET *net= &mysql->net; struct embedded_query_result *ei= data->embedded_info; - net->last_errno= ei->last_errno; - strmake(net->last_error, ei->info, sizeof(net->last_error)); + net->client_last_errno= ei->last_errno; + strmake(net->client_last_error, ei->info, sizeof(net->client_last_error)-1); memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate)); mysql->server_status= ei->server_status; my_free(data, MYF(0)); @@ -88,6 +88,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, /* Clear result variables */ thd->clear_error(); + thd->main_da.reset_diagnostics_area(); mysql->affected_rows= ~(my_ulonglong) 0; mysql->field_count= 0; net_clear_error(net); @@ -111,12 +112,11 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, arg_length= header_length; } - thd->net.no_send_error= 0; result= dispatch_command(command, thd, (char *) arg, arg_length); thd->cur_data= 0; if (!skip_check) - result= thd->net.last_errno ? -1 : 0; + result= thd->is_error() ? -1 : 0; return result; } @@ -373,7 +373,7 @@ static void emb_free_embedded_thd(MYSQL *mysql) static const char * emb_read_statistics(MYSQL *mysql) { THD *thd= (THD*)mysql->thd; - return thd->net.last_error; + return thd->is_error() ? thd->main_da.message() : ""; } @@ -628,6 +628,7 @@ int check_embedded_connection(MYSQL *mysql, const char *db) strmake(sctx->priv_host, (char*) my_localhost, MAX_HOSTNAME-1); sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0)); result= check_user(thd, COM_CONNECT, NULL, 0, db, true); + net_end_statement(thd); emb_read_query_result(mysql); return result; } @@ -677,8 +678,10 @@ int check_embedded_connection(MYSQL *mysql, const char *db) err: { NET *net= &mysql->net; - memcpy(net->last_error, thd->net.last_error, sizeof(net->last_error)); - memcpy(net->sqlstate, thd->net.sqlstate, sizeof(net->sqlstate)); + strmake(net->client_last_error, thd->main_da.message(), sizeof(net->client_last_error)-1); + memcpy(net->sqlstate, + mysql_errno_to_sqlstate(thd->main_da.sql_errno()), + sizeof(net->sqlstate)-1); } return result; } @@ -701,9 +704,8 @@ void THD::clear_data_list() void THD::clear_error() { - net.last_error[0]= 0; - net.last_errno= 0; - net.report_error= 0; + if (main_da.is_error()) + main_da.reset_diagnostics_area(); } static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length, @@ -766,20 +768,18 @@ MYSQL_DATA *THD::alloc_new_dataset() } -/* - stores server_status and warning_count in the current - query result structures - - SYNOPSIS - write_eof_packet() - thd current thread +/** + Stores server_status and warning_count in the current + query result structures. - NOTES - should be called to after we get the recordset-result + @param thd current thread + @note Should be called after we get the recordset-result. */ -static void write_eof_packet(THD *thd) +static +void +write_eof_packet(THD *thd, uint server_status, uint total_warn_count) { if (!thd->mysql) // bootstrap file handling return; @@ -790,13 +790,13 @@ static void write_eof_packet(THD *thd) */ if (thd->is_fatal_error) thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; - thd->cur_data->embedded_info->server_status= thd->server_status; + thd->cur_data->embedded_info->server_status= server_status; /* Don't send warn count during SP execution, as the warn_list is cleared between substatements, and mysqltest gets confused */ thd->cur_data->embedded_info->warning_count= - (thd->spcont ? 0 : min(thd->total_warn_count, 65535)); + (thd->spcont ? 0 : min(total_warn_count, 65535)); } @@ -952,7 +952,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) } if (flags & SEND_EOF) - write_eof_packet(thd); + write_eof_packet(thd, thd->server_status, thd->total_warn_count); DBUG_RETURN(prepare_for_send(list)); err: @@ -992,17 +992,35 @@ bool Protocol_binary::write() return false; } + +/** + Embedded library implementation of OK response. + + This function is used by the server to write 'OK' packet to + the "network" when the server is compiled as an embedded library. + Since there is no network in the embedded configuration, + a different implementation is necessary. + Instead of marshalling response parameters to a network representation + and then writing it to the socket, here we simply copy the data to the + corresponding client-side connection structures. + + @sa Server implementation of net_send_ok in protocol.cc for + description of the arguments. + + @return The function does not return errors. +*/ + void -send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message) +net_send_ok(THD *thd, + uint server_status, uint total_warn_count, + ha_rows affected_rows, ulonglong id, const char *message) { - DBUG_ENTER("send_ok"); + DBUG_ENTER("emb_net_send_ok"); MYSQL_DATA *data; MYSQL *mysql= thd->mysql; - + if (!mysql) // bootstrap file handling DBUG_VOID_RETURN; - if (thd->net.no_send_ok) // hack for re-parsing queries - DBUG_VOID_RETURN; if (!(data= thd->alloc_new_dataset())) return; data->embedded_info->affected_rows= affected_rows; @@ -1011,15 +1029,24 @@ send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message) strmake(data->embedded_info->info, message, sizeof(data->embedded_info->info)-1); - write_eof_packet(thd); + write_eof_packet(thd, server_status, total_warn_count); thd->cur_data= 0; DBUG_VOID_RETURN; } + +/** + Embedded library implementation of EOF response. + + @sa net_send_ok + + @return This function does not return errors. +*/ + void -send_eof(THD *thd) +net_send_eof(THD *thd, uint server_status, uint total_warn_count) { - write_eof_packet(thd); + write_eof_packet(thd, server_status, total_warn_count); thd->cur_data= 0; } diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index eb47a045669..a8542f6fca9 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -209,8 +209,9 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, DBUG_RETURN(mysql); error: - DBUG_PRINT("error",("message: %u (%s)", mysql->net.last_errno, - mysql->net.last_error)); + DBUG_PRINT("error",("message: %u (%s)", + mysql->net.client_last_errno, + mysql->net.client_last_error)); { /* Free alloced memory */ my_bool free_me=mysql->free_me; diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index bd6dd4cf6cf..73598fc1bac 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -304,6 +304,7 @@ sub mtr_report_stats ($) { /Slave: Error .*Unknown table/ or /Slave: Error in Write_rows event: / or /Slave: Field .* of table .* has no default value/ or + /Slave: Field .* doesn't have a default value/ or /Slave: Query caused different errors on master and slave/ or /Slave: Table .* doesn't exist/ or /Slave: Table width mismatch/ or diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result index d1ee6d1c5a1..7b68914e219 100644 --- a/mysql-test/r/events.result +++ b/mysql-test/r/events.result @@ -403,9 +403,10 @@ ERROR 42S02: Table 'mysql.event' doesn't exist DROP DATABASE IF EXISTS mysqltest_no_such_database; Warnings: Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist -Error 1146 Table 'mysql.event' doesn't exist CREATE DATABASE mysqltest_db2; DROP DATABASE mysqltest_db2; +Warnings: +Error 1146 Table 'mysql.event' doesn't exist OK, there is an unnecessary warning about the non-existent table but it's not easy to fix and no one complained about it. A similar warning is printed if mysql.proc is missing. diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index c46f29b787f..0df3ac6de8a 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1269,9 +1269,7 @@ use test; FLUSH PRIVILEGES without procs_priv table. RENAME TABLE mysql.procs_priv TO mysql.procs_gone; FLUSH PRIVILEGES; -Warnings: -Error 1146 Table 'mysql.procs_priv' doesn't exist -Error 1548 Cannot load from mysql.mysql.procs_priv. The table is probably corrupted +ERROR 42S02: Table 'mysql.procs_priv' doesn't exist Assigning privileges without procs_priv table. CREATE DATABASE mysqltest1; CREATE PROCEDURE mysqltest1.test() SQL SECURITY DEFINER diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index 4a0f70a7b88..9c4f1b17dcc 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -113,4 +113,34 @@ handler t1 open; ERROR HY000: Table storage engine for 't1' doesn't have this option --> client 1 drop table t1; +drop table if exists t1; +create table t1 (i int); +connection: default +lock tables t1 write; +connection: flush +flush tables with read lock;; +connection: default +alter table t1 add column j int; +connection: insert +insert into t1 values (1,2);; +connection: default +unlock tables; +connection: flush +select * from t1; +i j +unlock tables; +select * from t1; +i j +1 2 +drop table t1; +drop table if exists t1; +create table t1 (i int); +connection: default +lock tables t1 write; +connection: flush +flush tables with read lock;; +connection: default +flush tables; +unlock tables; +drop table t1; End of 5.1 tests diff --git a/mysql-test/r/no-threads.result b/mysql-test/r/no-threads.result index aefecd0f7bc..9bc2dad6e2a 100644 --- a/mysql-test/r/no-threads.result +++ b/mysql-test/r/no-threads.result @@ -7,3 +7,7 @@ select 1+2; SHOW GLOBAL VARIABLES LIKE 'thread_handling'; Variable_name Value thread_handling no-threads +select @@session.thread_handling; +ERROR HY000: Variable 'thread_handling' is a GLOBAL variable +set GLOBAL thread_handling='one-thread'; +ERROR HY000: Variable 'thread_handling' is a read only variable diff --git a/mysql-test/r/ps_ddl.result b/mysql-test/r/ps_ddl.result new file mode 100644 index 00000000000..0987e765265 --- /dev/null +++ b/mysql-test/r/ps_ddl.result @@ -0,0 +1,2329 @@ +===================================================================== +Testing 1: NOTHING -> TABLE transitions +===================================================================== +drop table if exists t1; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +prepare stmt from 'select * from t1'; +ERROR 42S02: Table 'test.t1' doesn't exist +===================================================================== +Testing 2: NOTHING -> TEMPORARY TABLE transitions +===================================================================== +===================================================================== +Testing 3: NOTHING -> VIEW transitions +===================================================================== +===================================================================== +Testing 4: TABLE -> NOTHING transitions +===================================================================== +drop table if exists t4; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t4(a int); +prepare stmt from 'select * from t4'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t4; +execute stmt; +ERROR 42S02: Table 'test.t4' doesn't exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ERROR 42S02: Table 'test.t4' doesn't exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +===================================================================== +Testing 5: TABLE -> TABLE (DDL) transitions +===================================================================== +drop table if exists t5; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t5(a int); +prepare stmt from 'select * from t5'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +alter table t5 add column (b int); +execute stmt; +a b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +drop table t5; +===================================================================== +Testing 6: TABLE -> TABLE (TRIGGER) transitions +===================================================================== +drop table if exists t6; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t6(a int); +prepare stmt from 'insert into t6(a) value (?)'; +set @val=1; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +set @val=2; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +create trigger t6_bi before insert on t6 for each row +begin +set @message= "t6_bi"; +end +$$ +set @message="none"; +set @val=3; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +select @message; +@message +t6_bi +set @val=4; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +select @message; +@message +t6_bi +prepare stmt from 'insert into t6(a) value (?)'; +set @message="none"; +set @val=5; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +select @message; +@message +t6_bi +set @message="none"; +set @val=6; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +select @message; +@message +t6_bi +create trigger t6_bd before delete on t6 for each row +begin +set @message= "t6_bd"; +end +$$ +set @message="none"; +set @val=7; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +select @message; +@message +t6_bi +set @message="none"; +set @val=8; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +select @message; +@message +t6_bi +prepare stmt from 'insert into t6(a) value (?)'; +set @message="none"; +set @val=9; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +select @message; +@message +t6_bi +set @message="none"; +set @val=10; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +select @message; +@message +t6_bi +drop trigger t6_bi; +create trigger t6_bi before insert on t6 for each row +begin +set @message= "t6_bi (2)"; +end +$$ +set @message="none"; +set @val=11; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +t6_bi (2) +set @val=12; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +t6_bi (2) +prepare stmt from 'insert into t6(a) value (?)'; +set @message="none"; +set @val=13; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +t6_bi (2) +set @message="none"; +set @val=14; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +t6_bi (2) +drop trigger t6_bd; +create trigger t6_bd before delete on t6 for each row +begin +set @message= "t6_bd (2)"; +end +$$ +set @message="none"; +set @val=15; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +t6_bi (2) +set @message="none"; +set @val=16; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +t6_bi (2) +prepare stmt from 'insert into t6(a) value (?)'; +set @message="none"; +set @val=17; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +t6_bi (2) +set @message="none"; +set @val=18; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +t6_bi (2) +drop trigger t6_bi; +set @message="none"; +set @val=19; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +none +set @val=20; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +none +prepare stmt from 'insert into t6(a) value (?)'; +set @message="none"; +set @val=21; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +none +set @val=22; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +none +drop trigger t6_bd; +set @val=23; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +none +set @val=24; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +select @message; +@message +none +select * from t6 order by a; +a +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +drop table t6; +===================================================================== +Testing 7: TABLE -> TABLE (TRIGGER dependencies) transitions +===================================================================== +drop table if exists t7_proc; +drop table if exists t7_func; +drop table if exists t7_view; +drop table if exists t7_table; +drop table if exists t7_dependent_table; +drop table if exists t7_table_trigger; +drop table if exists t7_audit; +drop procedure if exists audit_proc; +drop function if exists audit_func; +drop view if exists audit_view; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t7_proc(a int); +create table t7_func(a int); +create table t7_view(a int); +create table t7_table(a int); +create table t7_table_trigger(a int); +create table t7_audit(old_a int, new_a int, reason varchar(50)); +create table t7_dependent_table(old_a int, new_a int, reason varchar(50)); +create procedure audit_proc(a int) +insert into t7_audit values (NULL, a, "proc v1"); +create function audit_func() returns varchar(50) +return "func v1"; +create view audit_view as select "view v1" as reason from dual; +create trigger t7_proc_bi before insert on t7_proc for each row +call audit_proc(NEW.a); +create trigger t7_func_bi before insert on t7_func for each row +insert into t7_audit values (NULL, NEW.a, audit_func()); +create trigger t7_view_bi before insert on t7_view for each row +insert into t7_audit values (NULL, NEW.a, (select reason from audit_view)); +create trigger t7_table_bi before insert on t7_table for each row +insert into t7_dependent_table values (NULL, NEW.a, "dependent table"); +create trigger t7_table_trigger_bi before insert on t7_dependent_table +for each row set NEW.reason="trigger v1"; +prepare stmt_proc from 'insert into t7_proc(a) value (?)'; +set @val=101; +execute stmt_proc using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +set @val=102; +execute stmt_proc using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop procedure audit_proc; +create procedure audit_proc(a int) +insert into t7_audit values (NULL, a, "proc v2"); +set @val=103; +execute stmt_proc using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +set @val=104; +execute stmt_proc using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +prepare stmt_func from 'insert into t7_func(a) value (?)'; +set @val=201; +execute stmt_func using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +set @val=202; +execute stmt_func using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop function audit_func; +create function audit_func() returns varchar(50) +return "func v2"; +set @val=203; +execute stmt_func using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +set @val=204; +execute stmt_func using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +prepare stmt_view from 'insert into t7_view(a) value (?)'; +set @val=301; +execute stmt_view using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +set @val=302; +execute stmt_view using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop view audit_view; +create view audit_view as select "view v2" as reason from dual; +set @val=303; +execute stmt_view using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +set @val=304; +execute stmt_view using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +prepare stmt_table from 'insert into t7_table(a) value (?)'; +set @val=401; +execute stmt_table using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +set @val=402; +execute stmt_table using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +alter table t7_dependent_table add column comments varchar(100) default NULL; +set @val=403; +execute stmt_table using @val; +ERROR 21S01: Column count doesn't match value count at row 1 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +set @val=404; +execute stmt_table using @val; +ERROR 21S01: Column count doesn't match value count at row 1 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +alter table t7_dependent_table drop column comments; +set @val=405; +execute stmt_table using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +3 +set @val=406; +execute stmt_table using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +3 +prepare stmt_table_trigger from 'insert into t7_table(a) value (?)'; +set @val=501; +execute stmt_table_trigger using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +3 +set @val=502; +execute stmt_table_trigger using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +3 +drop trigger t7_table_trigger_bi; +create trigger t7_table_trigger_bi before insert on t7_dependent_table +for each row set NEW.reason="trigger v2"; +set @val=503; +execute stmt_table_trigger using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +4 +set @val=504; +execute stmt_table_trigger using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +4 +select * from t7_audit order by new_a; +old_a new_a reason +NULL 101 proc v1 +NULL 102 proc v1 +NULL 103 proc v2 +NULL 104 proc v2 +NULL 201 func v1 +NULL 202 func v1 +NULL 203 func v2 +NULL 204 func v2 +NULL 301 view v1 +NULL 302 view v1 +NULL 303 view v1 +NULL 304 view v1 +select * from t7_dependent_table order by new_a; +old_a new_a reason +NULL 401 trigger v1 +NULL 402 trigger v1 +NULL 405 trigger v1 +NULL 406 trigger v1 +NULL 501 trigger v1 +NULL 502 trigger v1 +NULL 503 trigger v2 +NULL 504 trigger v2 +drop table t7_proc; +drop table t7_func; +drop table t7_view; +drop table t7_table; +drop table t7_dependent_table; +drop table t7_table_trigger; +drop table t7_audit; +drop procedure audit_proc; +drop function audit_func; +drop view audit_view; +===================================================================== +Testing 8: TABLE -> TEMPORARY TABLE transitions +===================================================================== +drop table if exists t8; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t8(a int); +prepare stmt from 'select * from t8'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t8; +create temporary table t8(a int); +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +drop table t8; +===================================================================== +Testing 9: TABLE -> VIEW transitions +===================================================================== +drop table if exists t9; +drop table if exists t9_b; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t9(a int); +create table t9_b(a int); +prepare stmt from 'select * from t9'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t9; +create view t9 as select * from t9_b; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +drop view t9; +drop table t9_b; +===================================================================== +Testing 10: TEMPORARY TABLE -> NOTHING transitions +===================================================================== +drop temporary table if exists t10; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create temporary table t10(a int); +prepare stmt from 'select * from t10'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop temporary table t10; +execute stmt; +ERROR 42S02: Table 'test.t10' doesn't exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ERROR 42S02: Table 'test.t10' doesn't exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +===================================================================== +Testing 11: TEMPORARY TABLE -> TABLE transitions +===================================================================== +drop table if exists t11; +drop temporary table if exists t11; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t11(a int); +insert into t11(a) value (1); +create temporary table t11(a int); +prepare stmt from 'select * from t11'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop temporary table t11; +execute stmt; +a +1 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a +1 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +select * from t11; +a +1 +drop table t11; +===================================================================== +Testing 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) transitions +===================================================================== +drop temporary table if exists t12; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create temporary table t12(a int); +prepare stmt from 'select * from t12'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop temporary table t12; +create temporary table t12(a int, b int); +execute stmt; +a b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +select * from t12; +a b +drop table t12; +===================================================================== +Testing 13: TEMPORARY TABLE -> VIEW transitions +===================================================================== +drop temporary table if exists t13; +drop table if exists t13_b; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create temporary table t13(a int); +create table t13_b(a int); +prepare stmt from 'select * from t13'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop temporary table t13; +create view t13 as select * from t13_b; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +drop view t13; +drop table t13_b; +===================================================================== +Testing 14: VIEW -> NOTHING transitions +===================================================================== +drop view if exists t14; +drop table if exists t14_b; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t14_b(a int); +create view t14 as select * from t14_b; +prepare stmt from 'select * from t14'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop view t14; +execute stmt; +ERROR 42S02: Table 'test.t14' doesn't exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +ERROR 42S02: Table 'test.t14' doesn't exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +drop table t14_b; +===================================================================== +Testing 15: VIEW -> TABLE transitions +===================================================================== +drop view if exists t15; +drop table if exists t15_b; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t15_b(a int); +create view t15 as select * from t15_b; +prepare stmt from 'select * from t15'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop view t15; +create table t15(a int); +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +drop table t15_b; +drop table t15; +===================================================================== +Testing 16: VIEW -> TEMPORARY TABLE transitions +===================================================================== +drop view if exists t16; +drop table if exists t16_b; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t16_b(a int); +create view t16 as select * from t16_b; +prepare stmt from 'select * from t16'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop view t16; +create temporary table t16(a int); +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +drop table t16_b; +drop temporary table t16; +===================================================================== +Testing 17: VIEW -> VIEW (DDL) transitions +===================================================================== +drop view if exists t17; +drop table if exists t17_b; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t17_b(a int); +insert into t17_b values (10), (20), (30); +create view t17 as select a, 2*a as b, 3*a as c from t17_b; +select * from t17; +a b c +10 20 30 +20 40 60 +30 60 90 +prepare stmt from 'select * from t17'; +execute stmt; +a b c +10 20 30 +20 40 60 +30 60 90 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a b c +10 20 30 +20 40 60 +30 60 90 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop view t17; +create view t17 as select a, 2*a as b, 10*a as c from t17_b; +select * from t17; +a b c +10 20 100 +20 40 200 +30 60 300 +execute stmt; +a b c +10 20 100 +20 40 200 +30 60 300 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a b c +10 20 100 +20 40 200 +30 60 300 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +drop table t17_b; +drop view t17; +===================================================================== +Testing 18: VIEW -> VIEW (VIEW dependencies) transitions +===================================================================== +drop table if exists t18; +drop table if exists t18_dependent_table; +drop view if exists t18_func; +drop view if exists t18_view; +drop view if exists t18_table; +drop function if exists view_func; +drop view if exists view_view; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t18(a int); +insert into t18 values (1), (2), (3); +create function view_func(x int) returns int +return x+1; +create view view_view as select "view v1" as reason from dual; +create table t18_dependent_table(a int); +create view t18_func as select a, view_func(a) as b from t18; +create view t18_view as select a, reason as b from t18, view_view; +create view t18_table as select * from t18; +prepare stmt_func from 'select * from t18_func'; +execute stmt_func; +a b +1 2 +2 3 +3 4 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt_func; +a b +1 2 +2 3 +3 4 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop function view_func; +create function view_func(x int) returns int +return x*x; +execute stmt_func; +a b +1 1 +2 4 +3 9 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt_func; +a b +1 1 +2 4 +3 9 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +prepare stmt_view from 'select * from t18_view'; +execute stmt_view; +a b +1 view v1 +2 view v1 +3 view v1 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt_view; +a b +1 view v1 +2 view v1 +3 view v1 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop view view_view; +create view view_view as select "view v2" as reason from dual; +execute stmt_view; +a b +1 view v2 +2 view v2 +3 view v2 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt_view; +a b +1 view v2 +2 view v2 +3 view v2 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +prepare stmt_table from 'select * from t18_table'; +execute stmt_table; +a +1 +2 +3 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt_table; +a +1 +2 +3 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +alter table t18 add column comments varchar(50) default NULL; +execute stmt_table; +a +1 +2 +3 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +execute stmt_table; +a +1 +2 +3 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +drop table t18; +drop table t18_dependent_table; +drop view t18_func; +drop view t18_view; +drop view t18_table; +drop function view_func; +drop view view_view; +===================================================================== +Testing 19: Special tables (INFORMATION_SCHEMA) +===================================================================== +drop procedure if exists proc_19; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +prepare stmt from +'select ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE + from INFORMATION_SCHEMA.ROUTINES where + routine_name=\'proc_19\''; +create procedure proc_19() select "hi there"; +execute stmt; +ROUTINE_SCHEMA ROUTINE_NAME ROUTINE_TYPE +test proc_19 PROCEDURE +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ROUTINE_SCHEMA ROUTINE_NAME ROUTINE_TYPE +test proc_19 PROCEDURE +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop procedure proc_19; +create procedure proc_19() select "hi there, again"; +execute stmt; +ROUTINE_SCHEMA ROUTINE_NAME ROUTINE_TYPE +test proc_19 PROCEDURE +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ROUTINE_SCHEMA ROUTINE_NAME ROUTINE_TYPE +test proc_19 PROCEDURE +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop procedure proc_19; +===================================================================== +Testing 20: Special tables (log tables) +===================================================================== +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +prepare stmt from +'select * from mysql.general_log where argument=\'IMPOSSIBLE QUERY STRING\''; +execute stmt; +event_time user_host thread_id server_id command_type argument +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +event_time user_host thread_id server_id command_type argument +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +event_time user_host thread_id server_id command_type argument +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +event_time user_host thread_id server_id command_type argument +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +===================================================================== +Testing 21: Special tables (system tables) +===================================================================== +drop procedure if exists proc_21; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +prepare stmt from +'select type, db, name from mysql.proc where name=\'proc_21\''; +create procedure proc_21() select "hi there"; +execute stmt; +type db name +PROCEDURE test proc_21 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +type db name +PROCEDURE test proc_21 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop procedure proc_21; +create procedure proc_21() select "hi there, again"; +execute stmt; +type db name +PROCEDURE test proc_21 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +type db name +PROCEDURE test proc_21 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop procedure proc_21; +===================================================================== +Testing 22: Special tables (views temp tables) +===================================================================== +drop table if exists t22_b; +drop view if exists t22; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t22_b(a int); +create algorithm=temptable view t22 as select a*a as a2 from t22_b; +show create view t22; +View Create View character_set_client collation_connection +t22 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `t22` AS select (`t22_b`.`a` * `t22_b`.`a`) AS `a2` from `t22_b` latin1 latin1_swedish_ci +prepare stmt from 'select * from t22'; +insert into t22_b values (1), (2), (3); +execute stmt; +a2 +1 +4 +9 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a2 +1 +4 +9 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +insert into t22_b values (4), (5), (6); +execute stmt; +a2 +1 +4 +9 +16 +25 +36 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a2 +1 +4 +9 +16 +25 +36 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t22_b; +drop view t22; +===================================================================== +Testing 23: Special tables (internal join tables) +===================================================================== +drop table if exists t23_a; +drop table if exists t23_b; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t23_a(a int); +create table t23_b(b int); +prepare stmt from 'select * from t23_a join t23_b'; +insert into t23_a values (1), (2), (3); +insert into t23_b values (10), (20), (30); +execute stmt; +a b +1 10 +2 10 +3 10 +1 20 +2 20 +3 20 +1 30 +2 30 +3 30 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a b +1 10 +2 10 +3 10 +1 20 +2 20 +3 20 +1 30 +2 30 +3 30 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +insert into t23_a values (4); +insert into t23_b values (40); +execute stmt; +a b +1 10 +2 10 +3 10 +4 10 +1 20 +2 20 +3 20 +4 20 +1 30 +2 30 +3 30 +4 30 +1 40 +2 40 +3 40 +4 40 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a b +1 10 +2 10 +3 10 +4 10 +1 20 +2 20 +3 20 +4 20 +1 30 +2 30 +3 30 +4 30 +1 40 +2 40 +3 40 +4 40 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t23_a; +drop table t23_b; +===================================================================== +Testing 24: Special statements +===================================================================== +drop table if exists t24_alter; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t24_alter(a int); +prepare stmt from 'alter table t24_alter add column b int'; +execute stmt; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t24_alter; +create table t24_alter(a1 int, a2 int); +execute stmt; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +alter table t24_alter drop column b; +execute stmt; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +alter table t24_alter drop column b; +execute stmt; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t24_alter; +drop table if exists t24_repair; +create table t24_repair(a int); +insert into t24_repair values (1), (2), (3); +prepare stmt from 'repair table t24_repair'; +execute stmt; +Table Op Msg_type Msg_text +test.t24_repair repair status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t24_repair; +create table t24_repair(a1 int, a2 int); +insert into t24_repair values (1, 10), (2, 20), (3, 30); +execute stmt; +Table Op Msg_type Msg_text +test.t24_repair repair status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +alter table t24_repair add column b varchar(50) default NULL; +execute stmt; +Table Op Msg_type Msg_text +test.t24_repair repair status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +alter table t24_repair drop column b; +execute stmt; +Table Op Msg_type Msg_text +test.t24_repair repair status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t24_repair; +drop table if exists t24_analyze; +create table t24_analyze(a int); +insert into t24_analyze values (1), (2), (3); +prepare stmt from 'analyze table t24_analyze'; +execute stmt; +Table Op Msg_type Msg_text +test.t24_analyze analyze status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t24_analyze; +create table t24_analyze(a1 int, a2 int); +insert into t24_analyze values (1, 10), (2, 20), (3, 30); +execute stmt; +Table Op Msg_type Msg_text +test.t24_analyze analyze status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +alter table t24_analyze add column b varchar(50) default NULL; +execute stmt; +Table Op Msg_type Msg_text +test.t24_analyze analyze status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +alter table t24_analyze drop column b; +execute stmt; +Table Op Msg_type Msg_text +test.t24_analyze analyze status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t24_analyze; +drop table if exists t24_optimize; +create table t24_optimize(a int); +insert into t24_optimize values (1), (2), (3); +prepare stmt from 'optimize table t24_optimize'; +execute stmt; +Table Op Msg_type Msg_text +test.t24_optimize optimize status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t24_optimize; +create table t24_optimize(a1 int, a2 int); +insert into t24_optimize values (1, 10), (2, 20), (3, 30); +execute stmt; +Table Op Msg_type Msg_text +test.t24_optimize optimize status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +alter table t24_optimize add column b varchar(50) default NULL; +execute stmt; +Table Op Msg_type Msg_text +test.t24_optimize optimize status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +alter table t24_optimize drop column b; +execute stmt; +Table Op Msg_type Msg_text +test.t24_optimize optimize status OK +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t24_optimize; +drop procedure if exists changing_proc; +prepare stmt from 'show create procedure changing_proc'; +execute stmt; +ERROR 42000: PROCEDURE changing_proc does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ERROR 42000: PROCEDURE changing_proc does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +create procedure changing_proc() begin end; +execute stmt; +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +changing_proc CREATE DEFINER=`root`@`localhost` PROCEDURE `changing_proc`() +begin end latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +changing_proc CREATE DEFINER=`root`@`localhost` PROCEDURE `changing_proc`() +begin end latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop procedure changing_proc; +create procedure changing_proc(x int, y int) begin end; +execute stmt; +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +changing_proc CREATE DEFINER=`root`@`localhost` PROCEDURE `changing_proc`(x int, y int) +begin end latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation +changing_proc CREATE DEFINER=`root`@`localhost` PROCEDURE `changing_proc`(x int, y int) +begin end latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop procedure changing_proc; +execute stmt; +ERROR 42000: PROCEDURE changing_proc does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ERROR 42000: PROCEDURE changing_proc does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop function if exists changing_func; +prepare stmt from 'show create function changing_func'; +execute stmt; +ERROR 42000: FUNCTION changing_func does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ERROR 42000: FUNCTION changing_func does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +create function changing_func() returns int return 0; +execute stmt; +Function sql_mode Create Function character_set_client collation_connection Database Collation +changing_func CREATE DEFINER=`root`@`localhost` FUNCTION `changing_func`() RETURNS int(11) +return 0 latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +Function sql_mode Create Function character_set_client collation_connection Database Collation +changing_func CREATE DEFINER=`root`@`localhost` FUNCTION `changing_func`() RETURNS int(11) +return 0 latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop function changing_func; +create function changing_func(x int, y int) returns int return x+y; +execute stmt; +Function sql_mode Create Function character_set_client collation_connection Database Collation +changing_func CREATE DEFINER=`root`@`localhost` FUNCTION `changing_func`(x int, y int) RETURNS int(11) +return x+y latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +Function sql_mode Create Function character_set_client collation_connection Database Collation +changing_func CREATE DEFINER=`root`@`localhost` FUNCTION `changing_func`(x int, y int) RETURNS int(11) +return x+y latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop function changing_func; +execute stmt; +ERROR 42000: FUNCTION changing_func does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ERROR 42000: FUNCTION changing_func does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table if exists t24_trigger; +create table t24_trigger(a int); +prepare stmt from 'show create trigger t24_bi;'; +execute stmt; +ERROR HY000: Trigger does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ERROR HY000: Trigger does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +create trigger t24_bi before insert on t24_trigger for each row +begin +set @message= "t24_bi"; +end +$$ +execute stmt; +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +t24_bi CREATE DEFINER=`root`@`localhost` trigger t24_bi before insert on t24_trigger for each row +begin +set @message= "t24_bi"; +end latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +t24_bi CREATE DEFINER=`root`@`localhost` trigger t24_bi before insert on t24_trigger for each row +begin +set @message= "t24_bi"; +end latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop trigger t24_bi; +create trigger t24_bi before insert on t24_trigger for each row +begin +set @message= "t24_bi (2)"; +end +$$ +execute stmt; +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +t24_bi CREATE DEFINER=`root`@`localhost` trigger t24_bi before insert on t24_trigger for each row +begin +set @message= "t24_bi (2)"; +end latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +t24_bi CREATE DEFINER=`root`@`localhost` trigger t24_bi before insert on t24_trigger for each row +begin +set @message= "t24_bi (2)"; +end latin1 latin1_swedish_ci latin1_swedish_ci +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop trigger t24_bi; +execute stmt; +ERROR HY000: Trigger does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ERROR HY000: Trigger does not exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t24_trigger; +===================================================================== +Testing 25: Testing the strength of TABLE_SHARE version +===================================================================== +drop table if exists t25_num_col; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t25_num_col(a int); +prepare stmt from 'select * from t25_num_col'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +alter table t25_num_col add column b varchar(50) default NULL; +execute stmt; +a b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +drop table t25_num_col; +drop table if exists t25_col_name; +create table t25_col_name(a int); +prepare stmt from 'select * from t25_col_name'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +alter table t25_col_name change a b int; +execute stmt; +b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +execute stmt; +b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +drop table t25_col_name; +drop table if exists t25_col_type; +create table t25_col_type(a int); +prepare stmt from 'select * from t25_col_type'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +alter table t25_col_type change a a varchar(10); +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +3 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +3 +drop table t25_col_type; +drop table if exists t25_col_type_length; +create table t25_col_type_length(a varchar(10)); +prepare stmt from 'select * from t25_col_type_length'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +3 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +3 +alter table t25_col_type_length change a a varchar(20); +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +4 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +4 +drop table t25_col_type_length; +drop table if exists t25_col_null; +create table t25_col_null(a varchar(10)); +prepare stmt from 'select * from t25_col_null'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +4 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +4 +alter table t25_col_null change a a varchar(10) NOT NULL; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +5 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +5 +drop table t25_col_null; +drop table if exists t25_col_default; +create table t25_col_default(a int, b int DEFAULT 10); +prepare stmt from 'insert into t25_col_default(a) values (?)'; +set @val=1; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +5 +set @val=2; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +5 +alter table t25_col_default change b b int DEFAULT 20; +set @val=3; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +5 +set @val=4; +execute stmt using @val; +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +5 +select * from t25_col_default; +a b +1 10 +2 10 +3 20 +4 20 +drop table t25_col_default; +drop table if exists t25_index; +create table t25_index(a varchar(10)); +prepare stmt from 'select * from t25_index'; +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +5 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +5 +create index i1 on t25_index(a); +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +6 +execute stmt; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +6 +drop table t25_index; +drop table if exists t25_index_unique; +create table t25_index_unique(a varchar(10), b varchar(10)); +create index i1 on t25_index_unique(a, b); +show create table t25_index_unique; +Table Create Table +t25_index_unique CREATE TABLE `t25_index_unique` ( + `a` varchar(10) DEFAULT NULL, + `b` varchar(10) DEFAULT NULL, + KEY `i1` (`a`,`b`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +prepare stmt from 'select * from t25_index_unique'; +execute stmt; +a b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +6 +execute stmt; +a b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +6 +alter table t25_index_unique drop index i1; +create unique index i1 on t25_index_unique(a, b); +show create table t25_index_unique; +Table Create Table +t25_index_unique CREATE TABLE `t25_index_unique` ( + `a` varchar(10) DEFAULT NULL, + `b` varchar(10) DEFAULT NULL, + UNIQUE KEY `i1` (`a`,`b`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +execute stmt; +a b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +7 +execute stmt; +a b +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +7 +drop table t25_index_unique; +===================================================================== +Testing reported bugs +===================================================================== +drop table if exists table_12093; +drop function if exists func_12093; +drop function if exists func_12093_unrelated; +drop procedure if exists proc_12093; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table table_12093(a int); +create function func_12093() +returns int +begin +return (select count(*) from table_12093); +end// +create procedure proc_12093(a int) +begin +select * from table_12093; +end// +create function func_12093_unrelated() returns int return 2; +create procedure proc_12093_unrelated() begin end; +prepare stmt_sf from 'select func_12093();'; +prepare stmt_sp from 'call proc_12093(func_12093())'; +execute stmt_sf; +func_12093() +0 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt_sp; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop function func_12093_unrelated; +drop procedure proc_12093_unrelated; +execute stmt_sf; +func_12093() +0 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt_sp; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt_sf; +func_12093() +0 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt_sp; +a +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +deallocate prepare stmt_sf; +deallocate prepare stmt_sp; +drop table table_12093; +drop function func_12093; +drop procedure proc_12093; +drop function if exists func_21294; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create function func_21294() returns int return 10; +prepare stmt from "select func_21294()"; +execute stmt; +func_21294() +10 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop function func_21294; +create function func_21294() returns int return 10; +execute stmt; +func_21294() +10 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop function func_21294; +create function func_21294() returns int return 20; +execute stmt; +func_21294() +20 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +deallocate prepare stmt; +drop function func_21294; +drop table if exists t_27420_100; +drop table if exists t_27420_101; +drop view if exists v_27420; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t_27420_100(a int); +insert into t_27420_100 values (1), (2); +create table t_27420_101(a int); +insert into t_27420_101 values (1), (2); +create view v_27420 as select t_27420_100.a X, t_27420_101.a Y +from t_27420_100, t_27420_101 +where t_27420_100.a=t_27420_101.a; +prepare stmt from 'select * from v_27420'; +execute stmt; +X Y +1 1 +2 2 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop view v_27420; +create table v_27420(X int, Y int); +execute stmt; +X Y +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +drop table v_27420; +create table v_27420 (a int, b int, filler char(200)); +execute stmt; +a b filler +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +2 +deallocate prepare stmt; +drop table t_27420_100; +drop table t_27420_101; +drop table v_27420; +drop table if exists t_27430_1; +drop table if exists t_27430_2; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t_27430_1 (a int not null, oref int not null, key(a)); +insert into t_27430_1 values +(1, 1), +(1, 1234), +(2, 3), +(2, 1234), +(3, 1234); +create table t_27430_2 (a int not null, oref int not null); +insert into t_27430_2 values +(1, 1), +(2, 2), +(1234, 3), +(1234, 4); +prepare stmt from +'select oref, a, a in (select a from t_27430_1 where oref=t_27430_2.oref) Z from t_27430_2'; +execute stmt; +oref a Z +1 1 1 +2 2 0 +3 1234 0 +4 1234 0 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +oref a Z +1 1 1 +2 2 0 +3 1234 0 +4 1234 0 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table t_27430_1, t_27430_2; +create table t_27430_1 (a int, oref int, key(a)); +insert into t_27430_1 values +(1, 1), +(1, NULL), +(2, 3), +(2, NULL), +(3, NULL); +create table t_27430_2 (a int, oref int); +insert into t_27430_2 values +(1, 1), +(2,2), +(NULL, 3), +(NULL, 4); +execute stmt; +oref a Z +1 1 1 +2 2 0 +3 NULL NULL +4 NULL 0 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +oref a Z +1 1 1 +2 2 0 +3 NULL NULL +4 NULL 0 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +deallocate prepare stmt; +drop table t_27430_1; +drop table t_27430_2; +drop table if exists t_27690_1; +drop view if exists v_27690_1; +drop table if exists v_27690_2; +SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; +create table t_27690_1 (a int, b int); +insert into t_27690_1 values (1,1),(2,2); +create table v_27690_1 as select * from t_27690_1; +create table v_27690_2 as select * from t_27690_1; +prepare stmt from 'select * from v_27690_1, v_27690_2'; +execute stmt; +a b a b +1 1 1 1 +2 2 1 1 +1 1 2 2 +2 2 2 2 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +a b a b +1 1 1 1 +2 2 1 1 +1 1 2 2 +2 2 2 2 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +drop table v_27690_1; +execute stmt; +ERROR 42S02: Table 'test.v_27690_1' doesn't exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +execute stmt; +ERROR 42S02: Table 'test.v_27690_1' doesn't exist +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +0 +create view v_27690_1 as select A.a, A.b from t_27690_1 A, t_27690_1 B; +execute stmt; +a b a b +1 1 1 1 +2 2 1 1 +1 1 1 1 +2 2 1 1 +1 1 2 2 +2 2 2 2 +1 1 2 2 +2 2 2 2 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +execute stmt; +a b a b +1 1 1 1 +2 2 1 1 +1 1 1 1 +2 2 1 1 +1 1 2 2 +2 2 2 2 +1 1 2 2 +2 2 2 2 +SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; +REPREPARED +1 +deallocate prepare stmt; +drop table t_27690_1; +drop view v_27690_1; +drop table v_27690_2; diff --git a/mysql-test/r/read_only.result b/mysql-test/r/read_only.result index f270f1ed5ad..cf81566f4e5 100644 --- a/mysql-test/r/read_only.result +++ b/mysql-test/r/read_only.result @@ -97,3 +97,31 @@ Note 1051 Unknown table 'ttt' set global read_only=0; drop table t1,t2; drop user test@localhost; +# +# Bug #27440 read_only allows create and drop database +# +set global read_only= 1; +drop database if exists mysqltest_db1; +drop database if exists mysqltest_db2; +delete from mysql.user where User like 'mysqltest_%'; +delete from mysql.db where User like 'mysqltest_%'; +delete from mysql.tables_priv where User like 'mysqltest_%'; +delete from mysql.columns_priv where User like 'mysqltest_%'; +flush privileges; +grant all on mysqltest_db2.* to `mysqltest_u1`@`%`; +create database mysqltest_db1; +grant all on mysqltest_db1.* to `mysqltest_u1`@`%`; +flush privileges; +create database mysqltest_db2; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +show databases like '%mysqltest_db2%'; +Database (%mysqltest_db2%) +drop database mysqltest_db1; +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +delete from mysql.user where User like 'mysqltest_%'; +delete from mysql.db where User like 'mysqltest_%'; +delete from mysql.tables_priv where User like 'mysqltest_%'; +delete from mysql.columns_priv where User like 'mysqltest_%'; +flush privileges; +drop database mysqltest_db1; +set global read_only=0; diff --git a/mysql-test/r/trigger_notembedded.result b/mysql-test/r/trigger_notembedded.result index d56f83993a6..87e8f68da38 100644 --- a/mysql-test/r/trigger_notembedded.result +++ b/mysql-test/r/trigger_notembedded.result @@ -448,4 +448,18 @@ DROP TABLE t1; DROP DATABASE mysqltest_db1; USE test; End of 5.0 tests. +drop table if exists t1; +create table t1 (i int); +connection: default +lock tables t1 write; +connection: flush +flush tables with read lock;; +connection: default +create trigger t1_bi before insert on t1 for each row begin end; +unlock tables; +connection: flush +unlock tables; +select * from t1; +i +drop table t1; End of 5.1 tests. diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result index 06dc90f18aa..a8e1c8602e0 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result @@ -123,7 +123,7 @@ Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno 1364 -Last_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. +Last_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. Field 'x' doesn't have a default value Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -141,7 +141,7 @@ Master_SSL_Verify_Server_Cert No Last_IO_Errno 0 Last_IO_Error Last_SQL_Errno 1364 -Last_SQL_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. +Last_SQL_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. Field 'x' doesn't have a default value SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; INSERT INTO t9 VALUES (2); diff --git a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result index 3911fe89b7f..12203379269 100644 --- a/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result @@ -123,7 +123,7 @@ Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno 1364 -Last_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. +Last_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. Field 'x' doesn't have a default value Skip_Counter 0 Exec_Master_Log_Pos # Relay_Log_Space # @@ -141,7 +141,7 @@ Master_SSL_Verify_Server_Cert No Last_IO_Errno 0 Last_IO_Error Last_SQL_Errno 1364 -Last_SQL_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. +Last_SQL_Error Error in Write_rows event: error during transaction execution on table test.t1_nodef. Field 'x' doesn't have a default value SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; INSERT INTO t9 VALUES (2); diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 2c16017241c..3f9ec52ca36 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -20,6 +20,6 @@ lowercase_table3 : Bug#32667 lowercase_table3.test reports to error log kill : Bug#29149: Test "kill" fails on Windows innodb_mysql : Bug#32724: innodb_mysql.test fails randomly wait_timeout : Bug#32801 wait_timeout.test fails randomly -kill : Bug#29149 Test "kill" fails on Windows ctype_create : Bug#32965 main.ctype_create fails status : Bug#32966 main.status fails +ps_ddl : Bug#12093 2007-12-14 pending WL#4165 / WL#4166 diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index d9ee38d0c14..16cccd1a1f4 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -1362,6 +1362,7 @@ use test; # --echo FLUSH PRIVILEGES without procs_priv table. RENAME TABLE mysql.procs_priv TO mysql.procs_gone; +--error ER_NO_SUCH_TABLE FLUSH PRIVILEGES; --echo Assigning privileges without procs_priv table. CREATE DATABASE mysqltest1; diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index b2266c9bff1..0d36b79df78 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -150,7 +150,7 @@ send SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; connection locker; let $wait_condition= select count(*) = 1 from information_schema.processlist - where state = "Locked" and info = + where state = "Waiting for table" and info = "SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1"; --source include/wait_condition.inc # Make test case independent from earlier grants. @@ -343,4 +343,100 @@ handler t1 open; connection default; drop table t1; +# +# Bug#32395 Alter table under a impending global read lock causes a server crash +# + +# +# Test ALTER TABLE under LOCK TABLES and FLUSH TABLES WITH READ LOCK +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (i int); +connect (flush,localhost,root,,test,,); +connection default; +--echo connection: default +lock tables t1 write; +connection flush; +--echo connection: flush +--send flush tables with read lock; +connection default; +--echo connection: default +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Flushing tables"; +--source include/wait_condition.inc +alter table t1 add column j int; +connect (insert,localhost,root,,test,,); +connection insert; +--echo connection: insert +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Flushing tables"; +--source include/wait_condition.inc +--send insert into t1 values (1,2); +--echo connection: default +connection default; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for release of readlock"; +--source include/wait_condition.inc +unlock tables; +connection flush; +--echo connection: flush +--reap +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for release of readlock"; +--source include/wait_condition.inc +select * from t1; +unlock tables; +connection insert; +--reap +connection default; +select * from t1; +drop table t1; +disconnect flush; +disconnect insert; + +# +# Test that FLUSH TABLES under LOCK TABLES protects write locked tables +# from a impending FLUSH TABLES WITH READ LOCK +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (i int); +connect (flush,localhost,root,,test,,); +connection default; +--echo connection: default +lock tables t1 write; +connection flush; +--echo connection: flush +--send flush tables with read lock; +connection default; +--echo connection: default +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Flushing tables"; +--source include/wait_condition.inc +flush tables; +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Flushing tables"; +--source include/wait_condition.inc +unlock tables; +let $wait_condition= + select count(*) = 0 from information_schema.processlist + where state = "Flushing tables"; +--source include/wait_condition.inc +connection flush; +--reap +connection default; +disconnect flush; +drop table t1; + --echo End of 5.1 tests diff --git a/mysql-test/t/no-threads.test b/mysql-test/t/no-threads.test index 31ea6406ee9..fd8365e5678 100644 --- a/mysql-test/t/no-threads.test +++ b/mysql-test/t/no-threads.test @@ -4,3 +4,13 @@ select 1+1; select 1+2; SHOW GLOBAL VARIABLES LIKE 'thread_handling'; + +# +# Bug #30651 Problems with thread_handling system variable +# + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.thread_handling; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set GLOBAL thread_handling='one-thread'; diff --git a/mysql-test/t/ps_ddl.test b/mysql-test/t/ps_ddl.test new file mode 100644 index 00000000000..abb6563f052 --- /dev/null +++ b/mysql-test/t/ps_ddl.test @@ -0,0 +1,1851 @@ +# +# Testing the behavior of 'PREPARE', 'DDL', 'EXECUTE' scenarios +# +# Background: +# In a statement like "select * from t1", t1 can be: +# - nothing (the table does not exist) +# - a real table +# - a temporary table +# - a view +# +# Changing the nature of "t1" between a PREPARE and an EXECUTE +# can invalidate the internal state of a prepared statement, so that, +# during the execute, the server should: +# - detect state changes and fail to execute a statement, +# instead of crashing the server or returning wrong results +# - "RE-PREPARE" the statement to restore a valid internal state. +# +# Also, changing the physical structure of "t1", by: +# - changing the definition of t1 itself (DDL on tables, views) +# - changing TRIGGERs associated with a table +# - changing PROCEDURE, FUNCTION referenced by a TRIGGER body, +# - changing PROCEDURE, FUNCTION referenced by a VIEW body, +# impacts the internal structure of a prepared statement, and should +# cause the same verifications at execute time to be performed. +# +# This test provided in this file cover the different state transitions +# between a PREPARE and an EXECUTE, and are organized as follows: +# - Part 1: NOTHING -> TABLE +# - Part 2: NOTHING -> TEMPORARY TABLE +# - Part 3: NOTHING -> VIEW +# - Part 4: TABLE -> NOTHING +# - Part 5: TABLE -> TABLE (DDL) +# - Part 6: TABLE -> TABLE (TRIGGER) +# - Part 7: TABLE -> TABLE (TRIGGER dependencies) +# - Part 8: TABLE -> TEMPORARY TABLE +# - Part 9: TABLE -> VIEW +# - Part 10: TEMPORARY TABLE -> NOTHING +# - Part 11: TEMPORARY TABLE -> TABLE +# - Part 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) +# - Part 13: TEMPORARY TABLE -> VIEW +# - Part 14: VIEW -> NOTHING +# - Part 15: VIEW -> TABLE +# - Part 16: VIEW -> TEMPORARY TABLE +# - Part 17: VIEW -> VIEW (DDL) +# - Part 18: VIEW -> VIEW (VIEW dependencies) +# - Part 19: Special tables (INFORMATION_SCHEMA) +# - Part 20: Special tables (log tables) +# - Part 21: Special tables (system tables) +# - Part 22: Special tables (views temp tables) +# - Part 23: Special tables (internal join tables) +# - Part 24: Special statements +# - Part 25: Testing the strength of TABLE_SHARE version + +let $base_count = SELECT VARIABLE_VALUE from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' +into @base_count ; + +let $reprepared = SELECT VARIABLE_VALUE - @base_count AS REPREPARED from +INFORMATION_SCHEMA.SESSION_STATUS where variable_name='COM_STMT_REPREPARE' ; + +--echo ===================================================================== +--echo Testing 1: NOTHING -> TABLE transitions +--echo ===================================================================== + +--disable_warnings +drop table if exists t1; +--enable_warnings + +eval $base_count; + +# can not be tested since prepare failed +--error ER_NO_SUCH_TABLE +prepare stmt from 'select * from t1'; + +--echo ===================================================================== +--echo Testing 2: NOTHING -> TEMPORARY TABLE transitions +--echo ===================================================================== + +# can not be tested + +--echo ===================================================================== +--echo Testing 3: NOTHING -> VIEW transitions +--echo ===================================================================== + +# can not be tested + +--echo ===================================================================== +--echo Testing 4: TABLE -> NOTHING transitions +--echo ===================================================================== + +--disable_warnings +drop table if exists t4; +--enable_warnings + +eval $base_count; + +create table t4(a int); + +prepare stmt from 'select * from t4'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t4; +--error ER_NO_SUCH_TABLE +execute stmt; +eval $reprepared; +--error ER_NO_SUCH_TABLE +execute stmt; +eval $reprepared; + +--echo ===================================================================== +--echo Testing 5: TABLE -> TABLE (DDL) transitions +--echo ===================================================================== + +--disable_warnings +drop table if exists t5; +--enable_warnings + +eval $base_count; + +create table t5(a int); + +prepare stmt from 'select * from t5'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +alter table t5 add column (b int); + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t5; + +--echo ===================================================================== +--echo Testing 6: TABLE -> TABLE (TRIGGER) transitions +--echo ===================================================================== + +# +# Test 6-a: adding a relevant trigger +# Test 6-b: adding an irrelevant trigger +# Test 6-c: changing a relevant trigger +# Test 6-d: changing an irrelevant trigger +# Test 6-e: removing a relevant trigger +# Test 6-f: removing an irrelevant trigger +# + +--disable_warnings +drop table if exists t6; +--enable_warnings + +eval $base_count; + +create table t6(a int); + +prepare stmt from 'insert into t6(a) value (?)'; +set @val=1; +execute stmt using @val; +eval $reprepared; +set @val=2; +execute stmt using @val; +eval $reprepared; + +# Relevant trigger: execute should reprepare +delimiter $$; +create trigger t6_bi before insert on t6 for each row + begin + set @message= "t6_bi"; + end +$$ +delimiter ;$$ + +set @message="none"; +set @val=3; +# REPREPARED +1 +execute stmt using @val; +eval $reprepared; +select @message; +set @val=4; +execute stmt using @val; +eval $reprepared; +select @message; + +prepare stmt from 'insert into t6(a) value (?)'; +set @message="none"; +set @val=5; +execute stmt using @val; +eval $reprepared; +select @message; +set @message="none"; +set @val=6; +execute stmt using @val; +eval $reprepared; +select @message; + +# Unrelated trigger: execute can pass of fail, implementation dependent +delimiter $$; +create trigger t6_bd before delete on t6 for each row + begin + set @message= "t6_bd"; + end +$$ +delimiter ;$$ + +set @message="none"; +set @val=7; +execute stmt using @val; +eval $reprepared; +select @message; +set @message="none"; +set @val=8; +execute stmt using @val; +eval $reprepared; +select @message; + +prepare stmt from 'insert into t6(a) value (?)'; +set @message="none"; +set @val=9; +execute stmt using @val; +eval $reprepared; +select @message; +set @message="none"; +set @val=10; +execute stmt using @val; +eval $reprepared; +select @message; + +# Relevant trigger: execute should reprepare +drop trigger t6_bi; +delimiter $$; +create trigger t6_bi before insert on t6 for each row + begin + set @message= "t6_bi (2)"; + end +$$ +delimiter ;$$ + +set @message="none"; +set @val=11; +# REPREPARED +1 +execute stmt using @val; +eval $reprepared; +select @message; +set @val=12; +execute stmt using @val; +eval $reprepared; +select @message; + +prepare stmt from 'insert into t6(a) value (?)'; +set @message="none"; +set @val=13; +execute stmt using @val; +eval $reprepared; +select @message; +set @message="none"; +set @val=14; +execute stmt using @val; +eval $reprepared; +select @message; + +# Unrelated trigger: execute can pass of fail, implementation dependent +drop trigger t6_bd; +delimiter $$; +create trigger t6_bd before delete on t6 for each row + begin + set @message= "t6_bd (2)"; + end +$$ +delimiter ;$$ + +set @message="none"; +set @val=15; +execute stmt using @val; +eval $reprepared; +select @message; +set @message="none"; +set @val=16; +execute stmt using @val; +eval $reprepared; +select @message; + +prepare stmt from 'insert into t6(a) value (?)'; +set @message="none"; +set @val=17; +execute stmt using @val; +eval $reprepared; +select @message; +set @message="none"; +set @val=18; +execute stmt using @val; +eval $reprepared; +select @message; + +drop trigger t6_bi; + +set @message="none"; +set @val=19; +# safe to re-execute +execute stmt using @val; +eval $reprepared; +select @message; +set @val=20; +# safe to re-execute +execute stmt using @val; +eval $reprepared; +select @message; + +prepare stmt from 'insert into t6(a) value (?)'; +set @message="none"; +set @val=21; +execute stmt using @val; +eval $reprepared; +select @message; +set @val=22; +execute stmt using @val; +eval $reprepared; +select @message; + +drop trigger t6_bd; + +set @val=23; +# safe to re-execute +execute stmt using @val; +eval $reprepared; +select @message; +set @val=24; +# safe to re-execute +execute stmt using @val; +eval $reprepared; +select @message; + +select * from t6 order by a; +drop table t6; + +--echo ===================================================================== +--echo Testing 7: TABLE -> TABLE (TRIGGER dependencies) transitions +--echo ===================================================================== + +# +# Test 7-a: dependent PROCEDURE has changed +# Test 7-b: dependent FUNCTION has changed +# Test 7-c: dependent VIEW has changed +# Test 7-d: dependent TABLE has changed +# Test 7-e: dependent TABLE TRIGGER has changed +# + +--disable_warnings +drop table if exists t7_proc; +drop table if exists t7_func; +drop table if exists t7_view; +drop table if exists t7_table; +drop table if exists t7_dependent_table; +drop table if exists t7_table_trigger; +drop table if exists t7_audit; +drop procedure if exists audit_proc; +drop function if exists audit_func; +drop view if exists audit_view; +--enable_warnings + +eval $base_count; + +create table t7_proc(a int); +create table t7_func(a int); +create table t7_view(a int); +create table t7_table(a int); +create table t7_table_trigger(a int); + +create table t7_audit(old_a int, new_a int, reason varchar(50)); +create table t7_dependent_table(old_a int, new_a int, reason varchar(50)); + +create procedure audit_proc(a int) + insert into t7_audit values (NULL, a, "proc v1"); + +create function audit_func() returns varchar(50) + return "func v1"; + +create view audit_view as select "view v1" as reason from dual; + +create trigger t7_proc_bi before insert on t7_proc for each row + call audit_proc(NEW.a); + +create trigger t7_func_bi before insert on t7_func for each row + insert into t7_audit values (NULL, NEW.a, audit_func()); + +create trigger t7_view_bi before insert on t7_view for each row + insert into t7_audit values (NULL, NEW.a, (select reason from audit_view)); + +create trigger t7_table_bi before insert on t7_table for each row + insert into t7_dependent_table values (NULL, NEW.a, "dependent table"); + +create trigger t7_table_trigger_bi before insert on t7_dependent_table + for each row set NEW.reason="trigger v1"; + +prepare stmt_proc from 'insert into t7_proc(a) value (?)'; +set @val=101; +execute stmt_proc using @val; +eval $reprepared; +set @val=102; +execute stmt_proc using @val; +eval $reprepared; + +drop procedure audit_proc; + +create procedure audit_proc(a int) + insert into t7_audit values (NULL, a, "proc v2"); + +set @val=103; +execute stmt_proc using @val; +eval $reprepared; +set @val=104; +execute stmt_proc using @val; +eval $reprepared; + + +prepare stmt_func from 'insert into t7_func(a) value (?)'; +set @val=201; +execute stmt_func using @val; +eval $reprepared; +set @val=202; +execute stmt_func using @val; +eval $reprepared; + +drop function audit_func; + +create function audit_func() returns varchar(50) + return "func v2"; + +set @val=203; +execute stmt_func using @val; +eval $reprepared; +set @val=204; +execute stmt_func using @val; +eval $reprepared; + +prepare stmt_view from 'insert into t7_view(a) value (?)'; +set @val=301; +execute stmt_view using @val; +eval $reprepared; +set @val=302; +execute stmt_view using @val; +eval $reprepared; + +drop view audit_view; + +create view audit_view as select "view v2" as reason from dual; + +# Because of Bug#33255, the wrong result is still produced for cases +# 303 and 304, even after re-preparing the statement. +# This is because the table trigger is cached and is not invalidated. + +set @val=303; +# REPREPARED +1 +execute stmt_view using @val; +eval $reprepared; +set @val=304; +execute stmt_view using @val; +eval $reprepared; + + +prepare stmt_table from 'insert into t7_table(a) value (?)'; +set @val=401; +execute stmt_table using @val; +eval $reprepared; +set @val=402; +execute stmt_table using @val; +eval $reprepared; + +alter table t7_dependent_table add column comments varchar(100) default NULL; + +set @val=403; +# REPREPARED +1 +--error ER_WRONG_VALUE_COUNT_ON_ROW +execute stmt_table using @val; +eval $reprepared; +set @val=404; +--error ER_WRONG_VALUE_COUNT_ON_ROW +execute stmt_table using @val; +eval $reprepared; + +alter table t7_dependent_table drop column comments; + +set @val=405; +# REPREPARED +1 +execute stmt_table using @val; +eval $reprepared; +set @val=406; +execute stmt_table using @val; +eval $reprepared; + + +prepare stmt_table_trigger from 'insert into t7_table(a) value (?)'; +set @val=501; +execute stmt_table_trigger using @val; +eval $reprepared; +set @val=502; +execute stmt_table_trigger using @val; +eval $reprepared; + +drop trigger t7_table_trigger_bi; + +create trigger t7_table_trigger_bi before insert on t7_dependent_table + for each row set NEW.reason="trigger v2"; + +set @val=503; +# REPREPARED +1 +execute stmt_table_trigger using @val; +eval $reprepared; +set @val=504; +execute stmt_table_trigger using @val; +eval $reprepared; + +select * from t7_audit order by new_a; + +select * from t7_dependent_table order by new_a; + +drop table t7_proc; +drop table t7_func; +drop table t7_view; +drop table t7_table; +drop table t7_dependent_table; +drop table t7_table_trigger; +drop table t7_audit; +drop procedure audit_proc; +drop function audit_func; +drop view audit_view; + +--echo ===================================================================== +--echo Testing 8: TABLE -> TEMPORARY TABLE transitions +--echo ===================================================================== + +--disable_warnings +drop table if exists t8; +--enable_warnings + +eval $base_count; + +create table t8(a int); + +prepare stmt from 'select * from t8'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t8; +create temporary table t8(a int); + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t8; + +--echo ===================================================================== +--echo Testing 9: TABLE -> VIEW transitions +--echo ===================================================================== + +--disable_warnings +drop table if exists t9; +drop table if exists t9_b; +--enable_warnings + +eval $base_count; + +create table t9(a int); +create table t9_b(a int); + +prepare stmt from 'select * from t9'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t9; +create view t9 as select * from t9_b; + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop view t9; +drop table t9_b; + +--echo ===================================================================== +--echo Testing 10: TEMPORARY TABLE -> NOTHING transitions +--echo ===================================================================== + +--disable_warnings +drop temporary table if exists t10; +--enable_warnings + +eval $base_count; + +create temporary table t10(a int); + +prepare stmt from 'select * from t10'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop temporary table t10; +--error ER_NO_SUCH_TABLE +execute stmt; +eval $reprepared; +--error ER_NO_SUCH_TABLE +execute stmt; +eval $reprepared; + +--echo ===================================================================== +--echo Testing 11: TEMPORARY TABLE -> TABLE transitions +--echo ===================================================================== + +--disable_warnings +drop table if exists t11; +drop temporary table if exists t11; +--enable_warnings + +eval $base_count; + +create table t11(a int); +insert into t11(a) value (1); +create temporary table t11(a int); + +prepare stmt from 'select * from t11'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop temporary table t11; + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +select * from t11; +drop table t11; + +--echo ===================================================================== +--echo Testing 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) transitions +--echo ===================================================================== + +--disable_warnings +drop temporary table if exists t12; +--enable_warnings + +eval $base_count; + +create temporary table t12(a int); + +prepare stmt from 'select * from t12'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop temporary table t12; +create temporary table t12(a int, b int); + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +select * from t12; +drop table t12; + +--echo ===================================================================== +--echo Testing 13: TEMPORARY TABLE -> VIEW transitions +--echo ===================================================================== + +--disable_warnings +drop temporary table if exists t13; +drop table if exists t13_b; +--enable_warnings + +eval $base_count; + +create temporary table t13(a int); +create table t13_b(a int); + +prepare stmt from 'select * from t13'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop temporary table t13; +create view t13 as select * from t13_b; + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop view t13; +drop table t13_b; + +--echo ===================================================================== +--echo Testing 14: VIEW -> NOTHING transitions +--echo ===================================================================== + +--disable_warnings +drop view if exists t14; +drop table if exists t14_b; +--enable_warnings + +eval $base_count; + +create table t14_b(a int); +create view t14 as select * from t14_b; + +prepare stmt from 'select * from t14'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop view t14; + +# REPREPARED +1 +--error ER_NO_SUCH_TABLE +execute stmt; +eval $reprepared; +--error ER_NO_SUCH_TABLE +execute stmt; +eval $reprepared; + +drop table t14_b; + +--echo ===================================================================== +--echo Testing 15: VIEW -> TABLE transitions +--echo ===================================================================== + +--disable_warnings +drop view if exists t15; +drop table if exists t15_b; +--enable_warnings + +eval $base_count; + +create table t15_b(a int); +create view t15 as select * from t15_b; + +prepare stmt from 'select * from t15'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop view t15; +create table t15(a int); + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t15_b; +drop table t15; + +--echo ===================================================================== +--echo Testing 16: VIEW -> TEMPORARY TABLE transitions +--echo ===================================================================== + +--disable_warnings +drop view if exists t16; +drop table if exists t16_b; +--enable_warnings + +eval $base_count; + +create table t16_b(a int); +create view t16 as select * from t16_b; + +prepare stmt from 'select * from t16'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop view t16; +create temporary table t16(a int); + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t16_b; +drop temporary table t16; + +--echo ===================================================================== +--echo Testing 17: VIEW -> VIEW (DDL) transitions +--echo ===================================================================== + +--disable_warnings +drop view if exists t17; +drop table if exists t17_b; +--enable_warnings + +eval $base_count; + +create table t17_b(a int); +insert into t17_b values (10), (20), (30); + +create view t17 as select a, 2*a as b, 3*a as c from t17_b; +select * from t17; + +prepare stmt from 'select * from t17'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop view t17; +create view t17 as select a, 2*a as b, 10*a as c from t17_b; +select * from t17; + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t17_b; +drop view t17; + +--echo ===================================================================== +--echo Testing 18: VIEW -> VIEW (VIEW dependencies) transitions +--echo ===================================================================== + +# +# Test 18-a: dependent PROCEDURE has changed (via a trigger) +# Test 18-b: dependent FUNCTION has changed +# Test 18-c: dependent VIEW has changed +# Test 18-d: dependent TABLE has changed +# Test 18-e: dependent TABLE TRIGGER has changed +# + +--disable_warnings +drop table if exists t18; +drop table if exists t18_dependent_table; +drop view if exists t18_func; +drop view if exists t18_view; +drop view if exists t18_table; +drop function if exists view_func; +drop view if exists view_view; +--enable_warnings + +eval $base_count; + +# TODO: insertable view -> trigger +# TODO: insertable view -> trigger -> proc ? + +create table t18(a int); +insert into t18 values (1), (2), (3); + +create function view_func(x int) returns int + return x+1; + +create view view_view as select "view v1" as reason from dual; + +create table t18_dependent_table(a int); + +create view t18_func as select a, view_func(a) as b from t18; +create view t18_view as select a, reason as b from t18, view_view; +create view t18_table as select * from t18; + +prepare stmt_func from 'select * from t18_func'; +execute stmt_func; +eval $reprepared; +execute stmt_func; +eval $reprepared; + +drop function view_func; +create function view_func(x int) returns int + return x*x; + +execute stmt_func; +eval $reprepared; +execute stmt_func; +eval $reprepared; + +prepare stmt_view from 'select * from t18_view'; +execute stmt_view; +eval $reprepared; +execute stmt_view; +eval $reprepared; + +drop view view_view; +create view view_view as select "view v2" as reason from dual; + +# REPREPARED +1 +execute stmt_view; +eval $reprepared; +execute stmt_view; +eval $reprepared; + +prepare stmt_table from 'select * from t18_table'; +execute stmt_table; +eval $reprepared; +execute stmt_table; +eval $reprepared; + +alter table t18 add column comments varchar(50) default NULL; + +# REPREPARED +1 +execute stmt_table; +eval $reprepared; +execute stmt_table; +eval $reprepared; + +drop table t18; +drop table t18_dependent_table; +drop view t18_func; +drop view t18_view; +drop view t18_table; +drop function view_func; +drop view view_view; + +--echo ===================================================================== +--echo Testing 19: Special tables (INFORMATION_SCHEMA) +--echo ===================================================================== + +--disable_warnings +drop procedure if exists proc_19; +--enable_warnings + +eval $base_count; + +# Using a temporary table internally should not confuse the prepared +# statement code, and should not raise ER_PS_INVALIDATED errors +prepare stmt from + 'select ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE + from INFORMATION_SCHEMA.ROUTINES where + routine_name=\'proc_19\''; + +create procedure proc_19() select "hi there"; + +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop procedure proc_19; +create procedure proc_19() select "hi there, again"; + +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop procedure proc_19; + +--echo ===================================================================== +--echo Testing 20: Special tables (log tables) +--echo ===================================================================== + +eval $base_count; + +prepare stmt from + 'select * from mysql.general_log where argument=\'IMPOSSIBLE QUERY STRING\''; + +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +--echo ===================================================================== +--echo Testing 21: Special tables (system tables) +--echo ===================================================================== + +--disable_warnings +drop procedure if exists proc_21; +--enable_warnings + +eval $base_count; + +prepare stmt from + 'select type, db, name from mysql.proc where name=\'proc_21\''; + +create procedure proc_21() select "hi there"; + +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop procedure proc_21; +create procedure proc_21() select "hi there, again"; + +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop procedure proc_21; + +--echo ===================================================================== +--echo Testing 22: Special tables (views temp tables) +--echo ===================================================================== + +--disable_warnings +drop table if exists t22_b; +drop view if exists t22; +--enable_warnings + +eval $base_count; + +create table t22_b(a int); + +create algorithm=temptable view t22 as select a*a as a2 from t22_b; + +# Using a temporary table internally should not confuse the prepared +# statement code, and should not raise ER_PS_INVALIDATED errors +show create view t22; + +prepare stmt from 'select * from t22'; + +insert into t22_b values (1), (2), (3); +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +insert into t22_b values (4), (5), (6); +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t22_b; +drop view t22; + +--echo ===================================================================== +--echo Testing 23: Special tables (internal join tables) +--echo ===================================================================== + +--disable_warnings +drop table if exists t23_a; +drop table if exists t23_b; +--enable_warnings + +eval $base_count; + +create table t23_a(a int); +create table t23_b(b int); + +# Using a temporary table internally should not confuse the prepared +# statement code, and should not raise ER_PS_INVALIDATED errors +prepare stmt from 'select * from t23_a join t23_b'; + +insert into t23_a values (1), (2), (3); +insert into t23_b values (10), (20), (30); +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +insert into t23_a values (4); +insert into t23_b values (40); +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t23_a; +drop table t23_b; + +--echo ===================================================================== +--echo Testing 24: Special statements +--echo ===================================================================== + +# SQLCOM_ALTER_TABLE: + +--disable_warnings +drop table if exists t24_alter; +--enable_warnings + +eval $base_count; + +create table t24_alter(a int); + +prepare stmt from 'alter table t24_alter add column b int'; +execute stmt; +eval $reprepared; + +drop table t24_alter; +create table t24_alter(a1 int, a2 int); + +# t24_alter has changed, and it's not a problem +execute stmt; +eval $reprepared; + +alter table t24_alter drop column b; +execute stmt; +eval $reprepared; + +alter table t24_alter drop column b; +execute stmt; +eval $reprepared; + +drop table t24_alter; + +# SQLCOM_REPAIR: + +--disable_warnings +drop table if exists t24_repair; +--enable_warnings + +create table t24_repair(a int); +insert into t24_repair values (1), (2), (3); + +prepare stmt from 'repair table t24_repair'; +execute stmt; +eval $reprepared; + +drop table t24_repair; +create table t24_repair(a1 int, a2 int); +insert into t24_repair values (1, 10), (2, 20), (3, 30); + +# t24_repair has changed, and it's not a problem +execute stmt; +eval $reprepared; + +alter table t24_repair add column b varchar(50) default NULL; +execute stmt; +eval $reprepared; + +alter table t24_repair drop column b; +execute stmt; +eval $reprepared; + +drop table t24_repair; + +# SQLCOM_ANALYZE: + +--disable_warnings +drop table if exists t24_analyze; +--enable_warnings + +create table t24_analyze(a int); +insert into t24_analyze values (1), (2), (3); + +prepare stmt from 'analyze table t24_analyze'; +execute stmt; +eval $reprepared; + +drop table t24_analyze; +create table t24_analyze(a1 int, a2 int); +insert into t24_analyze values (1, 10), (2, 20), (3, 30); + +# t24_analyze has changed, and it's not a problem +execute stmt; +eval $reprepared; + +alter table t24_analyze add column b varchar(50) default NULL; +execute stmt; +eval $reprepared; + +alter table t24_analyze drop column b; +execute stmt; +eval $reprepared; + +drop table t24_analyze; + +# SQLCOM_OPTIMIZE: + +--disable_warnings +drop table if exists t24_optimize; +--enable_warnings + +create table t24_optimize(a int); +insert into t24_optimize values (1), (2), (3); + +prepare stmt from 'optimize table t24_optimize'; +execute stmt; +eval $reprepared; + +drop table t24_optimize; +create table t24_optimize(a1 int, a2 int); +insert into t24_optimize values (1, 10), (2, 20), (3, 30); + +# t24_optimize has changed, and it's not a problem +execute stmt; +eval $reprepared; + +alter table t24_optimize add column b varchar(50) default NULL; +execute stmt; +eval $reprepared; + +alter table t24_optimize drop column b; +execute stmt; +eval $reprepared; + +drop table t24_optimize; + +# SQLCOM_SHOW_CREATE_PROC: + +--disable_warnings +drop procedure if exists changing_proc; +--enable_warnings + +prepare stmt from 'show create procedure changing_proc'; +--error ER_SP_DOES_NOT_EXIST +execute stmt; +eval $reprepared; +--error ER_SP_DOES_NOT_EXIST +execute stmt; +eval $reprepared; + +create procedure changing_proc() begin end; + +# changing_proc has changed, and it's not a problem +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop procedure changing_proc; +create procedure changing_proc(x int, y int) begin end; + +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop procedure changing_proc; + +--error ER_SP_DOES_NOT_EXIST +execute stmt; +eval $reprepared; +--error ER_SP_DOES_NOT_EXIST +execute stmt; +eval $reprepared; + +# SQLCOM_SHOW_CREATE_FUNC: + +--disable_warnings +drop function if exists changing_func; +--enable_warnings + +prepare stmt from 'show create function changing_func'; +--error ER_SP_DOES_NOT_EXIST +execute stmt; +eval $reprepared; +--error ER_SP_DOES_NOT_EXIST +execute stmt; +eval $reprepared; + +create function changing_func() returns int return 0; + +# changing_proc has changed, and it's not a problem +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop function changing_func; +create function changing_func(x int, y int) returns int return x+y; + +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop function changing_func; + +--error ER_SP_DOES_NOT_EXIST +execute stmt; +eval $reprepared; +--error ER_SP_DOES_NOT_EXIST +execute stmt; +eval $reprepared; + +# SQLCOM_SHOW_CREATE_TRIGGER: + +--disable_warnings +drop table if exists t24_trigger; +--enable_warnings + +create table t24_trigger(a int); + +prepare stmt from 'show create trigger t24_bi;'; +--error ER_TRG_DOES_NOT_EXIST +execute stmt; +eval $reprepared; +--error ER_TRG_DOES_NOT_EXIST +execute stmt; +eval $reprepared; + +delimiter $$; +create trigger t24_bi before insert on t24_trigger for each row + begin + set @message= "t24_bi"; + end +$$ +delimiter ;$$ + +# t24_bi has changed, and it's not a problem +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop trigger t24_bi; +delimiter $$; +create trigger t24_bi before insert on t24_trigger for each row + begin + set @message= "t24_bi (2)"; + end +$$ +delimiter ;$$ + +# t24_bi has changed, and it's not a problem +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop trigger t24_bi; + +--error ER_TRG_DOES_NOT_EXIST +execute stmt; +eval $reprepared; +--error ER_TRG_DOES_NOT_EXIST +execute stmt; +eval $reprepared; + +drop table t24_trigger; + +--echo ===================================================================== +--echo Testing 25: Testing the strength of TABLE_SHARE version +--echo ===================================================================== + +# Test 25-a: number of columns + +--disable_warnings +drop table if exists t25_num_col; +--enable_warnings + +eval $base_count; + +create table t25_num_col(a int); + +prepare stmt from 'select * from t25_num_col'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +alter table t25_num_col add column b varchar(50) default NULL; + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t25_num_col; + +# Test 25-b: column name + +--disable_warnings +drop table if exists t25_col_name; +--enable_warnings + +create table t25_col_name(a int); + +prepare stmt from 'select * from t25_col_name'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +alter table t25_col_name change a b int; + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t25_col_name; + +# Test 25-c: column type + +--disable_warnings +drop table if exists t25_col_type; +--enable_warnings + +create table t25_col_type(a int); + +prepare stmt from 'select * from t25_col_type'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +alter table t25_col_type change a a varchar(10); + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t25_col_type; + +# Test 25-d: column type length + +--disable_warnings +drop table if exists t25_col_type_length; +--enable_warnings + +create table t25_col_type_length(a varchar(10)); + +prepare stmt from 'select * from t25_col_type_length'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +alter table t25_col_type_length change a a varchar(20); + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t25_col_type_length; + +# Test 25-e: column NULL property + +--disable_warnings +drop table if exists t25_col_null; +--enable_warnings + +create table t25_col_null(a varchar(10)); + +prepare stmt from 'select * from t25_col_null'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +alter table t25_col_null change a a varchar(10) NOT NULL; + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t25_col_null; + +# Test 25-f: column DEFAULT + +--disable_warnings +drop table if exists t25_col_default; +--enable_warnings + +create table t25_col_default(a int, b int DEFAULT 10); + +prepare stmt from 'insert into t25_col_default(a) values (?)'; +set @val=1; +execute stmt using @val; +eval $reprepared; +set @val=2; +execute stmt using @val; +eval $reprepared; + +alter table t25_col_default change b b int DEFAULT 20; + +set @val=3; +# Must insert the correct default value for b +execute stmt using @val; +eval $reprepared; + +set @val=4; +# Must insert the correct default value for b +execute stmt using @val; +eval $reprepared; + +select * from t25_col_default; + +drop table t25_col_default; + +# Test 25-g: number of keys + +--disable_warnings +drop table if exists t25_index; +--enable_warnings + +create table t25_index(a varchar(10)); + +prepare stmt from 'select * from t25_index'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +create index i1 on t25_index(a); + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t25_index; + +# Test 25-h: changing index uniqueness + +--disable_warnings +drop table if exists t25_index_unique; +--enable_warnings + +create table t25_index_unique(a varchar(10), b varchar(10)); +create index i1 on t25_index_unique(a, b); + +show create table t25_index_unique; + +prepare stmt from 'select * from t25_index_unique'; +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +alter table t25_index_unique drop index i1; +create unique index i1 on t25_index_unique(a, b); + +show create table t25_index_unique; + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t25_index_unique; + +--echo ===================================================================== +--echo Testing reported bugs +--echo ===================================================================== + +# +# Bug#12093 (SP not found on second PS execution if another thread drops +# other SP in between) +# + +--disable_warnings +drop table if exists table_12093; +drop function if exists func_12093; +drop function if exists func_12093_unrelated; +drop procedure if exists proc_12093; +--enable_warnings + +eval $base_count; + +connect (con1,localhost,root,,); + +connection default; + +create table table_12093(a int); + +delimiter //; + +create function func_12093() +returns int +begin + return (select count(*) from table_12093); +end// + +create procedure proc_12093(a int) +begin + select * from table_12093; +end// + +delimiter ;// + +create function func_12093_unrelated() returns int return 2; +create procedure proc_12093_unrelated() begin end; + +prepare stmt_sf from 'select func_12093();'; +prepare stmt_sp from 'call proc_12093(func_12093())'; + +execute stmt_sf; +eval $reprepared; +execute stmt_sp; +eval $reprepared; + +connection con1; + +drop function func_12093_unrelated; +drop procedure proc_12093_unrelated; + +connection default; + +# previously, failed with --error 1305 +execute stmt_sf; +eval $reprepared; +# previously, failed with --error 1305 +execute stmt_sp; +eval $reprepared; + +# previously, failed with --error 1305 +execute stmt_sf; +eval $reprepared; +# previously, failed with --error 1305 +execute stmt_sp; +eval $reprepared; + +deallocate prepare stmt_sf; +deallocate prepare stmt_sp; + +disconnect con1; + +drop table table_12093; +drop function func_12093; +drop procedure proc_12093; + +# +# Bug#21294 (executing a prepared statement that executes a stored function +# which was recreat) +# + +--disable_warnings +drop function if exists func_21294; +--enable_warnings + +eval $base_count; + +create function func_21294() returns int return 10; + +prepare stmt from "select func_21294()"; +execute stmt; +eval $reprepared; + +drop function func_21294; +create function func_21294() returns int return 10; + +# might pass or fail, implementation dependent +execute stmt; +eval $reprepared; + +drop function func_21294; +create function func_21294() returns int return 20; + +execute stmt; +eval $reprepared; + +deallocate prepare stmt; +drop function func_21294; + +# +# Bug#27420 (A combination of PS and view operations cause error + assertion +# on shutdown) +# + +--disable_warnings +drop table if exists t_27420_100; +drop table if exists t_27420_101; +drop view if exists v_27420; +--enable_warnings + +eval $base_count; + +connect (con1,localhost,root,,); + +connection default; + +create table t_27420_100(a int); +insert into t_27420_100 values (1), (2); + +create table t_27420_101(a int); +insert into t_27420_101 values (1), (2); + +create view v_27420 as select t_27420_100.a X, t_27420_101.a Y + from t_27420_100, t_27420_101 + where t_27420_100.a=t_27420_101.a; + +prepare stmt from 'select * from v_27420'; + +execute stmt; +eval $reprepared; + +connection con1; + +drop view v_27420; +create table v_27420(X int, Y int); + +connection default; + +# REPREPARED +1 +execute stmt; +eval $reprepared; + +connection con1; + +drop table v_27420; +# passes in 5.0, fails in 5.1, should pass +create table v_27420 (a int, b int, filler char(200)); + +connection default; + +# REPREPARED +1 +execute stmt; +eval $reprepared; + +disconnect con1; + +deallocate prepare stmt; +drop table t_27420_100; +drop table t_27420_101; +drop table v_27420; + +# +# Bug#27430 (Crash in subquery code when in PS and table DDL changed after +# PREPARE) +# + +--disable_warnings +drop table if exists t_27430_1; +drop table if exists t_27430_2; +--enable_warnings + +eval $base_count; + +create table t_27430_1 (a int not null, oref int not null, key(a)); +insert into t_27430_1 values + (1, 1), + (1, 1234), + (2, 3), + (2, 1234), + (3, 1234); + +create table t_27430_2 (a int not null, oref int not null); +insert into t_27430_2 values + (1, 1), + (2, 2), + (1234, 3), + (1234, 4); + +prepare stmt from + 'select oref, a, a in (select a from t_27430_1 where oref=t_27430_2.oref) Z from t_27430_2'; + +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table t_27430_1, t_27430_2; + +create table t_27430_1 (a int, oref int, key(a)); +insert into t_27430_1 values + (1, 1), + (1, NULL), + (2, 3), + (2, NULL), + (3, NULL); + +create table t_27430_2 (a int, oref int); +insert into t_27430_2 values + (1, 1), + (2,2), + (NULL, 3), + (NULL, 4); + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +deallocate prepare stmt; +drop table t_27430_1; +drop table t_27430_2; + +# +# Bug#27690 (Re-execution of prepared statement after table was replaced +# with a view crashes) +# + +--disable_warnings +drop table if exists t_27690_1; +drop view if exists v_27690_1; +drop table if exists v_27690_2; +--enable_warnings + +eval $base_count; + +create table t_27690_1 (a int, b int); +insert into t_27690_1 values (1,1),(2,2); + +create table v_27690_1 as select * from t_27690_1; +create table v_27690_2 as select * from t_27690_1; + +prepare stmt from 'select * from v_27690_1, v_27690_2'; + +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +drop table v_27690_1; + +--error ER_NO_SUCH_TABLE +execute stmt; +eval $reprepared; + +--error ER_NO_SUCH_TABLE +execute stmt; +eval $reprepared; + +create view v_27690_1 as select A.a, A.b from t_27690_1 A, t_27690_1 B; + +# REPREPARED +1 +execute stmt; +eval $reprepared; +execute stmt; +eval $reprepared; + +deallocate prepare stmt; +drop table t_27690_1; +drop view v_27690_1; +drop table v_27690_2; + diff --git a/mysql-test/t/read_only.test b/mysql-test/t/read_only.test index 709238c3d76..fd41a3225a6 100644 --- a/mysql-test/t/read_only.test +++ b/mysql-test/t/read_only.test @@ -225,3 +225,38 @@ connection default; set global read_only=0; drop table t1,t2; drop user test@localhost; +--echo # +--echo # Bug #27440 read_only allows create and drop database +--echo # +set global read_only= 1; +--disable_warnings +drop database if exists mysqltest_db1; +drop database if exists mysqltest_db2; +--enable_warnings + +delete from mysql.user where User like 'mysqltest_%'; +delete from mysql.db where User like 'mysqltest_%'; +delete from mysql.tables_priv where User like 'mysqltest_%'; +delete from mysql.columns_priv where User like 'mysqltest_%'; +flush privileges; + +grant all on mysqltest_db2.* to `mysqltest_u1`@`%`; +create database mysqltest_db1; +grant all on mysqltest_db1.* to `mysqltest_u1`@`%`; +flush privileges; +connect (con_bug27440,127.0.0.1,mysqltest_u1,,test,$MASTER_MYPORT,); +connection con_bug27440; +--error ER_OPTION_PREVENTS_STATEMENT +create database mysqltest_db2; +show databases like '%mysqltest_db2%'; +--error ER_OPTION_PREVENTS_STATEMENT +drop database mysqltest_db1; +disconnect con_bug27440; +connection default; +delete from mysql.user where User like 'mysqltest_%'; +delete from mysql.db where User like 'mysqltest_%'; +delete from mysql.tables_priv where User like 'mysqltest_%'; +delete from mysql.columns_priv where User like 'mysqltest_%'; +flush privileges; +drop database mysqltest_db1; +set global read_only=0; diff --git a/mysql-test/t/trigger_notembedded.test b/mysql-test/t/trigger_notembedded.test index 748ae6e1c27..5d2ab84adaf 100644 --- a/mysql-test/t/trigger_notembedded.test +++ b/mysql-test/t/trigger_notembedded.test @@ -880,8 +880,9 @@ USE test; # Bug#23713 LOCK TABLES + CREATE TRIGGER + FLUSH TABLES WITH READ LOCK = deadlock # -# Test temporarily disable due to Bug#32395 ---disable_parsing +--disable_warnings +drop table if exists t1; +--enable_warnings create table t1 (i int); connect (flush,localhost,root,,test,,); connection default; @@ -906,6 +907,5 @@ connection default; select * from t1; drop table t1; disconnect flush; ---enable_parsing --echo End of 5.1 tests. diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc index bf08f963aa3..3233b7513a1 100644 --- a/server-tools/instance-manager/mysql_connection.cc +++ b/server-tools/instance-manager/mysql_connection.cc @@ -257,7 +257,7 @@ int Mysql_connection::do_command() return 1; if (thread_registry->is_shutdown()) return 1; - net_send_error(&net, net.last_errno); + net_send_error(&net, net.client_last_errno); net.error= 0; return 0; } diff --git a/sql-common/client.c b/sql-common/client.c index f149442f12e..1a0f9c64d7d 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -289,8 +289,8 @@ void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate) DBUG_ASSERT(mysql != 0); net= &mysql->net; - net->last_errno= errcode; - strmov(net->last_error, ER(errcode)); + net->client_last_errno= errcode; + strmov(net->client_last_error, ER(errcode)); strmov(net->sqlstate, sqlstate); DBUG_VOID_RETURN; @@ -304,8 +304,8 @@ void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate) void net_clear_error(NET *net) { - net->last_errno= 0; - net->last_error[0]= '\0'; + net->client_last_errno= 0; + net->client_last_error[0]= '\0'; strmov(net->sqlstate, not_error_sqlstate); } @@ -331,9 +331,9 @@ static void set_mysql_extended_error(MYSQL *mysql, int errcode, DBUG_ASSERT(mysql != 0); net= &mysql->net; - net->last_errno= errcode; + net->client_last_errno= errcode; va_start(args, format); - my_vsnprintf(net->last_error, sizeof(net->last_error)-1, + my_vsnprintf(net->client_last_error, sizeof(net->client_last_error)-1, format, args); va_end(args); strmov(net->sqlstate, sqlstate); @@ -667,7 +667,7 @@ cli_safe_read(MYSQL *mysql) return (packet_error); #endif /*MYSQL_SERVER*/ end_server(mysql); - set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ? + set_mysql_error(mysql, net->client_last_errno == ER_NET_PACKET_TOO_LARGE ? CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST, unknown_sqlstate); return (packet_error); } @@ -676,7 +676,7 @@ cli_safe_read(MYSQL *mysql) if (len > 3) { char *pos=(char*) net->read_pos+1; - net->last_errno=uint2korr(pos); + net->client_last_errno=uint2korr(pos); pos+=2; len-=2; if (protocol_41(mysql) && pos[0] == '#') @@ -684,8 +684,8 @@ cli_safe_read(MYSQL *mysql) strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH); pos+= SQLSTATE_LENGTH+1; } - (void) strmake(net->last_error,(char*) pos, - min((uint) len,(uint) sizeof(net->last_error)-1)); + (void) strmake(net->client_last_error,(char*) pos, + min((uint) len,(uint) sizeof(net->client_last_error)-1)); } else set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate); @@ -701,7 +701,9 @@ cli_safe_read(MYSQL *mysql) mysql->server_status&= ~SERVER_MORE_RESULTS_EXISTS; DBUG_PRINT("error",("Got error: %d/%s (%s)", - net->last_errno, net->sqlstate, net->last_error)); + net->client_last_errno, + net->sqlstate, + net->client_last_error)); return(packet_error); } return len; @@ -744,7 +746,6 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command, } net_clear_error(net); - net->report_error=0; mysql->info=0; mysql->affected_rows= ~(my_ulonglong) 0; /* @@ -759,7 +760,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command, { DBUG_PRINT("error",("Can't send command to server. Error: %d", socket_errno)); - if (net->last_errno == ER_NET_PACKET_TOO_LARGE) + if (net->client_last_errno == ER_NET_PACKET_TOO_LARGE) { set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate); goto end; @@ -836,16 +837,15 @@ static my_bool is_NT(void) #ifdef CHECK_LICENSE -/* +/** Check server side variable 'license'. - If the variable does not exist or does not contain 'Commercial', + + If the variable does not exist or does not contain 'Commercial', we're talking to non-commercial server from commercial client. - SYNOPSIS - check_license() - RETURN VALUE - 0 success - !0 network error or the server is not commercial. - Error code is saved in mysql->net.last_errno. + + @retval 0 success + @retval !0 network error or the server is not commercial. + Error code is saved in mysql->net.client_last_errno. */ static int check_license(MYSQL *mysql) @@ -858,7 +858,7 @@ static int check_license(MYSQL *mysql) if (mysql_real_query(mysql, query, sizeof(query)-1)) { - if (net->last_errno == ER_UNKNOWN_SYSTEM_VARIABLE) + if (net->client_last_errno == ER_UNKNOWN_SYSTEM_VARIABLE) { set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate, ER(CR_WRONG_LICENSE), required_license); @@ -873,7 +873,7 @@ static int check_license(MYSQL *mysql) two is ever true for server variables now), or column value mismatch, set wrong license error. */ - if (!net->last_errno && + if (!net->client_last_errno && (!row || !row[0] || strncmp(row[0], required_license, sizeof(required_license)))) { @@ -881,7 +881,7 @@ static int check_license(MYSQL *mysql) ER(CR_WRONG_LICENSE), required_license); } mysql_free_result(res); - return net->last_errno; + return net->client_last_errno; } #endif /* CHECK_LICENSE */ @@ -2090,7 +2090,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, if ((pkt_length=cli_safe_read(mysql)) == packet_error) { - if (mysql->net.last_errno == CR_SERVER_LOST) + if (mysql->net.client_last_errno == CR_SERVER_LOST) set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, ER(CR_SERVER_LOST_EXTENDED), "reading initial communication packet", @@ -2324,7 +2324,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, if ((pkt_length=cli_safe_read(mysql)) == packet_error) { - if (mysql->net.last_errno == CR_SERVER_LOST) + if (mysql->net.client_last_errno == CR_SERVER_LOST) set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, ER(CR_SERVER_LOST_EXTENDED), "reading authorization packet", @@ -2352,7 +2352,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, /* Read what server thinks about out new auth message report */ if (cli_safe_read(mysql) == packet_error) { - if (mysql->net.last_errno == CR_SERVER_LOST) + if (mysql->net.client_last_errno == CR_SERVER_LOST) set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, ER(CR_SERVER_LOST_EXTENDED), "reading final connect information", @@ -2371,7 +2371,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, if (db && mysql_select_db(mysql, db)) { - if (mysql->net.last_errno == CR_SERVER_LOST) + if (mysql->net.client_last_errno == CR_SERVER_LOST) set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate, ER(CR_SERVER_LOST_EXTENDED), "Setting intital database", @@ -2415,7 +2415,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, error: reset_sigpipe(mysql); DBUG_PRINT("error",("message: %u/%s (%s)", - net->last_errno, net->sqlstate, net->last_error)); + net->client_last_errno, + net->sqlstate, + net->client_last_error)); { /* Free alloced memory */ end_server(mysql); @@ -2473,8 +2475,8 @@ my_bool mysql_reconnect(MYSQL *mysql) mysql->db, mysql->port, mysql->unix_socket, mysql->client_flag | CLIENT_REMEMBER_OPTIONS)) { - mysql->net.last_errno= tmp_mysql.net.last_errno; - strmov(mysql->net.last_error, tmp_mysql.net.last_error); + mysql->net.client_last_errno= tmp_mysql.net.client_last_errno; + strmov(mysql->net.client_last_error, tmp_mysql.net.client_last_error); strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate); DBUG_RETURN(1); } @@ -2483,8 +2485,8 @@ my_bool mysql_reconnect(MYSQL *mysql) DBUG_PRINT("error", ("mysql_set_character_set() failed")); bzero((char*) &tmp_mysql.options,sizeof(tmp_mysql.options)); mysql_close(&tmp_mysql); - mysql->net.last_errno= tmp_mysql.net.last_errno; - strmov(mysql->net.last_error, tmp_mysql.net.last_error); + mysql->net.client_last_errno= tmp_mysql.net.client_last_errno; + strmov(mysql->net.client_last_error, tmp_mysql.net.client_last_error); strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate); DBUG_RETURN(1); } @@ -3077,13 +3079,13 @@ unsigned int STDCALL mysql_num_fields(MYSQL_RES *res) uint STDCALL mysql_errno(MYSQL *mysql) { - return mysql->net.last_errno; + return mysql->net.client_last_errno; } const char * STDCALL mysql_error(MYSQL *mysql) { - return mysql->net.last_error; + return mysql->net.client_last_error; } @@ -3152,7 +3154,7 @@ int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name) ER(CR_CANT_READ_CHARSET), cs_name, cs_dir_name); } charsets_dir= save_csdir; - return mysql->net.last_errno; + return mysql->net.client_last_errno; } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b9d7e846d84..f72aa7cffea 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -577,7 +577,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) bzero((char*) &table_list,sizeof(table_list)); table_list.db= m_dbname; table_list.alias= table_list.table_name= m_tabname; - close_cached_tables(thd, 0, &table_list); + close_cached_tables(thd, &table_list, FALSE, FALSE, FALSE); break; } default: @@ -8125,7 +8125,7 @@ int handle_trailing_share(NDB_SHARE *share) table_list.db= share->db; table_list.alias= table_list.table_name= share->table_name; safe_mutex_assert_owner(&LOCK_open); - close_cached_tables(thd, 0, &table_list, TRUE); + close_cached_tables(thd, &table_list, TRUE, FALSE, FALSE); pthread_mutex_lock(&ndbcluster_mutex); /* ndb_share reference temporary free */ diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index d015750ee44..0e7ca28fd2a 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -261,6 +261,10 @@ static void run_query(THD *thd, char *buf, char *end, thd->options&= ~OPTION_BIN_LOG; DBUG_PRINT("query", ("%s", thd->query)); + + DBUG_ASSERT(!thd->in_sub_stmt); + DBUG_ASSERT(!thd->prelocked_mode); + mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); if (no_print_error && thd->is_slave_error) @@ -269,14 +273,27 @@ static void run_query(THD *thd, char *buf, char *end, Thd_ndb *thd_ndb= get_thd_ndb(thd); for (i= 0; no_print_error[i]; i++) if ((thd_ndb->m_error_code == no_print_error[i]) || - (thd->net.last_errno == (unsigned)no_print_error[i])) + (thd->main_da.sql_errno() == (unsigned) no_print_error[i])) break; if (!no_print_error[i]) sql_print_error("NDB: %s: error %s %d(ndb: %d) %d %d", - buf, thd->net.last_error, thd->net.last_errno, + buf, + thd->main_da.message(), + thd->main_da.sql_errno(), thd_ndb->m_error_code, (int) thd->is_error(), thd->is_slave_error); } + /* + XXX: this code is broken. mysql_parse()/mysql_reset_thd_for_next_command() + can not be called from within a statement, and + run_query() can be called from anywhere, including from within + a sub-statement. + This particular reset is a temporary hack to avoid an assert + for double assignment of the diagnostics area when run_query() + is called from ndbcluster_reset_logs(), which is called from + mysql_flush(). + */ + thd->main_da.reset_diagnostics_area(); thd->options= save_thd_options; thd->query_length= save_thd_query_length; @@ -892,7 +909,7 @@ int ndbcluster_setup_binlog_table_shares(THD *thd) { if (ndb_extra_logging) sql_print_information("NDB Binlog: ndb tables writable"); - close_cached_tables((THD*) 0, 0, (TABLE_LIST*) 0, TRUE); + close_cached_tables(NULL, NULL, TRUE, FALSE, FALSE); } pthread_mutex_unlock(&LOCK_open); /* Signal injector thread that all is setup */ @@ -1692,7 +1709,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp, bzero((char*) &table_list,sizeof(table_list)); table_list.db= (char *)dbname; table_list.alias= table_list.table_name= (char *)tabname; - close_cached_tables(thd, 0, &table_list, TRUE); + close_cached_tables(thd, &table_list, TRUE, FALSE, FALSE); if ((error= ndbcluster_binlog_open_table(thd, share, table_share, table, 1))) @@ -1798,7 +1815,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp, bzero((char*) &table_list,sizeof(table_list)); table_list.db= (char *)dbname; table_list.alias= table_list.table_name= (char *)tabname; - close_cached_tables(thd, 0, &table_list); + close_cached_tables(thd, &table_list, FALSE, FALSE, FALSE); /* ndb_share reference create free */ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u", share->key, share->use_count)); @@ -1917,7 +1934,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, bzero((char*) &table_list,sizeof(table_list)); table_list.db= schema->db; table_list.alias= table_list.table_name= schema->name; - close_cached_tables(thd, 0, &table_list, FALSE); + close_cached_tables(thd, &table_list, FALSE, FALSE, FALSE); } /* ndb_share reference temporary free */ if (share) @@ -2041,7 +2058,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, pthread_mutex_unlock(&ndb_schema_share_mutex); /* end protect ndb_schema_share */ - close_cached_tables((THD*) 0, 0, (TABLE_LIST*) 0, FALSE); + close_cached_tables(NULL, NULL, FALSE, FALSE, FALSE); // fall through case NDBEVENT::TE_ALTER: ndb_handle_schema_change(thd, ndb, pOp, tmp_share); @@ -2198,7 +2215,7 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd, bzero((char*) &table_list,sizeof(table_list)); table_list.db= schema->db; table_list.alias= table_list.table_name= schema->name; - close_cached_tables(thd, 0, &table_list, FALSE); + close_cached_tables(thd, &table_list, FALSE, FALSE, FALSE); } if (schema_type != SOT_ALTER_TABLE) break; @@ -2310,8 +2327,8 @@ static int open_ndb_binlog_index(THD *thd, TABLE_LIST *tables, if (open_tables(thd, &tables, &counter, MYSQL_LOCK_IGNORE_FLUSH)) { sql_print_error("NDB Binlog: Opening ndb_binlog_index: %d, '%s'", - thd->net.last_errno, - thd->net.last_error ? thd->net.last_error : ""); + thd->main_da.sql_errno(), + thd->main_da.message()); thd->proc_info= save_proc_info; return -1; } diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d251e056c3e..3f1634a6ad1 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1765,6 +1765,7 @@ partition_element *ha_partition::find_partition_element(uint part_id) return part_elem; } DBUG_ASSERT(0); + my_error(ER_OUT_OF_RESOURCES, MYF(0)); current_thd->fatal_error(); // Abort return NULL; } diff --git a/sql/item_func.cc b/sql/item_func.cc index c89474f46b3..bdd600c3fc9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2949,7 +2949,6 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, } } } - thd->net.last_error[0]=0; Udf_func_init init= u_d->func_init; if ((error=(uchar) init(&initid, &f_args, init_msg_buff))) { diff --git a/sql/log.cc b/sql/log.cc index 9fdede9ef2c..0cea59eed98 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -280,29 +280,34 @@ void Log_to_csv_event_handler::cleanup() /* log event handlers */ -/* +/** Log command to the general log table - SYNOPSIS - log_general() - - event_time command start timestamp - user_host the pointer to the string with user@host info - user_host_len length of the user_host string. this is computed once - and passed to all general log event handlers - thread_id Id of the thread, issued a query - command_type the type of the command being logged - command_type_len the length of the string above - sql_text the very text of the query being executed - sql_text_len the length of sql_text string - - DESCRIPTION - - Log given command to the general log table - - RETURN - FALSE - OK - TRUE - error occured + Log given command to the general log table. + + @param event_time command start timestamp + @param user_host the pointer to the string with user@host info + @param user_host_len length of the user_host string. this is computed + once and passed to all general log event handlers + @param thread_id Id of the thread, issued a query + @param command_type the type of the command being logged + @param command_type_len the length of the string above + @param sql_text the very text of the query being executed + @param sql_text_len the length of sql_text string + + + @return This function attempts to never call my_error(). This is + necessary, because general logging happens already after a statement + status has been sent to the client, so the client can not see the + error anyway. Besides, the error is not related to the statement + being executed and is internal, and thus should be handled + internally (@todo: how?). + If a write to the table has failed, the function attempts to + write to a short error message to the file. The failure is also + indicated in the return value. + + @retval FALSE OK + @retval TRUE error occured */ bool Log_to_csv_event_handler:: @@ -342,6 +347,20 @@ bool Log_to_csv_event_handler:: table_list.db= MYSQL_SCHEMA_NAME.str; table_list.db_length= MYSQL_SCHEMA_NAME.length; + /* + 1) open_performance_schema_table generates an error of the + table can not be opened or is corrupted. + 2) "INSERT INTO general_log" can generate warning sometimes. + + Suppress these warnings and errors, they can't be dealt with + properly anyway. + + QQ: this problem needs to be studied in more detail. + Comment this 2 lines and run "cast.test" to see what's happening. + */ + thd->push_internal_handler(& error_handler); + need_pop= TRUE; + if (!(table= open_performance_schema_table(thd, & table_list, & open_tables_backup))) goto err; @@ -358,14 +377,6 @@ bool Log_to_csv_event_handler:: table->next_number_field= table->found_next_number_field; /* - "INSERT INTO general_log" can generate warning sometimes. - QQ: this problem needs to be studied in more details. - Comment this 2 lines and run "cast.test" to see what's happening: - */ - thd->push_internal_handler(& error_handler); - need_pop= TRUE; - - /* NOTE: we do not call restore_record() here, as all fields are filled by the Logger (=> no need to load default ones). */ diff --git a/sql/log_event.cc b/sql/log_event.cc index 2b3037aedcc..00e3dc89f6b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1611,7 +1611,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, if (killed_status_arg == THD::KILLED_NO_VALUE) killed_status_arg= thd_arg->killed; error_code= - (killed_status_arg == THD::NOT_KILLED) ? thd_arg->net.last_errno : + (killed_status_arg == THD::NOT_KILLED) ? + (thd_arg->is_error() ? thd_arg->main_da.sql_errno() : 0) : ((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ? 0 : thd_arg->killed_errno()); @@ -2332,7 +2333,7 @@ START SLAVE; . Query: '%s'", expected_error, thd->query); } /* If the query was not ignored, it is printed to the general log */ - if (thd->net.last_errno != ER_SLAVE_IGNORED_TABLE) + if (!thd->is_error() || thd->main_da.sql_errno() != ER_SLAVE_IGNORED_TABLE) general_log_write(thd, COM_QUERY, thd->query, thd->query_length); compare_errors: @@ -2341,9 +2342,10 @@ compare_errors: If we expected a non-zero error code, and we don't get the same error code, and none of them should be ignored. */ - DBUG_PRINT("info",("expected_error: %d last_errno: %d", - expected_error, thd->net.last_errno)); - if ((expected_error != (actual_error= thd->net.last_errno)) && + actual_error= thd->is_error() ? thd->main_da.sql_errno() : 0; + DBUG_PRINT("info",("expected_error: %d sql_errno: %d", + expected_error, actual_error)); + if ((expected_error != actual_error) && expected_error && !ignored_error_code(actual_error) && !ignored_error_code(expected_error)) @@ -2355,7 +2357,7 @@ Error on master: '%s' (%d), Error on slave: '%s' (%d). \ Default database: '%s'. Query: '%s'", ER_SAFE(expected_error), expected_error, - actual_error ? thd->net.last_error: "no error", + actual_error ? thd->main_da.message() : "no error", actual_error, print_slave_db_safe(db), query_arg); thd->is_slave_error= 1; @@ -2377,7 +2379,7 @@ Default database: '%s'. Query: '%s'", { rli->report(ERROR_LEVEL, actual_error, "Error '%s' on query. Default database: '%s'. Query: '%s'", - (actual_error ? thd->net.last_error : + (actual_error ? thd->main_da.message() : "unexpected success or fatal error"), print_slave_db_safe(thd->db), query_arg); thd->is_slave_error= 1; @@ -3720,8 +3722,11 @@ error: /* this err/sql_errno code is copy-paste from net_send_error() */ const char *err; int sql_errno; - if ((err=thd->net.last_error)[0]) - sql_errno=thd->net.last_errno; + if (thd->is_error()) + { + err= thd->main_da.message(); + sql_errno= thd->main_da.sql_errno(); + } else { sql_errno=ER_UNKNOWN_ERROR; @@ -6222,10 +6227,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) Error reporting borrowed from Query_log_event with many excessive simplifications (we don't honour --slave-skip-errors) */ - uint actual_error= thd->net.last_errno; + uint actual_error= thd->main_da.sql_errno(); rli->report(ERROR_LEVEL, actual_error, "Error '%s' in %s event: when locking tables", - (actual_error ? thd->net.last_error : + (actual_error ? thd->main_da.message(): "unexpected success or fatal error"), get_type_str()); thd->is_fatal_error= 1; @@ -6266,10 +6271,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) Error reporting borrowed from Query_log_event with many excessive simplifications (we don't honour --slave-skip-errors) */ - uint actual_error= thd->net.last_errno; + uint actual_error= thd->main_da.sql_errno(); rli->report(ERROR_LEVEL, actual_error, "Error '%s' on reopening tables", - (actual_error ? thd->net.last_error : + (actual_error ? thd->main_da.message() : "unexpected success or fatal error")); thd->is_slave_error= 1; } @@ -6425,10 +6430,11 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) break; default: - rli->report(ERROR_LEVEL, thd->net.last_errno, + rli->report(ERROR_LEVEL, + thd->is_error() ? thd->main_da.sql_errno() : 0, "Error in %s event: row application failed. %s", get_type_str(), - thd->net.last_error ? thd->net.last_error : ""); + thd->is_error() ? thd->main_da.message() : ""); thd->is_slave_error= 1; break; } @@ -6475,12 +6481,13 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) if (error) { /* error has occured during the transaction */ - rli->report(ERROR_LEVEL, thd->net.last_errno, + rli->report(ERROR_LEVEL, + thd->is_error() ? thd->main_da.sql_errno() : 0, "Error in %s event: error during transaction execution " "on table %s.%s. %s", get_type_str(), table->s->db.str, table->s->table_name.str, - thd->net.last_error ? thd->net.last_error : ""); + thd->is_error() ? thd->main_da.message() : ""); /* If one day we honour --skip-slave-errors in row-based replication, and @@ -7094,10 +7101,10 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) Error reporting borrowed from Query_log_event with many excessive simplifications (we don't honour --slave-skip-errors) */ - uint actual_error= thd->net.last_errno; + uint actual_error= thd->main_da.sql_errno(); rli->report(ERROR_LEVEL, actual_error, "Error '%s' on opening table `%s`.`%s`", - (actual_error ? thd->net.last_error : + (actual_error ? thd->main_da.message() : "unexpected success or fatal error"), table_list->db, table_list->table_name); thd->is_slave_error= 1; @@ -7625,8 +7632,11 @@ Write_rows_log_event::do_exec_row(const Relay_log_info *const rli) DBUG_ASSERT(m_table != NULL); int error= write_row(rli, TRUE /* overwrite */); - if (error && !thd->net.last_errno) - thd->net.last_errno= error; + if (error && !thd->is_error()) + { + DBUG_ASSERT(0); + my_error(ER_UNKNOWN_ERROR, MYF(0)); + } return error; } diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index c6b691ec010..6d5d86e42fe 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -74,10 +74,10 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli Error reporting borrowed from Query_log_event with many excessive simplifications (we don't honour --slave-skip-errors) */ - uint actual_error= thd->net.last_errno; + uint actual_error= thd->main_da.sql_errno(); rli->report(ERROR_LEVEL, actual_error, "Error '%s' in %s event: when locking tables", - (actual_error ? thd->net.last_error : + (actual_error ? thd->main_da.message() : "unexpected success or fatal error"), ev->get_type_str()); thd->is_fatal_error= 1; @@ -118,10 +118,10 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli Error reporting borrowed from Query_log_event with many excessive simplifications (we don't honour --slave-skip-errors) */ - uint actual_error= thd->net.last_errno; + uint actual_error= thd->main_da.sql_errno(); rli->report(ERROR_LEVEL, actual_error, "Error '%s' on reopening tables", - (actual_error ? thd->net.last_error : + (actual_error ? thd->main_da.message() : "unexpected success or fatal error")); thd->is_slave_error= 1; } @@ -251,10 +251,10 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli break; default: - rli->report(ERROR_LEVEL, thd->net.last_errno, + rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), "Error in %s event: row application failed. %s", ev->get_type_str(), - thd->net.last_error ? thd->net.last_error : ""); + thd->is_error() ? thd->main_da.message() : ""); thd->is_slave_error= 1; break; } @@ -280,12 +280,12 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli if (error) { /* error has occured during the transaction */ - rli->report(ERROR_LEVEL, thd->net.last_errno, + rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), "Error in %s event: error during transaction execution " "on table %s.%s. %s", ev->get_type_str(), table->s->db.str, table->s->table_name.str, - thd->net.last_error ? thd->net.last_error : ""); + thd->is_error() ? thd->main_da.message() : ""); /* If one day we honour --skip-slave-errors in row-based replication, and diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6f3dda8afdf..f61267711b0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1631,7 +1631,8 @@ TABLE *open_performance_schema_table(THD *thd, TABLE_LIST *one_table, Open_tables_state *backup); void close_performance_schema_table(THD *thd, Open_tables_state *backup); -bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables, bool have_lock = FALSE); +bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock, + bool wait_for_refresh, bool wait_for_placeholders); bool close_cached_connection_tables(THD *thd, bool wait_for_refresh, LEX_STRING *connect_string, bool have_lock = FALSE); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3c680a89741..2f264482d94 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -492,7 +492,7 @@ ulong thread_id=1L,current_pid; ulong slow_launch_threads = 0, sync_binlog_period; ulong expire_logs_days = 0; ulong rpl_recovery_rank=0; -const char *log_output_str= "TABLE"; +const char *log_output_str= "FILE"; time_t server_start_time; @@ -2603,21 +2603,8 @@ int my_message_sql(uint error, const char *str, myf MyFlags) MYSQL_ERROR::WARN_LEVEL_ERROR)) DBUG_RETURN(0); - if (thd->spcont && - thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd)) - { - DBUG_RETURN(0); - } - thd->is_slave_error= 1; // needed to catch query errors during replication - if (!thd->no_warnings_for_error) - { - thd->no_warnings_for_error= TRUE; - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str); - thd->no_warnings_for_error= FALSE; - } - /* thd->lex->current_select == 0 if lex structure is not inited (not query command (COM_QUERY)) @@ -2634,14 +2621,39 @@ int my_message_sql(uint error, const char *str, myf MyFlags) } else { - NET *net= &thd->net; - net->report_error= 1; - query_cache_abort(net); - if (!net->last_error[0]) // Return only first message + if (! thd->main_da.is_error()) // Return only first message { - strmake(net->last_error, str, sizeof(net->last_error)-1); - net->last_errno= error ? error : ER_UNKNOWN_ERROR; + if (error == 0) + error= ER_UNKNOWN_ERROR; + if (str == NULL) + str= ER(error); + thd->main_da.set_error_status(thd, error, str); } + query_cache_abort(&thd->net); + } + /* + If a continue handler is found, the error message will be cleared + by the stored procedures code. + */ + if (thd->spcont && + thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd)) + { + /* + Do not push any warnings, a handled error must be completely + silenced. + */ + DBUG_RETURN(0); + } + + if (!thd->no_warnings_for_error) + { + /* + Suppress infinite recursion if there a memory allocation error + inside push_warning. + */ + thd->no_warnings_for_error= TRUE; + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str); + thd->no_warnings_for_error= FALSE; } } if (!thd || MyFlags & ME_NOREFRESH) @@ -7495,7 +7507,7 @@ mysqld_get_one_option(int optid, { if (!argument || !argument[0]) { - log_output_options= LOG_TABLE; + log_output_options= LOG_FILE; log_output_str= log_output_typelib.type_names[1]; } else diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 18cf1ebae5b..73eb340fbc0 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -123,20 +123,18 @@ my_bool my_net_init(NET *net, Vio* vio) MYF(MY_WME)))) DBUG_RETURN(1); net->buff_end=net->buff+net->max_packet; - net->no_send_ok= net->no_send_error= 0; net->error=0; net->return_errno=0; net->return_status=0; net->pkt_nr=net->compress_pkt_nr=0; net->write_pos=net->read_pos = net->buff; - net->last_error[0]=0; + net->client_last_error[0]=0; net->compress=0; net->reading_or_writing=0; net->where_b = net->remain_in_buf=0; - net->last_errno=0; + net->client_last_errno=0; #ifdef USE_QUERY_CACHE query_cache_init_query(net); #else net->query_cache_query= 0; #endif - net->report_error= 0; if (vio != 0) /* If real connection */ { @@ -176,9 +174,12 @@ my_bool net_realloc(NET *net, size_t length) { DBUG_PRINT("error", ("Packet too large. Max size: %lu", net->max_packet_size)); + /* @todo: 1 and 2 codes are identical. */ net->error= 1; - net->report_error= 1; - net->last_errno= ER_NET_PACKET_TOO_LARGE; + net->client_last_errno= ER_NET_PACKET_TOO_LARGE; +#ifdef MYSQL_SERVER + my_error(ER_NET_PACKET_TOO_LARGE, MYF(0)); +#endif DBUG_RETURN(1); } pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); @@ -190,9 +191,10 @@ my_bool net_realloc(NET *net, size_t length) NET_HEADER_SIZE + COMP_HEADER_SIZE, MYF(MY_WME)))) { + /* @todo: 1 and 2 codes are identical. */ net->error= 1; - net->report_error= 1; - net->last_errno= ER_OUT_OF_RESOURCES; + net->client_last_errno= ER_OUT_OF_RESOURCES; + /* In the server the error is reported by MY_WME flag. */ DBUG_RETURN(1); } net->buff=net->write_pos=buff; @@ -582,12 +584,9 @@ net_real_write(NET *net,const uchar *packet, size_t len) if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE, MYF(MY_WME)))) { -#ifdef MYSQL_SERVER - net->last_errno= ER_OUT_OF_RESOURCES; net->error= 2; - /* TODO is it needed to set this variable if we have no socket */ - net->report_error= 1; -#endif + net->client_last_errno= ER_OUT_OF_RESOURCES; + /* In the server, the error is reported by MY_WME flag. */ net->reading_or_writing= 0; DBUG_RETURN(1); } @@ -638,11 +637,11 @@ net_real_write(NET *net,const uchar *packet, size_t len) "%s: my_net_write: fcntl returned error %d, aborting thread\n", my_progname,vio_errno(net->vio)); #endif /* EXTRA_DEBUG */ -#ifdef MYSQL_SERVER - net->last_errno= ER_NET_ERROR_ON_WRITE; -#endif net->error= 2; /* Close socket */ - net->report_error= 1; + net->client_last_errno= ER_NET_PACKET_TOO_LARGE; +#ifdef MYSQL_SERVER + my_error(ER_NET_PACKET_TOO_LARGE, MYF(0)); +#endif goto end; } retry_count=0; @@ -669,10 +668,10 @@ net_real_write(NET *net,const uchar *packet, size_t len) } #endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */ net->error= 2; /* Close socket */ - net->report_error= 1; + net->client_last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED : + ER_NET_ERROR_ON_WRITE); #ifdef MYSQL_SERVER - net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED : - ER_NET_ERROR_ON_WRITE); + my_error(net->client_last_errno, MYF(0)); #endif /* MYSQL_SERVER */ break; } @@ -849,9 +848,9 @@ my_real_read(NET *net, size_t *complen) #endif /* EXTRA_DEBUG */ len= packet_error; net->error= 2; /* Close socket */ - net->report_error= 1; + net->client_last_errno= ER_NET_FCNTL_ERROR; #ifdef MYSQL_SERVER - net->last_errno= ER_NET_FCNTL_ERROR; + my_error(ER_NET_FCNTL_ERROR, MYF(0)); #endif goto end; } @@ -881,10 +880,11 @@ my_real_read(NET *net, size_t *complen) remain, vio_errno(net->vio), (long) length)); len= packet_error; net->error= 2; /* Close socket */ - net->report_error= 1; + net->client_last_errno= (vio_was_interrupted(net->vio) ? + ER_NET_READ_INTERRUPTED : + ER_NET_READ_ERROR); #ifdef MYSQL_SERVER - net->last_errno= (vio_was_interrupted(net->vio) ? ER_NET_READ_INTERRUPTED : - ER_NET_READ_ERROR); + my_error(net->client_last_errno, MYF(0)); #endif goto end; } @@ -915,9 +915,9 @@ my_real_read(NET *net, size_t *complen) #endif } len= packet_error; - net->report_error= 1; + /* Not a NET error on the client. XXX: why? */ #ifdef MYSQL_SERVER - net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER; + my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0)); #endif goto end; } @@ -1101,9 +1101,9 @@ my_net_read(NET *net) &complen)) { net->error= 2; /* caller will close socket */ - net->report_error= 1; + net->client_last_errno= ER_NET_UNCOMPRESS_ERROR; #ifdef MYSQL_SERVER - net->last_errno=ER_NET_UNCOMPRESS_ERROR; + my_error(ER_NET_UNCOMPRESS_ERROR, MYF(0)); #endif return packet_error; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 732f947c44e..b8bdb604eea 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1274,7 +1274,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) the storage engine calls in question happen to never fail with the existing storage engines. */ - thd->net.report_error= 1; /* purecov: inspected */ + my_error(ER_OUT_OF_RESOURCES, MYF(0)); /* purecov: inspected */ /* Caller will free the memory */ goto failure; /* purecov: inspected */ } diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 12ad504d738..91786ff3f4b 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -170,6 +170,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if(error) { tl->table->file->print_error(error, MYF(0)); + tl->table->in_use->fatal_error(); return error; } count*= tl->table->file->stats.records; @@ -418,6 +419,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE /* HA_ERR_LOCK_DEADLOCK or some other error */ table->file->print_error(error, MYF(0)); + table->in_use->fatal_error(); return(error); } removed_tables|= table->map; diff --git a/sql/protocol.cc b/sql/protocol.cc index c147b68ca1f..420912b0b63 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -23,13 +23,20 @@ #endif #include "mysql_priv.h" -#include "sp_rcontext.h" #include <stdarg.h> static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; +/* Declared non-static only because of the embedded library. */ void net_send_error_packet(THD *thd, uint sql_errno, const char *err); +void +net_send_ok(THD *thd, + uint server_status, uint total_warn_count, + ha_rows affected_rows, ulonglong id, const char *message); +void +net_send_eof(THD *thd, uint server_status, uint total_warn_count); #ifndef EMBEDDED_LIBRARY -static void write_eof_packet(THD *thd, NET *net); +static void write_eof_packet(THD *thd, NET *net, + uint server_status, uint total_warn_count); #endif #ifndef EMBEDDED_LIBRARY @@ -67,62 +74,26 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) */ void net_send_error(THD *thd, uint sql_errno, const char *err) { - NET *net= &thd->net; - bool generate_warning= thd->killed != THD::KILL_CONNECTION; DBUG_ENTER("net_send_error"); - DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, - err ? err : net->last_error[0] ? - net->last_error : "NULL")); DBUG_ASSERT(!thd->spcont); + DBUG_ASSERT(sql_errno); + DBUG_ASSERT(err && err[0]); - if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) - { - thd->killed= THD::NOT_KILLED; - thd->mysys_var->abort= 0; - } + DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, err)); - if (net && net->no_send_error) - { - thd->clear_error(); - thd->is_fatal_error= 0; // Error message is given - DBUG_PRINT("info", ("sending error messages prohibited")); - DBUG_VOID_RETURN; - } - - thd->is_slave_error= 1; // needed to catch query errors during replication - if (!err) - { - if (sql_errno) - err=ER(sql_errno); - else - { - if ((err=net->last_error)[0]) - { - sql_errno=net->last_errno; - generate_warning= 0; // This warning has already been given - } - else - { - sql_errno=ER_UNKNOWN_ERROR; - err=ER(sql_errno); /* purecov: inspected */ - } - } - } - - if (generate_warning) - { - /* Error that we have not got with my_error() */ - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, sql_errno, err); - } + /* + It's one case when we can push an error even though there + is an OK or EOF already. + */ + thd->main_da.can_overwrite_status= TRUE; /* Abort multi-result sets */ thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; net_send_error_packet(thd, sql_errno, err); - thd->is_fatal_error= 0; // Error message is given - thd->net.report_error= 0; + thd->main_da.can_overwrite_status= FALSE; DBUG_VOID_RETURN; } @@ -150,23 +121,21 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) warning_count Stored in 2 bytes; New in 4.1 protocol message Stored as packed length (1-9 bytes) + message Is not stored if no message - - If net->no_send_ok return without sending packet */ #ifndef EMBEDDED_LIBRARY void -send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) +net_send_ok(THD *thd, + uint server_status, uint total_warn_count, + ha_rows affected_rows, ulonglong id, const char *message) { NET *net= &thd->net; uchar buff[MYSQL_ERRMSG_SIZE+10],*pos; DBUG_ENTER("send_ok"); - if (net->no_send_ok || !net->vio) // hack for re-parsing queries + if (! net->vio) // hack for re-parsing queries { - DBUG_PRINT("info", ("no send ok: %s, vio present: %s", - (net->no_send_ok ? "YES" : "NO"), - (net->vio ? "YES" : "NO"))); + DBUG_PRINT("info", ("vio present: NO")); DBUG_VOID_RETURN; } @@ -179,28 +148,29 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) ("affected_rows: %lu id: %lu status: %u warning_count: %u", (ulong) affected_rows, (ulong) id, - (uint) (thd->server_status & 0xffff), - (uint) thd->total_warn_count)); - int2store(pos,thd->server_status); + (uint) (server_status & 0xffff), + (uint) total_warn_count)); + int2store(pos, server_status); pos+=2; /* We can only return up to 65535 warnings in two bytes */ - uint tmp= min(thd->total_warn_count, 65535); + uint tmp= min(total_warn_count, 65535); int2store(pos, tmp); pos+= 2; } else if (net->return_status) // For 4.0 protocol { - int2store(pos,thd->server_status); + int2store(pos, server_status); pos+=2; } - if (message) + thd->main_da.can_overwrite_status= TRUE; + + if (message && message[0]) pos= net_store_data(pos, (uchar*) message, strlen(message)); VOID(my_net_write(net, buff, (size_t) (pos-buff))); VOID(net_flush(net)); - /* We can't anymore send an error to the client */ - thd->net.report_error= 0; - thd->net.no_send_error= 1; + + thd->main_da.can_overwrite_status= FALSE; DBUG_PRINT("info", ("OK sent, so no more error sending allowed")); DBUG_VOID_RETURN; @@ -212,7 +182,7 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */ Send eof (= end of result set) to the client SYNOPSIS - send_eof() + net_send_eof() thd Thread handler no_flush Set to 1 if there will be more data to the client, like in send_fields(). @@ -231,15 +201,17 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */ */ void -send_eof(THD *thd) +net_send_eof(THD *thd, uint server_status, uint total_warn_count) { NET *net= &thd->net; - DBUG_ENTER("send_eof"); + DBUG_ENTER("net_send_eof"); + /* Set to TRUE if no active vio, to work well in case of --init-file */ if (net->vio != 0) { - write_eof_packet(thd, net); + thd->main_da.can_overwrite_status= TRUE; + write_eof_packet(thd, net, server_status, total_warn_count); VOID(net_flush(net)); - thd->net.no_send_error= 1; + thd->main_da.can_overwrite_status= FALSE; DBUG_PRINT("info", ("EOF sent, so no more error sending allowed")); } DBUG_VOID_RETURN; @@ -251,7 +223,9 @@ send_eof(THD *thd) write it to the network output buffer. */ -static void write_eof_packet(THD *thd, NET *net) +static void write_eof_packet(THD *thd, NET *net, + uint server_status, + uint total_warn_count) { if (thd->client_capabilities & CLIENT_PROTOCOL_41) { @@ -260,7 +234,7 @@ static void write_eof_packet(THD *thd, NET *net) Don't send warn count during SP execution, as the warn_list is cleared between substatements, and mysqltest gets confused */ - uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535)); + uint tmp= min(total_warn_count, 65535); buff[0]= 254; int2store(buff+1, tmp); /* @@ -269,8 +243,8 @@ static void write_eof_packet(THD *thd, NET *net) other queries (see the if test in dispatch_command / COM_QUERY) */ if (thd->is_fatal_error) - thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; - int2store(buff+3, thd->server_status); + server_status&= ~SERVER_MORE_RESULTS_EXISTS; + int2store(buff + 3, server_status); VOID(my_net_write(net, buff, 5)); } else @@ -364,6 +338,96 @@ static uchar *net_store_length_fast(uchar *packet, uint length) return packet+2; } +/** + Send the status of the current statement execution over network. + + @param thd in fact, carries two parameters, NET for the transport and + Diagnostics_area as the source of status information. + + In MySQL, there are two types of SQL statements: those that return + a result set and those that return status information only. + + If a statement returns a result set, it consists of 3 parts: + - result set meta-data + - variable number of result set rows (can be 0) + - followed and terminated by EOF or ERROR packet + + Once the client has seen the meta-data information, it always + expects an EOF or ERROR to terminate the result set. If ERROR is + received, the result set rows are normally discarded (this is up + to the client implementation, libmysql at least does discard them). + EOF, on the contrary, means "successfully evaluated the entire + result set". Since we don't know how many rows belong to a result + set until it's evaluated, EOF/ERROR is the indicator of the end + of the row stream. Note, that we can not buffer result set rows + on the server -- there may be an arbitrary number of rows. But + we do buffer the last packet (EOF/ERROR) in the Diagnostics_area and + delay sending it till the very end of execution (here), to be able to + change EOF to an ERROR if commit failed or some other error occurred + during the last cleanup steps taken after execution. + + A statement that does not return a result set doesn't send result + set meta-data either. Instead it returns one of: + - OK packet + - ERROR packet. + Similarly to the EOF/ERROR of the previous statement type, OK/ERROR + packet is "buffered" in the diagnostics area and sent to the client + in the end of statement. + + @pre The diagnostics area is assigned or disabled. It can not be empty + -- we assume that every SQL statement or COM_* command + generates OK, ERROR, or EOF status. + + @post The status information is encoded to protocol format and sent to the + client. + + @return We conventionally return void, since the only type of error + that can happen here is a NET (transport) error, and that one + will become visible when we attempt to read from the NET the + next command. + Diagnostics_area::is_sent is set for debugging purposes only. +*/ + +void net_end_statement(THD *thd) +{ + DBUG_ASSERT(! thd->main_da.is_sent); + + /* Can not be true, but do not take chances in production. */ + if (thd->main_da.is_sent) + return; + + switch (thd->main_da.status()) { + case Diagnostics_area::DA_ERROR: + /* The query failed, send error to log and abort bootstrap. */ + net_send_error(thd, + thd->main_da.sql_errno(), + thd->main_da.message()); + break; + case Diagnostics_area::DA_EOF: + net_send_eof(thd, + thd->main_da.server_status(), + thd->main_da.total_warn_count()); + break; + case Diagnostics_area::DA_OK: + net_send_ok(thd, + thd->main_da.server_status(), + thd->main_da.total_warn_count(), + thd->main_da.affected_rows(), + thd->main_da.last_insert_id(), + thd->main_da.message()); + break; + case Diagnostics_area::DA_DISABLED: + break; + case Diagnostics_area::DA_EMPTY: + default: + DBUG_ASSERT(0); + net_send_ok(thd, thd->server_status, thd->total_warn_count, + 0, 0, NULL); + break; + } + thd->main_da.is_sent= TRUE; +} + /**************************************************************************** Functions used by the protocol functions (like send_ok) to store strings @@ -412,6 +476,17 @@ void Protocol::init(THD *thd_arg) #endif } +/** + Finish the result set with EOF packet, as is expected by the client, + if there is an error evaluating the next row and a continue handler + for the error. +*/ + +void Protocol::end_partial_result_set(THD *thd) +{ + net_send_eof(thd, thd->server_status, 0 /* no warnings, we're inside SP */); +} + bool Protocol::flush() { @@ -577,7 +652,14 @@ bool Protocol::send_fields(List<Item> *list, uint flags) } if (flags & SEND_EOF) - write_eof_packet(thd, &thd->net); + { + /* + Mark the end of meta-data result set, and store thd->server_status, + to show that there is no cursor. + Send no warning information, as it will be sent at statement end. + */ + write_eof_packet(thd, &thd->net, thd->server_status, thd->total_warn_count); + } DBUG_RETURN(prepare_for_send(list)); err: diff --git a/sql/protocol.h b/sql/protocol.h index 53584326f03..cd58ec93bbb 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -75,6 +75,7 @@ public: return 0; } virtual bool flush(); + virtual void end_partial_result_set(THD *thd); virtual void prepare_for_resend()=0; virtual bool store_null()=0; @@ -173,9 +174,7 @@ public: void send_warning(THD *thd, uint sql_errno, const char *err=0); void net_send_error(THD *thd, uint sql_errno=0, const char *err=0); -void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, - const char *info=0); -void send_eof(THD *thd); +void net_end_statement(THD *thd); bool send_old_password_request(THD *thd); uchar *net_store_data(uchar *to,const uchar *from, size_t length); uchar *net_store_data(uchar *to,int32 from); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 834d87532af..e294cf8ae2d 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -685,7 +685,7 @@ int connect_to_master(THD *thd, MYSQL* mysql, Master_info* mi) if (!mi->host || !*mi->host) /* empty host */ { - strmov(mysql->net.last_error, "Master is not configured"); + strmov(mysql->net.client_last_error, "Master is not configured"); DBUG_RETURN(1); } mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout); @@ -880,6 +880,8 @@ bool load_master_data(THD* thd) cleanup_mysql_results(db_res, cur_table_res - 1, table_res); goto err; } + /* Clear the result of mysql_create_db(). */ + thd->main_da.reset_diagnostics_area(); if (mysql_select_db(&mysql, db) || mysql_real_query(&mysql, STRING_WITH_LEN("SHOW TABLES")) || diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index ed0dc82cf01..eb32897f937 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -338,12 +338,13 @@ int prepare_record(const Slave_reporting_capability *const log, if (check && ((f->flags & mask) == mask)) { DBUG_ASSERT(log); - log->report(ERROR_LEVEL, ER_NO_DEFAULT_FOR_FIELD, + error= ER_NO_DEFAULT_FOR_FIELD; + log->report(ERROR_LEVEL, error, "Field `%s` of table `%s`.`%s` " "has no default value and cannot be NULL", f->field_name, table->s->db.str, table->s->table_name.str); - error = ER_NO_DEFAULT_FOR_FIELD; + my_error(error, MYF(0), f->field_name); } else f->set_default(); diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 15d7d97affd..3467f6fd67c 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -166,7 +166,7 @@ int init_relay_log_info(Relay_log_info* rli, { sql_print_error("Failed to create a new relay log info file (\ file '%s', errno %d)", fname, my_errno); - msg= current_thd->net.last_error; + msg= current_thd->main_da.message(); goto err; } if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0, @@ -174,7 +174,7 @@ file '%s', errno %d)", fname, my_errno); { sql_print_error("Failed to create a cache on relay log info file '%s'", fname); - msg= current_thd->net.last_error; + msg= current_thd->main_da.message(); goto err; } diff --git a/sql/set_var.cc b/sql/set_var.cc index f1826729914..a01a0b49dbc 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -389,7 +389,7 @@ static sys_var_thd_ulong sys_trans_alloc_block_size(&vars, "transaction_alloc_bl static sys_var_thd_ulong sys_trans_prealloc_size(&vars, "transaction_prealloc_size", &SV::trans_prealloc_size, 0, fix_trans_mem_root); -sys_var_thd_enum sys_thread_handling(&vars, "thread_handling", +sys_var_enum_const sys_thread_handling(&vars, "thread_handling", &SV::thread_handling, &thread_handling_typelib, NULL); @@ -1230,6 +1230,13 @@ uchar *sys_var_enum::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) return (uchar*) enum_names->type_names[*value]; } + +uchar *sys_var_enum_const::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + return (uchar*) enum_names->type_names[global_system_variables.*offset]; +} + bool sys_var_thd_ulong::check(THD *thd, set_var *var) { return (get_unsigned(thd, var) || @@ -3762,7 +3769,7 @@ bool sys_var_opt_readonly::update(THD *thd, set_var *var) can cause to wait on a read lock, it's required for the client application to unlock everything, and acceptable for the server to wait on all locks. */ - if (result= close_cached_tables(thd, true, NULL, false)) + if (result= close_cached_tables(thd, NULL, FALSE, TRUE, TRUE)) goto end_with_read_lock; if (result= make_global_read_lock_block_commit(thd)) diff --git a/sql/set_var.h b/sql/set_var.h index 4e13409b7f6..5be54200c7d 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -305,6 +305,24 @@ public: }; +class sys_var_enum_const :public sys_var +{ + ulong SV::*offset; + TYPELIB *enum_names; +public: + sys_var_enum_const(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg, + TYPELIB *typelib, sys_after_update_func func) + :sys_var(name_arg,func), offset(offset_arg), enum_names(typelib) + { chain_sys_var(chain); } + bool check(THD *thd, set_var *var) { return 1; } + bool update(THD *thd, set_var *var) { return 1; } + SHOW_TYPE show_type() { return SHOW_CHAR; } + bool check_update_type(Item_result type) { return 1; } + bool is_readonly() const { return 1; } + uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); +}; + + class sys_var_thd :public sys_var { public: diff --git a/sql/slave.cc b/sql/slave.cc index f530f2a810d..7aa24319c86 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -982,17 +982,24 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, } thd->query= query; thd->is_slave_error = 0; - thd->net.no_send_ok = 1; bzero((char*) &tables,sizeof(tables)); tables.db = (char*)db; tables.alias= tables.table_name= (char*)table_name; /* Drop the table if 'overwrite' is true */ - if (overwrite && mysql_rm_table(thd,&tables,1,0)) /* drop if exists */ + if (overwrite) { - sql_print_error("create_table_from_dump: failed to drop the table"); - goto err; + if (mysql_rm_table(thd,&tables,1,0)) /* drop if exists */ + { + sql_print_error("create_table_from_dump: failed to drop the table"); + goto err; + } + else + { + /* Clear the OK result of mysql_rm_table(). */ + thd->main_da.reset_diagnostics_area(); + } } /* Create the table. We do not want to log the "create table" statement */ @@ -1013,6 +1020,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, if (thd->is_slave_error) goto err; // mysql_parse took care of the error send + thd->main_da.reset_diagnostics_area(); /* cleanup from CREATE_TABLE */ thd->proc_info = "Opening master dump table"; /* Note: If this function starts to fail for MERGE tables, @@ -1056,7 +1064,6 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, err: close_thread_tables(thd); - thd->net.no_send_ok = 0; DBUG_RETURN(error); } @@ -1108,7 +1115,6 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, error = 0; err: - thd->net.no_send_ok = 0; // Clear up garbage after create_table_from_dump if (!called_connected) mysql_close(mysql); if (errmsg && thd->vio_ok()) @@ -1722,26 +1728,31 @@ static int has_temporary_error(THD *thd) DBUG_ENTER("has_temporary_error"); if (thd->is_fatal_error) - { - DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno))); DBUG_RETURN(0); - } DBUG_EXECUTE_IF("all_errors_are_temporary_errors", - if (thd->net.last_errno) - thd->net.last_errno= ER_LOCK_DEADLOCK;); + if (thd->main_da.is_error()) + { + thd->clear_error(); + my_error(ER_LOCK_DEADLOCK, MYF(0)); + }); + + /* + If there is no message in THD, we can't say if it's a temporary + error or not. This is currently the case for Incident_log_event, + which sets no message. Return FALSE. + */ + if (!thd->is_error()) + DBUG_RETURN(0); /* Temporary error codes: currently, InnoDB deadlock detected by InnoDB or lock wait timeout (innodb_lock_wait_timeout exceeded */ - if (thd->net.last_errno == ER_LOCK_DEADLOCK || - thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT) - { - DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno))); + if (thd->main_da.sql_errno() == ER_LOCK_DEADLOCK || + thd->main_da.sql_errno() == ER_LOCK_WAIT_TIMEOUT) DBUG_RETURN(1); - } #ifdef HAVE_NDB_BINLOG /* @@ -2556,20 +2567,21 @@ Slave SQL thread aborted. Can't execute init_slave query"); */ uint32 const last_errno= rli->last_error().number; - DBUG_PRINT("info", ("thd->net.last_errno=%d; rli->last_error.number=%d", - thd->net.last_errno, last_errno)); - if (thd->net.last_errno != 0) + if (thd->is_error()) { - char const *const errmsg= - thd->net.last_error ? thd->net.last_error : "<no message>"; + char const *const errmsg= thd->main_da.message(); + + DBUG_PRINT("info", + ("thd->main_da.sql_errno()=%d; rli->last_error.number=%d", + thd->main_da.sql_errno(), last_errno)); if (last_errno == 0) { - rli->report(ERROR_LEVEL, thd->net.last_errno, errmsg); + rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), errmsg); } - else if (last_errno != thd->net.last_errno) + else if (last_errno != thd->main_da.sql_errno()) { sql_print_error("Slave (additional info): %s Error_code: %d", - errmsg, thd->net.last_errno); + errmsg, thd->main_da.sql_errno()); } } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 4b432cef5cd..2e36593a126 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1202,12 +1202,6 @@ sp_head::execute(THD *thd) err_status= i->execute(thd, &ip); - /* - If this SP instruction have sent eof, it has caused no_send_error to be - set. Clear it back to allow the next instruction to send error. (multi- - statement execution code clears no_send_error between statements too) - */ - thd->net.no_send_error= 0; if (i->free_list) cleanup_items(i->free_list); @@ -2762,14 +2756,22 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) thd->query, thd->query_length) <= 0) { res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); + + if (thd->main_da.is_eof()) + net_end_statement(thd); + + query_cache_end_of_result(thd); + if (!res && unlikely(thd->enable_slow_log)) log_slow_statement(thd); - query_cache_end_of_result(thd); } else *nextp= m_ip+1; thd->query= query; thd->query_length= query_length; + + if (!thd->is_error()) + thd->main_da.reset_diagnostics_area(); } DBUG_RETURN(res); } diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 70a043c4fac..8395648689b 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -287,7 +287,6 @@ sp_rcontext::find_handler(THD *thd, uint sql_errno, sql_errno The error code level Warning level thd The current thread - - thd->net.report_error is an optional output. RETURN TRUE if a handler was found. @@ -298,7 +297,6 @@ sp_rcontext::handle_error(uint sql_errno, MYSQL_ERROR::enum_warning_level level, THD *thd) { - bool handled= FALSE; MYSQL_ERROR::enum_warning_level elevated_level= level; @@ -310,25 +308,7 @@ sp_rcontext::handle_error(uint sql_errno, elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR; } - if (find_handler(thd, sql_errno, elevated_level)) - { - if (elevated_level == MYSQL_ERROR::WARN_LEVEL_ERROR) - { - /* - Forces to abort the current instruction execution. - NOTE: This code is altering the original meaning of - the net.report_error flag (send an error to the client). - In the context of stored procedures with error handlers, - the flag is reused to cause error propagation, - until the error handler is reached. - No messages will be sent to the client in that context. - */ - thd->net.report_error= 1; - } - handled= TRUE; - } - - return handled; + return find_handler(thd, sql_errno, elevated_level); } void diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 58ba8c28fb7..d2d26da229a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -695,7 +695,7 @@ my_bool acl_reload(THD *thd) if (simple_open_n_lock_tables(thd, tables)) { sql_print_error("Fatal error: Can't open and lock privilege tables: %s", - thd->net.last_error); + thd->main_da.message()); goto end; } @@ -3800,11 +3800,11 @@ my_bool grant_reload(THD *thd) close_thread_tables(thd); /* - It is ok failing to load procs_priv table because we may be + It is OK failing to load procs_priv table because we may be working with 4.1 privilege tables. */ if (grant_reload_procs_priv(thd)) - my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "mysql.procs_priv"); + return_val= 1; rw_wrlock(&LOCK_grant); grant_version++; @@ -5693,9 +5693,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) if (result) my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); - DBUG_PRINT("info", ("thd->net.last_errno: %d", thd->net.last_errno)); - DBUG_PRINT("info", ("thd->net.last_error: %s", thd->net.last_error)); - write_bin_log(thd, FALSE, thd->query, thd->query_length); rw_unlock(&LOCK_grant); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4474671eadf..67aba1a3a0d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -130,7 +130,7 @@ void table_cache_free(void) DBUG_ENTER("table_cache_free"); if (table_def_inited) { - close_cached_tables((THD*) 0,0,(TABLE_LIST*) 0); + close_cached_tables(NULL, NULL, FALSE, FALSE, FALSE); if (!open_cache.records) // Safety first hash_free(&open_cache); } @@ -491,9 +491,28 @@ static TABLE_SHARE int tmp; DBUG_ENTER("get_table_share_with_create"); - if ((share= get_table_share(thd, table_list, key, key_length, - db_flags, error)) || - thd->net.last_errno != ER_NO_SUCH_TABLE) + share= get_table_share(thd, table_list, key, key_length, db_flags, error); + /* + If share is not NULL, we found an existing share. + + If share is NULL, and there is no error, we're inside + pre-locking, which silences 'ER_NO_SUCH_TABLE' errors + with the intention to silently drop non-existing tables + from the pre-locking list. In this case we still need to try + auto-discover before returning a NULL share. + + If share is NULL and the error is ER_NO_SUCH_TABLE, this is + the same as above, only that the error was not silenced by + pre-locking. Once again, we need to try to auto-discover + the share. + + Finally, if share is still NULL, it's a real error and we need + to abort. + + @todo Rework alternative ways to deal with ER_NO_SUCH TABLE. + */ + if (share || thd->is_error() && thd->main_da.sql_errno() != ER_NO_SUCH_TABLE) + DBUG_RETURN(share); /* Table didn't exist. Check if some engine can provide it */ @@ -502,9 +521,13 @@ static TABLE_SHARE { /* No such table in any engine. - Hide "Table doesn't exist" errors if table belong to view + Hide "Table doesn't exist" errors if the table belongs to a view. + The check for thd->is_error() is necessary to not push an + unwanted error in case of pre-locking, which silences + "no such table" errors. + @todo Rework the alternative ways to deal with ER_NO_SUCH TABLE. */ - if (table_list->belong_to_view) + if (thd->is_error() && table_list->belong_to_view) { TABLE_LIST *view= table_list->belong_to_view; thd->clear_error(); @@ -885,16 +908,24 @@ void free_io_cache(TABLE *table) /* Close all tables which aren't in use by any thread - THD can be NULL, but then if_wait_for_refresh must be FALSE - and tables must be NULL. + @param thd Thread context + @param tables List of tables to remove from the cache + @param have_lock If LOCK_open is locked + @param wait_for_refresh Wait for a impending flush + @param wait_for_placeholders Wait for tables being reopened so that the GRL + won't proceed while write-locked tables are being reopened by other + threads. + + @remark THD can be NULL, but then wait_for_refresh must be FALSE + and tables must be NULL. */ -bool close_cached_tables(THD *thd, bool if_wait_for_refresh, - TABLE_LIST *tables, bool have_lock) +bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock, + bool wait_for_refresh, bool wait_for_placeholders) { bool result=0; DBUG_ENTER("close_cached_tables"); - DBUG_ASSERT(thd || (!if_wait_for_refresh && !tables)); + DBUG_ASSERT(thd || (!wait_for_refresh && !tables)); if (!have_lock) VOID(pthread_mutex_lock(&LOCK_open)); @@ -918,7 +949,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, } DBUG_PRINT("tcache", ("incremented global refresh_version to: %lu", refresh_version)); - if (if_wait_for_refresh) + if (wait_for_refresh) { /* Other threads could wait in a loop in open_and_lock_tables(), @@ -975,13 +1006,13 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, found=1; } if (!found) - if_wait_for_refresh=0; // Nothing to wait for + wait_for_refresh=0; // Nothing to wait for } #ifndef EMBEDDED_LIBRARY if (!tables) kill_delayed_threads(); #endif - if (if_wait_for_refresh) + if (wait_for_refresh) { /* If there is any table that has a lower refresh_version, wait until @@ -1004,6 +1035,9 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, for (uint idx=0 ; idx < open_cache.records ; idx++) { TABLE *table=(TABLE*) hash_element(&open_cache,idx); + /* Avoid a self-deadlock. */ + if (table->in_use == thd) + continue; /* Note that we wait here only for tables which are actually open, and not for placeholders with TABLE::open_placeholder set. Waiting for @@ -1018,7 +1052,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, are employed by CREATE TABLE as in this case table simply does not exist yet. */ - if (table->needs_reopen_or_name_lock() && table->db_stat) + if (table->needs_reopen_or_name_lock() && (table->db_stat || + (table->open_placeholder && wait_for_placeholders))) { found=1; DBUG_PRINT("signal", ("Waiting for COND_refresh")); @@ -1037,11 +1072,18 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, thd->in_lock_tables=0; /* Set version for table */ for (TABLE *table=thd->open_tables; table ; table= table->next) - table->s->version= refresh_version; + { + /* + Preserve the version (0) of write locked tables so that a impending + global read lock won't sneak in. + */ + if (table->reginfo.lock_type < TL_WRITE_ALLOW_WRITE) + table->s->version= refresh_version; + } } if (!have_lock) VOID(pthread_mutex_unlock(&LOCK_open)); - if (if_wait_for_refresh) + if (wait_for_refresh) { pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; @@ -1068,10 +1110,10 @@ bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh, DBUG_ASSERT(thd); bzero(&tmp, sizeof(TABLE_LIST)); - + if (!have_lock) VOID(pthread_mutex_lock(&LOCK_open)); - + for (idx= 0; idx < table_def_cache.records; idx++) { TABLE_SHARE *share= (TABLE_SHARE *) hash_element(&table_def_cache, idx); @@ -1100,11 +1142,11 @@ bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh, } if (tables) - result= close_cached_tables(thd, FALSE, tables, TRUE); - + result= close_cached_tables(thd, tables, TRUE, FALSE, FALSE); + if (!have_lock) VOID(pthread_mutex_unlock(&LOCK_open)); - + if (if_wait_for_refresh) { pthread_mutex_lock(&thd->mysys_var->mutex); @@ -2204,7 +2246,7 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond) current thread. @param thd current thread context - @param tables able list containing one table to open. + @param tables table list containing one table to open. @return FALSE on success, TRUE otherwise. */ @@ -3272,8 +3314,8 @@ static bool reattach_merge(THD *thd, TABLE **err_tables_p) @param thd Thread context @param get_locks Should we get locks after reopening tables ? - @param in_refresh Are we in FLUSH TABLES ? TODO: It seems that - we can remove this parameter. + @param mark_share_as_old Mark share as old to protect from a impending + global read lock. @note Since this function can't properly handle prelocking and create placeholders it should be used in very special @@ -3287,13 +3329,17 @@ static bool reattach_merge(THD *thd, TABLE **err_tables_p) @return FALSE in case of success, TRUE - otherwise. */ -bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) +bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old) { TABLE *table,*next,**prev; TABLE **tables,**tables_ptr; // For locks TABLE *err_tables= NULL; bool error=0, not_used; bool merge_table_found= FALSE; + const uint flags= MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN | + MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK | + MYSQL_LOCK_IGNORE_FLUSH; + DBUG_ENTER("reopen_tables"); if (!thd->open_tables) @@ -3354,7 +3400,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) /* Do not handle locks of MERGE children. */ if (get_locks && !db_stat && !table->parent) *tables_ptr++= table; // need new lock on this - if (in_refresh) + if (mark_share_as_old) { table->s->version=0; table->open_placeholder= 0; @@ -3387,7 +3433,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) */ thd->some_tables_deleted=0; if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables), - MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, ¬_used))) + flags, ¬_used))) { thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock); } diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index fa6aa8f5881..77c5155b41b 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -40,13 +40,6 @@ void mysql_client_binlog_statement(THD* thd) if (check_global_access(thd, SUPER_ACL)) DBUG_VOID_RETURN; - /* - Temporarily turn off send_ok, since different events handle this - differently - */ - my_bool nsok= thd->net.no_send_ok; - thd->net.no_send_ok= TRUE; - size_t coded_len= thd->lex->comment.length + 1; size_t decoded_len= base64_needed_decoded_length(coded_len); DBUG_ASSERT(coded_len > 0); @@ -193,20 +186,11 @@ void mysql_client_binlog_statement(THD* thd) } } - /* - Restore setting of no_send_ok - */ - thd->net.no_send_ok= nsok; DBUG_PRINT("info",("binlog base64 execution finished successfully")); send_ok(thd); end: - /* - Restore setting of no_send_ok - */ - thd->net.no_send_ok= nsok; - delete desc; my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); DBUG_VOID_RETURN; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 56b048a4f9d..f1803a329c5 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1403,6 +1403,7 @@ def_week_frmt: %lu", thd->limit_found_rows = query->found_rows(); thd->status_var.last_query_cost= 0.0; + thd->main_da.disable_status(); BLOCK_UNLOCK_RD(query_block); DBUG_RETURN(1); // Result sent to client diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 6ebd0e5f7dc..b4d728daa5e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -351,6 +351,124 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, return thd->strmake(str.ptr(), str.length()); } +/** + Clear this diagnostics area. + + Normally called at the end of a statement. +*/ + +void +Diagnostics_area::reset_diagnostics_area() +{ +#ifdef DBUG_OFF + can_overwrite_status= FALSE; + /** Don't take chances in production */ + m_message[0]= '\0'; + m_sql_errno= 0; + m_server_status= 0; + m_affected_rows= 0; + m_last_insert_id= 0; + m_total_warn_count= 0; +#endif + is_sent= FALSE; + /** Tiny reset in debug mode to see garbage right away */ + m_status= DA_EMPTY; +} + + +/** + Set OK status -- ends commands that do not return a + result set, e.g. INSERT/UPDATE/DELETE. +*/ + +void +Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg, + ulonglong last_insert_id_arg, + const char *message_arg) +{ + DBUG_ASSERT(! is_set()); +#ifdef DBUG_OFF + /* In production, refuse to overwrite an error with an OK packet. */ + if (is_error()) + return; +#endif + /** Only allowed to report success if has not yet reported an error */ + + m_server_status= thd->server_status; + m_total_warn_count= thd->total_warn_count; + m_affected_rows= affected_rows_arg; + m_last_insert_id= last_insert_id_arg; + if (message_arg) + strmake(m_message, message_arg, sizeof(m_message)); + else + m_message[0]= '\0'; + m_status= DA_OK; +} + + +/** + Set EOF status. +*/ + +void +Diagnostics_area::set_eof_status(THD *thd) +{ + /** Only allowed to report eof if has not yet reported an error */ + + DBUG_ASSERT(! is_set()); +#ifdef DBUG_OFF + /* In production, refuse to overwrite an error with an EOF packet. */ + if (is_error()) + return; +#endif + + m_server_status= thd->server_status; + /* + If inside a stored procedure, do not return the total + number of warnings, since they are not available to the client + anyway. + */ + m_total_warn_count= thd->spcont ? 0 : thd->total_warn_count; + + m_status= DA_EOF; +} + +/** + Set ERROR status. +*/ + +void +Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg, + const char *message_arg) +{ + /* + Only allowed to report error if has not yet reported a success + The only exception is when we flush the message to the client, + an error can happen during the flush. + */ + DBUG_ASSERT(! is_set() || can_overwrite_status); + + m_sql_errno= sql_errno_arg; + strmake(m_message, message_arg, sizeof(m_message)); + + m_status= DA_ERROR; +} + + +/** + Mark the diagnostics area as 'DISABLED'. + + This is used in rare cases when the COM_ command at hand sends a response + in a custom format. One example is the query cache, another is + COM_STMT_PREPARE. +*/ + +void +Diagnostics_area::disable_status() +{ + DBUG_ASSERT(! is_set()); + m_status= DA_DISABLED; +} THD::THD() @@ -431,7 +549,6 @@ THD::THD() net.vio=0; #endif client_capabilities= 0; // minimalistic client - net.last_error[0]=0; // If error on boot #ifdef HAVE_QUERY_CACHE query_cache_init_query(&net); // If error on boot #endif @@ -1324,12 +1441,12 @@ void select_send::abort() { DBUG_ENTER("select_send::abort"); if (is_result_set_started && thd->spcont && - thd->spcont->find_handler(thd, thd->net.last_errno, + thd->spcont->find_handler(thd, thd->main_da.sql_errno(), MYSQL_ERROR::WARN_LEVEL_ERROR)) { /* We're executing a stored procedure, have an open result - set, an SQL exception conditiona and a handler for it. + set, an SQL exception condition and a handler for it. In this situation we must abort the current statement, silence the error and start executing the continue/exit handler. @@ -1337,9 +1454,7 @@ void select_send::abort() otherwise the client will hang due to the violation of the client/server protocol. */ - thd->net.report_error= 0; - send_eof(); - thd->net.report_error= 1; // Abort SP + thd->protocol->end_partial_result_set(thd); } DBUG_VOID_RETURN; } @@ -1391,12 +1506,14 @@ bool select_send::send_data(List<Item> &items) } } thd->sent_row_count++; - if (!thd->vio_ok()) - DBUG_RETURN(0); - if (! thd->is_error()) + if (thd->is_error()) + { + protocol->remove_last_row(); + DBUG_RETURN(1); + } + if (thd->vio_ok()) DBUG_RETURN(protocol->write()); - protocol->remove_last_row(); - DBUG_RETURN(1); + DBUG_RETURN(0); } bool select_send::send_eof() @@ -1414,14 +1531,9 @@ bool select_send::send_eof() mysql_unlock_tables(thd, thd->lock); thd->lock=0; } - if (! thd->is_error()) - { - ::send_eof(thd); - is_result_set_started= 0; - return 0; - } - else - return 1; + ::send_eof(thd); + is_result_set_started= 0; + return FALSE; } @@ -2704,7 +2816,6 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, { backup->options= options; backup->in_sub_stmt= in_sub_stmt; - backup->no_send_ok= net.no_send_ok; backup->enable_slow_log= enable_slow_log; backup->limit_found_rows= limit_found_rows; backup->examined_row_count= examined_row_count; @@ -2735,9 +2846,6 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, cuted_fields= 0; transaction.savepoints= 0; first_successful_insert_id_in_cur_stmt= 0; - - /* Surpress OK packets in case if we will execute statements */ - net.no_send_ok= TRUE; } @@ -2760,7 +2868,6 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) transaction.savepoints= backup->savepoints; options= backup->options; in_sub_stmt= backup->in_sub_stmt; - net.no_send_ok= backup->no_send_ok; enable_slow_log= backup->enable_slow_log; first_successful_insert_id_in_prev_stmt= backup->first_successful_insert_id_in_prev_stmt; diff --git a/sql/sql_class.h b/sql/sql_class.h index ce035b34679..8c2c2dce1de 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -913,7 +913,6 @@ public: uint in_sub_stmt; bool enable_slow_log; bool last_insert_id_used; - my_bool no_send_ok; SAVEPOINT *savepoints; }; @@ -976,6 +975,123 @@ public: /** + Stores status of the currently executed statement. + Cleared at the beginning of the statement, and then + can hold either OK, ERROR, or EOF status. + Can not be assigned twice per statement. +*/ + +class Diagnostics_area +{ +public: + enum enum_diagnostics_status + { + /** The area is cleared at start of a statement. */ + DA_EMPTY= 0, + /** Set whenever one calls send_ok(). */ + DA_OK, + /** Set whenever one calls send_eof(). */ + DA_EOF, + /** Set whenever one calls my_error() or my_message(). */ + DA_ERROR, + /** Set in case of a custom response, such as one from COM_STMT_PREPARE. */ + DA_DISABLED + }; + /** True if status information is sent to the client. */ + bool is_sent; + /** Set to make set_error_status after set_{ok,eof}_status possible. */ + bool can_overwrite_status; + + void set_ok_status(THD *thd, ha_rows affected_rows_arg, + ulonglong last_insert_id_arg, + const char *message); + void set_eof_status(THD *thd); + void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg); + + void disable_status(); + + void reset_diagnostics_area(); + + bool is_set() const { return m_status != DA_EMPTY; } + bool is_error() const { return m_status == DA_ERROR; } + bool is_eof() const { return m_status == DA_EOF; } + bool is_ok() const { return m_status == DA_OK; } + bool is_disabled() const { return m_status == DA_DISABLED; } + enum_diagnostics_status status() const { return m_status; } + + const char *message() const + { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK); return m_message; } + + uint sql_errno() const + { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; } + + uint server_status() const + { + DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF); + return m_server_status; + } + + ha_rows affected_rows() const + { DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; } + + ulonglong last_insert_id() const + { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; } + + uint total_warn_count() const + { + DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF); + return m_total_warn_count; + } + + Diagnostics_area() { reset_diagnostics_area(); } + +private: + /** Message buffer. Can be used by OK or ERROR status. */ + char m_message[MYSQL_ERRMSG_SIZE]; + /** + SQL error number. One of ER_ codes from share/errmsg.txt. + Set by set_error_status. + */ + uint m_sql_errno; + + /** + Copied from thd->server_status when the diagnostics area is assigned. + We need this member as some places in the code use the following pattern: + thd->server_status|= ... + send_eof(thd); + thd->server_status&= ~... + Assigned by OK, EOF or ERROR. + */ + uint m_server_status; + /** + The number of rows affected by the last statement. This is + semantically close to thd->row_count_func, but has a different + life cycle. thd->row_count_func stores the value returned by + function ROW_COUNT() and is cleared only by statements that + update its value, such as INSERT, UPDATE, DELETE and few others. + This member is cleared at the beginning of the next statement. + + We could possibly merge the two, but life cycle of thd->row_count_func + can not be changed. + */ + ha_rows m_affected_rows; + /** + Similarly to the previous member, this is a replacement of + thd->first_successful_insert_id_in_prev_stmt, which is used + to implement LAST_INSERT_ID(). + */ + ulonglong m_last_insert_id; + /** The total number of warnings. */ + uint m_total_warn_count; + enum_diagnostics_status m_status; + /** + @todo: the following THD members belong here: + - warn_list, warn_count, + */ +}; + + +/** @class THD For each client connection we create a separate thread with THD serving as a thread/connection descriptor @@ -1398,6 +1514,7 @@ public: List <MYSQL_ERROR> warn_list; uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; uint total_warn_count; + Diagnostics_area main_da; /* Id of current query. Statement can be reused to execute several queries query_id is global in context of the whole MySQL server. @@ -1712,12 +1829,18 @@ public: CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); int send_explain_fields(select_result *result); #ifndef EMBEDDED_LIBRARY + /** + Clear the current error, if any. + We do not clear is_fatal_error or is_fatal_sub_stmt_error since we + assume this is never called if the fatal error is set. + @todo: To silence an error, one should use Internal_error_handler + mechanism. In future this function will be removed. + */ inline void clear_error() { DBUG_ENTER("clear_error"); - net.last_error[0]= 0; - net.last_errno= 0; - net.report_error= 0; + if (main_da.is_error()) + main_da.reset_diagnostics_area(); is_slave_error= 0; DBUG_VOID_RETURN; } @@ -1726,10 +1849,14 @@ public: void clear_error(); inline bool vio_ok() const { return true; } #endif + /** + Mark the current error as fatal. Warning: this does not + set any error, it sets a property of the error, so must be + followed or prefixed with my_error(). + */ inline void fatal_error() { is_fatal_error= 1; - net.report_error= 1; DBUG_PRINT("error",("Fatal error set")); } /** @@ -1745,7 +1872,7 @@ public: To raise this flag, use my_error(). */ - inline bool is_error() const { return net.report_error; } + inline bool is_error() const { return main_da.is_error(); } inline CHARSET_INFO *charset() { return variables.character_set_client; } void update_charset(); @@ -1969,6 +2096,24 @@ private: }; +/** A short cut for thd->main_da.set_ok_status(). */ + +inline void +send_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0, + const char *message= NULL) +{ + thd->main_da.set_ok_status(thd, affected_rows, id, message); +} + + +/** A short cut for thd->main_da.set_eof_status(). */ + +inline void +send_eof(THD *thd) +{ + thd->main_da.set_eof_status(thd); +} + #define tmp_disable_binlog(A) \ {ulonglong tmp_disable_binlog__save_options= (A)->options; \ (A)->options&= ~OPTION_BIN_LOG @@ -2506,6 +2651,7 @@ public: void send_error(uint errcode,const char *err); int do_deletes(); bool send_eof(); + virtual void abort(); }; @@ -2546,8 +2692,9 @@ public: bool send_data(List<Item> &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); - int do_updates (bool from_send_error); + int do_updates(); bool send_eof(); + virtual void abort(); }; class my_var : public Sql_alloc { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 76237576764..309a1c7ab5d 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -948,19 +948,20 @@ bool setup_connection_thread_globals(THD *thd) bool login_connection(THD *thd) { NET *net= &thd->net; + int error; DBUG_ENTER("login_connection"); DBUG_PRINT("info", ("login_connection called by thread %lu", thd->thread_id)); - net->no_send_error= 0; - /* Use "connect_timeout" value during connection phase */ my_net_set_read_timeout(net, connect_timeout); my_net_set_write_timeout(net, connect_timeout); - if (check_connection(thd)) + error= check_connection(thd); + net_end_statement(thd); + + if (error) { // Wrong permissions - net_send_error(thd); #ifdef __NT__ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) my_sleep(1000); /* must wait after eof() */ @@ -989,13 +990,12 @@ void end_connection(THD *thd) if (thd->user_connect) decrease_user_connections(thd->user_connect); - if (thd->killed || - net->error && net->vio != 0 && thd->is_error()) + if (thd->killed || net->error && net->vio != 0) { statistic_increment(aborted_threads,&LOCK_status); } - if (net->error && net->vio != 0 && thd->is_error()) + if (net->error && net->vio != 0) { if (!thd->killed && thd->variables.log_warnings > 1) { @@ -1005,11 +1005,9 @@ void end_connection(THD *thd) thd->thread_id,(thd->db ? thd->db : "unconnected"), sctx->user ? sctx->user : "unauthenticated", sctx->host_or_ip, - (net->last_errno ? ER(net->last_errno) : + (thd->main_da.is_error() ? thd->main_da.message() : ER(ER_UNKNOWN_ERROR))); } - - net_send_error(thd, net->last_errno, NullS); } } @@ -1045,24 +1043,14 @@ static void prepare_new_connection_state(THD* thd) if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL)) { execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); - /* - execute_init_command calls net_send_error. - If there was an error during execution of the init statements, - the error at this moment is present in thd->net.last_error and also - thd->is_slave_error and thd->net.report_error are set. - net_send_error sends the contents of thd->net.last_error and - clears thd->net.report_error. It doesn't, however, clean - thd->is_slave_error or thd->net.last_error. Here we make use of this - fact. - */ - if (thd->is_slave_error) + if (thd->is_error()) { thd->killed= THD::KILL_CONNECTION; sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), thd->thread_id,(thd->db ? thd->db : "unconnected"), sctx->user ? sctx->user : "unauthenticated", sctx->host_or_ip, "init_connect command failed"); - sql_print_warning("%s", thd->net.last_error); + sql_print_warning("%s", thd->main_da.message()); } thd->proc_info=0; thd->set_time(); @@ -1129,7 +1117,6 @@ pthread_handler_t handle_one_connection(void *arg) while (!net->error && net->vio != 0 && !(thd->killed == THD::KILL_CONNECTION)) { - net->no_send_error= 0; if (do_command(thd)) break; } diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 7686dc695ad..f158b5488d0 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -921,6 +921,8 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) { ha_drop_database(path); query_cache_invalidate1(db); + (void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */ + Events::drop_schema_events(thd, db); error = 0; } } @@ -956,6 +958,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) /* These DDL methods and logging protected with LOCK_mysql_create_db */ mysql_bin_log.write(&qinfo); } + thd->clear_error(); thd->server_status|= SERVER_STATUS_DB_DROPPED; send_ok(thd, (ulong) deleted); thd->server_status&= ~SERVER_STATUS_DB_DROPPED; @@ -999,8 +1002,6 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) } exit: - (void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */ - Events::drop_schema_events(thd, db); /* If this database was the client's selected database, we silently change the client's selected database to nothing (to have an empty diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 509e736f6e7..a73963d7f86 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -728,6 +728,14 @@ void multi_delete::send_error(uint errcode,const char *err) /* First send error what ever it is ... */ my_message(errcode, err, MYF(0)); + DBUG_VOID_RETURN; +} + + +void multi_delete::abort() +{ + DBUG_ENTER("multi_delete::abort"); + /* the error was handled or nothing deleted and no side effects return */ if (error_handled || !thd->transaction.stmt.modified_non_trans_table && !deleted) diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index ea7545fe5cb..10b42e11b26 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -147,8 +147,9 @@ exit: /* Hide "Unknown column" or "Unknown function" error */ if (orig_table_list->view) { - if (thd->net.last_errno == ER_BAD_FIELD_ERROR || - thd->net.last_errno == ER_SP_DOES_NOT_EXIST) + if (thd->is_error() && + (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR || + thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST)) { thd->clear_error(); my_error(ER_VIEW_INVALID, MYF(0), orig_table_list->db, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 805a8aeb445..1dd915fb9b6 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1916,7 +1916,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) main thread. Use of my_message will enable stored procedures continue handlers. */ - my_message(di->thd.net.last_errno, di->thd.net.last_error, + my_message(di->thd.main_da.sql_errno(), di->thd.main_da.message(), MYF(0)); } di->unlock(); @@ -1993,7 +1993,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) goto error; if (dead) { - my_message(thd.net.last_errno, thd.net.last_error, MYF(0)); + my_message(thd.main_da.sql_errno(), thd.main_da.message(), MYF(0)); goto error; } } @@ -2252,7 +2252,9 @@ pthread_handler_t handle_delayed_insert(void *arg) #if !defined( __WIN__) /* Win32 calls this in pthread_create */ if (my_thread_init()) { - strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES)); + /* Can't use my_error since store_globals has not yet been called */ + thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES, + ER(ER_OUT_OF_RESOURCES)); goto end; } #endif @@ -2261,8 +2263,10 @@ pthread_handler_t handle_delayed_insert(void *arg) thd->thread_stack= (char*) &thd; if (init_thr_lock() || thd->store_globals()) { + /* Can't use my_error since store_globals has perhaps failed */ + thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES, + ER(ER_OUT_OF_RESOURCES)); thd->fatal_error(); - strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES)); goto err; } @@ -2665,7 +2669,7 @@ bool Delayed_insert::handle_inserts(void) { /* This should never happen */ table->file->print_error(error,MYF(0)); - sql_print_error("%s",thd.net.last_error); + sql_print_error("%s", thd.main_da.message()); DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed in loop")); goto err; } @@ -2706,7 +2710,7 @@ bool Delayed_insert::handle_inserts(void) if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) { // This shouldn't happen table->file->print_error(error,MYF(0)); - sql_print_error("%s",thd.net.last_error); + sql_print_error("%s", thd.main_da.message()); DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed after loop")); goto err; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7c00ac6d1c9..b60a72e4c53 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -328,7 +328,6 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, */ save_vio= thd->net.vio; thd->net.vio= 0; - thd->net.no_send_error= 0; dispatch_command(COM_QUERY, thd, init_command_var->value, init_command_var->value_length); @@ -397,8 +396,8 @@ pthread_handler_t handle_bootstrap(void *arg) /* purecov: begin tested */ if (net_realloc(&(thd->net), 2 * thd->net.max_packet)) { - net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS); - thd->fatal_error(); + net_end_statement(thd); + bootstrap_error= 1; break; } buff= (char*) thd->net.buff; @@ -406,7 +405,7 @@ pthread_handler_t handle_bootstrap(void *arg) length+= (ulong) strlen(buff + length); /* purecov: end */ } - if (thd->is_fatal_error) + if (bootstrap_error) break; /* purecov: inspected */ while (length && (my_isspace(thd->charset(), buff[length-1]) || @@ -433,16 +432,11 @@ pthread_handler_t handle_bootstrap(void *arg) mysql_parse(thd, thd->query, length, & found_semicolon); close_thread_tables(thd); // Free tables - if (thd->is_fatal_error) - break; + bootstrap_error= thd->is_error(); + net_end_statement(thd); - if (thd->is_error()) - { - /* The query failed, send error to log and abort bootstrap */ - net_send_error(thd); - thd->fatal_error(); + if (bootstrap_error) break; - } free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); #ifdef USING_TRANSACTIONS @@ -451,9 +445,6 @@ pthread_handler_t handle_bootstrap(void *arg) } end: - /* Remember the exit code of bootstrap */ - bootstrap_error= thd->is_fatal_error; - net_end(&thd->net); thd->cleanup(); delete thd; @@ -712,7 +703,12 @@ bool do_command(THD *thd) */ my_net_set_read_timeout(net, thd->variables.net_wait_timeout); + /* + XXX: this code is here only to clear possible errors of init_connect. + Consider moving to init_connect() instead. + */ thd->clear_error(); // Clear error message + thd->main_da.reset_diagnostics_area(); net_new_transaction(net); if ((packet_length=my_net_read(net)) == packet_error) @@ -723,10 +719,13 @@ bool do_command(THD *thd) /* Check if we can continue without closing the connection */ + /* The error must be set. */ + DBUG_ASSERT(thd->is_error()); + net_end_statement(thd); + if (net->error != 3) DBUG_RETURN(TRUE); // We have to close it. - net_send_error(thd, net->last_errno, NullS); net->error= 0; DBUG_RETURN(FALSE); } @@ -767,6 +766,74 @@ bool do_command(THD *thd) #endif /* EMBEDDED_LIBRARY */ +/** + @brief Determine if an attempt to update a non-temporary table while the + read-only option was enabled has been made. + + This is a helper function to mysql_execute_command. + + @note SQLCOM_MULTI_UPDATE is an exception and delt with elsewhere. + + @see mysql_execute_command + @returns Status code + @retval TRUE The statement should be denied. + @retval FALSE The statement isn't updating any relevant tables. +*/ + +static my_bool deny_updates_if_read_only_option(THD *thd, + TABLE_LIST *all_tables) +{ + DBUG_ENTER("deny_updates_if_read_only_option"); + + if (!opt_readonly) + DBUG_RETURN(FALSE); + + LEX *lex= thd->lex; + + const my_bool user_is_super= + ((ulong)(thd->security_ctx->master_access & SUPER_ACL) == + (ulong)SUPER_ACL); + + if (user_is_super) + DBUG_RETURN(FALSE); + + if (!(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA)) + DBUG_RETURN(FALSE); + + /* Multi update is an exception and is dealt with later. */ + if (lex->sql_command == SQLCOM_UPDATE_MULTI) + DBUG_RETURN(FALSE); + + const my_bool create_temp_tables= + (lex->sql_command == SQLCOM_CREATE_TABLE) && + (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE); + + const my_bool drop_temp_tables= + (lex->sql_command == SQLCOM_DROP_TABLE) && + lex->drop_temporary; + + const my_bool update_real_tables= + some_non_temp_table_to_be_updated(thd, all_tables) && + !(create_temp_tables || drop_temp_tables); + + + const my_bool create_or_drop_databases= + (lex->sql_command == SQLCOM_CREATE_DB) || + (lex->sql_command == SQLCOM_DROP_DB); + + if (update_real_tables || create_or_drop_databases) + { + /* + An attempt was made to modify one or more non-temporary tables. + */ + DBUG_RETURN(TRUE); + } + + + /* Assuming that only temporary tables are modified. */ + DBUG_RETURN(FALSE); +} + /* Perform one connection-level (COM_XXXX) command. @@ -860,7 +927,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, db.length= db_len; tbl_name= strmake(db.str, packet + 1, db_len)+1; strmake(tbl_name, packet + db_len + 2, tbl_len); - mysql_table_dump(thd, &db, tbl_name); + if (mysql_table_dump(thd, &db, tbl_name) == 0) + thd->main_da.disable_status(); break; } case COM_CHANGE_USER: @@ -1024,7 +1092,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, while (!thd->killed && found_semicolon && ! thd->is_error()) { char *next_packet= (char*) found_semicolon; - net->no_send_error= 0; + + net_end_statement(thd); + query_cache_end_of_result(thd); /* Multiple queries exits, execute them individually */ @@ -1125,6 +1195,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* We don't calculate statistics for this command */ general_log_print(thd, command, NullS); net->error=0; // Don't give 'abort' message + thd->main_da.disable_status(); // Don't send anything back error=TRUE; // End server break; @@ -1241,16 +1312,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_PRINT("quit",("Got shutdown command for level %u", level)); general_log_print(thd, command, NullS); send_eof(thd); -#ifdef __WIN__ - sleep(1); // must wait after eof() -#endif - /* - The client is next going to send a COM_QUIT request (as part of - mysql_close()). Make the life simpler for the client by sending - the response for the coming COM_QUIT in advance - */ - send_eof(thd); - close_connection(thd, 0, 1); close_thread_tables(thd); // Free before kill kill_mysql(); error=TRUE; @@ -1263,13 +1324,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ulong uptime; uint length; ulonglong queries_per_second1000; -#ifndef EMBEDDED_LIBRARY char buff[250]; uint buff_len= sizeof(buff); -#else - char *buff= thd->net.last_error; - uint buff_len= sizeof(thd->net.last_error); -#endif general_log_print(thd, command, NullS); status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]); @@ -1291,6 +1347,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, cached_open_tables(), (uint) (queries_per_second1000 / 1000), (uint) (queries_per_second1000 % 1000)); +#ifdef EMBEDDED_LIBRARY + /* Store the buffer in permanent memory */ + send_ok(thd, 0, 0, buff); +#endif #ifdef SAFEMALLOC if (sf_malloc_cur_memory) // Using SAFEMALLOC { @@ -1303,7 +1363,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #endif #ifndef EMBEDDED_LIBRARY VOID(my_net_write(net, (uchar*) buff, length)); - VOID(net_flush(net)); + VOID(net_flush(net)); + thd->main_da.disable_status(); #endif break; } @@ -1383,10 +1444,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->transaction.xid_state.xid.null(); /* report error issued during command execution */ - if (thd->killed_errno() && ! thd->is_error()) - thd->send_kill_message(); - if (thd->is_error()) - net_send_error(thd); + if (thd->killed_errno()) + { + if (! thd->main_da.is_set()) + thd->send_kill_message(); + } + if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) + { + thd->killed= THD::NOT_KILLED; + thd->mysys_var->abort= 0; + } + + net_end_statement(thd); + query_cache_end_of_result(thd); log_slow_statement(thd); @@ -1756,7 +1826,6 @@ mysql_execute_command(THD *thd) SELECT_LEX_UNIT *unit= &lex->unit; /* Saved variable value */ DBUG_ENTER("mysql_execute_command"); - thd->net.no_send_error= 0; #ifdef WITH_PARTITION_STORAGE_ENGINE thd->work_part_info= 0; #endif @@ -1869,14 +1938,7 @@ mysql_execute_command(THD *thd) When option readonly is set deny operations which change non-temporary tables. Except for the replication thread and the 'super' users. */ - if (opt_readonly && - !(thd->security_ctx->master_access & SUPER_ACL) && - (sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) && - !((lex->sql_command == SQLCOM_CREATE_TABLE) && - (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) && - !((lex->sql_command == SQLCOM_DROP_TABLE) && lex->drop_temporary) && - ((lex->sql_command != SQLCOM_UPDATE_MULTI) && - some_non_temp_table_to_be_updated(thd, all_tables))) + if (deny_updates_if_read_only_option(thd, all_tables)) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); DBUG_RETURN(-1); @@ -2988,13 +3050,9 @@ end_with_restore_list: SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE, del_result, unit, select_lex); - res|= thd->net.report_error; - if (unlikely(res)) - { - /* If we had a another error reported earlier then this will be ignored */ - del_result->send_error(ER_UNKNOWN_ERROR, "Execution of the query failed"); + res|= thd->is_error(); + if (res) del_result->abort(); - } delete del_result; } else @@ -3927,8 +3985,6 @@ create_sp_error: goto error; } - my_bool save_no_send_ok= thd->net.no_send_ok; - thd->net.no_send_ok= TRUE; if (sp->m_flags & sp_head::MULTI_RESULTS) { if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS)) @@ -3938,7 +3994,6 @@ create_sp_error: back */ my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str); - thd->net.no_send_ok= save_no_send_ok; goto error; } /* @@ -3953,7 +4008,6 @@ create_sp_error: if (check_routine_access(thd, EXECUTE_ACL, sp->m_db.str, sp->m_name.str, TRUE, FALSE)) { - thd->net.no_send_ok= save_no_send_ok; goto error; } select_limit= thd->variables.select_limit; @@ -3977,7 +4031,6 @@ create_sp_error: thd->variables.select_limit= select_limit; - thd->net.no_send_ok= save_no_send_ok; thd->server_status&= ~bits_to_be_cleared; if (!res) @@ -4618,7 +4671,10 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_YES, str.ptr()); } - result->send_eof(); + if (res) + result->abort(); + else + result->send_eof(); delete result; } else @@ -5231,6 +5287,7 @@ void mysql_reset_thd_for_next_command(THD *thd) { DBUG_ENTER("mysql_reset_thd_for_next_command"); DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */ + DBUG_ASSERT(! thd->in_sub_stmt); thd->free_list= 0; thd->select_number= 1; /* @@ -5257,18 +5314,18 @@ void mysql_reset_thd_for_next_command(THD *thd) } DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx); thd->thread_specific_used= FALSE; - if (!thd->in_sub_stmt) + + if (opt_bin_log) { - if (opt_bin_log) - { - reset_dynamic(&thd->user_var_events); - thd->user_var_events_alloc= thd->mem_root; - } - thd->clear_error(); - thd->total_warn_count=0; // Warnings for this query - thd->rand_used= 0; - thd->sent_row_count= thd->examined_row_count= 0; + reset_dynamic(&thd->user_var_events); + thd->user_var_events_alloc= thd->mem_root; } + thd->clear_error(); + thd->main_da.reset_diagnostics_area(); + thd->total_warn_count=0; // Warnings for this query + thd->rand_used= 0; + thd->sent_row_count= thd->examined_row_count= 0; + /* Because we come here only for start of top-statements, binlog format is constant inside a complex statement (using stored functions) etc. @@ -5506,7 +5563,6 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, /* Actually execute the query */ lex->set_trg_event_type_for_tables(); mysql_execute_command(thd); - query_cache_end_of_result(thd); } } } @@ -6358,8 +6414,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, } if (thd) { - (void)acl_reload(thd); - (void)grant_reload(thd); + if (acl_reload(thd)) + result= 1; + if (grant_reload(thd)) + result= 1; } if (tmp_thd) { @@ -6449,8 +6507,8 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, tmp_write_to_binlog= 0; if (lock_global_read_lock(thd)) return 1; // Killed - result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, - tables); + result= close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? + FALSE : TRUE, TRUE); if (make_global_read_lock_block_commit(thd)) // Killed { /* Don't leave things in a half-locked state */ @@ -6459,7 +6517,8 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, } } else - result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables); + result= close_cached_tables(thd, tables, FALSE, (options & REFRESH_FAST) ? + FALSE : TRUE, FALSE); my_dbopt_cleanup(); } if (options & REFRESH_HOSTS) @@ -6476,7 +6535,6 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (reset_master(thd)) { result=1; - thd->fatal_error(); // Ensure client get error } } #endif diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 67190c94a56..ce70e177a85 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2068,6 +2068,7 @@ char *generate_partition_syntax(partition_info *part_info, default: DBUG_ASSERT(0); /* We really shouldn't get here, no use in continuing from here */ + my_error(ER_OUT_OF_RESOURCES, MYF(0)); current_thd->fatal_error(); DBUG_RETURN(NULL); } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9d4d62e57b6..52e6fcc5d58 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -230,6 +230,8 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns) NET *net= &stmt->thd->net; uchar buff[12]; uint tmp; + int error; + THD *thd= stmt->thd; DBUG_ENTER("send_prep_stmt"); buff[0]= 0; /* OK packet indicator */ @@ -244,11 +246,16 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns) Send types and names of placeholders to the client XXX: fix this nasty upcast from List<Item_param> to List<Item> */ - DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) || - (stmt->param_count && - stmt->thd->protocol_text.send_fields((List<Item> *) - &stmt->lex->param_list, - Protocol::SEND_EOF))); + error= my_net_write(net, buff, sizeof(buff)); + if (stmt->param_count && ! error) + { + error= thd->protocol_text.send_fields((List<Item> *) + &stmt->lex->param_list, + Protocol::SEND_EOF); + } + /* Flag that a response has already been sent */ + thd->main_da.disable_status(); + DBUG_RETURN(error); } #else static bool send_prep_stmt(Prepared_statement *stmt, @@ -259,6 +266,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, thd->client_stmt_id= stmt->id; thd->client_param_count= stmt->param_count; thd->clear_error(); + thd->main_da.disable_status(); return 0; } @@ -2526,6 +2534,8 @@ void mysql_stmt_close(THD *thd, char *packet) DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE)); (void) stmt->deallocate(); + thd->main_da.disable_status(); + DBUG_VOID_RETURN; } @@ -2590,6 +2600,8 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) DBUG_ENTER("mysql_stmt_get_longdata"); status_var_increment(thd->status_var.com_stmt_send_long_data); + + thd->main_da.disable_status(); #ifndef EMBEDDED_LIBRARY /* Minimal size of long data packet is 6 bytes */ if (packet_length < MYSQL_LONG_DATA_HEADER) @@ -2664,11 +2676,7 @@ bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags) bool Select_fetch_protocol_binary::send_eof() { - Protocol *save_protocol= thd->protocol; - - thd->protocol= &protocol; ::send_eof(thd); - thd->protocol= save_protocol; return FALSE; } @@ -3097,7 +3105,6 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) thd->query_length) <= 0) { error= mysql_execute_command(thd); - query_cache_end_of_result(thd); } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3a142568080..93486aa7b65 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -898,7 +898,6 @@ JOIN::optimize() } if (res > 1) { - thd->fatal_error(); error= res; DBUG_PRINT("error",("Error from opt_sum_query")); DBUG_RETURN(1); @@ -14518,6 +14517,7 @@ calc_group_buffer(JOIN *join,ORDER *group) default: /* This case should never be choosen */ DBUG_ASSERT(0); + my_error(ER_OUT_OF_RESOURCES, MYF(0)); join->thd->fatal_error(); } } diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 602c289a605..8203ca92eed 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -239,7 +239,7 @@ bool servers_reload(THD *thd) if (simple_open_n_lock_tables(thd, tables)) { sql_print_error("Can't open and lock privilege tables: %s", - thd->net.last_error); + thd->main_da.message()); goto end; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9a7d7c59af3..36f9cc780bd 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -578,7 +578,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* Only one table for now, but VIEW can involve several tables */ if (open_normal_and_derived_tables(thd, table_list, 0)) { - if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID) + if (!table_list->view || + thd->is_error() && thd->main_da.sql_errno() != ER_VIEW_INVALID) DBUG_RETURN(TRUE); /* @@ -786,10 +787,9 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) } restore_record(table, s->default_values); // Get empty record table->use_all_columns(); - if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS | - Protocol::SEND_EOF)) + if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS)) DBUG_VOID_RETURN; - thd->protocol->flush(); + send_eof(thd); DBUG_VOID_RETURN; } @@ -2919,7 +2919,7 @@ static int fill_schema_table_names(THD *thd, TABLE *table, default: DBUG_ASSERT(0); } - if (thd->net.last_errno == ER_NO_SUCH_TABLE) + if (thd->is_error() && thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) { thd->clear_error(); return 0; @@ -3267,8 +3267,16 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); lex->sql_command= save_sql_command; - - if (thd->net.last_errno == ER_NO_SUCH_TABLE) + /* + XXX: show_table_list has a flag i_is_requested, + and when it's set, open_normal_and_derived_tables() + can return an error without setting an error message + in THD, which is a hack. This is why we have to + check for res, then for thd->is_error() only then + for thd->main_da.sql_errno(). + */ + if (res && thd->is_error() && + thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) { /* Hide error for not existing table. @@ -3422,7 +3430,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, /* there was errors during opening tables */ - const char *error= thd->net.last_error; + const char *error= thd->main_da.message(); if (tables->view) table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); else if (tables->schema_table) @@ -3624,7 +3632,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, rather than in SHOW COLUMNS */ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->net.last_errno, thd->net.last_error); + thd->main_da.sql_errno(), thd->main_da.message()); thd->clear_error(); res= 0; } @@ -4098,9 +4106,9 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS rather than in SHOW KEYS */ - if (thd->net.last_errno) + if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->net.last_errno, thd->net.last_error); + thd->main_da.sql_errno(), thd->main_da.message()); thd->clear_error(); res= 0; } @@ -4290,9 +4298,9 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, if (schema_table_store_record(thd, table)) DBUG_RETURN(1); - if (res && thd->net.last_errno) + if (res && thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->net.last_errno, thd->net.last_error); + thd->main_da.sql_errno(), thd->main_da.message()); } if (res) thd->clear_error(); @@ -4323,9 +4331,9 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, DBUG_ENTER("get_schema_constraints_record"); if (res) { - if (thd->net.last_errno) + if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->net.last_errno, thd->net.last_error); + thd->main_da.sql_errno(), thd->main_da.message()); thd->clear_error(); DBUG_RETURN(0); } @@ -4428,9 +4436,9 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables, */ if (res) { - if (thd->net.last_errno) + if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->net.last_errno, thd->net.last_error); + thd->main_da.sql_errno(), thd->main_da.message()); thd->clear_error(); DBUG_RETURN(0); } @@ -4511,9 +4519,9 @@ static int get_schema_key_column_usage_record(THD *thd, DBUG_ENTER("get_schema_key_column_usage_record"); if (res) { - if (thd->net.last_errno) + if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->net.last_errno, thd->net.last_error); + thd->main_da.sql_errno(), thd->main_da.message()); thd->clear_error(); DBUG_RETURN(0); } @@ -4706,9 +4714,9 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, if (res) { - if (thd->net.last_errno) + if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->net.last_errno, thd->net.last_error); + thd->main_da.sql_errno(), thd->main_da.message()); thd->clear_error(); DBUG_RETURN(0); } @@ -4751,6 +4759,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, break; default: DBUG_ASSERT(0); + my_error(ER_OUT_OF_RESOURCES, MYF(0)); current_thd->fatal_error(); DBUG_RETURN(1); } @@ -5243,9 +5252,9 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, if (res) { - if (thd->net.last_errno) + if (thd->is_error()) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->net.last_errno, thd->net.last_error); + thd->main_da.sql_errno(), thd->main_da.message()); thd->clear_error(); DBUG_RETURN(0); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index dfb44f0d444..0bd742b898d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1694,7 +1694,10 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, !dont_log_query); if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && (if_exists || table_type == NULL)) + { error= 0; + thd->clear_error(); + } if (error == HA_ERR_ROW_IS_REFERENCED) { /* the table is referenced by a foreign key constraint */ @@ -4233,18 +4236,22 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, (table->table->file->ha_check_for_upgrade(check_opt) == HA_ADMIN_NEEDS_ALTER)) { - my_bool save_no_send_ok= thd->net.no_send_ok; DBUG_PRINT("admin", ("recreating table")); ha_autocommit_or_rollback(thd, 1); close_thread_tables(thd); tmp_disable_binlog(thd); // binlogging is done by caller if wanted - thd->net.no_send_ok= TRUE; result_code= mysql_recreate_table(thd, table); - thd->net.no_send_ok= save_no_send_ok; reenable_binlog(thd); + /* + mysql_recreate_table() can push OK or ERROR. + Clear 'OK' status. If there is an error, keep it: + we will store the error message in a result set row + and then clear. + */ + if (thd->main_da.is_ok()) + thd->main_da.reset_diagnostics_area(); goto send_result; } - } DBUG_PRINT("admin", ("calling operator_func '%s'", operator_name)); @@ -4338,7 +4345,6 @@ send_result_message: case HA_ADMIN_TRY_ALTER: { - my_bool save_no_send_ok= thd->net.no_send_ok; /* This is currently used only by InnoDB. ha_innobase::optimize() answers "try with alter", so here we close the table, do an ALTER TABLE, @@ -4350,10 +4356,16 @@ send_result_message: *save_next_global= table->next_global; table->next_local= table->next_global= 0; tmp_disable_binlog(thd); // binlogging is done by caller if wanted - thd->net.no_send_ok= TRUE; result_code= mysql_recreate_table(thd, table); - thd->net.no_send_ok= save_no_send_ok; reenable_binlog(thd); + /* + mysql_recreate_table() can push OK or ERROR. + Clear 'OK' status. If there is an error, keep it: + we will store the error message in a result set row + and then clear. + */ + if (thd->main_da.is_ok()) + thd->main_da.reset_diagnostics_area(); ha_autocommit_or_rollback(thd, 0); close_thread_tables(thd); if (!result_code) // recreation went ok @@ -4364,9 +4376,10 @@ send_result_message: } if (result_code) // either mysql_recreate_table or analyze failed { - const char *err_msg; - if ((err_msg= thd->net.last_error)) + DBUG_ASSERT(thd->is_error()); + if (thd->is_error()) { + const char *err_msg= thd->main_da.message(); if (!thd->vio_ok()) { sql_print_error(err_msg); @@ -4382,6 +4395,7 @@ send_result_message: protocol->store(table_name, system_charset_info); protocol->store(operator_name, system_charset_info); } + thd->clear_error(); } } result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK; @@ -6765,7 +6779,7 @@ view_err: if (thd->locked_tables && new_name == table_name && new_db == db) { thd->in_lock_tables= 1; - error= reopen_tables(thd, 1, 0); + error= reopen_tables(thd, 1, 1); thd->in_lock_tables= 0; if (error) goto err_with_placeholders; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index ecb7acda61b..e2dfd89aa32 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1696,7 +1696,11 @@ void multi_update::send_error(uint errcode,const char *err) { /* First send error what ever it is ... */ my_error(errcode, MYF(0), err); +} + +void multi_update::abort() +{ /* the error was handled or nothing deleted and no side effects return */ if (error_handled || !thd->transaction.stmt.modified_non_trans_table && !updated) @@ -1725,7 +1729,7 @@ void multi_update::send_error(uint errcode,const char *err) todo/fixme: do_update() is never called with the arg 1. should it change the signature to become argless? */ - VOID(do_updates(0)); + VOID(do_updates()); } } if (thd->transaction.stmt.modified_non_trans_table) @@ -1756,7 +1760,7 @@ void multi_update::send_error(uint errcode,const char *err) } -int multi_update::do_updates(bool from_send_error) +int multi_update::do_updates() { TABLE_LIST *cur_table; int local_error= 0; @@ -1903,7 +1907,6 @@ int multi_update::do_updates(bool from_send_error) DBUG_RETURN(0); err: - if (!from_send_error) { thd->fatal_error(); prepare_record_for_error_message(local_error, table); @@ -1945,7 +1948,7 @@ bool multi_update::send_eof() Does updates for the last n - 1 tables, returns 0 if ok; error takes into account killed status gained in do_updates() */ - int local_error = (table_count) ? do_updates(0) : 0; + int local_error = (table_count) ? do_updates() : 0; /* if local_error is not set ON until after do_updates() then later carried out killing should not affect binlogging. diff --git a/sql/table.cc b/sql/table.cc index 0f4c7cb7ba1..cacb3a94582 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3281,31 +3281,32 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) } -/* +/** Hide errors which show view underlying table information - SYNOPSIS - TABLE_LIST::hide_view_error() - thd thread handler + @param[in,out] thd thread handler + @pre This method can be called only if there is an error. */ void TABLE_LIST::hide_view_error(THD *thd) { /* Hide "Unknown column" or "Unknown function" error */ - if (thd->net.last_errno == ER_BAD_FIELD_ERROR || - thd->net.last_errno == ER_SP_DOES_NOT_EXIST || - thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR || - thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR || - thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR || - thd->net.last_errno == ER_TABLE_NOT_LOCKED || - thd->net.last_errno == ER_NO_SUCH_TABLE) + DBUG_ASSERT(thd->is_error()); + + if (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR || + thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST || + thd->main_da.sql_errno() == ER_PROCACCESS_DENIED_ERROR || + thd->main_da.sql_errno() == ER_COLUMNACCESS_DENIED_ERROR || + thd->main_da.sql_errno() == ER_TABLEACCESS_DENIED_ERROR || + thd->main_da.sql_errno() == ER_TABLE_NOT_LOCKED || + thd->main_da.sql_errno() == ER_NO_SUCH_TABLE) { TABLE_LIST *top= top_table(); - thd->clear_error(); + thd->clear_error(); my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str); } - else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD) + else if (thd->main_da.sql_errno() == ER_NO_DEFAULT_FOR_FIELD) { TABLE_LIST *top= top_table(); thd->clear_error(); diff --git a/sql/tztime.cc b/sql/tztime.cc index 920f8e87d13..f080c61e243 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1642,7 +1642,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup)) { sql_print_warning("Can't open and lock time zone table: %s " - "trying to live without them", thd->net.last_error); + "trying to live without them", thd->main_da.message()); /* We will try emulate that everything is ok */ return_val= time_zone_tables_exist= 0; goto end_with_setting_default_tz; diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 9d7f2d4b90d..0b69f9d135f 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1407,10 +1407,8 @@ int ha_myisam::enable_indexes(uint mode) might have been set by the first repair. They can still be seen with SHOW WARNINGS then. */ -#ifndef EMBEDDED_LIBRARY if (! error) thd->clear_error(); -#endif /* EMBEDDED_LIBRARY */ } info(HA_STATUS_CONST); thd->proc_info=save_proc_info; |