diff options
author | unknown <malff@lambda.hsd1.co.comcast.net.> | 2007-11-01 06:41:50 -0600 |
---|---|---|
committer | unknown <malff@lambda.hsd1.co.comcast.net.> | 2007-11-01 06:41:50 -0600 |
commit | cf8275e086eef4814bae8671666e1bdc69b789d9 (patch) | |
tree | ed9cc7f1e47bd6e23bed5418d81bbefcace750ae | |
parent | 41c2a2c490522da0f163aa25ac88da9db74e0c66 (diff) | |
parent | ad723cd5f80389e375f9397f1d6b703989a0aa24 (diff) | |
download | mariadb-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
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 } }; |