summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <kostja@bodhi.(none)>2007-12-15 16:59:43 +0300
committerunknown <kostja@bodhi.(none)>2007-12-15 16:59:43 +0300
commitcb48c979e506b1df3e314745bb5974e1b6cfeb41 (patch)
tree478d4e5aed82ca23a53a9264eb04f9131c5a43f9
parentcfd4951d1f33334b529dbb1ca0b1a1bed28cfbb3 (diff)
parent0a578711a2e44dcb6bfe6c1491b3b8e799ae13b8 (diff)
downloadmariadb-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
-rw-r--r--client/mysqltest.c1
-rw-r--r--include/mysql_com.h19
-rw-r--r--include/mysql_h.ic10
-rw-r--r--libmysql/libmysql.c40
-rw-r--r--libmysql/manager.c2
-rw-r--r--libmysqld/emb_qcache.cc2
-rw-r--r--libmysqld/emb_qcache.h1
-rw-r--r--libmysqld/lib_sql.cc89
-rw-r--r--libmysqld/libmysqld.c5
-rw-r--r--mysql-test/lib/mtr_report.pl1
-rw-r--r--mysql-test/r/events.result3
-rw-r--r--mysql-test/r/grant.result4
-rw-r--r--mysql-test/r/lock_multi.result30
-rw-r--r--mysql-test/r/no-threads.result4
-rw-r--r--mysql-test/r/ps_ddl.result2329
-rw-r--r--mysql-test/r/read_only.result28
-rw-r--r--mysql-test/r/trigger_notembedded.result14
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result4
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result4
-rw-r--r--mysql-test/t/disabled.def2
-rw-r--r--mysql-test/t/grant.test1
-rw-r--r--mysql-test/t/lock_multi.test98
-rw-r--r--mysql-test/t/no-threads.test10
-rw-r--r--mysql-test/t/ps_ddl.test1851
-rw-r--r--mysql-test/t/read_only.test35
-rw-r--r--mysql-test/t/trigger_notembedded.test6
-rw-r--r--server-tools/instance-manager/mysql_connection.cc2
-rw-r--r--sql-common/client.c74
-rw-r--r--sql/ha_ndbcluster.cc4
-rw-r--r--sql/ha_ndbcluster_binlog.cc37
-rw-r--r--sql/ha_partition.cc1
-rw-r--r--sql/item_func.cc1
-rw-r--r--sql/log.cc69
-rw-r--r--sql/log_event.cc52
-rw-r--r--sql/log_event_old.cc16
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/mysqld.cc54
-rw-r--r--sql/net_serv.cc58
-rw-r--r--sql/opt_range.cc2
-rw-r--r--sql/opt_sum.cc2
-rw-r--r--sql/protocol.cc228
-rw-r--r--sql/protocol.h5
-rw-r--r--sql/repl_failsafe.cc4
-rw-r--r--sql/rpl_record.cc5
-rw-r--r--sql/rpl_rli.cc4
-rw-r--r--sql/set_var.cc11
-rw-r--r--sql/set_var.h18
-rw-r--r--sql/slave.cc60
-rw-r--r--sql/sp_head.cc16
-rw-r--r--sql/sp_rcontext.cc22
-rw-r--r--sql/sql_acl.cc9
-rw-r--r--sql/sql_base.cc102
-rw-r--r--sql/sql_binlog.cc16
-rw-r--r--sql/sql_cache.cc1
-rw-r--r--sql/sql_class.cc155
-rw-r--r--sql/sql_class.h161
-rw-r--r--sql/sql_connect.cc33
-rw-r--r--sql/sql_db.cc5
-rw-r--r--sql/sql_delete.cc8
-rw-r--r--sql/sql_derived.cc5
-rw-r--r--sql/sql_insert.cc16
-rw-r--r--sql/sql_parse.cc210
-rw-r--r--sql/sql_partition.cc1
-rw-r--r--sql/sql_prepare.cc27
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_servers.cc2
-rw-r--r--sql/sql_show.cc55
-rw-r--r--sql/sql_table.cc34
-rw-r--r--sql/sql_update.cc11
-rw-r--r--sql/table.cc27
-rw-r--r--sql/tztime.cc2
-rw-r--r--storage/myisam/ha_myisam.cc2
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, &not_used)))
+ flags, &not_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;