diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index aee5613ff35..df9d79157af 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -1019,6 +1019,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/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 3a6758b38f4..2a0f9a930b8 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1286,6 +1286,40 @@ a b 2 2 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` ( 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 ed61cfffa6b..e8d9502e823 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/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/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/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/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 5d5c8a26447..c22d5ac53f5 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); + thd->net.report_error, thd->is_slave_error); } thd->options= save_thd_options; diff --git a/sql/handler.cc b/sql/handler.cc index 75c3a64bc27..706da76c000 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1447,7 +1447,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, (We should in the future either rewrite handler::print_error() or make a nice method of this. */ - bool query_error= thd->query_error; + bool is_slave_error= thd->is_slave_error; sp_rcontext *spcont= thd->spcont; SELECT_LEX *current_select= thd->lex->current_select; char buff[sizeof(thd->net.last_error)]; @@ -1455,7 +1455,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, int last_errno= thd->net.last_errno; strmake(buff, thd->net.last_error, sizeof(buff)-1); - thd->query_error= 0; + thd->is_slave_error= 0; thd->spcont= NULL; thd->lex->current_select= 0; thd->net.last_error[0]= 0; @@ -1475,7 +1475,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, strmake(new_error, thd->net.last_error, sizeof(buff)-1); /* restore thd */ - thd->query_error= query_error; + thd->is_slave_error= is_slave_error; thd->spcont= spcont; thd->lex->current_select= current_select; thd->net.last_errno= last_errno; diff --git a/sql/log.cc b/sql/log.cc index e923418b23a..02986bef493 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2891,8 +2891,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(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 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(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(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(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(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(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(rli)->cleanup_context(thd, error); - thd->query_error= 1; + thd->is_slave_error= 1; DBUG_RETURN(error); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a355c560996..cc964e417bf 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -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); diff --git a/sql/protocol.cc b/sql/protocol.cc index 9d473912ba3..31d23ec94dd 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -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) @@ -162,7 +162,7 @@ net_printf_error(THD *thd, uint errcode, ...) 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 #ifndef EMBEDDED_LIBRARY query_cache_abort(net); // Safety #endif 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_head.cc b/sql/sp_head.cc index 093544cdd0a..f7ab9bac3b1 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -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,8 +1275,8 @@ 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, + DBUG_PRINT("info", ("err_status: %d killed: %d is_slave_error: %d report_error: %d", + err_status, thd->killed, thd->is_slave_error, thd->net.report_error)); if (thd->killed) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c4e90165ced..6307564c14f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7393,7 +7393,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..d77e531ec13 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; @@ -2404,6 +2404,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 97a63ed9448..5aec68e1c61 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1466,7 +1466,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 (net.report_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 +1702,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; } diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 094bef9324e..afd97c27a55 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1030,7 +1030,7 @@ 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) + if (thd->net.report_error) { thd->killed= THD::KILL_CONNECTION; sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), diff --git a/sql/sql_select.cc b/sql/sql_select.cc index eb2731205ec..d041b2edcfa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -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(); + } } } } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index cd39623f2b4..2bd89d4a0ae 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)