summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <malff@lambda.hsd1.co.comcast.net.>2007-11-01 06:41:50 -0600
committerunknown <malff@lambda.hsd1.co.comcast.net.>2007-11-01 06:41:50 -0600
commitcf8275e086eef4814bae8671666e1bdc69b789d9 (patch)
treeed9cc7f1e47bd6e23bed5418d81bbefcace750ae
parent41c2a2c490522da0f163aa25ac88da9db74e0c66 (diff)
parentad723cd5f80389e375f9397f1d6b703989a0aa24 (diff)
downloadmariadb-git-cf8275e086eef4814bae8671666e1bdc69b789d9.tar.gz
Merge lambda.hsd1.co.comcast.net.:/home/malff/TREE/mysql-5.1-base
into lambda.hsd1.co.comcast.net.:/home/malff/TREE/mysql-5.1-rt-merge sql/item_func.cc: Auto merged
-rw-r--r--include/sql_common.h6
-rw-r--r--libmysql/libmysql.c159
-rw-r--r--libmysqld/lib_sql.cc22
-rw-r--r--mysql-test/include/mix1.inc49
-rw-r--r--mysql-test/r/events_bugs.result103
-rw-r--r--mysql-test/r/group_min_max.result4
-rw-r--r--mysql-test/r/index_merge_myisam.result2
-rw-r--r--mysql-test/r/innodb_mysql.result34
-rw-r--r--mysql-test/r/key.result15
-rw-r--r--mysql-test/r/select.result35
-rw-r--r--mysql-test/r/sp-error.result10
-rw-r--r--mysql-test/r/udf.result12
-rw-r--r--mysql-test/suite/rpl/include/rpl_mixed_dml.inc2
-rw-r--r--mysql-test/t/events.test3
-rw-r--r--mysql-test/t/events_bugs.test224
-rw-r--r--mysql-test/t/key.test23
-rw-r--r--mysql-test/t/select.test48
-rw-r--r--mysql-test/t/sp-error.test19
-rw-r--r--mysql-test/t/udf.test12
-rw-r--r--server-tools/instance-manager/mysqlmanager.cc3
-rw-r--r--sql-common/client.c254
-rw-r--r--sql/event_data_objects.cc16
-rw-r--r--sql/event_db_repository.cc9
-rw-r--r--sql/event_scheduler.cc7
-rw-r--r--sql/events.cc16
-rw-r--r--sql/filesort.cc4
-rw-r--r--sql/ha_ndbcluster_binlog.cc4
-rw-r--r--sql/handler.cc70
-rw-r--r--sql/item_func.cc9
-rw-r--r--sql/item_subselect.cc2
-rw-r--r--sql/log.cc7
-rw-r--r--sql/log_event.cc54
-rw-r--r--sql/log_event_old.cc12
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/mysqld.cc10
-rw-r--r--sql/protocol.cc122
-rw-r--r--sql/protocol.h1
-rw-r--r--sql/set_var.cc2
-rw-r--r--sql/slave.cc6
-rw-r--r--sql/sp.cc2
-rw-r--r--sql/sp_head.cc12
-rw-r--r--sql/sql_acl.cc24
-rw-r--r--sql/sql_base.cc15
-rw-r--r--sql/sql_class.cc41
-rw-r--r--sql/sql_class.h38
-rw-r--r--sql/sql_connect.cc205
-rw-r--r--sql/sql_delete.cc8
-rw-r--r--sql/sql_error.cc2
-rw-r--r--sql/sql_insert.cc12
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc31
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc39
-rw-r--r--sql/sql_table.cc12
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_update.cc6
-rw-r--r--sql/sql_view.cc6
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--tests/mysql_client_test.c94
59 files changed, 1305 insertions, 651 deletions
diff --git a/include/sql_common.h b/include/sql_common.h
index 80504140fae..56e7305130f 100644
--- a/include/sql_common.h
+++ b/include/sql_common.h
@@ -36,8 +36,10 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
const unsigned char *arg, ulong arg_length,
my_bool skip_check, MYSQL_STMT *stmt);
unsigned long cli_safe_read(MYSQL *mysql);
-void set_stmt_errmsg(MYSQL_STMT * stmt, const char *err, int errcode,
- const char *sqlstate);
+void net_clear_error(NET *net);
+void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net);
+void set_stmt_error(MYSQL_STMT *stmt, int errcode, const char *sqlstate,
+ const char *err);
void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate);
#ifdef __cplusplus
}
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index e2e42fe4a2d..cb326fa4685 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -686,9 +686,7 @@ int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd)
if (my_net_write(net, (uchar*) buff, SCRAMBLE_LENGTH_323 + 1) ||
net_flush(net))
{
- net->last_errno= CR_SERVER_LOST;
- strmov(net->sqlstate, unknown_sqlstate);
- strmov(net->last_error,ER(net->last_errno));
+ set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
return 1;
}
/* Read what server thinks about out new auth message report */
@@ -701,7 +699,8 @@ int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd)
my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
const char *passwd, const char *db)
{
- char buff[512],*end=buff;
+ char buff[USERNAME_LENGTH+SCRAMBLED_PASSWORD_CHAR_LENGTH+NAME_LEN+2];
+ char *end= buff;
int rc;
CHARSET_INFO *saved_cs= mysql->charset;
@@ -723,7 +722,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
passwd="";
/* Store user into the buffer */
- end=strmov(end,user)+1;
+ end= strmake(end, user, USERNAME_LENGTH) + 1;
/* write scrambled password according to server capabilities */
if (passwd[0])
@@ -743,7 +742,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
else
*end++= '\0'; /* empty password */
/* Add database if needed */
- end= strmov(end, db ? db : "") + 1;
+ end= strmake(end, db ? db : "", NAME_LEN) + 1;
/* Add character set number. */
@@ -860,8 +859,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
/* copy filename into local memory and allocate read buffer */
if (!(buf=my_malloc(packet_length, MYF(0))))
{
- strmov(net->sqlstate, unknown_sqlstate);
- strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY));
+ set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
DBUG_RETURN(1);
}
@@ -887,9 +885,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
{
DBUG_PRINT("error",
("Lost connection to MySQL server during LOAD DATA of local file"));
- strmov(net->sqlstate, unknown_sqlstate);
- net->last_errno=CR_SERVER_LOST;
- strmov(net->last_error,ER(net->last_errno));
+ set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
goto err;
}
}
@@ -897,9 +893,7 @@ my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
/* Send empty packet to mark end of file */
if (my_net_write(net, (const uchar*) "", 0) || net_flush(net))
{
- strmov(net->sqlstate, unknown_sqlstate);
- net->last_errno=CR_SERVER_LOST;
- sprintf(net->last_error,ER(net->last_errno),errno);
+ set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
goto err;
}
@@ -1400,9 +1394,7 @@ const char *cli_read_statistics(MYSQL *mysql)
mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
if (!mysql->net.read_pos[0])
{
- strmov(mysql->net.sqlstate, unknown_sqlstate);
- mysql->net.last_errno=CR_WRONG_HOST_INFO;
- strmov(mysql->net.last_error, ER(mysql->net.last_errno));
+ set_mysql_error(mysql, CR_WRONG_HOST_INFO, unknown_sqlstate);
return mysql->net.last_error;
}
return (char*) mysql->net.read_pos;
@@ -1848,24 +1840,17 @@ static my_bool my_realloc_str(NET *net, ulong length)
if (buf_length + length > net->max_packet)
{
res= net_realloc(net, buf_length + length);
+ if (res)
+ {
+ strmov(net->sqlstate, unknown_sqlstate);
+ strmov(net->last_error, ER(net->last_errno));
+ }
net->write_pos= net->buff+ buf_length;
}
DBUG_RETURN(res);
}
-/* Clear possible error statee of struct NET */
-
-static void net_clear_error(NET *net)
-{
- if (net->last_errno)
- {
- net->last_errno= 0;
- net->last_error[0]= '\0';
- strmov(net->sqlstate, not_error_sqlstate);
- }
-}
-
static void stmt_clear_error(MYSQL_STMT *stmt)
{
if (stmt->last_errno)
@@ -1876,18 +1861,21 @@ static void stmt_clear_error(MYSQL_STMT *stmt)
}
}
-/*
+/**
Set statement error code, sqlstate, and error message
from given errcode and sqlstate.
*/
-static void set_stmt_error(MYSQL_STMT * stmt, int errcode,
- const char *sqlstate)
+void set_stmt_error(MYSQL_STMT * stmt, int errcode,
+ const char *sqlstate, const char *err)
{
DBUG_ENTER("set_stmt_error");
DBUG_PRINT("enter", ("error: %d '%s'", errcode, ER(errcode)));
DBUG_ASSERT(stmt != 0);
+ if (err == 0)
+ err= ER(errcode);
+
stmt->last_errno= errcode;
strmov(stmt->last_error, ER(errcode));
strmov(stmt->sqlstate, sqlstate);
@@ -1896,21 +1884,24 @@ static void set_stmt_error(MYSQL_STMT * stmt, int errcode,
}
-/*
- Set statement error code, sqlstate, and error message.
+/**
+ Set statement error code, sqlstate, and error message from NET.
+
+ @param stmt a statement handle. Copy the error here.
+ @param net mysql->net. Source of the error.
*/
-void set_stmt_errmsg(MYSQL_STMT * stmt, const char *err, int errcode,
- const char *sqlstate)
+void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net)
{
DBUG_ENTER("set_stmt_errmsg");
- DBUG_PRINT("enter", ("error: %d/%s '%s'", errcode, sqlstate, err));
+ DBUG_PRINT("enter", ("error: %d/%s '%s'", net->last_errno, net->sqlstate,
+ net->last_error));
DBUG_ASSERT(stmt != 0);
- stmt->last_errno= errcode;
- if (err && err[0])
- strmov(stmt->last_error, err);
- strmov(stmt->sqlstate, sqlstate);
+ stmt->last_errno= net->last_errno;
+ if (net->last_error && net->last_error[0])
+ strmov(stmt->last_error, net->last_error);
+ strmov(stmt->sqlstate, net->sqlstate);
DBUG_VOID_RETURN;
}
@@ -2085,7 +2076,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
if (!mysql)
{
/* mysql can be reset in mysql_close called from mysql_reconnect */
- set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
+ set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
@@ -2123,23 +2114,20 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
stmt->state= MYSQL_STMT_INIT_DONE;
if (stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt))
{
- set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
- mysql->net.sqlstate);
+ set_stmt_errmsg(stmt, &mysql->net);
DBUG_RETURN(1);
}
}
if (stmt_command(mysql, COM_STMT_PREPARE, (const uchar*) query, length, stmt))
{
- set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
- mysql->net.sqlstate);
+ set_stmt_errmsg(stmt, &mysql->net);
DBUG_RETURN(1);
}
if ((*mysql->methods->read_prepare_result)(mysql, stmt))
{
- set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
- mysql->net.sqlstate);
+ set_stmt_errmsg(stmt, &mysql->net);
DBUG_RETURN(1);
}
@@ -2154,7 +2142,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
(stmt->param_count +
stmt->field_count))))
{
- set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
+ set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
stmt->bind= stmt->params + stmt->param_count;
@@ -2284,7 +2272,7 @@ mysql_stmt_result_metadata(MYSQL_STMT *stmt)
if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result),
MYF(MY_WME | MY_ZEROFILL))))
{
- set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
+ set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
DBUG_RETURN(0);
}
@@ -2517,7 +2505,7 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
*/
if ((my_realloc_str(net, *param->length)))
{
- set_stmt_error(stmt, net->last_errno, unknown_sqlstate);
+ set_stmt_errmsg(stmt, net);
DBUG_RETURN(1);
}
(*param->store_param_func)(net, param);
@@ -2554,7 +2542,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
stmt->insert_id= mysql->insert_id;
if (res)
{
- set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
+ set_stmt_errmsg(stmt, net);
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -2577,13 +2565,13 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
if (!stmt->bind_param_done)
{
- set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate);
+ set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
if (mysql->status != MYSQL_STATUS_READY ||
mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
{
- set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
+ set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
@@ -2592,7 +2580,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
null_count= (stmt->param_count+7) /8;
if (my_realloc_str(net, null_count + 1))
{
- set_stmt_error(stmt, net->last_errno, unknown_sqlstate);
+ set_stmt_errmsg(stmt, net);
DBUG_RETURN(1);
}
bzero((char*) net->write_pos, null_count);
@@ -2605,7 +2593,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
{
if (my_realloc_str(net, 2 * stmt->param_count))
{
- set_stmt_error(stmt, net->last_errno, unknown_sqlstate);
+ set_stmt_errmsg(stmt, net);
DBUG_RETURN(1);
}
/*
@@ -2628,7 +2616,7 @@ int cli_stmt_execute(MYSQL_STMT *stmt)
/* TODO: Look into avoding the following memdup */
if (!(param_data= my_memdup(net->buff, length, MYF(0))))
{
- set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
+ set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
result= execute(stmt, param_data, length);
@@ -2692,20 +2680,19 @@ static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row)
*/
if (!mysql)
{
- set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
+ set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
return 1;
}
if (mysql->status != MYSQL_STATUS_GET_RESULT)
{
set_stmt_error(stmt, stmt->unbuffered_fetch_cancelled ?
CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
- unknown_sqlstate);
+ unknown_sqlstate, NULL);
goto error;
}
if ((*mysql->methods->unbuffered_fetch)(mysql, (char**) row))
{
- set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
- mysql->net.sqlstate);
+ set_stmt_errmsg(stmt, &mysql->net);
/*
If there was an error, there are no more pending rows:
reset statement status to not hang up in following
@@ -2766,7 +2753,7 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row)
buff, sizeof(buff), (uchar*) 0, 0,
1, NULL))
{
- set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
+ set_stmt_errmsg(stmt, net);
return 1;
}
if ((*mysql->methods->read_rows_from_cursor)(stmt))
@@ -2797,7 +2784,7 @@ static int
stmt_read_row_no_result_set(MYSQL_STMT *stmt __attribute__((unused)),
unsigned char **row __attribute__((unused)))
{
- set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate);
+ set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate, NULL);
return 1;
}
@@ -2847,7 +2834,7 @@ my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt,
}
return FALSE;
err_not_implemented:
- set_stmt_error(stmt, CR_NOT_IMPLEMENTED, unknown_sqlstate);
+ set_stmt_error(stmt, CR_NOT_IMPLEMENTED, unknown_sqlstate, NULL);
return TRUE;
}
@@ -3232,7 +3219,7 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *my_bind)
{
if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
{
- set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
+ set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -3397,7 +3384,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
*/
if (param_number >= stmt->param_count)
{
- set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
+ set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
@@ -3433,8 +3420,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
buff, sizeof(buff), (uchar*) data,
length, 1, NULL))
{
- set_stmt_errmsg(stmt, mysql->net.last_error,
- mysql->net.last_errno, mysql->net.sqlstate);
+ set_stmt_errmsg(stmt, &mysql->net);
DBUG_RETURN(1);
}
}
@@ -3903,7 +3889,8 @@ static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
if (field->flags & ZEROFILL_FLAG && length < field->length &&
field->length < MAX_DOUBLE_STRING_REP_LENGTH - 1)
{
- bmove_upp((char*) buff + field->length, buff + length, length);
+ bmove_upp((uchar*) buff + field->length, (uchar*) buff + length,
+ length);
bfill((char*) buff, field->length - length, '0');
length= field->length;
}
@@ -4502,7 +4489,7 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *my_bind)
{
int errorcode= (int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE ?
CR_NO_PREPARE_STMT : CR_NO_STMT_METADATA;
- set_stmt_error(stmt, errorcode, unknown_sqlstate);
+ set_stmt_error(stmt, errorcode, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
@@ -4682,12 +4669,12 @@ int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *my_bind,
if ((int) stmt->state < (int) MYSQL_STMT_FETCH_DONE)
{
- set_stmt_error(stmt, CR_NO_DATA, unknown_sqlstate);
+ set_stmt_error(stmt, CR_NO_DATA, unknown_sqlstate, NULL);
return 1;
}
if (column >= stmt->field_count)
{
- set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
+ set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
@@ -4733,7 +4720,7 @@ int cli_read_binary_rows(MYSQL_STMT *stmt)
if (!mysql)
{
- set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
+ set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
@@ -4748,7 +4735,7 @@ int cli_read_binary_rows(MYSQL_STMT *stmt)
if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
sizeof(MYSQL_ROWS) + pkt_len - 1)))
{
- set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
+ set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
goto err;
}
cur->data= (MYSQL_ROW) (cur+1);
@@ -4769,7 +4756,7 @@ int cli_read_binary_rows(MYSQL_STMT *stmt)
DBUG_RETURN(0);
}
}
- set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
+ set_stmt_errmsg(stmt, net);
err:
DBUG_RETURN(1);
@@ -4836,7 +4823,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE)
{
- set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
+ set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
@@ -4856,13 +4843,13 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff),
(uchar*) 0, 0, 1, NULL))
{
- set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
+ set_stmt_errmsg(stmt, net);
DBUG_RETURN(1);
}
}
else if (mysql->status != MYSQL_STATUS_GET_RESULT)
{
- set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
+ set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
@@ -5043,8 +5030,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
if ((*mysql->methods->advanced_command)(mysql, COM_STMT_RESET, buff,
sizeof(buff), 0, 0, 0, NULL))
{
- set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
- mysql->net.sqlstate);
+ set_stmt_errmsg(stmt, &mysql->net);
stmt->state= MYSQL_STMT_INIT_DONE;
return 1;
}
@@ -5117,8 +5103,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
int4store(buff, stmt->stmt_id);
if ((rc= stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt)))
{
- set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
- mysql->net.sqlstate);
+ set_stmt_errmsg(stmt, &mysql->net);
}
}
}
@@ -5139,7 +5124,7 @@ my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
if (!stmt->mysql)
{
/* mysql can be reset in mysql_close called from mysql_reconnect */
- set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
+ set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
DBUG_RETURN(1);
}
/* Reset the client and server sides of the prepared statement */
@@ -5243,15 +5228,11 @@ int STDCALL mysql_next_result(MYSQL *mysql)
if (mysql->status != MYSQL_STATUS_READY)
{
- strmov(mysql->net.sqlstate, unknown_sqlstate);
- strmov(mysql->net.last_error,
- ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
DBUG_RETURN(1);
}
- mysql->net.last_error[0]= 0;
- mysql->net.last_errno= 0;
- strmov(mysql->net.sqlstate, not_error_sqlstate);
+ net_clear_error(&mysql->net);
mysql->affected_rows= ~(my_ulonglong) 0;
if (mysql->last_used_con->server_status & SERVER_MORE_RESULTS_EXISTS)
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
index 4e525f8447f..13847c324e1 100644
--- a/libmysqld/lib_sql.cc
+++ b/libmysqld/lib_sql.cc
@@ -81,8 +81,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
/* Check that we are calling the client functions in right order */
if (mysql->status != MYSQL_STATUS_READY)
{
- strmov(net->last_error,
- ER(net->last_errno=CR_COMMANDS_OUT_OF_SYNC));
+ set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
return 1;
}
@@ -90,7 +89,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
thd->clear_error();
mysql->affected_rows= ~(my_ulonglong) 0;
mysql->field_count= 0;
- net->last_errno= 0;
+ net_clear_error(net);
thd->current_stmt= stmt;
thd->store_globals(); // Fix if more than one connect
@@ -245,8 +244,7 @@ static my_bool emb_read_query_result(MYSQL *mysql)
mysql->fields= res->embedded_info->fields_list;
mysql->affected_rows= res->embedded_info->affected_rows;
mysql->insert_id= res->embedded_info->insert_id;
- mysql->net.last_errno= 0;
- mysql->net.last_error[0]= 0;
+ net_clear_error(&mysql->net);
mysql->info= 0;
if (res->embedded_info->info[0])
@@ -288,7 +286,7 @@ static int emb_stmt_execute(MYSQL_STMT *stmt)
if (res)
{
NET *net= &stmt->mysql->net;
- set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
+ set_stmt_errmsg(stmt, net);
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -299,14 +297,12 @@ int emb_read_binary_rows(MYSQL_STMT *stmt)
MYSQL_DATA *data;
if (!(data= emb_read_rows(stmt->mysql, 0, 0)))
{
- set_stmt_errmsg(stmt, stmt->mysql->net.last_error,
- stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate);
+ set_stmt_errmsg(stmt, &stmt->mysql->net);
return 1;
}
stmt->result= *data;
my_free((char *) data, MYF(0));
- set_stmt_errmsg(stmt, stmt->mysql->net.last_error,
- stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate);
+ set_stmt_errmsg(stmt, &stmt->mysql->net);
return 0;
}
@@ -320,16 +316,14 @@ int emb_read_rows_from_cursor(MYSQL_STMT *stmt)
if (res->embedded_info->last_errno)
{
embedded_get_error(mysql, res);
- set_stmt_errmsg(stmt, mysql->net.last_error,
- mysql->net.last_errno, mysql->net.sqlstate);
+ set_stmt_errmsg(stmt, &mysql->net);
return 1;
}
thd->cur_data= res;
mysql->warning_count= res->embedded_info->warning_count;
mysql->server_status= res->embedded_info->server_status;
- mysql->net.last_errno= 0;
- mysql->net.last_error[0]= 0;
+ net_clear_error(&mysql->net);
return emb_read_binary_rows(stmt);
}
diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc
index c8d3ba79e39..d55b404621d 100644
--- a/mysql-test/include/mix1.inc
+++ b/mysql-test/include/mix1.inc
@@ -1020,6 +1020,55 @@ SELECT * FROM t1 ORDER BY b DESC, a ASC;
DROP TABLE t1;
+###########################################################################
+
+--echo
+--echo #
+--echo # Bug#27610: ALTER TABLE ROW_FORMAT=... does not rebuild the table.
+--echo #
+
+--echo
+--echo # - prepare;
+--echo
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+--echo
+
+CREATE TABLE t1(c INT)
+ ENGINE = InnoDB
+ ROW_FORMAT = COMPACT;
+
+--echo
+--echo # - initial check;
+--echo
+
+SELECT table_schema, table_name, row_format
+FROM INFORMATION_SCHEMA.TABLES
+WHERE table_schema = DATABASE() AND table_name = 't1';
+
+--echo
+--echo # - change ROW_FORMAT and check;
+--echo
+
+ALTER TABLE t1 ROW_FORMAT = REDUNDANT;
+
+--echo
+
+SELECT table_schema, table_name, row_format
+FROM INFORMATION_SCHEMA.TABLES
+WHERE table_schema = DATABASE() AND table_name = 't1';
+
+--echo
+--echo # - that's it, cleanup.
+--echo
+
+DROP TABLE t1;
+
+###########################################################################
+
--echo End of 5.0 tests
# Fix for BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY
diff --git a/mysql-test/r/events_bugs.result b/mysql-test/r/events_bugs.result
index 3c9e6384c64..b6b77101874 100644
--- a/mysql-test/r/events_bugs.result
+++ b/mysql-test/r/events_bugs.result
@@ -610,7 +610,6 @@ id ev_nm ev_cnt
6 ev_sched_1823 6
DROP TABLE event_log;
SET GLOBAL event_scheduler = OFF;
-DROP DATABASE events_test;
SET GLOBAL event_scheduler= ON;
CREATE EVENT bug28641 ON SCHEDULE AT '2038.01.18 03:00:00'
DO BEGIN
@@ -618,3 +617,105 @@ SELECT 1;
END;|
SET GLOBAL event_scheduler= OFF;
DROP EVENT bug28641;
+
+#####################################################################
+#
+# BUG#31111: --read-only crashes MySQL (events fail to load).
+#
+#####################################################################
+
+DROP USER mysqltest_u1@localhost;
+DROP EVENT IF EXISTS e1;
+DROP EVENT IF EXISTS e2;
+
+GRANT EVENT ON *.* TO mysqltest_u1@localhost;
+
+SET GLOBAL READ_ONLY = 1;
+
+#
+# Connection: u1_con (mysqltest_u1@localhost/events_test).
+#
+
+CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1;
+ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
+
+ALTER EVENT e1 COMMENT 'comment';
+ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
+
+DROP EVENT e1;
+ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
+
+#
+# Connection: root_con (root@localhost/events_test).
+#
+
+CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1;
+
+ALTER EVENT e1 COMMENT 'comment';
+
+DROP EVENT e1;
+
+SET GLOBAL READ_ONLY = 0;
+
+#
+# Connection: u1_con (mysqltest_u1@localhost/test).
+#
+
+CREATE EVENT e1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 SECOND DO SET @a = 1;
+CREATE EVENT e2 ON SCHEDULE EVERY 1 SECOND DO SET @a = 1;
+
+SELECT
+event_name,
+last_executed IS NULL,
+definer
+FROM INFORMATION_SCHEMA.EVENTS
+WHERE event_schema = 'events_test';
+event_name last_executed IS NULL definer
+e1 1 mysqltest_u1@localhost
+e2 1 mysqltest_u1@localhost
+
+#
+# Connection: root_con (root@localhost/events_test).
+#
+
+SET GLOBAL READ_ONLY = 1;
+
+SET GLOBAL EVENT_SCHEDULER = ON;
+
+# Waiting for the event scheduler to execute and drop event e1...
+
+# Waiting for the event scheduler to execute and update event e2...
+
+SET GLOBAL EVENT_SCHEDULER = OFF;
+
+SELECT
+event_name,
+last_executed IS NULL,
+definer
+FROM INFORMATION_SCHEMA.EVENTS
+WHERE event_schema = 'events_test';
+event_name last_executed IS NULL definer
+e2 0 mysqltest_u1@localhost
+
+DROP EVENT e1;
+ERROR HY000: Unknown event 'e1'
+
+# Cleanup.
+
+DROP EVENT e2;
+
+SET GLOBAL READ_ONLY = 0;
+
+#
+# Connection: default
+#
+
+DROP USER mysqltest_u1@localhost;
+
+#####################################################################
+#
+# End of BUG#31111.
+#
+#####################################################################
+
+DROP DATABASE events_test;
diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result
index 02b1459afd0..f62fd662a5d 100644
--- a/mysql-test/r/group_min_max.result
+++ b/mysql-test/r/group_min_max.result
@@ -2251,7 +2251,7 @@ EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE
(SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) > 12;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
-2 SUBQUERY t1 range NULL a 5 NULL 8 Using index for group-by
+2 SUBQUERY t1 range NULL a 5 NULL 8
EXPLAIN SELECT 1 FROM t1 AS t1_outer WHERE
a IN (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2);
id select_type table type possible_keys key key_len ref rows Extra
@@ -2268,7 +2268,7 @@ AND t1_outer1.b = t1_outer2.b;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1_outer1 ref a a 5 const 1 Using where; Using index
1 PRIMARY t1_outer2 index NULL a 10 NULL 15 Using where; Using index; Using join buffer
-2 SUBQUERY t1 range NULL a 5 NULL 8 Using index for group-by
+2 SUBQUERY t1 range NULL a 5 NULL 8
EXPLAIN SELECT (SELECT (SELECT max(b) FROM t1 GROUP BY a HAVING a < 2) x
FROM t1 AS t1_outer) x2 FROM t1 AS t1_outer2;
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result
index 9d7d06f7f1b..ebeba53fdfa 100644
--- a/mysql-test/r/index_merge_myisam.result
+++ b/mysql-test/r/index_merge_myisam.result
@@ -286,7 +286,7 @@ NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL
explain select * from (select * from t1 where key1 = 3 or key2 =3) as Z where key8 >5;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 1
-2 DERIVED t1 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where; Using index
+2 DERIVED t1 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where
create table t3 like t0;
insert into t3 select * from t0;
alter table t3 add key9 int not null, add index i9(key9);
diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result
index 44d874ef018..05db4436a65 100644
--- a/mysql-test/r/innodb_mysql.result
+++ b/mysql-test/r/innodb_mysql.result
@@ -1288,6 +1288,40 @@ a b
3 2
1 1
DROP TABLE t1;
+
+#
+# Bug#27610: ALTER TABLE ROW_FORMAT=... does not rebuild the table.
+#
+
+# - prepare;
+
+DROP TABLE IF EXISTS t1;
+
+CREATE TABLE t1(c INT)
+ENGINE = InnoDB
+ROW_FORMAT = COMPACT;
+
+# - initial check;
+
+SELECT table_schema, table_name, row_format
+FROM INFORMATION_SCHEMA.TABLES
+WHERE table_schema = DATABASE() AND table_name = 't1';
+table_schema table_name row_format
+test t1 Compact
+
+# - change ROW_FORMAT and check;
+
+ALTER TABLE t1 ROW_FORMAT = REDUNDANT;
+
+SELECT table_schema, table_name, row_format
+FROM INFORMATION_SCHEMA.TABLES
+WHERE table_schema = DATABASE() AND table_name = 't1';
+table_schema table_name row_format
+test t1 Redundant
+
+# - that's it, cleanup.
+
+DROP TABLE t1;
End of 5.0 tests
CREATE TABLE `t2` (
`k` int(11) NOT NULL auto_increment,
diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result
index a2bed75a709..6c115435fb6 100644
--- a/mysql-test/r/key.result
+++ b/mysql-test/r/key.result
@@ -530,3 +530,18 @@ ORDER BY c.b, c.d
a b c d e f g h i j a b c d
2 2 1 2004-11-30 12:00:00 1 0 0 0 0 0 2 3388000 -553000 NULL
DROP TABLE t1, t2;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (a INT PRIMARY KEY AUTO_INCREMENT);
+INSERT INTO t1 VALUES (), (), ();
+SELECT 1 AS c1
+FROM t1
+ORDER BY (
+SELECT 1 AS c2
+FROM t1
+GROUP BY GREATEST(LAST_INSERT_ID(), t1.a) ASC
+LIMIT 1);
+c1
+1
+1
+1
+DROP TABLE t1;
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index d1d85aef0ec..1acb82e4137 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -4081,6 +4081,41 @@ SELECT `x` FROM v3;
x
1
DROP VIEW v1, v2, v3;
+
+#
+# Bug#30736: Row Size Too Large Error Creating a Table and
+# Inserting Data.
+#
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+
+CREATE TABLE t1(
+c1 DECIMAL(10, 2),
+c2 FLOAT);
+
+INSERT INTO t1 VALUES (0, 1), (2, 3), (4, 5);
+
+CREATE TABLE t2(
+c3 DECIMAL(10, 2))
+SELECT
+c1 * c2 AS c3
+FROM t1;
+
+SELECT * FROM t1;
+c1 c2
+0.00 1
+2.00 3
+4.00 5
+
+SELECT * FROM t2;
+c3
+0.00
+6.00
+20.00
+
+DROP TABLE t1;
+DROP TABLE t2;
+
End of 5.0 tests
create table t1(a INT, KEY (a));
INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index 1b14d75cd9c..300fa42f3ad 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -1523,3 +1523,13 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp
SELECT ..inexistent();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.inexistent()' at line 1
USE test;
+create function f1() returns int
+begin
+set @test = 1, password = password('foo');
+return 1;
+end|
+ERROR HY000: Not allowed to set autocommit from a stored function or trigger
+create trigger t1
+before insert on t2 for each row set password = password('foo');
+delimiter ;|
+ERROR HY000: Not allowed to set autocommit from a stored function or trigger
diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result
index da27a71c1a1..cb5afcf5f17 100644
--- a/mysql-test/r/udf.result
+++ b/mysql-test/r/udf.result
@@ -11,7 +11,7 @@ RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
CREATE AGGREGATE FUNCTION avgcost
RETURNS REAL SONAME "UDF_EXAMPLE_LIB";
select myfunc_double();
-ERROR HY000: myfunc_double must have at least one argument
+ERROR HY000: Can't initialize function 'myfunc_double'; myfunc_double must have at least one argument
select myfunc_double(1);
myfunc_double(1)
49.00
@@ -24,26 +24,26 @@ select myfunc_int();
myfunc_int()
0
select lookup();
-ERROR HY000: Wrong arguments to lookup; Use the source
+ERROR HY000: Can't initialize function 'lookup'; Wrong arguments to lookup; Use the source
select lookup("127.0.0.1");
lookup("127.0.0.1")
127.0.0.1
select lookup(127,0,0,1);
-ERROR HY000: Wrong arguments to lookup; Use the source
+ERROR HY000: Can't initialize function 'lookup'; Wrong arguments to lookup; Use the source
select lookup("localhost");
lookup("localhost")
127.0.0.1
select reverse_lookup();
-ERROR HY000: Wrong number of arguments to reverse_lookup; Use the source
+ERROR HY000: Can't initialize function 'reverse_lookup'; Wrong number of arguments to reverse_lookup; Use the source
select reverse_lookup("127.0.0.1");
select reverse_lookup(127,0,0,1);
select reverse_lookup("localhost");
reverse_lookup("localhost")
NULL
select avgcost();
-ERROR HY000: wrong number of arguments: AVGCOST() requires two arguments
+ERROR HY000: Can't initialize function 'avgcost'; wrong number of arguments: AVGCOST() requires two arguments
select avgcost(100,23.76);
-ERROR HY000: wrong argument type: AVGCOST() requires an INT and a REAL
+ERROR HY000: Can't initialize function 'avgcost'; wrong argument type: AVGCOST() requires an INT and a REAL
create table t1(sum int, price float(24));
insert into t1 values(100, 50.00), (100, 100.00);
select avgcost(sum, price) from t1;
diff --git a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc
index 96dfdbed541..a3ff022c43c 100644
--- a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc
+++ b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc
@@ -53,7 +53,7 @@ DELETE FROM t2 WHERE a = 2;
--echo ******************** LOAD DATA INFILE ********************
--exec cp ./suite/rpl/data/rpl_mixed.dat $MYSQLTEST_VARDIR/tmp/
LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;
---exec rm $MYSQLTEST_VARDIR/tmp/rpl_mixed.dat
+--remove_file $MYSQLTEST_VARDIR/tmp/rpl_mixed.dat
SELECT * FROM t1;
--source suite/rpl/include/rpl_mixed_check_select.inc
--source suite/rpl/include/rpl_mixed_clear_tables.inc
diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test
index d1ca5f1b609..a4c7eaebc30 100644
--- a/mysql-test/t/events.test
+++ b/mysql-test/t/events.test
@@ -454,7 +454,8 @@ create event закачка on schedule every 10 hour do select get_lock("test_l
--echo "Should have only 2 processes: the scheduler and the locked event"
let $wait_condition= select count(*) = 2 from information_schema.processlist
where ( (state like 'User lock%' AND info like 'select get_lock%')
- OR (command='Daemon' AND user='event_scheduler'));
+ OR (command='Daemon' AND user='event_scheduler' AND
+ state = 'Waiting for next activation'));
--source include/wait_condition.inc
select /*2*/ user, host, db, command, state, info
diff --git a/mysql-test/t/events_bugs.test b/mysql-test/t/events_bugs.test
index 36052fdb9af..ebd86f3a3d2 100644
--- a/mysql-test/t/events_bugs.test
+++ b/mysql-test/t/events_bugs.test
@@ -712,18 +712,6 @@ DROP TABLE event_log;
#DROP DATABASE ev_db_1;
SET GLOBAL event_scheduler = OFF;
-#
-# End of tests
-#
-
-let $wait_condition=
- select count(*) = 0 from information_schema.processlist
- where db='events_test' and command = 'Connect' and user=current_user();
---source include/wait_condition.inc
-
-DROP DATABASE events_test;
-
-
#
# Bug#28641 CREATE EVENT with '2038.01.18 03:00:00' let server crash.
#
@@ -737,3 +725,215 @@ CREATE EVENT bug28641 ON SCHEDULE AT '2038.01.18 03:00:00'
DELIMITER ;|
SET GLOBAL event_scheduler= OFF;
DROP EVENT bug28641;
+
+###########################################################################
+
+--echo
+--echo #####################################################################
+--echo #
+--echo # BUG#31111: --read-only crashes MySQL (events fail to load).
+--echo #
+--echo #####################################################################
+--echo
+
+--error 0,ER_CANNOT_USER
+DROP USER mysqltest_u1@localhost;
+
+--disable_warnings
+DROP EVENT IF EXISTS e1;
+DROP EVENT IF EXISTS e2;
+--enable_warnings
+
+--echo
+
+# Check that an ordinary user can not create/update/drop events in the
+# read-only mode.
+
+GRANT EVENT ON *.* TO mysqltest_u1@localhost;
+
+--echo
+
+SET GLOBAL READ_ONLY = 1;
+
+--echo
+
+--echo #
+--echo # Connection: u1_con (mysqltest_u1@localhost/events_test).
+--echo #
+
+--connect(u1_con,localhost,mysqltest_u1,,events_test)
+
+--echo
+
+--error ER_OPTION_PREVENTS_STATEMENT
+CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1;
+
+--echo
+
+--error ER_OPTION_PREVENTS_STATEMENT
+ALTER EVENT e1 COMMENT 'comment';
+
+--echo
+
+--error ER_OPTION_PREVENTS_STATEMENT
+DROP EVENT e1;
+
+--echo
+
+# Check that the super user still can create/update/drop events.
+
+--echo #
+--echo # Connection: root_con (root@localhost/events_test).
+--echo #
+
+--connect(root_con,localhost,root,,events_test)
+
+--echo
+
+CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1;
+
+--echo
+
+ALTER EVENT e1 COMMENT 'comment';
+
+--echo
+
+DROP EVENT e1;
+
+--echo
+
+#
+# Switch to read-write mode; create test events under the user mysqltest_u1;
+# switch back to read-only mode.
+#
+
+SET GLOBAL READ_ONLY = 0;
+
+--echo
+
+--echo #
+--echo # Connection: u1_con (mysqltest_u1@localhost/test).
+--echo #
+
+--connection u1_con
+
+--echo
+
+CREATE EVENT e1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 SECOND DO SET @a = 1;
+CREATE EVENT e2 ON SCHEDULE EVERY 1 SECOND DO SET @a = 1;
+
+--echo
+
+SELECT
+ event_name,
+ last_executed IS NULL,
+ definer
+FROM INFORMATION_SCHEMA.EVENTS
+WHERE event_schema = 'events_test';
+
+--echo
+
+--echo #
+--echo # Connection: root_con (root@localhost/events_test).
+--echo #
+
+--connection root_con
+
+--echo
+
+SET GLOBAL READ_ONLY = 1;
+
+# Check that the event scheduler is able to update event.
+
+--echo
+
+SET GLOBAL EVENT_SCHEDULER = ON;
+
+--echo
+
+--echo # Waiting for the event scheduler to execute and drop event e1...
+
+let $wait_timeout = 2;
+let $wait_condition =
+ SELECT COUNT(*) = 0
+ FROM INFORMATION_SCHEMA.EVENTS
+ WHERE event_schema = 'events_test' AND event_name = 'e1';
+--source include/wait_condition.inc
+
+--echo
+
+--echo # Waiting for the event scheduler to execute and update event e2...
+
+let $wait_condition =
+ SELECT last_executed IS NOT NULL
+ FROM INFORMATION_SCHEMA.EVENTS
+ WHERE event_schema = 'events_test' AND event_name = 'e2';
+--source include/wait_condition.inc
+
+--echo
+
+SET GLOBAL EVENT_SCHEDULER = OFF;
+
+--echo
+
+SELECT
+ event_name,
+ last_executed IS NULL,
+ definer
+FROM INFORMATION_SCHEMA.EVENTS
+WHERE event_schema = 'events_test';
+
+--echo
+
+--error ER_EVENT_DOES_NOT_EXIST
+DROP EVENT e1;
+
+--echo
+--echo # Cleanup.
+--echo
+
+DROP EVENT e2;
+
+--echo
+
+SET GLOBAL READ_ONLY = 0;
+
+--echo
+
+--echo #
+--echo # Connection: default
+--echo #
+
+--disconnect u1_con
+--disconnect root_con
+--connection default
+
+--echo
+
+DROP USER mysqltest_u1@localhost;
+
+--echo
+--echo #####################################################################
+--echo #
+--echo # End of BUG#31111.
+--echo #
+--echo #####################################################################
+--echo
+
+
+###########################################################################
+#
+# End of tests
+#
+# !!! KEEP this section AT THE END of this file !!!
+#
+###########################################################################
+
+let $wait_condition=
+ select count(*) = 0 from information_schema.processlist
+ where db='events_test' and command = 'Connect' and user=current_user();
+--source include/wait_condition.inc
+
+DROP DATABASE events_test;
+
+# THIS MUST BE THE LAST LINE in this file.
diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test
index f1eb8e68b49..cd6c480407d 100644
--- a/mysql-test/t/key.test
+++ b/mysql-test/t/key.test
@@ -501,3 +501,26 @@ ORDER BY c.b, c.d
;
DROP TABLE t1, t2;
+
+#
+# Bug #31148: bool close_thread_table(THD*, TABLE**): Assertion
+# `table->key_read == 0' failed.
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (a INT PRIMARY KEY AUTO_INCREMENT);
+
+INSERT INTO t1 VALUES (), (), ();
+
+SELECT 1 AS c1
+FROM t1
+ORDER BY (
+ SELECT 1 AS c2
+ FROM t1
+ GROUP BY GREATEST(LAST_INSERT_ID(), t1.a) ASC
+ LIMIT 1);
+
+DROP TABLE t1;
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index 76a66cc4783..71a7caba399 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -3473,6 +3473,54 @@ DROP VIEW v1, v2, v3;
--enable_ps_protocol
+###########################################################################
+
+--echo
+--echo #
+--echo # Bug#30736: Row Size Too Large Error Creating a Table and
+--echo # Inserting Data.
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+--enable_warnings
+
+--echo
+
+CREATE TABLE t1(
+ c1 DECIMAL(10, 2),
+ c2 FLOAT);
+
+--echo
+
+INSERT INTO t1 VALUES (0, 1), (2, 3), (4, 5);
+
+--echo
+
+CREATE TABLE t2(
+ c3 DECIMAL(10, 2))
+ SELECT
+ c1 * c2 AS c3
+ FROM t1;
+
+--echo
+
+SELECT * FROM t1;
+
+--echo
+
+SELECT * FROM t2;
+
+--echo
+
+DROP TABLE t1;
+DROP TABLE t2;
+
+--echo
+
+###########################################################################
+
--echo End of 5.0 tests
#
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index a956a246770..9f20d02480c 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -2223,6 +2223,25 @@ SELECT ..inexistent();
USE test;
#
+# Bug#30904 SET PASSWORD statement is non-transactional
+#
+
+delimiter |;
+
+--error ER_SP_CANT_SET_AUTOCOMMIT
+create function f1() returns int
+begin
+ set @test = 1, password = password('foo');
+ return 1;
+end|
+
+--error ER_SP_CANT_SET_AUTOCOMMIT
+create trigger t1
+ before insert on t2 for each row set password = password('foo');
+
+delimiter ;|
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test
index 663dc08d72e..32cfca57546 100644
--- a/mysql-test/t/udf.test
+++ b/mysql-test/t/udf.test
@@ -35,20 +35,20 @@ eval CREATE FUNCTION reverse_lookup
eval CREATE AGGREGATE FUNCTION avgcost
RETURNS REAL SONAME "$UDF_EXAMPLE_LIB";
---error 0
+--error ER_CANT_INITIALIZE_UDF
select myfunc_double();
select myfunc_double(1);
select myfunc_double(78654);
--error 1305
select myfunc_nonexist();
select myfunc_int();
---error 0
+--error ER_CANT_INITIALIZE_UDF
select lookup();
select lookup("127.0.0.1");
---error 0
+--error ER_CANT_INITIALIZE_UDF
select lookup(127,0,0,1);
select lookup("localhost");
---error 0
+--error ER_CANT_INITIALIZE_UDF
select reverse_lookup();
# These two functions should return "localhost", but it's
@@ -59,9 +59,9 @@ select reverse_lookup(127,0,0,1);
--enable_result_log
select reverse_lookup("localhost");
---error 0
+--error ER_CANT_INITIALIZE_UDF
select avgcost();
---error 0
+--error ER_CANT_INITIALIZE_UDF
select avgcost(100,23.76);
create table t1(sum int, price float(24));
insert into t1 values(100, 50.00), (100, 100.00);
diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc
index 6d6ebbee57d..276d1ca3b49 100644
--- a/server-tools/instance-manager/mysqlmanager.cc
+++ b/server-tools/instance-manager/mysqlmanager.cc
@@ -79,6 +79,9 @@ int main(int argc, char *argv[])
{
int return_value;
+ puts("\n"
+ "WARNING: This program is deprecated and will be removed in 6.0.\n");
+
/* Initialize. */
MY_INIT(argv[0]);
diff --git a/sql-common/client.c b/sql-common/client.c
index baf154dcc43..0ca7ef16c0d 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -272,6 +272,76 @@ static int wait_for_data(my_socket fd, uint timeout)
}
#endif /* defined(__WIN__) || defined(__NETWARE__) */
+/**
+ Set the internal error message to mysql handler
+
+ @param mysql connection handle (client side)
+ @param errcode CR_ error code, passed to ER macro to get
+ error text
+ @parma sqlstate SQL standard sqlstate
+*/
+
+void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate)
+{
+ NET *net;
+ DBUG_ENTER("set_mysql_error");
+ DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER(errcode)));
+ DBUG_ASSERT(mysql != 0);
+
+ net= &mysql->net;
+ net->last_errno= errcode;
+ strmov(net->last_error, ER(errcode));
+ strmov(net->sqlstate, sqlstate);
+
+ DBUG_VOID_RETURN;
+}
+
+/**
+ Clear possible error state of struct NET
+
+ @param net clear the state of the argument
+*/
+
+void net_clear_error(NET *net)
+{
+ net->last_errno= 0;
+ net->last_error[0]= '\0';
+ strmov(net->sqlstate, not_error_sqlstate);
+}
+
+/**
+ Set an error message on the client.
+
+ @param mysql connection handle
+ @param errcode CR_* errcode, for client errors
+ @param sqlstate SQL standard sql state, unknown_sqlstate for the
+ majority of client errors.
+ @param format error message template, in sprintf format
+ @param ... variable number of arguments
+*/
+
+static void set_mysql_extended_error(MYSQL *mysql, int errcode,
+ const char *sqlstate,
+ const char *format, ...)
+{
+ NET *net;
+ va_list args;
+ DBUG_ENTER("set_mysql_extended_error");
+ DBUG_PRINT("enter", ("error :%d '%s'", errcode, format));
+ DBUG_ASSERT(mysql != 0);
+
+ net= &mysql->net;
+ net->last_errno= errcode;
+ va_start(args, format);
+ my_vsnprintf(net->last_error, sizeof(net->last_error)-1,
+ format, args);
+ va_end(args);
+ strmov(net->sqlstate, sqlstate);
+
+ DBUG_VOID_RETURN;
+}
+
+
/*
Create a named pipe connection
@@ -279,7 +349,7 @@ static int wait_for_data(my_socket fd, uint timeout)
#ifdef __WIN__
-HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
+HANDLE create_named_pipe(MYSQL *mysql, uint connect_timeout, char **arg_host,
char **arg_unix_socket)
{
HANDLE hPipe=INVALID_HANDLE_VALUE;
@@ -312,42 +382,34 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
break;
if (GetLastError() != ERROR_PIPE_BUSY)
{
- net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
- strmov(net->sqlstate, unknown_sqlstate);
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(net->last_errno), host, unix_socket,
- (ulong) GetLastError());
+ set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR,
+ unknown_sqlstate, ER(CR_NAMEDPIPEOPEN_ERROR),
+ host, unix_socket, (ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
/* wait for for an other instance */
if (! WaitNamedPipe(pipe_name, connect_timeout*1000) )
{
- net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
- strmov(net->sqlstate, unknown_sqlstate);
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(net->last_errno), host, unix_socket,
- (ulong) GetLastError());
+ set_mysql_extended_error(mysql, CR_NAMEDPIPEWAIT_ERROR, unknown_sqlstate,
+ ER(CR_NAMEDPIPEWAIT_ERROR),
+ host, unix_socket, (ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
}
if (hPipe == INVALID_HANDLE_VALUE)
{
- net->last_errno=CR_NAMEDPIPEOPEN_ERROR;
- strmov(net->sqlstate, unknown_sqlstate);
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(net->last_errno), host, unix_socket,
- (ulong) GetLastError());
+ set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, unknown_sqlstate,
+ ER(CR_NAMEDPIPEOPEN_ERROR), host, unix_socket,
+ (ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
{
CloseHandle( hPipe );
- net->last_errno=CR_NAMEDPIPESETSTATE_ERROR;
- strmov(net->sqlstate, unknown_sqlstate);
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(net->last_errno),host, unix_socket,
- (ulong) GetLastError());
+ set_mysql_extended_error(mysql, CR_NAMEDPIPESETSTATE_ERROR,
+ unknown_sqlstate, ER(CR_NAMEDPIPESETSTATE_ERROR),
+ host, unix_socket, (ulong) GetLastError());
return INVALID_HANDLE_VALUE;
}
*arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
@@ -566,14 +628,12 @@ err:
CloseHandle(handle_connect_file_map);
if (error_allow)
{
- net->last_errno=error_allow;
- strmov(net->sqlstate, unknown_sqlstate);
if (error_allow == CR_SHARED_MEMORY_EVENT_ERROR)
- my_snprintf(net->last_error,sizeof(net->last_error)-1,
- ER(net->last_errno),suffix_pos,error_code);
+ set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
+ ER(error_allow), suffix_pos, error_code);
else
- my_snprintf(net->last_error,sizeof(net->last_error)-1,
- ER(net->last_errno),error_code);
+ set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
+ ER(error_allow), error_code);
return(INVALID_HANDLE_VALUE);
}
return(handle_map);
@@ -683,10 +743,8 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
DBUG_RETURN(1);
}
- net->last_error[0]=0;
- net->last_errno= 0;
- strmov(net->sqlstate, not_error_sqlstate);
- mysql->net.report_error=0;
+ net_clear_error(net);
+ net->report_error=0;
mysql->info=0;
mysql->affected_rows= ~(my_ulonglong) 0;
/*
@@ -703,8 +761,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
socket_errno));
if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
{
- net->last_errno=CR_NET_PACKET_TOO_LARGE;
- strmov(net->last_error,ER(net->last_errno));
+ set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
goto end;
}
end_server(mysql);
@@ -713,8 +770,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
if (net_write_command(net,(uchar) command, header, header_length,
arg, arg_length))
{
- net->last_errno=CR_SERVER_GONE_ERROR;
- strmov(net->last_error,ER(net->last_errno));
+ set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
goto end;
}
}
@@ -742,48 +798,6 @@ void free_old_query(MYSQL *mysql)
}
/*
- Set the internal error message to mysql handler
-*/
-
-void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate)
-{
- NET *net;
- DBUG_ENTER("set_mysql_error");
- DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER(errcode)));
- DBUG_ASSERT(mysql != 0);
-
- net= &mysql->net;
- net->last_errno= errcode;
- strmov(net->last_error, ER(errcode));
- strmov(net->sqlstate, sqlstate);
-
- DBUG_VOID_RETURN;
-}
-
-
-static void set_mysql_extended_error(MYSQL *mysql, int errcode,
- const char *sqlstate,
- const char *format, ...)
-{
- NET *net;
- va_list args;
- DBUG_ENTER("set_mysql_extended_error");
- DBUG_PRINT("enter", ("error :%d '%s'", errcode, format));
- DBUG_ASSERT(mysql != 0);
-
- net= &mysql->net;
- net->last_errno= errcode;
- va_start(args, format);
- my_vsnprintf(net->last_error, sizeof(net->last_error)-1,
- format, args);
- va_end(args);
- strmov(net->sqlstate, sqlstate);
-
- DBUG_VOID_RETURN;
-}
-
-
-/*
Flush result set sent from server
*/
@@ -846,9 +860,8 @@ static int check_license(MYSQL *mysql)
{
if (net->last_errno == ER_UNKNOWN_SYSTEM_VARIABLE)
{
- net->last_errno= CR_WRONG_LICENSE;
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(net->last_errno), required_license);
+ set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
+ ER(CR_WRONG_LICENSE), required_license);
}
return 1;
}
@@ -864,9 +877,8 @@ static int check_license(MYSQL *mysql)
(!row || !row[0] ||
strncmp(row[0], required_license, sizeof(required_license))))
{
- net->last_errno= CR_WRONG_LICENSE;
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(net->last_errno), required_license);
+ set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
+ ER(CR_WRONG_LICENSE), required_license);
}
mysql_free_result(res);
return net->last_errno;
@@ -1717,7 +1729,6 @@ static MYSQL_METHODS client_methods=
C_MODE_START
int mysql_init_character_set(MYSQL *mysql)
{
- NET *net= &mysql->net;
const char *default_collation_name;
/* Set character set */
@@ -1761,24 +1772,22 @@ int mysql_init_character_set(MYSQL *mysql)
}
charsets_dir= save;
}
-
+
if (!mysql->charset)
{
- net->last_errno=CR_CANT_READ_CHARSET;
- strmov(net->sqlstate, unknown_sqlstate);
if (mysql->options.charset_dir)
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(net->last_errno),
- mysql->options.charset_name,
- mysql->options.charset_dir);
+ set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
+ ER(CR_CANT_READ_CHARSET),
+ mysql->options.charset_name,
+ mysql->options.charset_dir);
else
{
char cs_dir_name[FN_REFLEN];
get_charsets_dir(cs_dir_name);
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(net->last_errno),
- mysql->options.charset_name,
- cs_dir_name);
+ set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
+ ER(CR_CANT_READ_CHARSET),
+ mysql->options.charset_name,
+ cs_dir_name);
}
return 1;
}
@@ -1910,10 +1919,10 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket));
if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR)
{
- net->last_errno=CR_SOCKET_CREATE_ERROR;
- strmov(net->sqlstate, unknown_sqlstate);
- my_snprintf(net->last_error,sizeof(net->last_error)-1,
- ER(net->last_errno),socket_errno);
+ set_mysql_extended_error(mysql, CR_SOCKET_CREATE_ERROR,
+ unknown_sqlstate,
+ ER(CR_SOCKET_CREATE_ERROR),
+ socket_errno);
goto error;
}
net->vio= vio_new(sock, VIO_TYPE_SOCKET,
@@ -1926,10 +1935,10 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
{
DBUG_PRINT("error",("Got error %d on connect to local server",
socket_errno));
- net->last_errno=CR_CONNECTION_ERROR;
- strmov(net->sqlstate, unknown_sqlstate);
- my_snprintf(net->last_error,sizeof(net->last_error)-1,
- ER(net->last_errno),unix_socket,socket_errno);
+ set_mysql_extended_error(mysql, CR_CONNECTION_ERROR,
+ unknown_sqlstate,
+ ER(CR_CONNECTION_ERROR),
+ unix_socket, socket_errno);
goto error;
}
mysql->options.protocol=MYSQL_PROTOCOL_SOCKET;
@@ -1941,8 +1950,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
(! have_tcpip && (unix_socket || !host && is_NT()))))
{
sock=0;
- if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout,
- (char**) &host, (char**) &unix_socket)) ==
+ if ((hPipe= create_named_pipe(mysql, mysql->options.connect_timeout,
+ (char**) &host, (char**) &unix_socket)) ==
INVALID_HANDLE_VALUE)
{
DBUG_PRINT("error",
@@ -1986,10 +1995,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
#endif
if (sock == SOCKET_ERROR)
{
- net->last_errno=CR_IPSOCK_ERROR;
- strmov(net->sqlstate, unknown_sqlstate);
- my_snprintf(net->last_error,sizeof(net->last_error)-1,
- ER(net->last_errno),socket_errno);
+ set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
+ ER(CR_IPSOCK_ERROR), socket_errno);
goto error;
}
net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
@@ -2014,10 +2021,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
if (!hp)
{
my_gethostbyname_r_free();
- net->last_errno=CR_UNKNOWN_HOST;
- strmov(net->sqlstate, unknown_sqlstate);
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(CR_UNKNOWN_HOST), host, tmp_errno);
+ set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
+ ER(CR_UNKNOWN_HOST), host, tmp_errno);
goto error;
}
memcpy(&sock_addr.sin_addr, hp->h_addr,
@@ -2030,10 +2035,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
{
DBUG_PRINT("error",("Got error %d on connect to '%s'",socket_errno,
host));
- net->last_errno= CR_CONN_HOST_ERROR;
- strmov(net->sqlstate, unknown_sqlstate);
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(CR_CONN_HOST_ERROR), host, socket_errno);
+ set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
+ ER(CR_CONN_HOST_ERROR), host, socket_errno);
goto error;
}
}
@@ -2097,11 +2100,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
PROTOCOL_VERSION, mysql->protocol_version));
if (mysql->protocol_version != PROTOCOL_VERSION)
{
- strmov(net->sqlstate, unknown_sqlstate);
- net->last_errno= CR_VERSION_ERROR;
- my_snprintf(net->last_error, sizeof(net->last_error)-1,
- ER(CR_VERSION_ERROR), mysql->protocol_version,
- PROTOCOL_VERSION);
+ set_mysql_extended_error(mysql, CR_VERSION_ERROR, unknown_sqlstate,
+ ER(CR_VERSION_ERROR), mysql->protocol_version,
+ PROTOCOL_VERSION);
goto error;
}
end=strend((char*) net->read_pos+1);
@@ -2625,7 +2626,7 @@ void mysql_detach_stmt_list(LIST **stmt_list __attribute__((unused)),
for (; element; element= element->next)
{
MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
- set_stmt_errmsg(stmt, buff, CR_STMT_CLOSED, unknown_sqlstate);
+ set_stmt_error(stmt, CR_STMT_CLOSED, unknown_sqlstate, buff);
stmt->mysql= 0;
/* No need to call list_delete for statement here */
}
@@ -3142,11 +3143,8 @@ int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
{
char cs_dir_name[FN_REFLEN];
get_charsets_dir(cs_dir_name);
- mysql->net.last_errno= CR_CANT_READ_CHARSET;
- strmov(mysql->net.sqlstate, unknown_sqlstate);
- my_snprintf(mysql->net.last_error, sizeof(mysql->net.last_error) - 1,
- ER(mysql->net.last_errno), cs_name, cs_dir_name);
-
+ set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
+ ER(CR_CANT_READ_CHARSET), cs_name, cs_dir_name);
}
charsets_dir= save_csdir;
return mysql->net.last_errno;
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 787b04c12c6..adac2b596c1 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -2017,6 +2017,7 @@ end_no_lex_start:
ret= 1;
else
{
+ ulong saved_master_access;
/*
Peculiar initialization order is a crutch to avoid races in SHOW
PROCESSLIST which reads thd->{query/query_length} without a mutex.
@@ -2024,8 +2025,19 @@ end_no_lex_start:
thd->query_length= 0;
thd->query= sp_sql.c_ptr_safe();
thd->query_length= sp_sql.length();
- if (Events::drop_event(thd, dbname, name, FALSE))
- ret= 1;
+
+ /*
+ NOTE: even if we run in read-only mode, we should be able to lock
+ the mysql.event table for writing. In order to achieve this, we
+ should call mysql_lock_tables() under the super-user.
+ */
+
+ saved_master_access= thd->security_ctx->master_access;
+ thd->security_ctx->master_access |= SUPER_ACL;
+
+ ret= Events::drop_event(thd, dbname, name, FALSE);
+
+ thd->security_ctx->master_access= saved_master_access;
}
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index 705bd8b2704..4451e763ff7 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -525,6 +525,10 @@ Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables,
- whether this open mode would work under LOCK TABLES, or inside a
stored function or trigger.
+ Note that if the table can't be locked successfully this operation will
+ close it. Therefore it provides guarantee that it either opens and locks
+ table or fails without leaving any tables open.
+
@param[in] thd Thread context
@param[in] lock_type How to lock the table
@param[out] table We will store the open table here
@@ -544,7 +548,10 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
tables.init_one_table("mysql", "event", lock_type);
if (simple_open_n_lock_tables(thd, &tables))
+ {
+ close_thread_tables(thd, FALSE, FALSE);
DBUG_RETURN(TRUE);
+ }
*table= tables.table;
tables.table->use_all_columns();
@@ -995,6 +1002,8 @@ update_timing_fields_for_event(THD *thd,
if (thd->current_stmt_binlog_row_based)
thd->clear_current_stmt_binlog_row_based();
+ DBUG_ASSERT(thd->security_ctx->master_access & SUPER_ACL);
+
if (open_event_table(thd, TL_WRITE, &table))
goto end;
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index b03b51f1134..d3a031fd8f8 100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -399,6 +399,13 @@ Event_scheduler::start()
new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
new_thd->command= COM_DAEMON;
+ /*
+ We should run the event scheduler thread under the super-user privileges.
+ In particular, this is needed to be able to lock the mysql.event table
+ for writing when the server is running in the read-only mode.
+ */
+ new_thd->security_ctx->master_access |= SUPER_ACL;
+
scheduler_param_value=
(struct scheduler_param *)my_malloc(sizeof(struct scheduler_param), MYF(0));
scheduler_param_value->thd= new_thd;
diff --git a/sql/events.cc b/sql/events.cc
index 5246bccc388..1bfbc5d6645 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -1124,11 +1124,25 @@ Events::load_events_from_db(THD *thd)
READ_RECORD read_record_info;
bool ret= TRUE;
uint count= 0;
+ ulong saved_master_access;
DBUG_ENTER("Events::load_events_from_db");
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
- if (db_repository->open_event_table(thd, TL_WRITE, &table))
+ /*
+ NOTE: even if we run in read-only mode, we should be able to lock the
+ mysql.event table for writing. In order to achieve this, we should call
+ mysql_lock_tables() under the super user.
+ */
+
+ saved_master_access= thd->security_ctx->master_access;
+ thd->security_ctx->master_access |= SUPER_ACL;
+
+ ret= db_repository->open_event_table(thd, TL_WRITE, &table);
+
+ thd->security_ctx->master_access= saved_master_access;
+
+ if (ret)
{
sql_print_error("Event Scheduler: Failed to open table mysql.event");
DBUG_RETURN(TRUE);
diff --git a/sql/filesort.cc b/sql/filesort.cc
index c074f90e780..2e6f0ecaf05 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -555,7 +555,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
else
file->unlock_row();
/* It does not make sense to read more keys in case of a fatal error */
- if (thd->net.report_error)
+ if (thd->is_error())
break;
}
if (quick_select)
@@ -573,7 +573,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
file->ha_rnd_end();
}
- if (thd->net.report_error)
+ if (thd->is_error())
DBUG_RETURN(HA_POS_ERROR);
/* Signal we should use orignal column read and write maps */
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index 5d5c8a26447..fc35a7a930e 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -259,7 +259,7 @@ static void run_query(THD *thd, char *buf, char *end,
DBUG_PRINT("query", ("%s", thd->query));
mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
- if (no_print_error && thd->query_error)
+ if (no_print_error && thd->is_slave_error)
{
int i;
Thd_ndb *thd_ndb= get_thd_ndb(thd);
@@ -271,7 +271,7 @@ static void run_query(THD *thd, char *buf, char *end,
sql_print_error("NDB: %s: error %s %d(ndb: %d) %d %d",
buf, thd->net.last_error, thd->net.last_errno,
thd_ndb->m_error_code,
- thd->net.report_error, thd->query_error);
+ (int) thd->is_error(), thd->is_slave_error);
}
thd->options= save_thd_options;
diff --git a/sql/handler.cc b/sql/handler.cc
index 3939873ec7d..22374d57e99 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1414,6 +1414,36 @@ static const char *check_lowercase_names(handler *file, const char *path,
}
+/**
+ An interceptor to hijack the text of the error message without
+ setting an error in the thread. We need the text to present it
+ in the form of a warning to the user.
+*/
+
+struct Ha_delete_table_error_handler: public Internal_error_handler
+{
+public:
+ virtual bool handle_error(uint sql_errno,
+ const char *message,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd);
+ char buff[MYSQL_ERRMSG_SIZE];
+};
+
+
+bool
+Ha_delete_table_error_handler::
+handle_error(uint sql_errno,
+ const char *message,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd)
+{
+ /* Grab the error message */
+ strmake(buff, message, sizeof(buff)-1);
+ return TRUE;
+}
+
+
/** @brief
This should return ENOENT if the file doesn't exists.
The .frm file will be deleted only if we return 0 or ENOENT
@@ -1442,23 +1472,11 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
{
/*
Because file->print_error() use my_error() to generate the error message
- we must store the error state in thd, reset it and restore it to
- be able to get hold of the error message.
- (We should in the future either rewrite handler::print_error() or make
- a nice method of this.
+ we use an internal error handler to intercept it and store the text
+ in a temporary buffer. Later the message will be presented to user
+ as a warning.
*/
- bool query_error= thd->query_error;
- sp_rcontext *spcont= thd->spcont;
- SELECT_LEX *current_select= thd->lex->current_select;
- char buff[sizeof(thd->net.last_error)];
- char new_error[sizeof(thd->net.last_error)];
- int last_errno= thd->net.last_errno;
-
- strmake(buff, thd->net.last_error, sizeof(buff)-1);
- thd->query_error= 0;
- thd->spcont= NULL;
- thd->lex->current_select= 0;
- thd->net.last_error[0]= 0;
+ Ha_delete_table_error_handler ha_delete_table_error_handler;
/* Fill up strucutures that print_error may need */
dummy_share.path.str= (char*) path;
@@ -1471,16 +1489,18 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
file->table_share= &dummy_share;
file->table= &dummy_table;
+
+ thd->push_internal_handler(&ha_delete_table_error_handler);
file->print_error(error, 0);
- strmake(new_error, thd->net.last_error, sizeof(buff)-1);
- /* restore thd */
- thd->query_error= query_error;
- thd->spcont= spcont;
- thd->lex->current_select= current_select;
- thd->net.last_errno= last_errno;
- strmake(thd->net.last_error, buff, sizeof(buff)-1);
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, new_error);
+ thd->pop_internal_handler();
+
+ /*
+ XXX: should we convert *all* errors to warnings here?
+ What if the error is fatal?
+ */
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error,
+ ha_delete_table_error_handler.buff);
}
delete file;
DBUG_RETURN(error);
@@ -2203,7 +2223,7 @@ void handler::print_error(int error, myf errflag)
case HA_ERR_NO_SUCH_TABLE:
my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str,
table_share->table_name.str);
- break;
+ DBUG_VOID_RETURN;
case HA_ERR_RBR_LOGGING_FAILED:
textno= ER_BINLOG_ROW_LOGGING_FAILED;
break;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 64574a9ad74..ec0ecc89394 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -187,7 +187,7 @@ Item_func::fix_fields(THD *thd, Item **ref)
}
}
fix_length_and_dec();
- if (thd->net.report_error) // An error inside fix_length_and_dec occured
+ if (thd->is_error()) // An error inside fix_length_and_dec occured
return TRUE;
fixed= 1;
return FALSE;
@@ -2897,6 +2897,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
if (u_d->func_init)
{
+ char init_msg_buff[MYSQL_ERRMSG_SIZE];
char *to=num_buffer;
for (uint i=0; i < arg_count; i++)
{
@@ -2949,10 +2950,10 @@ 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, thd->net.last_error)))
+ if ((error=(uchar) init(&initid, &f_args, init_msg_buff)))
{
my_error(ER_CANT_INITIALIZE_UDF, MYF(0),
- u_d->name.str, thd->net.last_error);
+ u_d->name.str, init_msg_buff);
free_udf(u_d);
DBUG_RETURN(TRUE);
}
@@ -4073,7 +4074,7 @@ my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val)
NOTES
For now it always return OK. All problem with value evaluating
- will be caught by thd->net.report_error check in sql_set_variables().
+ will be caught by thd->is_error() check in sql_set_variables().
RETURN
FALSE OK.
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 843c6ced263..8eb7421f854 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -248,7 +248,7 @@ bool Item_subselect::exec()
{
int res;
- if (thd->net.report_error)
+ if (thd->is_error())
/* Do not execute subselect in case of a fatal error */
return 1;
diff --git a/sql/log.cc b/sql/log.cc
index e923418b23a..688ed03d5d1 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -72,13 +72,14 @@ public:
virtual ~Silence_log_table_errors() {}
- virtual bool handle_error(uint sql_errno,
+ virtual bool handle_error(uint sql_errno, const char *message,
MYSQL_ERROR::enum_warning_level level,
THD *thd);
};
bool
Silence_log_table_errors::handle_error(uint /* sql_errno */,
+ const char * /* message */,
MYSQL_ERROR::enum_warning_level /* level */,
THD * /* thd */)
{
@@ -2891,8 +2892,8 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
*decrease_log_space-= file_size;
ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
- if (current_thd->query_error) {
- DBUG_PRINT("info",("query error: %d", current_thd->query_error));
+ if (current_thd->is_slave_error) {
+ DBUG_PRINT("info",("slave error: %d", current_thd->is_slave_error));
if (my_errno == EMFILE) {
DBUG_PRINT("info",("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno));
ret = LOG_INFO_EMFILE;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index a435894382b..a6d07e72033 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -148,7 +148,7 @@ static void pretty_print_str(IO_CACHE* cache, char* str, int len)
static void clear_all_errors(THD *thd, Relay_log_info *rli)
{
- thd->query_error = 0;
+ thd->is_slave_error = 0;
thd->clear_error();
rli->clear_error();
}
@@ -2106,7 +2106,7 @@ and was aborted. There is a chance that your master is inconsistent at this \
point. If you are sure that your master is ok, run this query manually on the \
slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; \
START SLAVE; . Query: '%s'", expected_error, thd->query);
- thd->query_error= 1;
+ thd->is_slave_error= 1;
}
goto end;
}
@@ -2138,7 +2138,7 @@ Default database: '%s'. Query: '%s'",
actual_error ? thd->net.last_error: "no error",
actual_error,
print_slave_db_safe(db), query_arg);
- thd->query_error= 1;
+ thd->is_slave_error= 1;
}
/*
If we get the same error code as expected, or they should be ignored.
@@ -2153,14 +2153,14 @@ Default database: '%s'. Query: '%s'",
/*
Other cases: mostly we expected no error and get one.
*/
- else if (thd->query_error || thd->is_fatal_error)
+ else if (thd->is_slave_error || thd->is_fatal_error)
{
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' on query. Default database: '%s'. Query: '%s'",
(actual_error ? thd->net.last_error :
"unexpected success or fatal error"),
print_slave_db_safe(thd->db), query_arg);
- thd->query_error= 1;
+ thd->is_slave_error= 1;
}
/*
@@ -2171,7 +2171,7 @@ Default database: '%s'. Query: '%s'",
sql_print_error("Slave: did not get the expected number of affected \
rows running query from master - expected %d, got %d (this numbers \
should have matched modulo 4294967296).", 0, ...);
- thd->query_error = 1;
+ thd->is_slave_error = 1;
}
We may also want an option to tell the slave to ignore "affected"
mismatch. This mismatch could be implemented with a new ER_ code, and
@@ -2215,7 +2215,7 @@ end:
thd->first_successful_insert_id_in_prev_stmt= 0;
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- return thd->query_error;
+ return thd->is_slave_error;
}
int Query_log_event::do_update_pos(Relay_log_info *rli)
@@ -3255,7 +3255,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
thd->set_db(new_db.str, new_db.length);
DBUG_ASSERT(thd->query == 0);
thd->query_length= 0; // Should not be needed
- thd->query_error= 0;
+ thd->is_slave_error= 0;
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
/* see Query_log_event::do_apply_event() and BUG#13360 */
@@ -3429,7 +3429,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
List<Item> tmp_list;
if (mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
handle_dup, ignore, net != 0))
- thd->query_error= 1;
+ thd->is_slave_error= 1;
if (thd->cuted_fields)
{
/* log_pos is the position of the LOAD event in the master log */
@@ -3468,9 +3468,9 @@ error:
close_thread_tables(thd);
DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error",
- thd->query_error= 0; thd->is_fatal_error= 1;);
+ thd->is_slave_error= 0; thd->is_fatal_error= 1;);
- if (thd->query_error)
+ if (thd->is_slave_error)
{
/* this err/sql_errno code is copy-paste from net_send_error() */
const char *err;
@@ -5655,7 +5655,7 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
m_width(tbl_arg ? tbl_arg->s->fields : 1),
m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0)
#ifdef HAVE_REPLICATION
- ,m_key(NULL), m_curr_row(NULL), m_curr_row_end(NULL)
+ , m_curr_row(NULL), m_curr_row_end(NULL), m_key(NULL)
#endif
{
/*
@@ -5703,7 +5703,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len,
#endif
m_table_id(0), m_rows_buf(0), m_rows_cur(0), m_rows_end(0)
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
- ,m_key(NULL), m_curr_row(NULL), m_curr_row_end(NULL)
+ , m_curr_row(NULL), m_curr_row_end(NULL), m_key(NULL)
#endif
{
DBUG_ENTER("Rows_log_event::Rows_log_event(const char*,...)");
@@ -5951,7 +5951,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
{
if (!need_reopen)
{
- if (thd->query_error || thd->is_fatal_error)
+ if (thd->is_slave_error || thd->is_fatal_error)
{
/*
Error reporting borrowed from Query_log_event with many excessive
@@ -5995,7 +5995,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
uint tables_count= rli->tables_to_lock_count;
if ((error= open_tables(thd, &tables, &tables_count, 0)))
{
- if (thd->query_error || thd->is_fatal_error)
+ if (thd->is_slave_error || thd->is_fatal_error)
{
/*
Error reporting borrowed from Query_log_event with many excessive
@@ -6006,7 +6006,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
"Error '%s' on reopening tables",
(actual_error ? thd->net.last_error :
"unexpected success or fatal error"));
- thd->query_error= 1;
+ thd->is_slave_error= 1;
}
const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
DBUG_RETURN(error);
@@ -6029,7 +6029,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
{
mysql_unlock_tables(thd, thd->lock);
thd->lock= 0;
- thd->query_error= 1;
+ thd->is_slave_error= 1;
const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
DBUG_RETURN(ERR_BAD_TABLE_DEF);
}
@@ -6159,7 +6159,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
"Error in %s event: row application failed. %s",
get_type_str(),
thd->net.last_error ? thd->net.last_error : "");
- thd->query_error= 1;
+ thd->is_slave_error= 1;
break;
}
@@ -6221,7 +6221,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
thd->reset_current_stmt_binlog_row_based();
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
- thd->query_error= 1;
+ thd->is_slave_error= 1;
DBUG_RETURN(error);
}
@@ -6519,9 +6519,15 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
m_dblen(m_dbnam ? tbl->s->db.length : 0),
m_tblnam(tbl->s->table_name.str),
m_tbllen(tbl->s->table_name.length),
- m_colcnt(tbl->s->fields), m_field_metadata(0),
- m_field_metadata_size(0), m_memory(NULL), m_meta_memory(NULL), m_data_size(0),
- m_table_id(tid), m_null_bits(0), m_flags(flags)
+ m_colcnt(tbl->s->fields),
+ m_memory(NULL),
+ m_table_id(tid),
+ m_flags(flags),
+ m_data_size(0),
+ m_field_metadata(0),
+ m_field_metadata_size(0),
+ m_null_bits(0),
+ m_meta_memory(NULL)
{
DBUG_ASSERT(m_table_id != ~0UL);
/*
@@ -6798,7 +6804,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
TABLE_LIST *tmp_table_list= table_list;
if ((error= open_tables(thd, &tmp_table_list, &count, 0)))
{
- if (thd->query_error || thd->is_fatal_error)
+ if (thd->is_slave_error || thd->is_fatal_error)
{
/*
Error reporting borrowed from Query_log_event with many excessive
@@ -6810,7 +6816,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
(actual_error ? thd->net.last_error :
"unexpected success or fatal error"),
table_list->db, table_list->table_name);
- thd->query_error= 1;
+ thd->is_slave_error= 1;
}
goto err;
}
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 949179386ea..c6b691ec010 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -68,7 +68,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli
{
if (!need_reopen)
{
- if (thd->query_error || thd->is_fatal_error)
+ if (thd->is_slave_error || thd->is_fatal_error)
{
/*
Error reporting borrowed from Query_log_event with many excessive
@@ -112,7 +112,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli
uint tables_count= rli->tables_to_lock_count;
if ((error= open_tables(thd, &tables, &tables_count, 0)))
{
- if (thd->query_error || thd->is_fatal_error)
+ if (thd->is_slave_error || thd->is_fatal_error)
{
/*
Error reporting borrowed from Query_log_event with many excessive
@@ -123,7 +123,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli
"Error '%s' on reopening tables",
(actual_error ? thd->net.last_error :
"unexpected success or fatal error"));
- thd->query_error= 1;
+ thd->is_slave_error= 1;
}
const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
DBUG_RETURN(error);
@@ -146,7 +146,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli
{
mysql_unlock_tables(thd, thd->lock);
thd->lock= 0;
- thd->query_error= 1;
+ thd->is_slave_error= 1;
const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
DBUG_RETURN(Rows_log_event::ERR_BAD_TABLE_DEF);
}
@@ -255,7 +255,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli
"Error in %s event: row application failed. %s",
ev->get_type_str(),
thd->net.last_error ? thd->net.last_error : "");
- thd->query_error= 1;
+ thd->is_slave_error= 1;
break;
}
@@ -300,7 +300,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli
*/
thd->reset_current_stmt_binlog_row_based();
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
- thd->query_error= 1;
+ thd->is_slave_error= 1;
DBUG_RETURN(error);
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 3b88fe0fca8..3484b8096e3 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -920,7 +920,6 @@ bool init_new_connection_handler_thread();
void reset_mqh(LEX_USER *lu, bool get_them);
bool check_mqh(THD *thd, uint check_command);
void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
-int check_for_max_user_connections(THD *thd, USER_CONN *uc);
void decrease_user_connections(USER_CONN *uc);
void thd_init_client_charset(THD *thd, uint cs_number);
bool setup_connection_thread_globals(THD *thd);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index a355c560996..4cf6e05751f 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2583,7 +2583,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
TODO: There are two exceptions mechanism (THD and sp_rcontext),
this could be improved by having a common stack of handlers.
*/
- if (thd->handle_error(error,
+ if (thd->handle_error(error, str,
MYSQL_ERROR::WARN_LEVEL_ERROR))
DBUG_RETURN(0);
@@ -2593,7 +2593,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
DBUG_RETURN(0);
}
- thd->query_error= 1; // needed to catch query errors during replication
+ thd->is_slave_error= 1; // needed to catch query errors during replication
if (!thd->no_warnings_for_error)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
@@ -4302,6 +4302,7 @@ void create_thread_to_handle_connection(THD *thd)
}
else
{
+ char error_message_buff[MYSQL_ERRMSG_SIZE];
/* Create new thread to handle connection */
int error;
thread_created++;
@@ -4320,7 +4321,10 @@ void create_thread_to_handle_connection(THD *thd)
thd->killed= THD::KILL_CONNECTION; // Safety
(void) pthread_mutex_unlock(&LOCK_thread_count);
statistic_increment(aborted_connects,&LOCK_status);
- net_printf_error(thd, ER_CANT_CREATE_THREAD, error);
+ /* Can't use my_error() since store_globals has not been called. */
+ my_snprintf(error_message_buff, sizeof(error_message_buff),
+ ER(ER_CANT_CREATE_THREAD), error);
+ net_send_error(thd, ER_CANT_CREATE_THREAD, error_message_buff);
(void) pthread_mutex_lock(&LOCK_thread_count);
close_connection(thd,0,0);
delete thd;
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 838d9e373b3..bf8faec006a 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -58,7 +58,7 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length)
Design note:
- net_printf_error and net_send_error are low-level functions
+ net_send_error is a low-level functions
that shall be used only when a new connection is being
established or at server startup.
For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
@@ -84,7 +84,7 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
DBUG_VOID_RETURN;
}
- thd->query_error= 1; // needed to catch query errors during replication
+ thd->is_slave_error= 1; // needed to catch query errors during replication
if (!err)
{
if (sql_errno)
@@ -120,124 +120,6 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
DBUG_VOID_RETURN;
}
-/*
- Write error package and flush to client
- It's a little too low level, but I don't want to use another buffer for
- this
-
- Design note:
-
- net_printf_error and net_send_error are low-level functions
- that shall be used only when a new connection is being
- established or at server startup.
- For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
- critical that every error that can be intercepted is issued in one
- place only, my_message_sql.
-*/
-
-void
-net_printf_error(THD *thd, uint errcode, ...)
-{
- va_list args;
- uint length,offset;
- const char *format;
-#ifndef EMBEDDED_LIBRARY
- const char *text_pos;
- int head_length= NET_HEADER_SIZE;
-#else
- char text_pos[1024];
-#endif
- NET *net= &thd->net;
-
- DBUG_ENTER("net_printf_error");
- DBUG_PRINT("enter",("message: %u",errcode));
-
- DBUG_ASSERT(!thd->spcont);
-
- 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->query_error= 1; // needed to catch query errors during replication
-#ifndef EMBEDDED_LIBRARY
- query_cache_abort(net); // Safety
-#endif
- va_start(args,errcode);
- /*
- The following is needed to make net_printf_error() work with 0 argument
- for errorcode and use the argument after that as the format string. This
- is useful for rare errors that are not worth the hassle to put in
- errmsg.sys, but at the same time, the message is not fixed text
- */
- if (errcode)
- format= ER(errcode);
- else
- {
- format=va_arg(args,char*);
- errcode= ER_UNKNOWN_ERROR;
- }
- offset= (net->return_errno ?
- ((thd->client_capabilities & CLIENT_PROTOCOL_41) ?
- 2+SQLSTATE_LENGTH+1 : 2) : 0);
-#ifndef EMBEDDED_LIBRARY
- text_pos=(char*) net->buff + head_length + offset + 1;
- length= (uint) ((char*)net->buff_end - text_pos);
-#else
- length=sizeof(text_pos)-1;
-#endif
- length=my_vsnprintf(my_const_cast(char*) (text_pos),
- min(length, sizeof(net->last_error)),
- format,args);
- va_end(args);
-
- /* Replication slave relies on net->last_* to see if there was error */
- net->last_errno= errcode;
- strmake(net->last_error, text_pos, sizeof(net->last_error)-1);
-
-#ifndef EMBEDDED_LIBRARY
- if (net->vio == 0)
- {
- if (thd->bootstrap)
- {
- /*
- In bootstrap it's ok to print on stderr
- This may also happen when we get an error from a slave thread
- */
- fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos);
- thd->fatal_error();
- }
- DBUG_VOID_RETURN;
- }
-
- int3store(net->buff,length+1+offset);
- net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
- net->buff[head_length]=(uchar) 255; // Error package
- if (offset)
- {
- uchar *pos= net->buff+head_length+1;
- int2store(pos, errcode);
- if (thd->client_capabilities & CLIENT_PROTOCOL_41)
- {
- pos[2]= '#'; /* To make the protocol backward compatible */
- memcpy(pos+3, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
- }
- }
- VOID(net_real_write(net, net->buff, length+head_length+1+offset));
-#else
- net->last_errno= errcode;
- strmake(net->last_error, text_pos, length);
- strmake(net->sqlstate, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
-#endif
- if (thd->killed != THD::KILL_CONNECTION)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, errcode,
- text_pos ? text_pos : ER(errcode));
- thd->is_fatal_error=0; // Error message is given
- DBUG_VOID_RETURN;
-}
/*
Return ok to the client.
diff --git a/sql/protocol.h b/sql/protocol.h
index 46a2b6d36b6..53584326f03 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -172,7 +172,6 @@ public:
};
void send_warning(THD *thd, uint sql_errno, const char *err=0);
-void net_printf_error(THD *thd, uint sql_errno, ...);
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);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 138c71fa559..11874b1020c 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -3051,7 +3051,7 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list)
if ((error= var->check(thd)))
goto err;
}
- if (!(error= test(thd->net.report_error)))
+ if (!(error= test(thd->is_error())))
{
it.rewind();
while ((var= it++))
diff --git a/sql/slave.cc b/sql/slave.cc
index fcbd4eb841b..494e13d8c9f 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -980,7 +980,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
DBUG_RETURN(1);
}
thd->query= query;
- thd->query_error = 0;
+ thd->is_slave_error = 0;
thd->net.no_send_ok = 1;
bzero((char*) &tables,sizeof(tables));
@@ -1009,7 +1009,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
thd->db_length= save_db_length;
thd->options = save_options;
- if (thd->query_error)
+ if (thd->is_slave_error)
goto err; // mysql_parse took care of the error send
thd->proc_info = "Opening master dump table";
@@ -2501,7 +2501,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
if (sys_init_slave.value_length)
{
execute_init_command(thd, &sys_init_slave, &LOCK_sys_init_slave);
- if (thd->query_error)
+ if (thd->is_slave_error)
{
sql_print_error("\
Slave SQL thread aborted. Can't execute init_slave query");
diff --git a/sql/sp.cc b/sql/sp.cc
index 1b5d8ca87b8..b4f0ec7729b 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1866,7 +1866,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
an error with it's return value without calling my_error(), we
set the generic "mysql.proc table corrupt" error here.
*/
- if (!thd->net.report_error)
+ if (! thd->is_error())
{
/*
SP allows full NAME_LEN chars thus he have to allocate enough
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 093544cdd0a..6e8749aa745 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -370,7 +370,7 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
thd->abort_on_warning= save_abort_on_warning;
thd->transaction.stmt.modified_non_trans_table= save_stmt_modified_non_trans_table;
- if (thd->net.report_error)
+ if (thd->is_error())
{
/* Return error status if something went wrong. */
err_status= TRUE;
@@ -1108,7 +1108,7 @@ sp_head::execute(THD *thd)
if ((ctx= thd->spcont))
ctx->clear_handler();
- thd->query_error= 0;
+ thd->is_slave_error= 0;
old_arena= thd->stmt_arena;
/*
@@ -1275,9 +1275,9 @@ sp_head::execute(THD *thd)
state= EXECUTED;
done:
- DBUG_PRINT("info", ("err_status: %d killed: %d query_error: %d report_error: %d",
- err_status, thd->killed, thd->query_error,
- thd->net.report_error));
+ DBUG_PRINT("info", ("err_status: %d killed: %d is_slave_error: %d report_error: %d",
+ err_status, thd->killed, thd->is_slave_error,
+ thd->is_error()));
if (thd->killed)
err_status= TRUE;
@@ -2673,7 +2673,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
cleanup_items() is called in sp_head::execute()
*/
- DBUG_RETURN(res || thd->net.report_error);
+ DBUG_RETURN(res || thd->is_error());
}
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 0c8c4b8c2d8..070a943da9e 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -428,7 +428,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
continue;
}
- const char *password= get_field(&mem, table->field[2]);
+ const char *password= get_field(thd->mem_root, table->field[2]);
uint password_len= password ? strlen(password) : 0;
set_user_salt(&user, password, password_len);
if (user.salt_len == 0 && password_len != 0)
@@ -495,7 +495,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
/* Starting from 4.0.2 we have more fields */
if (table->s->fields >= 31)
{
- char *ssl_type=get_field(&mem, table->field[next_field++]);
+ char *ssl_type=get_field(thd->mem_root, table->field[next_field++]);
if (!ssl_type)
user.ssl_type=SSL_TYPE_NONE;
else if (!strcmp(ssl_type, "ANY"))
@@ -509,11 +509,11 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
user.x509_issuer= get_field(&mem, table->field[next_field++]);
user.x509_subject= get_field(&mem, table->field[next_field++]);
- char *ptr = get_field(&mem, table->field[next_field++]);
+ char *ptr = get_field(thd->mem_root, table->field[next_field++]);
user.user_resource.questions=ptr ? atoi(ptr) : 0;
- ptr = get_field(&mem, table->field[next_field++]);
+ ptr = get_field(thd->mem_root, table->field[next_field++]);
user.user_resource.updates=ptr ? atoi(ptr) : 0;
- ptr = get_field(&mem, table->field[next_field++]);
+ ptr = get_field(thd->mem_root, table->field[next_field++]);
user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
if (user.user_resource.questions || user.user_resource.updates ||
user.user_resource.conn_per_hour)
@@ -522,7 +522,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
if (table->s->fields >= 36)
{
/* Starting from 5.0.3 we have max_user_connections field */
- ptr= get_field(&mem, table->field[next_field++]);
+ ptr= get_field(thd->mem_root, table->field[next_field++]);
user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
}
else
@@ -5050,6 +5050,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
uchar user_key[MAX_KEY_LENGTH];
uint key_prefix_length;
DBUG_ENTER("handle_grant_table");
+ THD *thd= current_thd;
table->use_all_columns();
if (! table_no) // mysql.user table
@@ -5118,17 +5119,18 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
DBUG_PRINT("info",("scan error: %d", error));
continue;
}
- if (! (host= get_field(&mem, host_field)))
+ if (! (host= get_field(thd->mem_root, host_field)))
host= "";
- if (! (user= get_field(&mem, user_field)))
+ if (! (user= get_field(thd->mem_root, user_field)))
user= "";
#ifdef EXTRA_DEBUG
DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'",
user, host,
- get_field(&mem, table->field[1]) /*db*/,
- get_field(&mem, table->field[3]) /*table*/,
- get_field(&mem, table->field[4]) /*column*/));
+ get_field(thd->mem_root, table->field[1]) /*db*/,
+ get_field(thd->mem_root, table->field[3]) /*table*/,
+ get_field(thd->mem_root,
+ table->field[4]) /*column*/));
#endif
if (strcmp(user_str, user) ||
my_strcasecmp(system_charset_info, host_str, host))
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index ab532c4fd15..2584390d756 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -44,7 +44,7 @@ public:
virtual ~Prelock_error_handler() {}
- virtual bool handle_error(uint sql_errno,
+ virtual bool handle_error(uint sql_errno, const char *message,
MYSQL_ERROR::enum_warning_level level,
THD *thd);
@@ -58,6 +58,7 @@ private:
bool
Prelock_error_handler::handle_error(uint sql_errno,
+ const char * /* message */,
MYSQL_ERROR::enum_warning_level /* level */,
THD * /* thd */)
{
@@ -6260,7 +6261,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
thd->lex->allow_sum_func= save_allow_sum_func;
thd->mark_used_columns= save_mark_used_columns;
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
- DBUG_RETURN(test(thd->net.report_error));
+ DBUG_RETURN(test(thd->is_error()));
}
@@ -6804,7 +6805,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
select_lex->conds_processed_with_permanent_arena= 1;
}
thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
- DBUG_RETURN(test(thd->net.report_error));
+ DBUG_RETURN(test(thd->is_error()));
err_no_arena:
select_lex->is_item_list_lookup= save_is_item_list_lookup;
@@ -6886,7 +6887,7 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
goto err;
}
}
- DBUG_RETURN(thd->net.report_error);
+ DBUG_RETURN(thd->is_error());
err:
if (table)
table->auto_increment_field_not_null= FALSE;
@@ -6971,7 +6972,7 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
table= (*ptr)->table;
table->auto_increment_field_not_null= FALSE;
}
- while ((field = *ptr++) && !thd->net.report_error)
+ while ((field = *ptr++) && ! thd->is_error())
{
value=v++;
table= field->table;
@@ -6980,7 +6981,7 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
if (value->save_in_field(field, 0) < 0)
goto err;
}
- DBUG_RETURN(thd->net.report_error);
+ DBUG_RETURN(thd->is_error());
err:
if (table)
@@ -7390,7 +7391,7 @@ open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
else
{
/* only VIEWs are supported now */
- my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), share->path, parser->type()->str);
+ my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), share->path.str, parser->type()->str);
goto err;
}
DBUG_RETURN(0);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index ffbf0649961..a904023cbff 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -395,7 +395,7 @@ THD::THD()
count_cuted_fields= CHECK_FIELD_IGNORE;
killed= NOT_KILLED;
col_access=0;
- query_error= thread_specific_used= FALSE;
+ is_slave_error= thread_specific_used= FALSE;
hash_clear(&handler_tables_hash);
tmp_table=0;
used_tables=0;
@@ -498,12 +498,12 @@ void THD::push_internal_handler(Internal_error_handler *handler)
}
-bool THD::handle_error(uint sql_errno,
+bool THD::handle_error(uint sql_errno, const char *message,
MYSQL_ERROR::enum_warning_level level)
{
if (m_internal_handler)
{
- return m_internal_handler->handle_error(sql_errno, level, this);
+ return m_internal_handler->handle_error(sql_errno, message, level, this);
}
return FALSE; // 'FALSE', as per coding style
@@ -1305,23 +1305,26 @@ bool select_send::send_fields(List<Item> &list, uint flags)
{
bool res;
if (!(res= thd->protocol->send_fields(&list, flags)))
- status= 1;
+ is_result_set_started= 1;
return res;
}
void select_send::abort()
{
DBUG_ENTER("select_send::abort");
- if (status && thd->spcont &&
+ if (is_result_set_started && thd->spcont &&
thd->spcont->find_handler(thd, thd->net.last_errno,
MYSQL_ERROR::WARN_LEVEL_ERROR))
{
/*
- Executing stored procedure without a handler.
- Here we should actually send an error to the client,
- but as an error will break a multiple result set, the only thing we
- can do for now is to nicely end the current data set and remembering
- the error so that the calling routine will abort
+ We're executing a stored procedure, have an open result
+ set, an SQL exception conditiona and a handler for it.
+ In this situation we must abort the current statement,
+ silence the error and start executing the continue/exit
+ handler.
+ Before aborting the statement, let's end the open result set, as
+ otherwise the client will hang due to the violation of the
+ client/server protocol.
*/
thd->net.report_error= 0;
send_eof();
@@ -1331,6 +1334,17 @@ void select_send::abort()
}
+/**
+ Cleanup an instance of this class for re-use
+ at next execution of a prepared statement/
+ stored procedure statement.
+*/
+
+void select_send::cleanup()
+{
+ is_result_set_started= FALSE;
+}
+
/* Send data to client. Returns 0 if ok */
bool select_send::send_data(List<Item> &items)
@@ -1368,7 +1382,7 @@ bool select_send::send_data(List<Item> &items)
thd->sent_row_count++;
if (!thd->vio_ok())
DBUG_RETURN(0);
- if (!thd->net.report_error)
+ if (! thd->is_error())
DBUG_RETURN(protocol->write());
protocol->remove_last_row();
DBUG_RETURN(1);
@@ -1389,10 +1403,10 @@ bool select_send::send_eof()
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
- if (!thd->net.report_error)
+ if (! thd->is_error())
{
::send_eof(thd);
- status= 0;
+ is_result_set_started= 0;
return 0;
}
else
@@ -2404,6 +2418,7 @@ void Security_context::init()
host= user= priv_user= ip= 0;
host_or_ip= "connecting host";
priv_host[0]= '\0';
+ master_access= 0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
db_access= NO_ACCESS;
#endif
diff --git a/sql/sql_class.h b/sql/sql_class.h
index c286a87653c..632c440266f 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -969,6 +969,7 @@ public:
@return true if the error is handled
*/
virtual bool handle_error(uint sql_errno,
+ const char *message,
MYSQL_ERROR::enum_warning_level level,
THD *thd) = 0;
};
@@ -1466,7 +1467,14 @@ public:
/* for IS NULL => = last_insert_id() fix in remove_eq_conds() */
bool substitute_null_with_insert_id;
bool in_lock_tables;
- bool query_error, bootstrap, cleanup_done;
+ /**
+ True if a slave error. Causes the slave to stop. Not the same
+ as the statement execution error (is_error()), since
+ a statement may be expected to return an error, e.g. because
+ it returned an error on master, and this is OK on the slave.
+ */
+ bool is_slave_error;
+ bool bootstrap, cleanup_done;
/** is set if some thread specific value(s) used in a statement. */
bool thread_specific_used;
@@ -1695,7 +1703,7 @@ public:
net.last_error[0]= 0;
net.last_errno= 0;
net.report_error= 0;
- query_error= 0;
+ is_slave_error= 0;
DBUG_VOID_RETURN;
}
inline bool vio_ok() const { return net.vio != 0; }
@@ -1709,6 +1717,20 @@ public:
net.report_error= 1;
DBUG_PRINT("error",("Fatal error set"));
}
+ /**
+ TRUE if there is an error in the error stack.
+
+ Please use this method instead of direct access to
+ net.report_error.
+
+ If TRUE, the current (sub)-statement should be aborted.
+ The main difference between this member and is_fatal_error
+ is that a fatal error can not be handled by a stored
+ procedure continue handler, whereas a normal error can.
+
+ To raise this flag, use my_error().
+ */
+ inline bool is_error() const { return net.report_error; }
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
@@ -1902,7 +1924,7 @@ public:
@param level the error level
@return true if the error is handled
*/
- virtual bool handle_error(uint sql_errno,
+ virtual bool handle_error(uint sql_errno, const char *message,
MYSQL_ERROR::enum_warning_level level);
/**
@@ -2029,14 +2051,20 @@ public:
class select_send :public select_result {
- int status;
+ /**
+ True if we have sent result set metadata to the client.
+ In this case the client always expects us to end the result
+ set with an eof or error packet
+ */
+ bool is_result_set_started;
public:
- select_send() :status(0) {}
+ select_send() :is_result_set_started(FALSE) {}
bool send_fields(List<Item> &list, uint flags);
bool send_data(List<Item> &items);
bool send_eof();
virtual bool check_simple_select() const { return FALSE; }
void abort();
+ virtual void cleanup();
};
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 094bef9324e..9b5f1a9b0e5 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -87,7 +87,7 @@ static int get_or_create_user_conn(THD *thd, const char *user,
my_malloc(sizeof(struct user_conn) + temp_len+1,
MYF(MY_WME)))))
{
- net_send_error(thd, 0, NullS); // Out of memory
+ /* MY_WME ensures an error is set in THD. */
return_val= 1;
goto end;
}
@@ -100,8 +100,8 @@ static int get_or_create_user_conn(THD *thd, const char *user,
uc->reset_utime= thd->thr_create_utime;
if (my_hash_insert(&hash_user_connections, (uchar*) uc))
{
+ /* The only possible error is out of memory, MY_WME sets an error. */
my_free((char*) uc,0);
- net_send_error(thd, 0, NullS); // Out of memory
return_val= 1;
goto end;
}
@@ -132,6 +132,7 @@ end:
1 error
*/
+static
int check_for_max_user_connections(THD *thd, USER_CONN *uc)
{
int error=0;
@@ -141,7 +142,7 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
if (max_user_connections && !uc->user_resources.user_conn &&
max_user_connections < (uint) uc->connections)
{
- net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
+ my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user);
error=1;
goto end;
}
@@ -149,24 +150,24 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
if (uc->user_resources.user_conn &&
uc->user_resources.user_conn < uc->connections)
{
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
- "max_user_connections",
- (long) uc->user_resources.user_conn);
+ my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user,
+ "max_user_connections",
+ (long) uc->user_resources.user_conn);
error= 1;
goto end;
}
if (uc->user_resources.conn_per_hour &&
uc->user_resources.conn_per_hour <= uc->conn_per_hour)
{
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
- "max_connections_per_hour",
- (long) uc->user_resources.conn_per_hour);
+ my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user,
+ "max_connections_per_hour",
+ (long) uc->user_resources.conn_per_hour);
error=1;
goto end;
}
uc->conn_per_hour++;
- end:
+end:
if (error)
uc->connections--; // no need for decrease_user_connections() here
(void) pthread_mutex_unlock(&LOCK_user_conn);
@@ -258,8 +259,8 @@ bool check_mqh(THD *thd, uint check_command)
if (uc->user_resources.questions &&
uc->questions++ >= uc->user_resources.questions)
{
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
- (long) uc->user_resources.questions);
+ my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_questions",
+ (long) uc->user_resources.questions);
error=1;
goto end;
}
@@ -270,8 +271,8 @@ bool check_mqh(THD *thd, uint check_command)
(sql_command_flags[check_command] & CF_CHANGES_DATA) &&
uc->updates++ >= uc->user_resources.updates)
{
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
- (long) uc->user_resources.updates);
+ my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates",
+ (long) uc->user_resources.updates);
error=1;
goto end;
}
@@ -284,33 +285,33 @@ end:
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-/*
- Check if user exist and password supplied is correct.
-
- SYNOPSIS
- check_user()
- thd thread handle, thd->security_ctx->{host,user,ip} are used
- command originator of the check: now check_user is called
- during connect and change user procedures; used for
- logging.
- passwd scrambled password received from client
- passwd_len length of scrambled password
- db database name to connect to, may be NULL
- check_count dont know exactly
-
- Note, that host, user and passwd may point to communication buffer.
- Current implementation does not depend on that, but future changes
- should be done with this in mind; 'thd' is INOUT, all other params
- are 'IN'.
-
- RETURN VALUE
- 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
- thd->db are updated; OK is sent to client;
- -1 access denied or handshake error; error is sent to client;
- >0 error, not sent to client
+/**
+ Check if user exist and password supplied is correct.
+
+ @param thd thread handle, thd->security_ctx->{host,user,ip} are used
+ @param command originator of the check: now check_user is called
+ during connect and change user procedures; used for
+ logging.
+ @param passwd scrambled password received from client
+ @param passwd_len length of scrambled password
+ @param db database name to connect to, may be NULL
+ @param check_count TRUE if establishing a new connection. In this case
+ check that we have not exceeded the global
+ max_connections limist
+
+ @note Host, user and passwd may point to communication buffer.
+ Current implementation does not depend on that, but future changes
+ should be done with this in mind; 'thd' is INOUT, all other params
+ are 'IN'.
+
+ @retval 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
+ thd->db are updated; OK is sent to the client.
+ @retval 1 error, e.g. access denied or handshake error, not sent to
+ the client. A message is pushed into the error stack.
*/
-int check_user(THD *thd, enum enum_server_command command,
+int
+check_user(THD *thd, enum enum_server_command command,
const char *passwd, uint passwd_len, const char *db,
bool check_count)
{
@@ -328,11 +329,7 @@ int check_user(THD *thd, enum enum_server_command command,
*/
thd->reset_db(NULL, 0);
if (mysql_change_db(thd, &db_str, FALSE))
- {
- /* Send the error to the client */
- net_send_error(thd);
- DBUG_RETURN(-1);
- }
+ DBUG_RETURN(1);
}
send_ok(thd);
DBUG_RETURN(0);
@@ -349,14 +346,17 @@ int check_user(THD *thd, enum enum_server_command command,
*/
if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
{
- net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
}
if (passwd_len != 0 &&
passwd_len != SCRAMBLE_LENGTH &&
passwd_len != SCRAMBLE_LENGTH_323)
- DBUG_RETURN(ER_HANDSHAKE_ERROR);
+ {
+ my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
+ DBUG_RETURN(1);
+ }
/*
Clear thd->db as it points to something, that will be freed when
@@ -380,20 +380,21 @@ int check_user(THD *thd, enum enum_server_command command,
NET *net= &thd->net;
if (opt_secure_auth_local)
{
- net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip);
+ my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0),
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip);
general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
thd->main_security_ctx.user,
thd->main_security_ctx.host_or_ip);
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
}
/* We have to read very specific packet size */
if (send_old_password_request(thd) ||
my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
{
inc_host_errors(&thd->remote.sin_addr);
- DBUG_RETURN(ER_HANDSHAKE_ERROR);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
+ DBUG_RETURN(1);
}
/* Final attempt to check the user based on reply */
/* So as passwd is short, errcode is always >= 0 */
@@ -427,8 +428,8 @@ int check_user(THD *thd, enum enum_server_command command,
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (!count_ok)
{ // too many connections
- net_send_error(thd, ER_CON_COUNT_ERROR);
- DBUG_RETURN(-1);
+ my_error(ER_CON_COUNT_ERROR, MYF(0));
+ DBUG_RETURN(1);
}
}
@@ -462,24 +463,29 @@ int check_user(THD *thd, enum enum_server_command command,
(opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
thd->main_security_ctx.priv_host),
&ur))
- DBUG_RETURN(-1);
+ {
+ /* The error is set by get_or_create_user_conn(). */
+ DBUG_RETURN(1);
+ }
if (thd->user_connect &&
(thd->user_connect->user_resources.conn_per_hour ||
thd->user_connect->user_resources.user_conn ||
max_user_connections) &&
check_for_max_user_connections(thd, thd->user_connect))
- DBUG_RETURN(-1);
+ {
+ /* The error is set in check_for_max_user_connections(). */
+ DBUG_RETURN(1);
+ }
/* Change database if necessary */
if (db && db[0])
{
if (mysql_change_db(thd, &db_str, FALSE))
{
- /* Send error to the client */
- net_send_error(thd);
+ /* mysql_change_db() has pushed the error message. */
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
}
}
send_ok(thd);
@@ -490,19 +496,19 @@ int check_user(THD *thd, enum enum_server_command command,
}
else if (res == 2) // client gave short hash, server has long hash
{
- net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
}
- net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
+ my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip,
+ passwd_len ? ER(ER_YES) : ER(ER_NO));
general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
thd->main_security_ctx.user,
thd->main_security_ctx.host_or_ip,
passwd_len ? ER(ER_YES) : ER(ER_NO));
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
@@ -666,9 +672,12 @@ static int check_connection(THD *thd)
char ip[30];
if (vio_peer_addr(net->vio, ip, &thd->peer_port))
- return (ER_BAD_HOST_ERROR);
- if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
- return (ER_OUT_OF_RESOURCES);
+ {
+ my_error(ER_BAD_HOST_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
+ return 1;
+ }
+ if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME))))
+ return 1; /* The error is set by my_strdup(). */
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
vio_in_addr(net->vio,&thd->remote.sin_addr);
if (!(specialflag & SPECIAL_NO_RESOLVE))
@@ -685,7 +694,10 @@ static int check_connection(THD *thd)
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
}
if (connect_errors > max_connect_errors)
- return(ER_HOST_IS_BLOCKED);
+ {
+ my_error(ER_HOST_IS_BLOCKED, MYF(0), thd->main_security_ctx.host_or_ip);
+ return 1;
+ }
}
DBUG_PRINT("info",("Host: %s ip: %s",
(thd->main_security_ctx.host ?
@@ -693,7 +705,11 @@ static int check_connection(THD *thd)
(thd->main_security_ctx.ip ?
thd->main_security_ctx.ip : "unknown ip")));
if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
- return(ER_HOST_NOT_PRIVILEGED);
+ {
+ my_error(ER_HOST_NOT_PRIVILEGED, MYF(0),
+ thd->main_security_ctx.host_or_ip);
+ return 1;
+ }
}
else /* Hostname given means that the connection was on a socket */
{
@@ -753,7 +769,9 @@ static int check_connection(THD *thd)
pkt_len < MIN_HANDSHAKE_SIZE)
{
inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0),
+ thd->main_security_ctx.host_or_ip);
+ return 1;
}
}
#ifdef _CUSTOMCONFIG_
@@ -762,7 +780,7 @@ static int check_connection(THD *thd)
if (connect_errors)
reset_host_errors(&thd->remote.sin_addr);
if (thd->packet.alloc(thd->variables.net_buffer_length))
- return(ER_OUT_OF_RESOURCES);
+ return 1; /* The error is set by alloc(). */
thd->client_capabilities=uint2korr(net->read_pos);
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
@@ -790,14 +808,16 @@ static int check_connection(THD *thd)
if (!ssl_acceptor_fd)
{
inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
+ return 1;
}
DBUG_PRINT("info", ("IO layer change in progress..."));
if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
{
DBUG_PRINT("error", ("Failed to accept new SSL connection"));
inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
+ return 1;
}
DBUG_PRINT("info", ("Reading user information over SSL layer"));
if ((pkt_len= my_net_read(net)) == packet_error ||
@@ -806,7 +826,8 @@ static int check_connection(THD *thd)
DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
pkt_len));
inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
+ return 1;
}
}
#endif /* HAVE_OPENSSL */
@@ -814,7 +835,8 @@ static int check_connection(THD *thd)
if (end >= (char*) net->read_pos+ pkt_len +2)
{
inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
+ return 1;
}
if (thd->client_capabilities & CLIENT_INTERACTIVE)
@@ -851,7 +873,8 @@ static int check_connection(THD *thd)
if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
{
inc_host_errors(&thd->remote.sin_addr);
- return ER_HANDSHAKE_ERROR;
+ my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
+ return 1;
}
/* Since 4.1 all database names are stored in utf8 */
@@ -879,8 +902,8 @@ static int check_connection(THD *thd)
if (thd->main_security_ctx.user)
x_free(thd->main_security_ctx.user);
- if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
- return (ER_OUT_OF_RESOURCES);
+ if (!(thd->main_security_ctx.user= my_strdup(user, MYF(MY_WME))))
+ return 1; /* The error is set by my_strdup(). */
return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
}
@@ -929,7 +952,6 @@ bool setup_connection_thread_globals(THD *thd)
bool login_connection(THD *thd)
{
- int error;
NET *net= &thd->net;
Security_context *sctx= thd->security_ctx;
DBUG_ENTER("login_connection");
@@ -942,10 +964,9 @@ bool login_connection(THD *thd)
my_net_set_read_timeout(net, connect_timeout);
my_net_set_write_timeout(net, connect_timeout);
- if ((error=check_connection(thd)))
+ if (check_connection(thd))
{ // Wrong permissions
- if (error > 0)
- net_printf_error(thd, error, sctx->host_or_ip);
+ net_send_error(thd);
#ifdef __NT__
if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
my_sleep(1000); /* must wait after eof() */
@@ -975,12 +996,12 @@ void end_connection(THD *thd)
decrease_user_connections(thd->user_connect);
if (thd->killed ||
- net->error && net->vio != 0 && net->report_error)
+ net->error && net->vio != 0 && thd->is_error())
{
statistic_increment(aborted_threads,&LOCK_status);
}
- if (net->error && net->vio != 0 && net->report_error)
+ if (net->error && net->vio != 0 && thd->is_error())
{
if (!thd->killed && thd->variables.log_warnings > 1)
{
@@ -1030,7 +1051,17 @@ 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);
- if (thd->query_error)
+ /*
+ 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)
{
thd->killed= THD::KILL_CONNECTION;
sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 4c57fad8d87..219dc90429b 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -252,10 +252,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
table->mark_columns_needed_for_delete();
while (!(error=info.read_record(&info)) && !thd->killed &&
- !thd->net.report_error)
+ ! thd->is_error())
{
- // thd->net.report_error is tested to disallow delete row on error
- if (!(select && select->skip_record())&& !thd->net.report_error )
+ // thd->is_error() is tested to disallow delete row on error
+ if (!(select && select->skip_record())&& ! thd->is_error() )
{
if (table->triggers &&
@@ -389,7 +389,7 @@ cleanup:
send_ok(thd, (ha_rows) thd->row_count_func);
DBUG_PRINT("info",("%ld records deleted",(long) deleted));
}
- DBUG_RETURN(error >= 0 || thd->net.report_error);
+ DBUG_RETURN(error >= 0 || thd->is_error());
}
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index 8bdb2e59ed5..89cff73d153 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -137,7 +137,7 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
level= MYSQL_ERROR::WARN_LEVEL_ERROR;
}
- if (thd->handle_error(code, level))
+ if (thd->handle_error(code, msg, level))
DBUG_RETURN(NULL);
if (thd->spcont &&
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index e868afede51..077141c4d7a 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -738,7 +738,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
table->triggers,
TRG_EVENT_INSERT))
{
- if (values_list.elements != 1 && !thd->net.report_error)
+ if (values_list.elements != 1 && ! thd->is_error())
{
info.records++;
continue;
@@ -769,7 +769,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
table->triggers,
TRG_EVENT_INSERT))
{
- if (values_list.elements != 1 && ! thd->net.report_error)
+ if (values_list.elements != 1 && ! thd->is_error())
{
info.records++;
continue;
@@ -1909,7 +1909,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
thd->proc_info="got old table";
if (di->thd.killed)
{
- if (di->thd.net.report_error)
+ if (di->thd.is_error())
{
/*
Copy the error message. Note that we don't treat fatal
@@ -1940,7 +1940,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
pthread_mutex_unlock(&di->mutex);
if (table_list->table)
{
- DBUG_ASSERT(thd->net.report_error == 0);
+ DBUG_ASSERT(! thd->is_error());
thd->di= di;
}
/* Unlock the delayed insert object after its last access. */
@@ -1949,7 +1949,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
end_create:
pthread_mutex_unlock(&LOCK_delayed_create);
- DBUG_RETURN(thd->net.report_error);
+ DBUG_RETURN(thd->is_error());
}
@@ -3015,7 +3015,7 @@ bool select_insert::send_data(List<Item> &values)
thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields
store_values(values);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
- if (thd->net.report_error)
+ if (thd->is_error())
DBUG_RETURN(1);
if (table_list) // Not CREATE ... SELECT
{
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index a26c4fd1ca0..507d64daf89 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1616,7 +1616,7 @@ typedef struct st_lex : public Query_tables_list
uint8 create_view_algorithm;
uint8 create_view_check;
bool drop_if_exists, drop_temporary, local_file, one_shot_set;
-
+ bool autocommit;
bool verbose, no_write_to_binlog;
bool tx_chain, tx_release;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e6d953bcbe1..ea6a25d9866 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -436,7 +436,7 @@ pthread_handler_t handle_bootstrap(void *arg)
if (thd->is_fatal_error)
break;
- if (thd->net.report_error)
+ if (thd->is_error())
{
/* The query failed, send error to log and abort bootstrap */
net_send_error(thd);
@@ -915,11 +915,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (res)
{
- /* authentication failure, we shall restore old user */
- if (res > 0)
- my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
- else
- thd->clear_error(); // Error already sent to client
x_free(thd->security_ctx->user);
*thd->security_ctx= save_security_ctx;
thd->user_connect= save_user_connect;
@@ -990,7 +985,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
mysql_parse(thd, thd->query, thd->query_length, & found_semicolon);
- while (!thd->killed && found_semicolon && !thd->net.report_error)
+ while (!thd->killed && found_semicolon && ! thd->is_error())
{
char *next_packet= (char*) found_semicolon;
net->no_send_error= 0;
@@ -1355,9 +1350,9 @@ 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->net.report_error)
+ if (thd->killed_errno() && ! thd->is_error())
thd->send_kill_message();
- if (thd->net.report_error)
+ if (thd->is_error())
net_send_error(thd);
log_slow_statement(thd);
@@ -3053,6 +3048,10 @@ end_with_restore_list:
case SQLCOM_SET_OPTION:
{
List<set_var_base> *lex_var_list= &lex->var_list;
+
+ if (lex->autocommit && end_active_trans(thd))
+ goto error;
+
if ((check_table_access(thd, SELECT_ACL, all_tables, 0) ||
open_and_lock_tables(thd, all_tables)))
goto error;
@@ -3930,7 +3929,7 @@ create_sp_error:
thd->row_count_func));
else
{
- DBUG_ASSERT(thd->net.report_error == 1 || thd->killed);
+ DBUG_ASSERT(thd->is_error() || thd->killed);
goto error; // Substatement should already have sent error
}
}
@@ -4523,7 +4522,7 @@ finish:
*/
start_waiting_global_read_lock(thd);
}
- DBUG_RETURN(res || thd->net.report_error);
+ DBUG_RETURN(res || thd->is_error());
}
@@ -5467,7 +5466,7 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
else
#endif
{
- if (! thd->net.report_error)
+ if (! thd->is_error())
{
/*
Binlog logs a string starting from thd->query and having length
@@ -5491,7 +5490,7 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
}
else
{
- DBUG_ASSERT(thd->net.report_error);
+ DBUG_ASSERT(thd->is_error());
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
thd->is_fatal_error));
@@ -6311,7 +6310,7 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
RETURN
0 ok
- !=0 error. thd->killed or thd->net.report_error is set
+ !=0 error. thd->killed or thd->is_error() is set
*/
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
@@ -7274,10 +7273,10 @@ bool parse_sql(THD *thd,
bool mysql_parse_status= MYSQLparse(thd) != 0;
- /* Check that if MYSQLparse() failed, thd->net.report_error is set. */
+ /* Check that if MYSQLparse() failed, thd->is_error() is set. */
DBUG_ASSERT(!mysql_parse_status ||
- mysql_parse_status && thd->net.report_error);
+ mysql_parse_status && thd->is_error());
/* Reset Lex_input_stream. */
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index a6cdcf14881..b1b1502f015 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2864,7 +2864,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
lex_start(thd);
error= parse_sql(thd, &lip, NULL) ||
- thd->net.report_error ||
+ thd->is_error() ||
init_param_array(this);
lex->set_trg_event_type_for_tables();
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 140daf8b55d..ef1151d82f3 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -263,8 +263,8 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
result, unit, select_lex);
}
DBUG_PRINT("info",("res: %d report_error: %d", res,
- thd->net.report_error));
- res|= thd->net.report_error;
+ thd->is_error()));
+ res|= thd->is_error();
if (unlikely(res))
result->abort();
@@ -491,7 +491,7 @@ JOIN::prepare(Item ***rref_pointer_array,
(having->fix_fields(thd, &having) ||
having->check_cols(1)));
select_lex->having_fix_field= 0;
- if (having_fix_rc || thd->net.report_error)
+ if (having_fix_rc || thd->is_error())
DBUG_RETURN(-1); /* purecov: inspected */
thd->lex->allow_sum_func= save_allow_sum_func;
}
@@ -817,7 +817,7 @@ JOIN::optimize()
}
conds= optimize_cond(this, conds, join_list, &cond_value);
- if (thd->net.report_error)
+ if (thd->is_error())
{
error= 1;
DBUG_PRINT("error",("Error from optimize_cond"));
@@ -826,7 +826,7 @@ JOIN::optimize()
{
having= optimize_cond(this, having, join_list, &having_value);
- if (thd->net.report_error)
+ if (thd->is_error())
{
error= 1;
DBUG_PRINT("error",("Error from optimize_cond"));
@@ -1031,7 +1031,7 @@ JOIN::optimize()
{
ORDER *org_order= order;
order=remove_const(this, order,conds,1, &simple_order);
- if (thd->net.report_error)
+ if (thd->is_error())
{
error= 1;
DBUG_PRINT("error",("Error from remove_const"));
@@ -1162,7 +1162,7 @@ JOIN::optimize()
group_list= remove_const(this, (old_group_list= group_list), conds,
rollup.state == ROLLUP::STATE_NONE,
&simple_group);
- if (thd->net.report_error)
+ if (thd->is_error())
{
error= 1;
DBUG_PRINT("error",("Error from remove_const"));
@@ -1185,7 +1185,7 @@ JOIN::optimize()
{
group_list= procedure->group= remove_const(this, procedure->group, conds,
1, &simple_group);
- if (thd->net.report_error)
+ if (thd->is_error())
{
error= 1;
DBUG_PRINT("error",("Error from remove_const"));
@@ -2098,10 +2098,10 @@ JOIN::exec()
}
}
}
- /* XXX: When can we have here thd->net.report_error not zero? */
- if (thd->net.report_error)
+ /* XXX: When can we have here thd->is_error() not zero? */
+ if (thd->is_error())
{
- error= thd->net.report_error;
+ error= thd->is_error();
DBUG_VOID_RETURN;
}
curr_join->having= curr_join->tmp_having;
@@ -2307,7 +2307,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
join->having_history= (join->having?join->having:join->tmp_having);
}
- if (thd->net.report_error)
+ if (thd->is_error())
goto err;
join->exec();
@@ -2333,7 +2333,7 @@ err:
{
thd->proc_info="end";
err|= select_lex->cleanup();
- DBUG_RETURN(err || thd->net.report_error);
+ DBUG_RETURN(err || thd->is_error());
}
DBUG_RETURN(join->error);
}
@@ -6651,7 +6651,14 @@ void JOIN::cleanup(bool full)
for (tab= join_tab, end= tab+tables; tab != end; tab++)
{
if (tab->table)
- tab->table->file->ha_index_or_rnd_end();
+ {
+ if (tab->table->key_read)
+ {
+ tab->table->key_read= 0;
+ tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ tab->table->file->ha_index_or_rnd_end();
+ }
}
}
}
@@ -10710,7 +10717,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
DBUG_PRINT("error",("Error: do_select() failed"));
}
#endif
- DBUG_RETURN(join->thd->net.report_error ? -1 : rc);
+ DBUG_RETURN(join->thd->is_error() ? -1 : rc);
}
@@ -16043,7 +16050,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
first->options | thd->options | SELECT_DESCRIBE,
result, unit, first);
}
- DBUG_RETURN(res || thd->net.report_error);
+ DBUG_RETURN(res || thd->is_error());
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 86d1fe79a00..6edb8494b03 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2380,8 +2380,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
sql_field->length= dup_field->char_length;
sql_field->pack_length= dup_field->pack_length;
sql_field->key_length= dup_field->key_length;
- sql_field->create_length_to_internal_length();
sql_field->decimals= dup_field->decimals;
+ sql_field->create_length_to_internal_length();
sql_field->unireg_check= dup_field->unireg_check;
/*
We're making one field from two, the result field will have
@@ -4985,6 +4985,7 @@ compare_tables(TABLE *table,
create_info->used_fields & HA_CREATE_USED_ENGINE ||
create_info->used_fields & HA_CREATE_USED_CHARSET ||
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
+ create_info->used_fields & HA_CREATE_USED_ROW_FORMAT ||
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
order_num ||
!table->s->mysql_version ||
@@ -5200,7 +5201,8 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
if (error == HA_ERR_WRONG_COMMAND)
{
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), table->s->table_name);
+ ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
+ table->s->table_name.str);
error= 0;
} else if (error)
table->file->print_error(error, MYF(0));
@@ -5392,7 +5394,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
{
if (def->change && ! def->field)
{
- my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
goto err;
}
/*
@@ -5427,7 +5429,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
if (!find)
{
- my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
goto err;
}
find_it.after(def); // Put element after this
@@ -5437,7 +5439,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (alter_info->alter_list.elements)
{
my_error(ER_BAD_FIELD_ERROR, MYF(0),
- alter_info->alter_list.head()->name, table->s->table_name);
+ alter_info->alter_list.head()->name, table->s->table_name.str);
goto err;
}
if (!new_create_list.elements)
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 5da4b97cc5d..a48cff82715 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -58,7 +58,7 @@ bool select_union::send_data(List<Item> &values)
return 0;
}
fill_record(thd, table->field, values, 1);
- if (thd->net.report_error)
+ if (thd->is_error())
return 1;
if ((error= table->file->ha_write_row(table->record[0])))
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 4071bb86c90..036d7e06d0e 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -844,7 +844,7 @@ int mysql_update(THD *thd,
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
thd->abort_on_warning= 0;
- DBUG_RETURN((error >= 0 || thd->net.report_error) ? 1 : 0);
+ DBUG_RETURN((error >= 0 || thd->is_error()) ? 1 : 0);
err:
delete select;
@@ -1193,8 +1193,8 @@ bool mysql_multi_update(THD *thd,
OPTION_SETUP_TABLES_DONE,
result, unit, select_lex);
DBUG_PRINT("info",("res: %d report_error: %d", res,
- thd->net.report_error));
- res|= thd->net.report_error;
+ (int) thd->is_error()));
+ res|= thd->is_error();
if (unlikely(res))
{
/* If we had a another error reported earlier then this will be ignored */
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 6e27af63e8a..f7223cafb5e 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -607,7 +607,7 @@ err:
thd->proc_info= "end";
lex->link_first_table_back(view, link_to_local);
unit->cleanup();
- DBUG_RETURN(res || thd->net.report_error);
+ DBUG_RETURN(res || thd->is_error());
}
@@ -823,7 +823,7 @@ loop_out:
view_parameters + revision_number_position, 1,
&file_parser_dummy_hook))
{
- error= thd->net.report_error? -1 : 0;
+ error= thd->is_error() ? -1 : 0;
goto err;
}
}
@@ -886,7 +886,7 @@ loop_out:
if (sql_create_definition_file(&dir, &file, view_file_type,
(uchar*)view, view_parameters, num_view_backups))
{
- error= thd->net.report_error? -1 : 1;
+ error= thd->is_error() ? -1 : 1;
goto err;
}
DBUG_RETURN(0);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 109e8f5434f..69cd7060778 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -9804,7 +9804,7 @@ NUM_literal:
| DECIMAL_NUM
{
$$= new Item_decimal($1.str, $1.length, YYTHD->charset());
- if (YYTHD->net.report_error)
+ if (YYTHD->is_error())
{
MYSQL_YYABORT;
}
@@ -9812,7 +9812,7 @@ NUM_literal:
| FLOAT_NUM
{
$$ = new Item_float($1.str, $1.length);
- if (YYTHD->net.report_error)
+ if (YYTHD->is_error())
{
MYSQL_YYABORT;
}
@@ -10516,6 +10516,7 @@ set:
lex->option_type=OPT_SESSION;
lex->var_list.empty();
lex->one_shot_set= 0;
+ lex->autocommit= 0;
}
option_value_list
{}
@@ -10558,6 +10559,7 @@ option_type_value:
lex->option_type=OPT_SESSION;
lex->var_list.empty();
lex->one_shot_set= 0;
+ lex->autocommit= 0;
lex->sphead->m_tmp_query= lip->get_tok_start();
}
}
@@ -10799,10 +10801,16 @@ option_value:
user->host=null_lex_str;
user->user.str=thd->security_ctx->priv_user;
thd->lex->var_list.push_back(new set_var_password(user, $3));
+ thd->lex->autocommit= TRUE;
+ if (lex->sphead)
+ lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
}
| PASSWORD FOR_SYM user equal text_or_password
{
Lex->var_list.push_back(new set_var_password($3,$5));
+ Lex->autocommit= TRUE;
+ if (Lex->sphead)
+ Lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
}
;
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index d3ba0660198..0cb9ff49128 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -17100,6 +17100,99 @@ static void test_bug31418()
}
+
+/**
+ Bug#31669 Buffer overflow in mysql_change_user()
+*/
+
+#define LARGE_BUFFER_SIZE 2048
+
+static void test_bug31669()
+{
+ int rc;
+ static char buff[LARGE_BUFFER_SIZE+1];
+#ifndef EMBEDDED_LIBRARY
+ static char user[USERNAME_CHAR_LENGTH+1];
+ static char db[NAME_CHAR_LEN+1];
+ static char query[LARGE_BUFFER_SIZE*2];
+#endif
+
+ DBUG_ENTER("test_bug31669");
+ myheader("test_bug31669");
+
+ rc= mysql_change_user(mysql, NULL, NULL, NULL);
+ DIE_UNLESS(rc);
+
+ rc= mysql_change_user(mysql, "", "", "");
+ DIE_UNLESS(rc);
+
+ memset(buff, 'a', sizeof(buff));
+
+ rc= mysql_change_user(mysql, buff, buff, buff);
+ DIE_UNLESS(rc);
+
+ rc = mysql_change_user(mysql, opt_user, opt_password, current_db);
+ DIE_UNLESS(!rc);
+
+#ifndef EMBEDDED_LIBRARY
+ memset(db, 'a', sizeof(db));
+ db[NAME_CHAR_LEN]= 0;
+ strxmov(query, "CREATE DATABASE IF NOT EXISTS ", db, NullS);
+ rc= mysql_query(mysql, query);
+ myquery(rc);
+
+ memset(user, 'b', sizeof(user));
+ user[USERNAME_CHAR_LENGTH]= 0;
+ memset(buff, 'c', sizeof(buff));
+ buff[LARGE_BUFFER_SIZE]= 0;
+ strxmov(query, "GRANT ALL PRIVILEGES ON *.* TO '", user, "'@'%' IDENTIFIED BY "
+ "'", buff, "' WITH GRANT OPTION", NullS);
+ rc= mysql_query(mysql, query);
+ myquery(rc);
+
+ rc= mysql_query(mysql, "FLUSH PRIVILEGES");
+ myquery(rc);
+
+ rc= mysql_change_user(mysql, user, buff, db);
+ DIE_UNLESS(!rc);
+
+ user[USERNAME_CHAR_LENGTH-1]= 'a';
+ rc= mysql_change_user(mysql, user, buff, db);
+ DIE_UNLESS(rc);
+
+ user[USERNAME_CHAR_LENGTH-1]= 'b';
+ buff[LARGE_BUFFER_SIZE-1]= 'd';
+ rc= mysql_change_user(mysql, user, buff, db);
+ DIE_UNLESS(rc);
+
+ buff[LARGE_BUFFER_SIZE-1]= 'c';
+ db[NAME_CHAR_LEN-1]= 'e';
+ rc= mysql_change_user(mysql, user, buff, db);
+ DIE_UNLESS(rc);
+
+ db[NAME_CHAR_LEN-1]= 'a';
+ rc= mysql_change_user(mysql, user, buff, db);
+ DIE_UNLESS(!rc);
+
+ rc= mysql_change_user(mysql, user + 1, buff + 1, db + 1);
+ DIE_UNLESS(rc);
+
+ rc = mysql_change_user(mysql, opt_user, opt_password, current_db);
+ DIE_UNLESS(!rc);
+
+ strxmov(query, "DROP DATABASE ", db, NullS);
+ rc= mysql_query(mysql, query);
+ myquery(rc);
+
+ strxmov(query, "DELETE FROM mysql.user WHERE User='", user, "'", NullS);
+ rc= mysql_query(mysql, query);
+ myquery(rc);
+ DIE_UNLESS(mysql_affected_rows(mysql) == 1);
+#endif
+
+ DBUG_VOID_RETURN;
+}
+
/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -17403,6 +17496,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug30472", test_bug30472 },
{ "test_bug20023", test_bug20023 },
{ "test_bug31418", test_bug31418 },
+ { "test_bug31669", test_bug31669 },
{ 0, 0 }
};