[Commits] 0fa3079ccc9: Mdev-17588 replicate-do filters cause errors when creating filtered-out tables on master with syntax unsupported on slave

sachin.setiya at mariadb.com sachin.setiya at mariadb.com
Mon May 27 19:15:22 EEST 2019


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);


More information about the commits mailing list