revision-id: 0fa3079ccc93288d4ec93f713bc162d69cc477d0 (mariadb-10.1.38-114-g0fa3079ccc9) parent(s): 6c5e4c9bc0d9ac30f7ec7ee334630bacb58687ba author: Sachin committer: Sachin timestamp: 2019-05-27 21:44:48 +0530 message: Mdev-17588 replicate-do filters cause errors when creating filtered-out tables on master with syntax unsupported on slave Prototype -4 Use a ME_DEFERRED_ERROR/ WARN_LEVEL_DEFERRED_WARN for my_error/push_warning when error can be deferred. It will store the error/warning in m_warn_list. And thd->is_error() will return false. To actiave the error/warning we need to call these functions change_deferred_to_normal_warn/error --- include/my_sys.h | 5 +++ mysql-test/suite/rpl/r/rpl_mdev_17588.result | 27 +++++++++++++ mysql-test/suite/rpl/t/rpl_mdev_17588-slave.opt | 1 + mysql-test/suite/rpl/t/rpl_mdev_17588.test | 36 +++++++++++++++++ sql/mysqld.cc | 10 +++++ sql/sql_class.cc | 2 + sql/sql_class.h | 4 ++ sql/sql_error.cc | 51 +++++++++++++++++++++++++ sql/sql_error.h | 33 +++++++++++++++- sql/sql_parse.cc | 18 +++++++++ sql/sql_yacc.yy | 14 +++++-- 11 files changed, 196 insertions(+), 5 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index c30580a8c06..f6dcc278225 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -112,6 +112,11 @@ typedef struct my_aio_result { #define ME_JUST_INFO 1024 /**< not error but just info */ #define ME_JUST_WARNING 2048 /**< not error but just warning */ #define ME_FATALERROR 4096 /* Fatal statement error */ +/* Throw error at later stage */ +#define ME_DEFERRED_JUST_INFO 8192 /* Not USED*/ +#define ME_DEFERRED_JUST_WARNING 16384 +#define ME_DEFERRED_ERROR 32768 + /* Bits in last argument to fn_format */ #define MY_REPLACE_DIR 1 /* replace dir in name with 'dir' */ diff --git a/mysql-test/suite/rpl/r/rpl_mdev_17588.result b/mysql-test/suite/rpl/r/rpl_mdev_17588.result new file mode 100644 index 00000000000..e1b017950c2 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_mdev_17588.result @@ -0,0 +1,27 @@ +include/master-slave.inc +[connection master] +set sql_log_bin= 0; +install soname 'ha_tokudb'; +set sql_log_bin= 1; +set server_id=23; +create table t1 (a int) engine=TokuDB; +create table t2 (a int); +create table t3 (a int) engine=TokuDB; +include/wait_for_slave_sql_error.inc [errno=1286] +show create table t1; +ERROR 42S02: Table 'test.t1' doesn't exist +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show create table t3; +ERROR 42S02: Table 'test.t3' doesn't exist +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +drop table t1, t2, t3; +set sql_log_bin= 0; +uninstall soname 'ha_tokudb'; +set sql_log_bin= 1; +CALL mtr.add_suppression('Slave: Unknown storage engine .* Error_code: 1286'); +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev_17588-slave.opt b/mysql-test/suite/rpl/t/rpl_mdev_17588-slave.opt new file mode 100644 index 00000000000..19497afd22a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev_17588-slave.opt @@ -0,0 +1 @@ +--replicate-do-table=test.t2 --replicate-do-table=test.t3 --sql-mode='NO_ENGINE_SUBSTITUTION' diff --git a/mysql-test/suite/rpl/t/rpl_mdev_17588.test b/mysql-test/suite/rpl/t/rpl_mdev_17588.test new file mode 100644 index 00000000000..b073b791d7a --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev_17588.test @@ -0,0 +1,36 @@ +--source include/master-slave.inc + + +--connection slave +# For debugging +#create table xyz(a int ); + +--connection master +set sql_log_bin= 0; +install soname 'ha_tokudb'; +set sql_log_bin= 1; +set server_id=23; + +create table t1 (a int) engine=TokuDB; +create table t2 (a int); +create table t3 (a int) engine=TokuDB; + +--connection slave +let $slave_sql_errno= 1286; +source include/wait_for_slave_sql_error.inc; +--sleep 10 +--error ER_NO_SUCH_TABLE +show create table t1; +show create table t2; +--error ER_NO_SUCH_TABLE +show create table t3; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +--connection master +drop table t1, t2, t3; +set sql_log_bin= 0; +uninstall soname 'ha_tokudb'; +set sql_log_bin= 1; +--sync_slave_with_master +CALL mtr.add_suppression('Slave: Unknown storage engine .* Error_code: 1286'); +--source include/rpl_end.inc diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8d464ed75e6..d68b3c16e95 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3524,6 +3524,16 @@ void my_message_sql(uint error, const char *str, myf MyFlags) level= Sql_condition::WARN_LEVEL_WARN; func= sql_print_warning; } + else if (MyFlags & ME_DEFERRED_JUST_WARNING) + { + level= Sql_condition::WARN_LEVEL_DEFERRED_WARN; + func= sql_print_warning; + } + else if (MyFlags & ME_DEFERRED_ERROR) + { + level= Sql_condition::WARN_LEVEL_DEFERRED_ERROR; + func= sql_print_error; + } else { level= Sql_condition::WARN_LEVEL_ERROR; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 639c7c1784a..de637ccaf8c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1167,9 +1167,11 @@ Sql_condition* THD::raise_condition(uint sql_errno, { case Sql_condition::WARN_LEVEL_NOTE: case Sql_condition::WARN_LEVEL_WARN: + case Sql_condition::WARN_LEVEL_DEFERRED_WARN: got_warning= 1; break; case Sql_condition::WARN_LEVEL_ERROR: + case Sql_condition::WARN_LEVEL_DEFERRED_ERROR: break; default: DBUG_ASSERT(FALSE); diff --git a/sql/sql_class.h b/sql/sql_class.h index 6640e02147a..c51800cb6d7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3405,6 +3405,10 @@ class THD :public Statement, Diagnostics_area *get_stmt_da() { return m_stmt_da; } + /// Get Deferred error status + bool get_deferred_error() + { return m_stmt_da->get_deferred_error();} + /// Returns Diagnostics-area for the current statement. const Diagnostics_area *get_stmt_da() const { return m_stmt_da; } diff --git a/sql/sql_error.cc b/sql/sql_error.cc index b72d642efbc..b0b0349e968 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -312,6 +312,7 @@ Sql_condition::get_message_octet_length() const return m_message_text.length(); } + void Sql_condition::set_sqlstate(const char* sqlstate) { @@ -319,6 +320,15 @@ Sql_condition::set_sqlstate(const char* sqlstate) m_returned_sqlstate[SQLSTATE_LENGTH]= '\0'; } +void +Sql_condition::deferred_to_normal() +{ + if (m_level == Sql_condition::WARN_LEVEL_DEFERRED_ERROR) + m_level= Sql_condition::WARN_LEVEL_ERROR; + if (m_level == Sql_condition::WARN_LEVEL_DEFERRED_WARN) + m_level= Sql_condition::WARN_LEVEL_WARN; +} + Diagnostics_area::Diagnostics_area(bool initialize) : m_main_wi(0, false, initialize) { @@ -657,6 +667,47 @@ void Warning_info::remove_marked_sql_conditions() m_marked_sql_conditions.empty(); } +const Sql_condition* Warning_info::get_first_deferred_error() +{ + Diagnostics_area::Sql_condition_iterator it(m_warn_list); + const Sql_condition *err; + + while ((err= it++)) + { + if (err->m_level == Sql_condition::WARN_LEVEL_DEFERRED_ERROR) + return err; + } + return NULL; +} +void Warning_info::change_deferred_to_normal_warning() +{ + Diagnostics_area::Sql_condition_iterator it(m_warn_list); + const Sql_condition *err; + + while ((err= it++)) + ((Sql_condition *)err)->deferred_to_normal(); + m_warn_count[Sql_condition::WARN_LEVEL_WARN]+= + m_warn_count[Sql_condition::WARN_LEVEL_DEFERRED_WARN]; + m_warn_count[Sql_condition::WARN_LEVEL_ERROR]+= + m_warn_count[Sql_condition::WARN_LEVEL_DEFERRED_ERROR]; + m_warn_count[Sql_condition::WARN_LEVEL_DEFERRED_WARN]= 0; + m_warn_count[Sql_condition::WARN_LEVEL_DEFERRED_ERROR]= 0; + +} +void Warning_info::remove_deferred_error_and_warning() +{ + Diagnostics_area::Sql_condition_iterator it(m_warn_list); + const Sql_condition *err; + + while ((err= it++)) + { + if (err->m_level > Sql_condition::WARN_LEVEL_DEFERRED_ERROR) + m_warn_list.remove((Sql_condition *)err); + } + m_warn_count[Sql_condition::WARN_LEVEL_DEFERRED_WARN]= 0; + m_warn_count[Sql_condition::WARN_LEVEL_DEFERRED_ERROR]= 0; + +} bool Warning_info::is_marked_for_removal(const Sql_condition *cond) const { diff --git a/sql/sql_error.h b/sql/sql_error.h index 0134f938c75..8613eb642bf 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -45,7 +45,8 @@ class Sql_condition : public Sql_alloc of the sql_print_message_handlers array. */ enum enum_warning_level - { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; + { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, + WARN_LEVEL_DEFERRED_WARN, WARN_LEVEL_DEFERRED_ERROR, WARN_LEVEL_END}; /** Convert a bitmask consisting of MYSQL_TIME_{NOTE|WARN}_XXX bits @@ -170,6 +171,8 @@ class Sql_condition : public Sql_alloc /** Set the SUBCLASS_ORIGIN of this condition. */ void set_subclass_origin(); + void deferred_to_normal(); + /** Clear this SQL condition. */ @@ -307,6 +310,13 @@ class Warning_info /* Allocate memory for structures */ void init(); void free_memory(); + bool get_deferred_error() + { + if (m_warn_count[Sql_condition::WARN_LEVEL_DEFERRED_WARN] || + m_warn_count[Sql_condition::WARN_LEVEL_DEFERRED_ERROR]) + return true; + return false; + } private: Warning_info(const Warning_info &rhs); /* Not implemented */ @@ -387,6 +397,9 @@ class Warning_info This is done to simulate stacked DAs for HANDLER statements. */ void remove_marked_sql_conditions(); + const Sql_condition* get_first_deferred_error(); + void change_deferred_to_normal_warning(); + void remove_deferred_error_and_warning(); /** Check if the given SQL-condition is marked for removal in this Warning_info @@ -833,6 +846,24 @@ class Diagnostics_area void remove_marked_sql_conditions() { get_warning_info()->remove_marked_sql_conditions(); } + void change_deferred_to_normal_error() + { + const Sql_condition *cond= get_warning_info()->get_first_deferred_error(); + if (!cond) + return; + this->set_error_status(cond->get_sql_errno(), cond->get_message_text(), + cond->get_sqlstate(), cond); + } + + void change_deferred_to_normal_warning() + {get_warning_info()->change_deferred_to_normal_warning();} + + void remove_deferred_error_and_warning() + { get_warning_info()->remove_deferred_error_and_warning();} + + bool get_deferred_error() + { return get_warning_info()->get_deferred_error();} + const Sql_condition *get_error_condition() const { return get_warning_info()->get_error_condition(); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6649c60f827..0949883d1c7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2653,9 +2653,27 @@ mysql_execute_command(THD *thd) lex->tmp_table() && lex->if_exists()) && all_tables_not_ok(thd, all_tables)) { + if (thd->get_deferred_error()) + { + /* Clear the WARN_LEVEL_DEFERRED_WARN and WARN_LEVEL_DEFERRED_ERROR */ + thd->get_stmt_da()->remove_deferred_error_and_warning(); + } /* we warn the slave SQL thread */ my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); + + DBUG_RETURN(0); + } + if (thd->get_deferred_error()) + { + thd->is_slave_error= true; + /* + 1 Set the thd err status + 2 convert WARN_LEVEL_DEFERRED_WARN WARN_LEVEL_DEFERRED_ERROR to + WARN_LEVEL_WARN and WARN_LEVEL_DEFERRED_ERROR + */ + thd->get_stmt_da()->change_deferred_to_normal_error(); + thd->get_stmt_da()->change_deferred_to_normal_warning(); DBUG_RETURN(0); } /* diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 5111f0690ab..444d2c06075 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -107,6 +107,7 @@ int yylex(void *yylval, void *yythd); #else #define YYDEBUG 0 #endif +#define DEFERRED_OR_NORMAL(A) A ? Sql_condition::WARN_LEVEL_WARN:Sql_condition::WARN_LEVEL_DEFERRED_WARN /** @brief Push an error message into MySQL error stack with line @@ -2476,10 +2477,10 @@ create: LEX *lex= thd->lex; lex->current_select= &lex->select_lex; if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && - !lex->create_info.db_type) + !lex->create_info.db_type && !thd->slave_thread) { lex->create_info.use_default_db_type(thd); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + push_warning_printf(thd, DEFERRED_OR_NORMAL(thd->slave_thread), ER_WARN_USING_OTHER_HANDLER, ER_THD(thd, ER_WARN_USING_OTHER_HANDLER), hton_name(lex->create_info.db_type)->str, @@ -5791,9 +5792,14 @@ storage_engines: else { if (thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION) - my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str)); + { + if (!thd->slave_thread) + my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str)); + else + my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(ME_DEFERRED_ERROR), $1.str); + } $$= 0; - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + push_warning_printf(thd, DEFERRED_OR_NORMAL(thd->slave_thread), ER_UNKNOWN_STORAGE_ENGINE, ER_THD(thd, ER_UNKNOWN_STORAGE_ENGINE), $1.str);